SPDK對接Ceph效能優化
作者:天翼雲 譚龍
關鍵詞: S PDK 、 NVM e OF 、 Ceph、 CPU 負載均衡
SPDK是intel公司主導開發的一套儲存高效能開發套件,提供了一組工具和庫,用於編寫高效能、可擴充套件和使用者態儲存應用。它通過使用一些關鍵技術實現了高效能:
1. 將所有必需的驅動程式移到使用者空間,以避免系統呼叫並且支援零拷貝訪問
2. IO的完成通過輪詢硬體而不是依賴中斷,以降低時延
3. 使用訊息傳遞,以避免 IO路徑中使用鎖
SPDK是一個框架而不是分散式系統,它的基石是使用者態(user space)、輪詢(polled-mode)、非同步( asynchronous )和無鎖的 NVMe驅動,其提供了零拷貝、高併發直接使用者態訪問SSD的特性。SPDK的最初目的是為了優化塊儲存落盤效能,但伴隨持續的演進,已經被用於優化各種儲存協議棧。S PDK 架構分為協議層、服務層和驅動層,協議層包含 NVM e OF T arget、vhost-nvme T arget、iscsi T arget、vhost-scsi T arget以及vhost-blk T arget等,服務層包含L V 、 Raid、A IO 、 malloc以及Ceph RBD 等, driver層主要是 NVM e OF initiator、N VM e PCI e、virtio以及其他用於持久化記憶體的driver等。
SPDK 架構
Ceph是目前應用比較廣泛的一種分散式儲存,它提供了塊、物件和 檔案( ) 等儲存服務,SPDK 很早就支援連線Ceph RBD作為塊儲存服務,我們在使用SPDK測試RBD做效能測試時發現效能到達一定規格後無法繼續提升,影響產品的綜合效能,經過多種定位方法並結合現場與程式碼分析,最終定位問題原因並解決,過程如下。
1. 測試方法 :啟動 SPDK nvmf_tgt並繫結0 ~7 號核, . /build/bin/nvmf_tgt -m 0xff ,建立 8個rbd bdev,8個nvmf subsystem,每個rbd bdev作為namespace attach到nvmf subsystem上,開啟監聽,initiator端通過nvme over rdma連線每一個subsystem,生成8個nvme bdev,使用fio對8個nvme bdev同時進行效能測試。
2. 問題 :我們搭建了一個 4 8 OSD 的 Ceph全閃叢集,叢集效能大約4 0 w IOPS ,我們發現最高跑到 2 0 w IOPS 就上不去了,無論增加盤數或調節其他引數均不奏效。
3. 分析定位 :使用 spdk_top顯示0號核相對其他核更加忙碌,繼續加壓, 0 號核忙碌程度增加而其他核則增加不明顯。
檢視 poller顯示rbd只有一個poller bdev_rbd_group_poll,與nvmf_tgt_poll_group_0都執行在id為2的thread上,而nvmf_tgt_poll_group_ 0 是執行在 0號核上的,故bdev_rbd_group_poll也執行在0號核。
[root@test]# spdk_rpc.py thread_get_pollers
{
"tick_rate": 2300000000,
"threads": [
{
"timed_pollers": [
{
"period_ticks": 23000000,
"run_count": 77622,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_tgt_accept"
},
{
"period_ticks": 9200000,
"run_count": 194034,
"busy_count": 194034,
"state": "waiting",
"name": "rpc_subsystem_poll"
}
],
"active_pollers": [],
"paused_pollers": [],
"id": 1,
"name": "app_thread"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5919074761,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
},
{
"run_count": 40969661,
"busy_count": 0,
"state": "waiting",
"name": "bdev_rbd_group_poll"
}
],
"paused_pollers": [],
"id": 2,
"name": "nvmf_tgt_poll_group_0"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5937329587,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
}
],
"paused_pollers": [],
"id": 3,
"name": "nvmf_tgt_poll_group_1"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5927158562,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
}
],
"paused_pollers": [],
"id": 4,
"name": "nvmf_tgt_poll_group_2"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5971529095,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
}
],
"paused_pollers": [],
"id": 5,
"name": "nvmf_tgt_poll_group_3"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5923260338,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
}
],
"paused_pollers": [],
"id": 6,
"name": "nvmf_tgt_poll_group_4"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5968032945,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
}
],
"paused_pollers": [],
"id": 7,
"name": "nvmf_tgt_poll_group_5"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5931553507,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
}
],
"paused_pollers": [],
"id": 8,
"name": "nvmf_tgt_poll_group_6"
},
{
"timed_pollers": [],
"active_pollers": [
{
"run_count": 5058745767,
"busy_count": 0,
"state": "waiting",
"name": "nvmf_poll_group_poll"
}
],
"paused_pollers": [],
"id": 9,
"name": "nvmf_tgt_poll_group_7"
}
]
}
再結合程式碼分析, rbd模組載入時會將建立io_channel的介面bdev_rbd_create_cb向外註冊,rbd bdev在建立rbd bdev時預設做bdev_examine,這個流程會建立一次io_channel,然後銷燬。在將rbd bdev attach到nvmf subsystem時,會呼叫建立io_channel介面,因為nvmf_tgt有8個執行緒,所以會呼叫8次建立io_channel介面,但disk->main_td總是第一次呼叫者的執行緒,即nvmf_tgt_poll_group_0,而每個IO到達rbd模組後b dev_rbd_submit_request 介面會將 IO上下文排程到disk->main_td,所以每個rbd的執行緒都執行在0號核上。
綜合環境現象與程式碼分析,最終定位該問題的原因是:由於 spdk rbd模組在建立盤時bdev_rbd_create_cb介面會將每個盤的主執行緒disk->main_td分配到0號核上,故導致多盤測試時C PU 負載不均衡,效能無法持續提高。
4. 解決方案 :既然問題的原因是 C PU 負載不均衡導致,那麼我們的思路就是讓 CPU 更加均衡的負責盤的效能,使得每個盤分配一個核且儘可能均衡。具體到程式碼層面,我們需要給每個盤的 disk->main_td分配一個執行緒,且這個執行緒均勻分佈在0 ~7 號核上。我們知道 bdev_rbd_create_cb是在每次需要建立io_channel時被呼叫,第一次bdev_examine的呼叫執行緒是spdk主執行緒app_thread,之後的呼叫均是在呼叫者執行緒上執行,比如當rbd bdev attach到nvmf subsystem時,呼叫者所線上程為nvmf_tgt_poll_group_#,因為這些執行緒本身就是均勻的建立在0 ~7 號核上,故我們可以複用這些執行緒給 rbd模組繼續使用,將這些執行緒儲存到一個global thread list,使用round-robin的方式依次分配給每個盤使用,該方案程式碼已推送到 SPDK 社群: bdev/rbd: Loadshare IOs for rbd bdevs between CPU cores (I9acf218c) · Gerrit Code Review (spdk.io) 。打上該 patch後,可以觀察到 CPU 負載變得均衡,效能突破 2 0 w,達到叢集4 0 w能力。
5. 思考回溯 :該問題是如何出現或引入的?我們分析 rbd模組的合入記錄,發現在 bdev/rbd: open image on only one spdk_thread · spdk/spdk@e1e7344 (github.com) 和 bdev/rbd: Always save the submit_td while submitting the request · spdk/spdk@70e2e5d (github.com) 對 rbd的結構做了較大的變化,主要原因是rbd image有一把獨佔鎖 exclusive_lock ,通過 rbd info volumes/ rbd 0 可檢視,這把鎖的作用是防止多客戶端同時對一個 image寫操作時併發操作,當一個客戶端持有這把鎖後,其他客戶端需要等待該鎖釋放後才可寫入,所以多客戶端同時寫導致搶鎖效能非常低,為此這兩個patch做了兩個大的改動:1)對每個rbd bdev,無論有多少個io_channel,最後只呼叫一次 rbd_open ,即只有一個 rbd客戶端,參見介面 bdev_rbd_handle 的呼叫上下文; 2)對每個盤而言, IO 全部收斂到一個執行緒 disk->main_td傳送給librbd。
因為每個盤的 disk->main_td均為第一個io_channel呼叫者的執行緒上下文,所以他們的執行緒都在同一個核上,導致I O 從上游到達 rbd模組後全部匯聚到一個核上,負載不均衡導致效能無法繼續提高。
6. 總結 :在定位效能問題時, C PU 利用率是一個重要的指標, spdk_top是一個很好的工具,它可以實時顯示每個核的繁忙程度以及被哪些執行緒佔用,通過觀察C PU 使用情況,結合走讀程式碼流程,能夠更快定位到問題原因。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70014251/viewspace-2898700/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- glance對接ceph
- Harbor對接Ceph S3推映象retry的問題S3
- OpenStack學習系列之十二:安裝ceph並對接OpenStack
- 【前端效能優化】vue效能優化前端優化Vue
- Spark效能優化:對RDD持久化或CheckPoint操作Spark優化持久化
- 滴滴Ceph分散式儲存系統優化之鎖優化分散式優化
- 對於iOS效能優化的一點看法iOS優化
- 談談你對前端效能優化的理解前端優化
- 效能優化優化
- 分支對程式碼效能的影響和優化優化
- 前端效能優化(JS/CSS優化,SEO優化)前端優化JSCSS
- Android效能優化——效能優化的難題總結Android優化
- [效能優化]DateFormatter深度優化探索優化ORM
- 前端效能優化 --- 圖片優化前端優化
- 效能優化|Tomcat 服務優化優化Tomcat
- Android 效能優化 ---- 啟動優化Android優化
- Android效能優化----卡頓優化Android優化
- Javascript 效能優化JavaScript優化
- java效能優化Java優化
- react效能優化React優化
- Canvas效能優化Canvas優化
- UI效能優化UI優化
- mongodb效能優化MongoDB優化
- Android效能優化Android優化
- EF效能優化優化
- TableView效能優化View優化
- web效能優化Web優化
- mysql效能優化MySql優化
- MySQL——效能優化MySql優化
- Redis 效能優化Redis優化
- python效能優化Python優化
- 效能優化有感優化
- javascript效能優化JavaScript優化
- javasciprt效能優化Java優化
- php效能優化PHP優化
- 效能優化篇優化
- React 效能優化React優化
- JVM效能優化JVM優化