桔妹導讀:Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響,Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上,Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持,Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統,此外,Ceph也廣泛應用在檔案、物件等存盤領域,Ceph在滴滴也支撐了很多關鍵業務的運行,在Ceph的大規模部署和使用程序中,我們發現了Ceph的一些性能問題,圍繞Ceph的性能優化,我們做了很多深入細致的作業,這篇文章主要介紹我們通過除錯分析發現的Ceph在鎖方面存在的問題和我們的優化方法,
1. 背景
在支撐一些延遲敏感的在線應用程序中,我們發現Ceph的尾延遲較差,當應用并發負載較高時,Ceph很容易出現延遲的毛刺,對延遲敏感的應用造成超時甚至崩潰,我們對Ceph的尾延遲問題進行了深入細致的分析和優化,造成尾延遲的一個重要原因就是代碼中鎖的使用問題,下面根據鎖問題的型別分別介紹我們的優化作業,本文假設讀者已熟悉Ceph的基本讀寫代碼流程,代碼的版本為Luminous,
2. 持鎖時間過長
2.1 異步讀優化
Ceph的osd處理客戶端請求的執行緒池為osd_op_tp,在處理操作請求的時候,執行緒會先鎖住操作對應pg的lock,其中,處理物件讀請求的代碼如下圖所示,在鎖住物件所屬pg的lock后,對于最常用的多副本存盤方式,執行緒會同步進行讀操作,直到給客戶端發送回傳的資料后,才會釋放pg lock,
在進行讀操作時,如果資料沒有命中page cache而需要從磁盤讀,是一個耗時的操作,并且pg lock是一個相對粗粒度的鎖,在pg lock持有期間,其它同屬一個pg的物件的讀寫操作都會在加鎖上等待,增大了讀寫延遲,降低了吞吐率,同步讀的另一個缺點是讀操作沒有參與流量控制,
我們對線上集群日志的分析也驗證了上述問題,例如,一個日志片段如下圖所示,圖中列舉了兩個op的詳細耗時資訊,這兩個op均為同一個osd的執行緒所執行,且操作的是同一個pg的物件,根據時間順序,第一個op為read,總耗時為56ms,第二個op為write,總耗時為69ms,圖中資訊顯示,第二個op處理的一個中間程序,即副本寫的完成訊息在處理之前,在osd請求佇列中等待了36ms,結合上圖的代碼可以知道,這36ms都是耗在等待pg lock上,因為前一個read操作持有pg lock,而兩個物件屬于相同pg,
我們的優化如下圖所示,我們創建了獨立的讀執行緒,負責處理讀請求,osd_op_tp執行緒只需將讀請求提交到讀執行緒的佇列即可回傳解鎖,大大減少了pg lock的持有時間,讀執行緒完成磁盤讀之后,將結果放到finisher執行緒的佇列,finisher執行緒重新申請pg lock后負責后續處理,這樣將耗時的磁盤訪問放在了不持有pg lock的流程中,結合我們在流量控制所做的優化,讀寫操作可以在統一的框架下進行流量控制,從而精準控制磁盤的利用率,以免磁盤訪問擁塞造成尾延遲,
我們用fio進行了異步讀優化效果的測驗,測驗方法:對同一個pool的兩個rbd,一個做隨機讀,另一個同時做隨機寫操作,將pg number配置為1,這樣所有物件讀寫會落到同一個osd的同一個pg,異步讀優化后,隨機寫平均延遲下降了53%,下圖為某業務的filestore集群異步讀上線前后讀吞吐率的資料,箭頭所指為上線時間,可見上線之后,集群承載的讀操作的吞吐率增加了120%,
上述優化在使用filestore存盤后端時取得了明顯的效果,但在使用bluestore存盤后端時,bluestore代碼中還存在持有pg粒度鎖同步讀的問題,具體見BlueStore::read的代碼,我們對bluestore的讀也進行了異步的優化,這里就不詳細介紹了,
3. 鎖粒度過粗
3.1 object cache lock優化
Ceph在客戶端實作了一個基于記憶體的object cache,供rbd和cephfs使用,但cache只有一把大的互斥鎖,任何cache中物件的讀寫都需要先獲得這把鎖,在使用寫回模式時,cache flusher執行緒在寫回臟資料之前,也會鎖住這個鎖,這時對cache中快取物件的讀寫都會因為獲取鎖而卡住,使讀寫延遲增加,限制了吞吐率,我們實作了細粒度的物件粒度的鎖,在進行物件的讀寫操作時,只需獲取對應的物件鎖,無需獲取全域鎖,只有訪問全域資料結構時,才需要獲取全域鎖,大大增加了物件間操作的并行,并且物件鎖采用讀寫鎖,增加了同一物件上讀的并行,測驗表明,高并發下rbd的吞吐率增加了超過20%,
4. 不必要的鎖競爭
4.1減少pg lock競爭
Ceph的osd對客戶端請求的處理流程為,messenger執行緒收到請求后,將請求放入osd_op_tp執行緒池的快取佇列,osd_op_tp執行緒池的執行緒從請求快取佇列中出隊一個請求,然后根據該請求操作的物件對應的pg將請求放入一個與pg一一對應的pg slot佇列的尾部,然后獲取該pg的pg lock,從pg slot佇列首部出隊一個元素處理,可見,如果osd_op_tp執行緒池的請求快取佇列中連續兩個請求操作的物件屬于相同的pg,則一個osd_op_tp執行緒出隊前一個請求加入pg slot佇列后,獲取pg lock,從pg slot佇列首部出隊一個請求開始處理,另一個osd_op_tp執行緒從請求快取佇列出隊第二個請求,因為兩個請求是對應相同的pg,則它會加入相同的pg slot佇列,然后,第二個執行緒在獲取pg lock時會阻塞,這降低了osd_op_tp執行緒池的吞吐率,增加了請求的延遲,我們的優化方式是保證任意時刻每個pg slot佇列只有一個執行緒處理,因為在處理pg slot佇列中的請求之前需要獲取pg lock,因此同一個pg slot佇列的請求是無法并行處理的,我們在每個pg slot佇列增加一個標記,記錄當前正在處理該pg slot的請求的執行緒,當有執行緒正在處理一個pg slot的請求時,別的執行緒會跳過處理該pg slot,繼續從osd_op_tp執行緒池的請求快取佇列出隊請求,
4.2 log lock優化
Ceph的日志系統實作是有一個全域的日志快取佇列,由一個全域鎖保護,由專門的日志執行緒從日志快取佇列中取日志列印,作業執行緒提交日志時,需要獲取全域鎖,日志執行緒在獲取日志列印之前,也需要獲取全域鎖,然后做一個交換將佇列中的日志交換到一個臨時佇列,另外,當日志快取佇列長度超過閾值時,提交日志的作業執行緒需要睡眠等待日志執行緒列印一些日志后,再提交,鎖的爭搶和等待都增加了作業執行緒的延遲,
我們為每個日志提交執行緒引入一個執行緒區域日志快取佇列,該佇列為經典的單生產者單消費者無鎖佇列,執行緒提交日志直接提交到自己的區域日志快取佇列,該程序是無鎖的,只有佇列中的日志數超過閾值后,才會通知日志執行緒,日志執行緒也會定期輪詢各個日志提交執行緒的區域日志快取佇列,列印一些日志,該程序也是無鎖的,通過上述優化,基本避免了日志提交程序中因為鎖競爭造成的等待,降低了日志的提交延遲,測驗在高并發日志提交時,日志的提交延遲可降低接近90%,
4.3 filestore apply lock優化
對于Ceph filestore存盤引擎,同一個pg的op需要串行apply,每個pg有一個OpSequencer(簡稱osr),用于控制apply順序,每個osr有一個apply lock以及一個op佇列,對于每個待apply的op,首先加入對應pg的osr的佇列,然后把osr加到filestore的負責apply的執行緒池op_tp的佇列,簡稱為apply佇列,op_tp執行緒從apply佇列中取出一個osr,加上它的apply lock,再從osr的佇列里取出一個op apply,邏輯代碼如下圖左所示,可見,每個op都會把其對應的osr加入到apply佇列一次,如果多個op是針對同一個pg的物件,則這個pg的osr可能多次加入到apply佇列,如果apply佇列中連續兩個osr是同一個pg的,也就是同一個osr,則前一個op被一個執行緒進行apply時,osr的apply lock已經加鎖,另一個執行緒會在該osr的apply lock上阻塞等待,降低了并發度,
這個問題也體現在日志中,一個線上集群日志片段如下圖,有兩個op_tp執行緒6700和5700,apply佇列里三個物件依次來自pg: 1.1833, 1.1833. 1.5f2,執行緒6700先拿到第一個物件進行apply, 執行緒5700拿第二個物件進行apply時卡在apply lock上,因為兩個物件都來自pg 1.1833,直到6700做完才開始apply,而6700拿到第三個物件,即1.5f2的物件進行apply即寫page cache只用了不到1ms,但實際apply延遲234ms,可見第三個物件在佇列里等待了233ms,如果5700不用等待apply lock,則第二和第三個物件的apply延遲可以大大縮短,
我們優化后的邏輯代碼如上圖右所示,同一個osr只加入apply佇列一次,取消apply lock,利用原子操作實作無鎖演算法,上面的演算法可以進一步優化,在將一個osr出隊之后,可以一次從它的佇列中取m(m>1)個op進行apply,在op apply完成階段,改為如果atomic::fetch_sub(osr->queue_length, m) > m,則將osr重新入隊以提高吞吐率,
我們用fio進行了apply lock優化效果測驗,方法為建兩個pool,每個pool的pg number為1,每個pool一個rbd, 對兩個rbd同時進行隨機寫的操作,一個pool寫入資料的量為31k10k,另一個pool寫入資料的量為4k100k, 衡量所有請求apply的總耗時,優化前總耗時434ks, 優化后總耗時45ks,減少89.6%, ### !
團隊介紹
滴滴云平臺事業群滴滴云存盤團隊原隸屬于滴滴基礎平臺部,現隸屬于新成立的滴滴云事業部,團隊承擔著公司在線非結構化存盤服務的研發,并參與運維作業,具體來說,團隊承擔了公司內外部業務的絕大部分的物件、塊、檔案存盤需求,資料存盤量數十PB,團隊技術氛圍濃厚,同時具備良好的用戶服務意識,立足于用技術創造客戶價值,業務上追求極致,團隊對于分布式存盤、互聯網服務架構、Linux存盤堆疊有著深入的理解,
作者介紹
負責滴滴在線非結構化存盤研發,曾任國防科技大學計算機學院副研究員,教研室主任,天河云存盤負責人
延伸閱讀
內容編輯 | Charlotte
聯系我們 | [email protected]
滴滴技術 出品
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/1087.html
標籤:大數據