Ceph運維告訴你:如何駕馭開源分布式存儲?
過去兩年,我的主要工作都在 Hadoop 這個技術棧中,而最近有幸接觸到了 Ceph。
我覺得這是一件很幸運的事,讓我有機會體驗另一種大型分布式存儲解決方案。
因此我可以對比出 HDFS 與 Ceph 這兩種幾乎完全不同的存儲系統分別有哪些優缺點、適合哪些場景。
站在一個 SRE 的角度,對于分布式存儲,尤其是開源的分布式存儲,我認為主要為商業公司解決了如下幾個問題:
- 可擴展性,滿足業務增長導致的海量數據存儲需求。
- 比商用存儲便宜,大幅降低成本。
- 穩定,可以駕馭,好運維。
總之目標就是:又好用,又便宜,還穩定。但現實似乎并沒有這么美好……
本文將從這三個我認為的根本價值出發,分析我運維 Ceph 的體會,同時對比中心化的分布式存儲系統,比如 HDFS,橫向說一說。
可擴展性
Ceph 聲稱可以無限擴展,因為它是基于 CRUSH 算法,沒有中心節點。 而事實上,Ceph 確實可以無限擴展,但 Ceph 的無限擴展的過程,并不美好。
首先梳理一下 Ceph 的寫入流程:Ceph 的新對象寫入需要經過 PG 這一層預先定義好的定額 Hash 分片,然后 PG,再經過一次集群所有物理機器硬盤 OSD 構成的 Hash,最后落到物理磁盤。
因此,Ceph 的所有對象,是先被 pre-hash 到了一個固定數量的桶(PG)當中,然后根據集群的整體物理架構 crushmap,選擇落在具體的機器磁盤上。
這對擴容有什么影響呢?
擴容粒度
我給擴容粒度的定義是:一次可以擴容多少臺機器。
Ceph 在實踐中,擴容受“容錯域”制約,一次只能擴一個“容錯域”。
容錯域就是:副本隔離級別,即同一個 Replica 的數據,放在不同的磁盤/機器/Rack/機房。容錯域這個概念,在很多存儲方案里都有,包括 HDFS。
為什么 Ceph 會受影響呢?因為 Ceph 沒有中心化的元數據結點,導致數據放置策略受之影響。
數據放置策略,即一份數據 replica,放在哪臺機器,哪塊硬盤。
中心化,比如 HDFS,會記錄每一個文件,下面每一個數據塊的存放位置。
這個位置是不會經常變動的,只有在文件新創建、Balancer 重平衡、有硬盤壞了,中心節點針對損壞硬件上的數據重新放置時才會改變。
而 Ceph,因為去中心化,導致容納數據的 PG 的位置,會根據 Crushmap 的變化而變化。
來了新的機器、硬盤,就要為一些受影響的 PG 計算新的位置。基于一致性哈希的技術,在擴容時也要面臨同樣的問題。
因此,Ceph 擴容需要 PG 們調整。正因為這個調整,導致 Ceph 受“容錯域”制約。
例如:有一個 PG,是 3 副本,Ceph 集群有一個配置是 PG 要向外提供正常服務,至少有 2 個完整的副本。
而當這個數據 Pool 的容錯域是 Host 時,同時擴容 2 臺機器,一些 PG 就有可能把 3 副本中的 2 個都映射到 2 臺新機器上去。
而這 2 個副本都是新副本,都沒有完整的最新數據。剩下的一個副本,無法滿足老機器至少有完整的 2 副本的要求,也就不能提供正常讀寫服務了。
這就會導致這個 PG 里的所有對象,停止對外服務。
作為 Admin,當然可以把配置降低,把數據 Pool 的 min_size 下降為 1。但這種配置,即使在正常情況下,因為磁盤故障,都有可能丟失數據,因此一般不會這樣設置。
那在擴容時,一次只擴容一臺機器時,是不是就安全了呢?
這樣就能保證所有 PG 都至少在老機器有 2 個完整的副本了。可是,即使是擴容一臺機器,也還要面臨擴容時老機器中有硬盤壞掉,導致 PG 的完整副本又下降為 1 的極端情況發生。
雖然 PG 有可能不能服務,但數據的持久性是沒有問題的。國內 AT 的云,服務可靠性都沒有做得特別高,做到像持久性那樣 3 個 9、4 個 9。
雖然我不確定這兩朵大云里的對象存儲是不是使用的 Ceph,但只要是基于類似 CRUSH 算法,或者一致性哈希等類似的去中心化技術實現的對象存儲,應該都會面對部分數據暫時不可服務的情況。
我們拋開最極端的情況,即假設在擴容時,以一個“容錯域”加入機器時,暫時沒有磁盤損壞。那么有沒有辦法可以提升擴容粒度呢?
辦法是,在開始規劃 Ceph 集群時,設定好更大層次的“容錯域”,比如 Rack。
可以是真實的 Rack,即使沒有也可以是邏輯的 Rack。這樣擴容時,可以擴一個邏輯“容錯域”,就可以打破擴一臺機器的限制,擴一整個 Rack,至少有好幾臺機器。
Tips:這里我沒有講為什么擴容粒度小是個不好的事。在很多公司,數據的日均增長量是很有可能大于一臺機器的存儲容量的。
這就會造成擴容速度趕不上寫入速度的尷尬局面。這對于開始沒有設計好,圖快速 Deploy 而架設的集群,在后期是一個不小的傷害。
擴容時 crushmap 的改變
Ceph 是根據 crushmap 去放置 PG 的物理位置的,倘若在擴容進行了一半時,又有硬盤壞掉了,那 Ceph 的 crushmap 就會改變,Ceph 又會重新進行 PG 的 re-hash,很多 PG 的位置又會重新計算。
如果運氣比較差,很可能一臺機器的擴容進度被迫進行了很久才回到穩定的狀態。
這個 crushmap 改變導致的 Ceph 重平衡,不單單在擴容時,幾乎在任何時候,對一個大的存儲集群都有些頭疼。
在建立一個新集群時,硬盤都比較新,因此故障率并不高。但是在運行了 2-3 年的大存儲集群,壞盤真的是一個稀松平常的事情,1000 臺規模的集群一天壞個 2-3 塊盤很正常。
crushmap 經常變動,對 Ceph 內部不穩定,影響真的很大。隨之而來,可能是整體 IO 的下降(磁盤 IO 被反復的 rebalance 占滿),甚至是某些數據暫時不可用。
所以總的來說,Ceph 的擴容是有那么一丁點不痛快的。Ceph 確實提供了無限的擴展能力,但擴容過程并不平滑,也不完全可控。
crushmap 的設計,達到了很好的去中心化效果,但也給集群大了之后的不穩定埋下了一個坑。
而對比中心化元數據的 HDFS,在擴容時幾乎無限制,你可以撒歡地擴容。老數據的搬遷,重平衡都會由單獨的 Job 來處理,處理也很高效。
它采用了滿節點和空節點兩兩配對的方式,從老節點移動足夠的數據,填滿新機器即可。中心化元數據在擴容&重平衡時,反而變成了一個優點。
擴容到一定量級后,PG 數量需調整
如上文的 Ceph 數據寫入流程圖所示,Ceph 對象的最小放置單位是 PG,PG 又會被放在硬盤上,PG 理論上肯定是越大越好。
因為這樣數據的分片隨機性更好,更能掩蓋偽隨機造成的單塊盤容量偏差過大問題。
但 PG 數量在現實中不是越大越好的,它要受限于硬件,如 CPU、內存、網絡。因此我們在規劃 PG 數時,不會盲目調大,一般社區也是建議 200pg / osd。
假設我們現在有 10 臺機器,每臺一塊硬盤一共 10 塊盤,有 1024 個 PG,PG 都是單副本,那么每個盤會存 100 個 PG。
此時這個設置非常健康,但當我們集群擴容到 1000 臺機器,每臺硬盤就只放一個 PG 了,這會導致偽隨機造成的不平衡現象放大。因此,Admin 就要面臨調整 PG 數量,這就帶來了問題。
調 PG,基本也就意味著整個集群會進入一種嚴重不正常的狀態。幾乎 50% 的對象,涉及到調整后的 PG 都需要重新放置物理位置,這會引起服務質量的嚴重下降。
雖然調整 PG 不是一個經常性的事件,但在一個大型存儲,隨著發展,不可避免會經歷這個大考。
比商用存儲便宜
我們所說的和商業存儲比較,一般就是和 EMC、IBM 這類硬件軟件存儲解決方案廠家,或者云解決方案 Aliyun、AWS 之類的對比。
自己建設機房,當然在硬件單價上更為便宜,但需要考慮綜合成本,包括:
- 硬件成本
- 自養運維人員成本
- 服務質量由一般向好慢慢收斂
人的成本這種玄學的問題,我就不談了,本文只談 Ceph 在硬件成本這塊有什么有趣的地方。
講道理,自己建機房,硬件成本應該是毫無疑問的便宜,那么 Ceph 在這里有什么特殊呢?問題在于,集群可靠利用率。
集群可靠利用率,即整個集群在容量達到某個水平時不可對外服務,或者說不能保持高可用的服務。
打個比方,我們的手機閃存/電腦硬盤,是不是到 99% 了還能正常工作?當然,因為是本地存儲嘛。對于云解決方案,也天然就沒有這個問題了。
對于商用存儲解決方案,比如 EMC 的 Isilon 分布式文件系統,存儲容量達到甚至 98-99%,仍能對外提供服務。
對于 HDFS,在 95% 以下,存儲也能很好地對外提供服務。跑在 HDFS 上的 Hadoop Job,會因為沒辦法寫入本地而掛掉。
而對于 Ceph,在這一塊表現得并不好。根據經驗,在集群整體使用率達到 70% 后,就有可能進入不穩定的狀態。
這是為什么呢?問題在于,去中心化帶來的 tradeoff。
Ceph 是去中心化的分布式解決方案,對象的元數據是分布在各臺物理機上的。因此所有對象,是被“偽隨機”地分配到各個磁盤上的。
偽隨機不能保證所有磁盤的完全均勻分配,不能降低很多大對象同時落在一塊盤上的概率(我理解加入一層 PG,又使 PG 多 replica,是可以讓磁盤的方差變小的),因此總有一些磁盤的使用率會高出均值。
在集群整體使用率不高時,都沒有問題。而在使用率達到 70% 后,就需要管理員介入了。
因為方差大的盤,很有可能會觸及 95% 這條紅線。Admin 開始調低容量過高磁盤的 Reweight。
但如果在這一批磁盤被調整 Reweight 沒有結束時,又有一些磁盤被寫滿了,那管理員就必須被迫在 Ceph 沒有達到穩定狀態前,又一次 Reweight 過高的磁盤。
這就導致了 crushmap 的再一次變更,從而導致 Ceph 離穩定狀態越來越遠。而此時擴容又不及時的話,更是雪上加霜。
而且之前的 crushmap 的中間狀態,也會導致一些 PG 遷移了一半,這些“不完整的”PG 并不會被馬上刪除,這給本來就緊張的磁盤空間又加重了負擔。
有同學可能會好奇,一塊磁盤滿了,Ceph 為什么就不可用了。Ceph 還真的就是這樣設計的,因為 Ceph 沒法保證新的對象是否落在空盤而不落在滿盤,所以 Ceph 選擇在有盤滿了時,就拒絕服務。
在我咨詢了一些同事和業界同行后得知基本上大家的 Ceph 集群都是在達到 50% 使用率時,就要開始準備擴容了。
這其實是挺不省錢的,因為必須空置一大批機器的存儲資源。并且未來集群的規模越大,空置效應就會放得越大,意味著浪費的錢/電費越多。
而很多傳統的中心化的分布式存儲系統,由于寫入時可以由主控節點選擇相對空閑的機器進行寫入,因此不會存在某些磁盤滿了,導致整個集群不可寫入的問題。
也正是如此,才可以做到整體寫入到 95% 了,仍然保持可用性。
我沒有真正核算過這種效應帶來的成本 Waste,但至少看上去是有點不夠完美的。
打個比方,當我預估有 50PB 的存儲時,需要 300 臺物理機了,我居然要提前采購好另外 200-300 臺物理機,還不能馬上用上,還要插上電。
因此 Ceph 也并不一定會很便宜,去中心化的分布式存儲也并沒有那么美好。
但中心化的危害,似乎又是沒有爭議的問題(單點問題、中心節點擴展性問題等等 ),因此分布式里真的沒有銀彈,只有 tradeoff。
還有一種辦法,就是 Ceph 的集群按整個 Pool 來擴容,一個 Pool 滿了,就不擴容了,開新的 Pool,新的對象只準寫新的 Pool,老的 Pool 的對象可以刪除,可以讀取。
這乍看之下是一個很棒的解決方案,但仔細想想,這和 HDFS 的 federation,和 MySQL 的分庫分表,做前端的大 Hash,似乎沒有區別。
這也就談不上是“無限擴容”了,而且還需要寫一個前面的路由層。
穩定,可駕馭,好運維
這個穩定好運維,基本就看團隊的硬實力了。對開源軟件是否熟悉,是否有經驗,真的會有很大不同。
同時,這還受開源社區文檔質量的影響。Ceph 的開源社區還是不錯的,Red Hat 收購并主導了 Ceph 之后,重新整理了 Red Hat 版本的 Ceph 文檔,我認為讀起來邏輯感更強。
在公司內積累自己的運維文檔也很關鍵。一個新手很可能會犯很多錯誤,導致事故發生。但對于公司,踩了一次的坑,就盡量不要再踩第二次了。
這對公司的技術積累管理、技術文檔管理、核心人才流失管理,都產生了一些挑戰。
我在 Ceph 運維中,曾遇到一個棘手的問題。即 Ceph 集群達到了 80% 后,經常有磁盤變滿,然后管理員就要介入,調低過高磁盤的 Reweight。
而在這臺磁盤使用量沒降下來之前,又有更多的磁盤被寫滿了,管理員就又要介入,又調整 Reweight,Ceph 至此就再也沒有進入過穩定狀態了,管理員還必須時時刻刻盯著集群。
這導致了極大的運維投入,所以像這種事情一定要避免,這對運維人員的士氣是很大的傷害。
那么,是否應該在早期進行容量預警,啟動采購流程呢?
可是這樣做,又回到了資源浪費的問題上。此外,Ceph 的對象是沒有 last_access_time 這種元數據的,因此 Ceph 對象的冷/熱之分,需要二次開發,做額外的工作。
集群大了之后,如何清理垃圾數據、如何歸檔冷數據,也帶來了不小的挑戰。
總結思考
Ceph 確實有無限擴容的能力,但需要良好的初始規劃,擴容過程也并不完美。
中心化造就了擴容的上限是單臺 Master 結點的物理極限,造就了無限擴容的理論基礎,但實際擴容時,服務質量會受到嚴重制約。
Ceph 有些浪費硬件,成本核算時要考慮更多。
Ceph 本身的去中心化設計犧牲了不少元數據,比如 lastacesstime,這給未來數據治理帶來了壓力,也需要更強的團隊來運維和二次開發。
積累運維經驗,積累運維團隊,是駕馭好開源分布式存儲的核心。對手隨著時間越來越強大,應對的運維團隊也需要越來越好,才能讓生產關系匹配生產力的要求。
技術本身沒有絕對的好壞,不同的技術是用來解決不同問題的。但在場景下,技術是有好壞的。
因為在場景下,你有了立場,就有了亟待解決的問題的優先級,也就一定能按優先級選擇出最適合你的技術。