eBay PB級日誌系統的存儲方案實踐

CAL(Central Application Logging) 系統主要負責收集和處理eBay內部各個應用程序池的日誌,日處理超過3PB的數據,供運維團隊和開發團隊日常監控使用。

CAL系統通過HTTP接口接受應用產生的日誌,將日誌持久化到經NFS掛載的網絡存儲上, 用戶(運維團隊和開發團隊)可以通過CAL系統方便地查找、查看日誌。同時,日誌也會被導入Hadoop進行進一步的分析形成報告。該系統自21世紀初至今,已經有10多年的歷史了。

CAL從第一天起就運行在Netapp的商業存儲上。隨着業務的發展,業務產生的數據量急劇增加,單個存儲集羣已經無法承載 CAL的流量和性能需求,存儲團隊和業務團隊通過增加集羣來解決性能問題。一直到2018年,CAL在每個數據中心已經需要25個集羣才能支撐起其性能需求。

雖然統計上,CAL只使用了eBay 5%的NFS Filer總容量,但實際上卻消耗了50%的總性能。性能和容量的巨大偏離,使得實際成本已經比該存儲方案的裸$/GB成本高了一個數量級。

高成本,疊加上由eBay業務驅動的每年30%自然增長,這套架構亟需重構優化。

2014年,eBay 存儲團隊開始在公司內將Ceph應用於生產環境。第一階段主要是RBD塊設備服務。

2017年,Jewel版本發佈後,我們開始嘗試提供CephFS分佈式文件系統服務,多個天使應用從商業存儲遷移到CephFS上,從中我們發現修復了MDS的多個bug並貢獻回社區,也在社區首次完成了MDS的性能分析。

2018年,隨着MDS多活功能的初步成熟,我們也和業務團隊一起,開始了把CAL遷移到CephFS上的征程。

2019年初上線至今,Ceph在大流量下穩定運行。平均讀寫帶寬同時超過了3GB/S,讀寫請求數合計超過100K IOPS(每秒進行讀寫操作的次數), 文件系統元數據操作數超過30K OP/S(每秒操作次數)。

01 總體設計

通過對CAL現有業務邏輯和歷史性能數據的分析,我們明確了設計目標

1)文件系統元數據路徑,支持100K OP/S ,包括:create / getattr / lookup / readdir / unlink等文件系統操作;並預留足夠的升級空間滿足業務發展。
2)文件系統的數據路徑,支持150K IOPS(50%讀,50%寫),以及至少6GB/S(50%讀,50%寫)的吞吐。
3)單集羣容量需求300TB 可用空間,滿足性能需求的前提下儘可能降低存儲成本。

這個略顯激進的設計目標,其實在很大程度上已經決定了我們的方案。

  • 基於我們之前針對Ceph MDS的性能研究,單MDS只能支持2K ~ 4K OP/S, 要支持100K OP/S,MDS多活負載均衡集羣是唯一的路徑。至少需要25個MDS Active-Active 組成集羣。同時,業務負載還要能相對均衡地分佈到每個MDS上。
  • 150K IOPS的讀寫性能,如果單用機械硬盤HDD,需要至少1500塊盤,可用容量接近3PB,又回到了用盡性能而浪費容量的老路。如果全部用SSD1PB 裸容量的SSD 雖然能比商業存儲省錢,但仍是一筆不小的數字。針對日誌數據有明顯冷熱度的特點,使用分層存儲,把頻繁訪問的數據放在SSD上,相對冷的數據放在HDD上,才能達到最佳費效比。

02 實現細節

1. MDS多活負載均衡集羣

要實現向外擴展(scale-out)的架構,核心是任務分配,把負載相對均等地分配到每個MDS上。對於文件系統來說,整個目錄結構是一棵樹。任務分配的本質,是通過設計目錄樹的結構,使得葉子(文件)平均地長在這顆樹的每個枝幹(目錄)上。同時,每個層次的文件/文件夾個數必須是可控且相對均衡的,這樣才能儘量降低樹的深度,避免對一個巨大文件夾進行ListDir操作帶來的延遲和開銷。

CAL原先的目錄層次如下圖1所示,一共有15層,100多萬個文件夾,幾乎違反了上面討論的所有原則,目錄過深且不均衡。eBay每個pool承擔一個服務,每個服務的流量,服務器數量差異顯著。更糟糕的是整個目錄樹,在每個小時開始的時候,幾乎完全重建(虛線部分),導致每小時開始時元數據操作風暴。

圖1(點擊可查看大圖)

針對這個問題,我們和CAL團隊合作設計並實現了一套新的目錄層次,如圖2所示:

圖2(點擊可查看大圖)

1)在根目錄下建立1024個BucketClient(CAL的Client,其實是業務APP服務器)通過哈希映射到其中一個bucket下。由於哈希的(統計意義)均衡性,每個Bucket裏的Client文件夾數量是均衡的。而Client文件夾的總數,和業務APP服務器的總數對應。
雖然虛擬化、容器化使得Client越來越小,越來越多,但因爲Bucket數量足夠多,每個Bucket下的文件夾數依舊是可控的。而對於每個Client文件夾裏的文件數,根據配置,每小時產生5-20個不等的文件,文件總數 = 5~20/hour * rotation_hours。可見,其文件數也是可控的
2) Bucket 通過auth_pin ,綁定到MDS_rank上, 簡單來說:

auth_pin = bucket_id % NUM_MDSs

基於之前討論的Bucket均衡性,以及所有Bucket被均衡地分佈到各個MDS。可見,MDS的負載也是均衡的
除此之外,我們也預留了拓展性。當前我們用了33個MDS 做了AA,其中32個MDS分別綁定了32個Bucket,rank 爲0的MDS綁定到了根目錄。日後,只需要增加MDS的數量,例如從33(32+1)增加到65(64+1),修改auth_pin 綁定關係,就能在客戶不感知的情況下實現無縫擴容。

2. Cache Tier

Ceph Cache Tier是一個在誕生之初被抱以巨大期望,而在現實中讓不少部署踩坑的技術,尤其是在RBD 和CephFS上。在社區郵件組和IRC裏最經常出現的問題就是應用了Cache Tier,性能反而下降了。

其實,那些場景多數是誤讀了Cache Tier的應用領域。Cache Tier的管理粒度是Object(默認4MB), 而在RBD/CephFS上的用戶IO通常明顯小於4MB。當用戶訪問未命中,Cache Tier決定將這個Object從Base Tier 緩存到 Cache Tier時, 付出了OBJ_SIZE 大小的慢速讀(Base Tier)加上 OBJ_SIZE大小的快速寫(Cache Tier)。

只有後續用戶對同一個Object的重複訪問達到足夠多的次數,才能體現Cache Tier的性能和成本優勢。例如,業務負載是隨機IO,平均請求大小4KB,則命中率必須達到**99.9%**以上。

現實是許多業務負載並沒有這樣的特性。

在CAL的業務模型裏,典型的IO負載是應用日誌每隔一分鐘或者128KB觸發一次寫入。同時,讀取端不斷地追蹤日誌,以同樣的間隔把數據讀走。針對這個特點,我們決定將Cache Tier配置成爲一個Writeback Cache(回寫式緩存), 這樣就能實現多個目的

1)寫入緩衝與合併。Cache Tier的設計容量足夠緩存一小時的寫入量,不論業務的寫入請求大小是多少,都會被Cache Tier吸收,以OBJ_SIZE(4M)爲單位刷回Base Tier。4M的大塊寫,是對HDD最友好的訪問行爲,可以最大化Base Tier的吞吐量。
2)讀取緩存。CAL的讀取行爲也大多集中在對最近一個小時寫入數據的讀取。這部分數據在Cache Tier裏,所以讀請求也能基本全部命中Cache Tier。
3)故障隔離。機械硬盤的故障率比SSD高几個數量級,並且更容易因壞道導致響應時間增長,從而使得Ceph集羣出現慢請求(slow request)。表現在服務質量上,就是延遲相對不穩定且尾延遲(tail latency)特別長。藉助Cache Tier的緩衝,業務並不會直接感受到由全機械硬盤構成的Base Tier的性能抖動,從而達到更好的性能一致性。

值得一提的一個優化點是:我們通過禁用Hitset關閉了Proxy Write這個功能。Ceph Cache Tier的默認行爲是Proxy Write——即若待寫入數據在Cache Tier不命中,Cache Tier會直接把請求寫入Base Tier,並在寫入完成後纔將結果返回給應用。

這是一個正確的設計,主要是爲了避免寫請求不命中時promote帶來的額外延遲,並解耦數據寫入邏輯和 Cache Promote邏輯。

但在eBay日誌的應用場景中,因爲寫入行爲的順序性和日誌不可變更的特性,可以明確知道寫入不命中一定是因爲寫入了一個新的Ceph Object,而非對老Object的改寫,因此proxy write的邏輯就帶來了額外的開銷

例如,對obj x 的第一次寫入, write(obj_x, 128kb),在默認的Proxy Write行爲下,這個寫被proxy到了Base Tier。寫入成功後,在Base Tier留下128KB的object,然後Cache Tier再把obj_x 從Base_tier promote上來。

而關閉proxy write後,則先對obj_x做一次promote,在Cache Tier中產生一個空對象,再直接寫入128KB數據即可。

相比之下,後者節約了Base Tier一次128KB寫和一次128KB讀,對於由全機械硬盤構成的Base Tier來說,這樣的節約意義重大,並且應用的寫入延遲大大降低了。這部分Ceph具體代碼,可以閱讀PrimaryLogPG::maybe_handle_cache_detail的實現。

其他的配置優化包括設置min_flush_age和min_evict_age來保證最近一小時的數據不會被刷出Cache,以及對target_max_byte, target_dirty_ratio, target_dirty_ratio_high的調整,在此不一一贅述。

通過上述一系列優化, 如圖3所示,在寫入側, Cache Tier非常好地完成了寫入緩衝與合併,來自應用的25K IOPS經由Cache Tier緩衝與合併之後到Base Tier(fs_data)寫入請求只有1.5K IOPS。

換句話說,通過Cache Tier我們減少了94的寫IOPS

圖3 集羣客戶端寫入性能(點擊可查看大圖)

而在讀取側,如圖4所示,幾乎所有的IO都在Cache Tier上發生,Base Tier 讀流量近乎爲0

圖4 集羣客戶端讀取性能(點擊可查看大圖)

綜合來看, 在Cache Tier上的總IOPS達到了70K,而Base Tier 只有1.5K IOPS。通過深入理解業務的IO模型,合理配置Cache Tier,我們實現了分層存儲

應用享受到了全閃存集羣的性能,成本上卻接近全機械盤的價格,實現了了性價比最大化

03 遇到的問題

下面分享幾個在實施日誌存儲方案中遇到的軟硬件問題,附上我們的解決方案,以供大家參考。

1. Bluestore Allocator(空間分配器)

在上線過程中,我們很順利地度過了25%, 50%的流量。但在75%流量時,遇到了詭異的性能問題

如下圖5所示,Cache Tier 的寫入延遲暴增,甚至能達到分鐘級別,通過OSD Performance Counter很快把問題縮小到Bluestore內部, 結合日誌發現延遲主由STATE_KV_COMMITING_LATSTATE_KV_COMMITING_LAT約等於 commit_lat。

我們第一個懷疑的對象是RocksDB的性能,尤其是compaction帶來的影響,並在此做了大量的調優,然而一無所獲。

但我們發現,在調優的過程中,爲了修改參數重啓OSD服務後,被重啓的OSD能保持20小時良好性能,之後延遲慢慢衰減到重啓以前。既然重啓OSD能暫時緩解問題,那RocksDB就沒有嫌疑了

圖5 Bluestore commit latency性能監控
(點擊可查看大圖)

如下圖6所示,進一步觀察分析性能計數器(performance counter)的數據並結合代碼,我們注意到:STATE_KV_DONE_LAT雖然平均值只有STATE_KV_COMMITING_LAT的3%,但與STATE_KV_COMMITING_LAT有明顯的相關性。

這個發現大大縮小了問題的範圍,因爲STATE_KV_DONE_LAT 所覆蓋的代碼範圍基本只包含_txc_finish 這一個函數。在某些時候,_txc_finish 釋放空間後,需要等待超過100毫秒才能獲得分配器的鎖。同時,perf 的結果也指向了StupidAllocator這個循環

圖6(點擊可查看大圖)

如下圖7所示,進一步分析日誌,我們發現在StupidAllocator中的空間碎片非常嚴重。雖然磁盤利用率不超過50%,但分配器裏已經沒有超過256K數據段(segment)可供分配。這就解釋了爲什麼StupidAllocator 會在上述的分配空間循環中耗費大量時間。因爲分配時持有了分配器鎖,所以釋放空間時需要等待很長時間來獲得鎖。

圖7(點擊可查看大圖)

通過分析Bluestore的分配表,我們發現其實物理空間並沒有碎片化,只是StupidAllocator在內存中的實現導致了碎片化

StupidAllocator是一個類似於內存管理中Buddy分配的一個實現。

通過下圖8的例子,我們看看碎片是如何產生的

一個20K的連續空間,經過5次4K分配,和亂序的5次對應的4K釋放後,會變成8k+4k+8k三塊空間。

其中[8K, 12K) 區域已經是個碎片,但因爲和周邊區塊不是同樣大小,落到不同的bin中,已經很難再被合併了,而類似的操作序列,在Bluestore日常面臨的空間分配回收請求中並不鮮見。

OSD重啓過程中, 分配器的內存結構會根據磁盤上的位圖重新建立,恰好是一次全局的合併,這也就解釋了爲什麼重啓服務能暫時緩解這個問題

圖8(點擊可查看大圖)

我們首先在社區發現定位了這個問題,並與核心開發者一起驗證了Naultilus中的位圖分配器(Bitmap Allocator)沒有類似問題,且性能表現更爲穩定。因此也使得位圖分配器被完整地反向移植到Luminous和Mimic 版本中,併成爲默認分配器。

2. 應對SSD穩態性能下降

關於SSD性能有一個並不冷門的常識——SSD的穩態性能與標稱性能不一定是一致的。對於普通數據中心級別的SSD來說,穩態性能通常比非穩態性能低(相應的,非穩態可以認爲SSD尚有足夠空間供分配,或者後臺維護行爲對業務IO無干擾),非寫入密集型的型號差距會尤其明顯。

SSD進入穩態是需要一定寫入量和時間的,因此在做硬件性能和軟件性能調優時需要將這個因素充分考慮進去,否則實際產品運行起來以後就會出現意料不到的問題。

圖9是我們實測某DWPD0.7的產品穩態與非穩態性能比較。藍色線是穩態性能,橘色線是非穩態性能(對SSD做了全盤TRIM)。

圖9 SSD穩態與非穩態性能對比
(點擊可查看大圖)

受限於成本以及當前可用服務器選擇,我們所採用的SSD即屬於非寫入密集型(DWPD較低),同機型同容量,來自3個不同廠商的SSD的DWPD分佈在0.7~1之間。而eBay日誌存儲Cache Tier恰好是寫入讀取都很密集的類型。這下,我們似乎面臨了巧婦難爲無米之炊的困境。

基於我們對SSD實現原理的理解,非寫入密集型SSD(DWPD指標低)穩態與非穩態性能差距大的主要原因之一是廠商針對這類SSD的產品設計上,出廠預留的Over Provision空間較小。

當合理的產品設計面臨“不合理”的業務需求時,大寫入壓力持續一段時間以後,SSD固件做空間整理垃圾回收(GC)的效率會變低。應用端的表現是在持續的大負載寫入下,GC發生時延遲和吞吐都會受到很大的負面影響。

分析完這個可能原因後,在無法變更硬件的前提下,我們的解決辦法是通過主動預留空間,來彌補廠商原有OP先天不足的“缺點”

在SSD被加入集羣前,我們對全盤TRIM之後,分區時只使用80%的空間;留下20%被TRIM過的區域因爲在固件FTL中標記爲空閒,自然會在GC等操作的時候當作緩衝來使用。加上這額外的20% OP後,我們SSD的寫入延遲和帶寬都能穩定在最佳狀態(圖9中橘色線的性能)。

這套實踐應用在同機型、多批次來自3個不同廠商的SSD上都獲得同樣好的效果,上線至今並未觀察到衰減。

那麼20%的空間預留是目前的經驗值,當應用行爲有所改變時SSD性能再次衰減又該怎麼應對呢?需要停下服務重新修改預留空間大小嗎?

其實不然,對於已經衰減的SSD, 只需要TRIM 20 的區域提供OP,再經過一個完整的寫入週期後,性能就可以回升到最佳狀態

圖10展示的就是這樣一個過程,在模擬測試開始約600秒時,性能開始大幅下降,此時對預留的20%區域做TRIM,經過一個多小時,性能逐步回升,最終回到峯值並持續穩定下去。

圖10 對預留區域TRIM恢復全盤性能測試
(點擊可查看大圖)

在這裏需要指出:上述經驗是我們基於存儲產品的理解和合理猜測基礎上,經測試驗證通過,並在生產中應用的。限於條件和知識所限,我們無法進一步探究OP是否是同系列不同定位的SSD產品之間的主要差別

通過我們所接觸的有限樣本中的數據,可得出以下觀點:讀密集型SSD 加上大的OP,能達到同系列寫入密集型SSD同樣的性能和可靠性,但我們並不確定該經驗是否在更大範圍內具有通用性。這裏僅供讀者參考,也歡迎來自各廠商的專家提供更多的分享。

04 總結

在eBay存儲團隊和業務團隊的無縫合作下,我們完美地將eBay應用的日誌從商業存儲遷移到了CephFS上,達到了非常高的性能和費效比(遷移給eBay帶來的成本下降在單數據中心達數百萬美金)。整個方案沒有單點和瓶頸,各個部分均可以橫向拓展,支撐更高的性能和吞吐。

CephFS由於成熟得相對晚,在國內外的大規模商用案例有限,更多的被作爲歸檔和冷存儲使用,較少有大流量的線上業務應用。儘管我們比較激進的使用了MultiMDS多活Cache Tier等當前在業界還較少部署的技術,但CephFS在大流量的生產環境中證明了自己的價值和穩定性,爲其他eBay內部應用遷移到CephFS打下了堅實的基礎

本文轉載自公衆號eBay技術薈(ID:eBayTechRecruiting)

原文鏈接

https://mp.weixin.qq.com/s/vUrp6Nyj06lsq8mZGR2n8g

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章