人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

背景

經過幾年的努力,58同城已經自研了4款分佈式存儲產品。分別是Key-Value、Key-List、對象存儲、共享文件系統。其中分佈式Key-Value存儲WTable是最早開發的,在集團內使用最為廣泛,甚至對象存儲與共享文件系統都是用WTable來存儲Meta信息。WTable的開發大致上可以分成三個階段,2015年發佈第一版,滿足了業務的核心需求。第二階段重點優化了讀寫性能與請求延遲,提高運維自動化與速度。第三階段從2019年開始,分步引入NewSQL的相關技術,為業務提供更人性化與更高效的使用體驗。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

WTable第一階段

在WTable之前58存儲主要使用MySQL+Cache。當數據量太大時需要做分庫分表,若數據增量又很大就需要定期做擴容,非常耗時費力。因此對WTable的核心需求總結為:擴容、可用性、高性能、擴展能力。為了簡化架構,在設計上引入了兩個外部組件:ETCD用作配置中心與多副本選主,Rocksdb作為數據節點的存儲引擎。通過代理服務層對請求進行路由,存儲節點以Group為單位,每個Group中通常是一主兩備,主備之前通過異步實時同步來保持數據最終一致。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

WTable將數據分成2048個Slot,Key哈希之後對2048取模,作為該Key所屬的Slot。Proxy本地緩存著每個Slot所屬的Group以及每個Group的存儲節點列表。當請求到來時根據Slot將請求轉發到後端的存儲節點。當存儲空間不夠或者寫性能不足時可以通過增加Group方式來擴展。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

為了應對各種異常,WTable使用了多級容災策略。首先客戶端會定期從NameCenter拉取Proxy列表以感知Proxy的列表的更新。取到列表之後每2秒會檢測Proxy是否正常,若多次檢測異常則會將其加入黑名單。Proxy也會檢測後端存儲節點。如果Master角色異常則會通過ETCD自動選舉新的Master,若是Slave異常自動被Proxy屏蔽。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

為了儘可能提高KV使用的靈活性,WTable還提供了豐富的操作接口,如,樂觀鎖,自動過期等,而且對其中大多數接口都提供了批量操作支持。從2015年上線至今,線上幾十個集群,存儲著有百T的數據量,日請求量達到三千億,為一千多個業務提供服務。

WTable第二階段

第二階段主要通過研究Rocksdb來獲取性能的提升以及運維速度的提高。首先將Rocksdb版本從3.11升級到5.15,並且對Rocksdb參數進行優化,讀寫性能與延遲都有很大的提高。當寫入量大時,底層Compaction會階段性地產生IO峰值。在這些IO峰值處,讀寫延遲會變高。經過調研,Rocksdb有成熟的Comapction限速方案。通過設置AutoTune以及磁盤IO上限能夠自適應Compaction與寫入量的關係。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

運維主要涉及換機器時的加備機,磁盤空間不夠時的擴容操作。原先這兩個操作速度較慢,在應對一些突發情況時比較捉急。加備機操作原先的方法是在主機上創建迭代器,把KV遍歷出來依次寫到新備機。瓶頸出現在KV的遍歷上,因為這個操作非常耗IO,快了會影響線上服務,因此必須限速。另外由於迭代器沒有及時釋放可能會出現為了加備機導致主機磁盤空間告警的悲劇。經過調研,其實Rocksdb提供了Checkpoint這種非常友好的數據同步方式。得益於LSM存儲結構中的SST寫入後不會被修改,因此Checkpoint只需要為當前版本所有SST文件創建硬鏈即可,整體耗時只需要幾百毫秒。創建完成之後,發送SST文件到新備機,幾乎不消耗IO,瓶頸只剩下網絡帶寬了,對於萬兆網卡的機器,速度可以輕鬆達到三五百兆。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

集群的擴容涉及到數據的遷移,WTable的擴容以Slot為單位進行。當增加一個Group之後,通過Manager服務會計算好每個Group需要承載的Slot個數,然後制定遷移計劃,按照Slot進行遷移。每完成一個Slot遷移相應更新ETCD中的路由配置信息。但是這種方式有一個瓶頸就是在遷移的過程中,前面遷移的Slot已經提供線上服務。新的Slot遷移會有大量數據寫入,會影響線上服務。例如:總共有8個Slot需要遷移,當遷移第5個Slot時前面四個Slot已經提供線上服務。

為了避免這種影響,不再以Slot為單位進行數據遷移,而是將所有待遷移的Slot作為一個整體進行。接上例:先對這8個Slot做全量同步,然後對這8個Slot做增量同步,最後修改ETCD中的路由信息。數據擴容完成之後需要從原Group中刪除,以釋放空間。原刪除是遍歷出Key,然後依次刪除,非常消耗IO,而且速度很慢。現在優化成先通過DeleteFileInRange接口把完全處於待刪除Key範圍的SST文件直接刪除,然後通過CompactRange+CompactFilter組合把剩餘的數據刪除。整體耗時非常短,IO消耗非常低,達到及時釋放存儲空間的目的。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

WTable第三階段

第三階段,目的是引入NewSQL相關技術提高WTable的使用效率。第一步就是提供強一致性版本。為了實現強一致,需要使用一致性協議。最初計劃是使用ETCD中的Raft實現,將其修改成MultiRaft。後來發現有一個DragonBoat開源庫,其有非常高的測試覆蓋率以及讀寫性能。經過實際測試,在有足夠併發時其整體吞吐量相對於異步複製高,但是每個請求延遲也相對較高,因為需要走一遍Raft協議流程。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

在強一致性版本中儘量保持了原先的設計,依然保持2048個Slot,每個Slot的數據通過一個RaftGroup來實現同步。而這個Slot多副本的分佈則在整個集群內自動均衡。原先的固定主備關係已經不存在,Leader的選舉也不再需要ETCD,因為每個RaftGroup自動會選舉Leader。在Proxy中依然緩存著路由信息,並通過ETCD來實時更新。

擴容時只需要增加機器即可,WTable會自動計算每臺機器應該承載的Slot個數,並做數據遷移。擴容過程首先將節點以Observer方式加入到RaftGroup中開始做數據同步。當數據同步完成之後將該節點提升為Follower,並更新ETCD中的路由信息,接著去所有Proxy確認信息已經更新。然後把一個老節點從ETCD的路由信息中移除,再去Proxy確認。最後才將該節點真正從RaftGroup中移除。通過這兩次確認可以保證路由信息的準確。

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐

目前強一致性版本的WTable已經開發完成,後面計劃開發分佈式事務。對於KV類的存儲,分佈式事務的支持能夠很好地提高業務數據的邏輯一致性。最後在WTable基礎上支持常用的SQL語法,這些都已完成,實際上可以算是一個簡化版的NewSQL了。



總結

每個系統在設計階段會有很多變量,需要充分考慮業務核心需求與痛點以及當前可用資源後做出權衡,最終得到一個業務可接受、資源消耗可控的設計。WTable的迭代過程,就是平衡各方面因素的結果。第一階段重點解決容災、高性能等核心需求,但是在集群運維方面有很多不足,第二階段重點解決了這些問題,第三階段考慮如何提供更好的用戶體驗。一個好的系統總是慢慢進化而來,相信WTable未來會更好用,更高效。

謝謝大家!

人物|鍾昌壽:58同城分佈式存儲系統架構設計和優化實踐


歡迎大家關注“58技術”微信公眾號,“58技術”是58官方技術號,58技術創新、分享與交流平臺。


分享到:


相關文章: