微信後臺基於時間序的新一代海量數據存儲架構的設計實踐

本文做者騰訊WXG後臺開發工程師jeryyzhang,收錄時有改動,感謝原做者的分享。html

一、引言

大約3年前,微信技術團隊分享了《微信後臺基於時間序的海量數據冷熱分級架構設計實踐》一文,文中總結了微信這種超級IM基於時間序的海量數據存儲架構的設計實踐,也得以讓你們瞭解了微信後臺的架構設計思路。前端

時隔3年,微信再次分享了基於時間序的新一代海量數據存儲架構的設計實踐,但願能帶給你啓發。編程

阿里團隊也分享過IM基於時序的數據同步和存儲方案,有興趣能夠一併閱讀:《現代IM系統中聊天消息的同步和存儲方案探討》。緩存

二、微信基於時序的數據業務場景

做爲以手機爲主要平臺的移動社交應用,微信內大部分業務生成的數據是有共性可言的:數據鍵值帶有時間戳信息,而且單用戶數據隨着時間在不斷的生成,咱們將這類數據稱爲基於時間序的數據。例如朋友圈的發表,支付帳單流水,公衆號文章閱讀記錄等。安全

這類基於時間序的數據一般不會刪除,而是會隨着時間流逝不斷積累,相應須要的存儲空間也與日俱增:key 量在萬億級別、數據量達到 PB 級別、天天新增 key 十億級別。同時在十億用戶的加持下,天天的訪問量也高達萬億級別。微信

三、微信的數據訪問模式

通過數據分析,咱們發現基於時間序的存儲通常有以下三個特色。多線程

特色1——讀多寫少:架構

這類基於時間序的存儲,若是須要訪問一段時間內的數據就須要對對應時間段內的全部鍵值對都進行一次訪問。與所有寫入到一個鍵值對的場景相比能夠視爲讀擴散的場景。部分業務場景下的讀寫比甚至高達 100:1。負載均衡

特色2——冷熱分明:運維

這類基於時間序的存儲,數據的時效性每每也決定了訪問頻率。好比對用戶進行公衆號文章的推薦,用戶近期的閱讀記錄會更加具備參考意義。這就致使數據的訪問不是均勻的,而會更集中在最近一段時間所產生的數據。以某業務場景爲例,70%以上的訪問來自最近一天內的新增數據,90%來自 3 個月內的新增數據。一年外的數據訪問佔比只有 5%。

特色3:數據安全性要求高:

這類數據一般是由用戶主動產生,一旦丟失,很是容易被用戶感知,致使投訴。

下圖是數據的讀取分佈狀況統計:

▲ 本圖在上篇《微信後臺基於時間序的海量數據冷熱分級架構設計實踐》也有相似統計

四、本次升級以前的架構及其面臨的挑戰

 

在本次升級以前,咱們使用一致性緩存層+SSD 熱數據層+機械盤冷數據層的分層架構方案來解決此類基於時間序的存儲。更多的技術細節能夠參考上篇《微信後臺基於時間序的海量數據冷熱分級架構設計實踐》。

對於冷數據集羣,咱們使用微信自研的 WFS(Wechat File System 微信分佈式文件系統)對其進行了一次升級,極大的簡化了運維成本。不過這部分不是本文重點,在此再也不詳述。

舊架構在過去幾年微信後臺的發展過程當中始終表現平穩,可是也依然面臨着一些挑戰。

首先是擴展能力方面的挑戰:舊架構中,考慮到讀多寫少的訪問模型,爲了加快宕機後的數據 catchup 速度,咱們使用了細粒度的 paxos group,即每一個 key 有一個獨立的 paxos group。這樣在進程重啓等宕機場景下,只有少許寫入的 key 須要進行 catchup。理想很豐滿,現實很骨感。在 PaxosStore 架構中,數據的擴縮容是以 paxos group 爲粒度的。也就是說,對於使用細粒度 paxos group 的存儲,進行擴縮容是逐 key 的,耗時能夠當作與 key 量成正比;單機百億級別的 key 量放大了這一問題,即便咱們採起一系列的工程優化縮短耗時,總體的遷移週期依然比較長,須要幾周時間。

另一個方面則是來自容災能力的挑戰:PaxosStore 使用 KV64+三園區的部署方式(PaxosStore在上篇《微信後臺基於時間序的海量數據冷熱分級架構設計實踐》中,被認爲是該架構中的技術關鍵點)。同一個 key 的三個副本分屬三個園區,同一個園區的兩臺機器服務分片沒有重疊,所以能夠容忍園區級別的故障。然而對於同組兩臺不一樣園區機器故障的狀況,則有佔比 1/6 的數據只剩餘單個副本,沒法提供讀寫服務。

可能有同窗會認爲,同組兩臺不一樣園區機器故障,機率無異於中彩票。然而根據墨菲定律:「凡是可能出錯的事情,最終必定會出錯」。在過去幾年也曾出現過同 Set 兩臺不一樣園區機器前後發生故障的狀況。

咱們都知道,分佈式系統的一個核心觀點就是基於海量的,不可靠的硬件,構造可靠的系統。那麼硬件究竟有多不可靠呢?

Jeff Dean 在 2009 年的一次 Talk 中曾經提到過:

 
 
 

Jeff Dean是誰?

Jeff Dean是谷歌Level 11(Google Senior Fellow)級別的超級工程師。Jeff Dean被認爲是谷歌技術的代名詞,谷歌之因此如此強大,Jeff Dean是其中的很重要的緣由之一。能夠看看知乎上的這個討論:zhihu.com/question/22081653

PaxosStore 使用 no raid 的磁盤陣列,磁盤故障致使單盤數據丟失時有發生。在機器故障檢修以及數據恢復的過程當中,有大量數據(佔單組 50%,逐漸收斂爲 0)是以 2 副本形式存在,這就進一步削弱了系統的容災能力。

總結一下,咱們面臨以下幾個挑戰:

1)單機百億級別 key 量,10TB 級別數據,如何快速擴容?

2)如何低成本的提高系統的容災能力,使之容忍任意雙機故障?

3)磁盤故障,數據清空後如何快速恢復。

4)做爲一款十億月活的國民 APP,對其進行改造無異於給一架正在飛行的飛機更換髮動機,改造過程稍有不慎均可能招致用戶投訴,甚至上個熱搜。

接下來我會針對這幾個難點逐一展開,介紹咱們的解決思路與方案。

五、本次架構升級過程的技術的詳細實踐總結

5.1 計算和存儲分離的思路

對於細粒度的的 paxos group,遷移過程當中,掃 key、遷移、校驗等步驟都是逐 key 粒度的。這會產生大量的磁盤 IO 與 CPU 消耗,致使遷移速度上不去,須要幾周才能夠完成遷移。

那麼咱們可否能夠採起粗粒度 paxos group 以加快遷移呢?答案是確定的。

對比細粒度的 paxos group,單個粗粒度的 paxos group 能夠同時保證多個 key 的內容強一致。所以遷移校驗等過程當中,能夠減小大量的 paxos 交互。

然而粗粒度 paxos group 的存儲,與細粒度 paxos group 的存儲相比,在遷移過程當中對目標集羣的寫入不會減小,整體依然涉及了大量數據的騰挪。而因爲 LSMTree 存儲引擎存在的寫放大問題,數據大量寫入目標機這一過程會成爲瓶頸。

整體來看,擴容時間能夠縮短爲原來的 1/2 甚至 1/3,達到天級別的水平。

看起來相比細粒度 paxos group 的遷移已經有很大改進,咱們可否更進一步?

首先咱們分析一下在什麼場景下須要擴容,通常來講是如下兩個場景:

1)因爲數據增長,磁盤容量達到瓶頸;

2)因爲請求增長,CPU 處理能力達到瓶頸。

對於狀況 1:若是咱們使用分佈式文件系統替代本地文件系統,當容量達到瓶頸時只須要增長分佈式文件系統的機器就能夠實現容量的快速擴容,對上層應用而言至關於得到了一塊容量能夠無限增加的磁盤。

對於狀況 2:採用計算存儲分離結構後。計算節點無狀態,不涉及數據騰挪,天然能夠實現快速擴容;若是是存儲層節點 CPU 瓶頸,也能夠經過文件塊級別的騰挪來實現快速擴容以及熱點打散。

應用計算存儲分離的思路,咱們基於 WFS(微信分佈式文件系統)以及微信 Chubby(分佈式鎖),實現了一套計算存儲分離的存儲架構,代號 Infinity,寓意無限的擴展能力。

5.2 「任何計算機問題均可以經過增長一箇中間層來解決」

計算機科學經典名語:「All problems in computer science can be solved by another level of indirection」。

在 Infinity 中,咱們引入了一個被稱爲 Container 的中間層。Container 能夠近似理解爲一個數據分片。每臺機器能夠裝載一個或多個 Container,咱們稱之爲 ContainerServer。ContainerServer 會處理其上 Container 對應數據的讀寫請求,Master 負責 Container 在 ContainerServer 間的調度,Chubby 則提供了分佈式鎖服務以及 Container 位置信息在內的元信息存儲。

當 master 發現有新加入的機器時,會主動觸發負載均衡,將其餘 ContainerServer 上的 Container 調度到新機。整個調度過程當中,不涉及數據的騰挪。在咱們實際的測試中,Container 騰挪的平均耗時在百毫秒級別。

 
 

如上圖所示,這是一個多園區部署的 Infinity 示意圖。每一個園區內都有獨立的 WFS 與 Chubby 存儲,每一個園區都對應全量的數據。對於同一個數據分片,分別位於 3 個園區的 3 個 container 組成一個 paxos group。

 
 

對於這樣一個方案,咱們是能夠對每一個園區實現彈性伸縮的,系統總體的可用率由最上層的 paxos 提供保證。

咱們來計算下這一方案的存儲成本:園區內 3 副本的 WFS 存儲 X 園區間的 3 副本 Replica,總體就是 9 副本。對於 PB 體量的存儲,這一方案所增長的存儲成本是咱們難以承擔的。既然多 zone 部署的 Infinity 存在成本問題。咱們天然想到,可否使用單 zone 部署的 Infinity 來負責存儲。

首先分析成本:單 zone 部署 Infinity 的存儲成本爲 3 副本 WFS,與現有架構的成本一致。其次分析擴展能力,單 zone 部署的 Infinity 同樣具備出色的擴展能力,優於現有架構。對於 Chubby 這一中心點依賴,咱們能夠實行 Set 化改造來儘可能消除風險。

 
 

分 Set 改造後,咱們不禁得又想起那些年舊架構常常遇到的一種狀況:單組請求突增。

此處有必要簡單介紹一下 PaxosStore 的路由方案,組間一致性 Hash,單組內是 KV64 結構。一致性 Hash 消除訪問熱點,一切看起來很美好。然而假設因爲某些緣由,大量請求集中訪問某組 KV 時,如何應急?

此時咱們既沒法快速增長該組內的機器處理請求(KV64 限制),也沒法快速分散請求到其餘組(若是這組 KV 須要 3 倍容量,那就要把整個服務總體擴容 3 倍才能夠)。

這就引起了一個尷尬的局面:

1)一組 KV 水深火熱,其餘組 KV 心有餘而力不足;

2)只能反覆調整前端請求的訪問比例,直到業務低峯期。

 
 

那麼在 Infinity 中,咱們如何解決這一問題呢?

首先:咱們的 Set 化本質上是對 Container 進行分組,其中 Container 到組的映射關係是存儲於 Chubby 中的。若是咱們想分散一組請求到其餘組,只須要依次修改每一組 Chubby 中存儲的映射關係便可。在實際實現中還有一些工程細節須要考慮,好比對於要移入其餘組的 Container,必須在原組進行 Unload 並中止調度等。這裏就不一一展開了。

 
 

咱們在線上也進行了一次大規模騰挪 Container 到其餘組的實驗:結果顯示,單個 container 騰挪到其餘組,平均耗時不足 1 秒。

5.3 單 zone Infinity 架構的一些問題

單 zone Infinity 架構解決了多 zone Infinity 成本問題的同時,也必然作出了取捨。

對於某個 container,任一時刻必須只在最多一個 containersvr 上服務。不然就有致使數據錯亂的風險。類比多線程中的 data race。咱們經過引入分佈式鎖服務來避免 double assign。同時爲了減小分佈式鎖開銷,咱們將鎖的粒度由 Container 級別收斂到 ContainerSvr 級別。每臺 ContainerSvr 開始提供服務後會按期前往 chubby 續租。若是一臺 ContainerSvr 崩潰,master 也須要等到鎖租約過時後才能夠認爲這臺 ContainerSvr 掛掉,並將其上的 container 分配出去。

這就會致使存在一部分 container 在租約切換期間(秒級別)不能服務。

 
 

咱們引入兩個可靠性工程的常見指標來進行說明:

1)MTTR:全稱是 Mean Time To Repair,即平均修復時間。是指可修復系統的平均修復時間,就是從出現故障到修復中間的這段時間。MTTR 越短表示易恢復性越好;

2)MTBF:全稱是 Mean Time Between Failure,是指可修復系統中相鄰兩次故障間的平均間隔。MTBF 越高說明越不容易出現故障。

能夠說,單 zone Infinity 架構縮短了 MTTR,可是也縮短了 MTBF,致使總體的可用性依然不高。

5.4 不可能三角?

在不少領域中,都有相似「不可能三角」的理論。好比分佈式理論中經典的 CAP 定理,經濟學理論中的蒙代爾不可能三角等。

在咱們上面的討論中,其實也蘊含了這樣的一個「不可能三角」:

1)成本

2)擴展性

3)可用性。

 

具你原本說:

1)PaxosStore 兼顧了成本與可用性,但擴展能力稍遜;

2)多 zone Infinity 可用性與擴展性都爲上乘,但成本是個問題;

3)單 zone Infinity 犧牲了一點可用性,換來了成本和擴展性的優點。

三者不可得兼,咱們該如何取捨?

1)首先是成本:是咱們必須考慮的因素,這關係到咱們架構實際落地仍是成爲巴貝奇的分析機;

2)其次是可用性:這關係到用戶的使用體驗。

在咱們的新架構中,可用性不只不能降低,甚至還應該有所提高。好比:容忍任意雙機故障。結合上面的討論,一個核心的目標逐漸浮出水面:低成本雙機容災改造。

5.5 低成本雙機容災改造

咱們首先來分析一下如何實現雙機容災改造。

一個簡單的思路是:提高咱們的副本數,由 3 副本提高爲 5 副本。

5 副本天然能夠容忍小於多數派(<=2)的機器故障,實現雙機容災。然而考慮到成本問題,3 副本改造爲 5 副本,成本增長 66%,這是咱們沒法接受的。

此時咱們想到了函數式編程中的常見思想:Immutable! 對於靜態不可變的數據而言,只要有 3 個副本,那麼咱們也能夠在丟失 2 個副本的狀況下,信任惟一的副本。

然而對於一個存儲系統而言,咱們沒辦法控制用戶不修改 Key 對應的 Value 值,那麼咱們該如何實現靜態化 3 副本呢?

5.6 LSMTree Revisited

關於 LSMTree 這一存儲引擎的介紹,資料有不少。這裏就再也不詳述了。

這裏引用一張 LSMTree 的架構圖:

 

咱們分析一下圖中每一個類型的文件:

1)對於 SSTable 文件,寫入完成後即不可變,並且是 LSMTree 中主要的數據存儲(佔比超過 99%),對於這一部分文件咱們只須要存儲 3 副本便可;

2)對於其餘的文件如 WAL log,以及 Manifest,咱們使用 5 副本存儲,整體的存儲成本增加能夠忽略不計。

這樣,咱們就可使用單 zone Infinity,在保持存儲成本不變的狀況下,得到雙機容災的能力。

5.7 分而治之

架構的不足之處:

1)單 zone Infinity 能夠以 3 副本的存儲成本實現雙機容災,然而存在租約切換期間的不可用問題;

2)5 副本 KV 實現了無租約的雙機容災,而後存儲成本相比原來增長了 2/3。

兩種架構各有不足,看似咱們陷入了死局。然而回顧基於時間序數據的訪問模型,咱們發現對於熱數據與溫數據,他們表現出了大相徑庭甚至相反的一些有趣性質。

 
 

咱們能夠採起計算機科學中的重要思想——分治來解決:

1)對於熱數據:訪問量較大,咱們但願他有最高的可用性,同時它的數據佔比又不大,適於採用 5 副本 KV 的方案進行雙機容災改造;

2)對於溫數據:數據量較大,不能採起 5 副本方案改造,而使用單 zone Infinity 的方案,則能夠完美解決成本問題。

雖然會有偶爾短暫的不可用時長,可是因爲總體的訪問佔比很少,系統總體的可用率依然能夠保持在很高的水準。

對新架構的成本分析:

 

這樣咱們就在不顯著增長存儲成本,不犧牲可用性的前提下,實現了雙機容災的目標。

爲了提高熱數據部分的擴展性,咱們可使用粗粒度 paxos group 的交互方案。對於熱數據,在數據量減小+粗粒度 paxos group 雙重改進下,擴容時間能夠提高到小時級別。同時,咱們實現了熱數據由 5 副本 KV 到單 zone Infinity 的自動下沉。一方面能夠保持整體的存儲成本不膨脹,另外一方面也減小了熱數據的總量,熱數據集羣的擴容需求也就沒有那麼強烈。

5.8 磁盤清空後的數據快速恢復

對於 Infinity 部分的數據,能夠依靠 WFS 自動檢測,補全副本數。在機器檢修期間就能夠完成大部分數據的補全。對於熱數據部分的數據,雖然數據減小,可是恢復過程當中仍是會受限於 lsmtree 的寫入過程當中 Compact 產生的寫放大問題。

通過一些業界的調研,對於 lsmtree 批量導入的場景,一種常見的作法是 BulkLoad,也即先將全部 key 進行排序,生成有序的 SSTable 文件,直接提交到 lsmtree 的最後一層,這樣能夠徹底繞過寫放大實現數據的導入。

咱們通過分析,發現這種作法還不是最優的。首先,咱們對於 SSTable 中的數據會進行 block 級別的壓縮,在遍歷數據的過程當中須要進行解壓;而在生成 SSTable 的過程當中,爲了減小存儲成本,又須要進行壓縮。通過研究,發現咱們這種場景下有更優的恢復方案:基於目錄級別的快速恢復。

5.9 目錄級別的快速恢復

要想實現目錄級別的快速恢復,首要條件就是:須要數據的路由規則與目錄分佈是徹底對齊的。這樣才能夠保證恢復目錄後,不會得到不屬於本機的數據,也不會遺漏數據。

在此前的 kv 中都忽略了這一設計,致使沒法經過拷貝文件實現快速恢復。結合 5 副本的路由方案,咱們得到了一個能夠實現對齊的目錄分佈方案。推導後的方案很是簡潔,用一張圖片便可說明。

 
 

咱們進行的測試也印證了這一改造的效果,基於目錄拷貝的恢復方案相比原來逐 paxos group 恢復方案取得了近 50 倍的速度提高,從小時級進入到分鐘級。

5.10 新架構終得成型

對幾個架構方案的對比:

5.11 平穩升級到最新架構成果

至此咱們的改造方案有了,然而改造過程一樣值得注意。咱們必須在保證系統穩定的前提下,平穩的完成數據與訪問的切換。

首先是灰度能力,咱們作了兩個粒度的灰度控制:

1)一是訪問時間級別,按照 key 上面的時間,分批將數據從原架構中騰挪出來;

2)二是命令字級別,數據騰挪完成後,咱們會先保持雙寫狀態觀察,先逐步切換讀請求到新架構中,觀察正常後纔會去掉雙寫,完成切換。

其次是改造的正確性:

1)咱們採起了全量的數據校驗方案,保證改造過程當中不會丟失數據;

2)最後是在騰挪過程當中,咱們開發了一套基於機器資源以及監控上報的自動反饋機制,當業務高峯期或者出現失敗時自動降速,低峯期自動加速,減小了人爲介入。

目前,咱們已經完成部分核心存儲集羣的架構改造,實現了全程無端障切換。

六、本文小結

2019 年,微信後臺經過如上持續不斷的改造,在不增長成本的前提下,極大提高了基於時間序存儲的擴展能力,從周級別的擴容速度升級到總體小時級的擴容速度,而且溫數據部分的計算節點作到了分鐘級的擴容速度。

同時,利用數據的特性進行集羣劃分,將 5 副本 PaxosStore 存儲與計算存儲分離架構進行有機結合,在極大提高了擴展能力的同時,將可用性提高到容忍雙機故障的水平。(本文同步發佈於:http://www.52im.net/thread-2970-1-1.html

相關文章
相關標籤/搜索