極光筆記|百億級KV儲存在極光的運維實踐之路

極光推送發表於2021-12-02


前言
極光從某種意義上講,是一家資料公司。在整個公司的技術運營體系中,需要儲存大量的KV資料。根據資料量、KV結構特點、資料更新頻率、資料冷熱、讀寫請求量和比例等因素,在極光逐步形成了CouchBase、Redis和Pika三種不同的KV解決方案。
以下我們主要是從大規模資料量/請求量場景下碰到的運維難題,以及服務的效能、可擴容性、資料備份與安全、運維保障工具等方面介紹一下極光在使用以上KV元件的實踐經驗。
一、CouchBase實踐
極光 CouchBase 規模

CouchBase 當前總使用量大約在 6.5T 左右;單個叢集最大25臺(16核128G記憶體)。

CouchBase是一個非關係型資料庫,它實際上是由couchdb+membase組成,所以它既能像couchdb那樣儲存json文件,也能像membase那樣高速儲存鍵值對。
在極光我們主要用它做KV儲存,主要有以下幾個特點:
速度快
由於是放在記憶體中的資料庫,所有的讀寫操作都是直接操作記憶體,因此速度非常快。極光資料量最大的叢集規模約25臺機器(16核128G),可以提供1.5TB的可用記憶體。讀寫壓力最大的叢集,大概是8臺機器,但是需要抗住100萬的QPS,單機可以抗住10萬以上的QPS,效能相當強悍了。

與官網宣稱的效能與節點數的線性關係不同,實際使用中發現,超過40個節點的叢集,在擴縮容、故障節點替換、叢集穩定性方面存在明顯的問題,在擴縮容、替換節點的時候,叢集容易進入假死的狀態,在控制檯上沒有任何反應,客戶端斷斷續續出現超時或者錯誤的返回結果。這個過程無法快速自動恢復,在極光類似的故障最長的一次持續了3個多小時,最終我們是停掉了業務才修復的。
另外有一次故障,發現主要原因CouchBase 記憶體佔用只增不減,導致機器記憶體爆滿,最終被 oom。最終通過進行叢集拆分暫時解決了問題,新叢集也同步使用更新的版本。


高可用
主要有兩個方面的高可用:一個是它自帶叢集方案,支援多副本模式,我們一般是選擇2副本模式,類似一主一備的方案,這樣可以確保沒有單點故障的問題;
另一個是它自帶持久化方案,可以設定定時把資料非同步寫到檔案系統上,所以在一般情況下單一節點的當機,對叢集的可用性和效能影響有限,但是一次性故障超過2個節點,就有出現資料丟失的可能性了。

配置使用方便
CouchBase安裝後自帶web管理臺,可以在管理臺上對叢集、桶、索引、搜尋等進行管理和操作,大大簡化運維的工作。這也是一般開源軟體所普遍不具備的能力,商業化的產品對於使用者體驗確實做得很好。

當然,CouchBase也有一些明顯的缺點:
1、只能提供簡單KV儲存模型,不支援複雜資料結構(value 支援json 格式)
2、為了提升查詢效率,KV中的Key全部都快取在記憶體,需要消耗大量記憶體,特別是每一對KV所附加的MetaData(一個KV儲存至少消耗56Bytes的MetaData)同樣快取在記憶體中。在極光的實踐過程中,經常碰到MetaData超過50%記憶體佔用的情況,對記憶體容量提出高要求,也導致成本較高。

3、本身是閉源產品,文件較少,出現異常故障處理手段有限,存在一定的風險;我們碰到過好幾次的叢集節點假死,還有資料量大的叢集無法進行備份的情況,沒有找到任何有效的方案。那麼對於核心、關鍵資料,放在CouchBase上進行儲存是不可靠的,這塊是需要根據業務場景來判斷的,目前極光使用CouchBase的資料都是中間層資料,一旦發生資料丟失,都可以從其他渠道恢復回來。
資料備份問題:
對於資料量達到一定規模,使用 CouchBase 自帶的備份工具進行備份時就會出現備份失敗的情況。與 CouchBase 官方溝通也沒有回覆。



針對CouchBase大規模叢集下的rebalance會存在假死的問題,後面我們把大叢集拆解成了數個小叢集,實現了壓力的分散和運維管理的分散,不過需要在業務側做資料的分片處理,需要業務介入,對業務方存在一定的侵入。

監控和告警生態相對比較成熟,通過對應的Exporter獲取資料上傳到Prometheus,整體比較簡單方便

我們設定了以下的主要告警規則,便於及時發現問題:

1、bucket記憶體使用超過85%
2、CouchBase叢集節點CPU使用超過90%
3、xdcr同步失敗
4、CouchBase 節點發生異常/重啟

二、Redis實踐
Redis是知名的開源KV儲存,在業界使用極為廣泛,極光也在大量使用Redis。
極光Redis規模
當前極光 Redis 資源使用量大約在 30TB 左右,例項總數大概在 7K

生態豐富
Redis因本身的知名度,實踐案例非常多,網上的文章和教程十分豐富,有一個很好的生態,運維和研發人員也非常熟悉。這塊對比CouchBase和Pika來說,真的非常重要,不但可以節省大量的溝通成本,還可以直接複用很多的成熟解決方案,排查故障和優化工作也更加簡便。

在選擇基礎元件這塊,成熟、通用、生態豐富真的非常重要。

高效能
同樣因為全記憶體操作,Redis表現出相當高的效能,我們實際使用中單Redis例項峰值效能可以到達5萬QPS(這是公司的峰值標準,達到該值我們就認為已經達到瓶頸了,但實際效能測試要高於此),如果按照單機8個例項,理論上可以達到40萬QPS,這個資料相當驚人了。當然,由於redis的單程式+阻塞模型,碰到慢指令就會導致延遲整體上漲,這塊我們在應用架構設計和運維方面需要特別考慮,比如在業務低峰期再進行一些高延遲的操作。
redis 效能測試:

主從模式下,我們一般都使用哨兵模式,這個一般來講不會有什麼問題;但是有一次我們懷著提高可用性的目的,把一套哨兵從3節點擴容到5節點,之後發現該哨兵監管的redis例項出現大量的延遲告警,後來排查發現和擴容到5節點密切相關,進一步排查slowlog發現是哨兵傳送的INFO指令導致redis例項響應延遲增加。在這塊,要特別注意哨兵的探活導致的資源消耗,在高QPS壓力下,任何一點新增的壓力都十分敏感。

自帶叢集模式
Redis自帶了Redis-Cluster架構,在一定程度上解決了超大規模資料集的儲存問題。
Redis cluster 效能測試:

不過,由於其無中心的架構模型,在大規模叢集下運維和資料遷移較為困難。在極光,我們當前最大的Redis-Cluster叢集達到244個主從節點,總共超過800G的資料量,峰值QPS可以達到8M(八百萬QPS),壓力相當大,帶來的運維壓力也是相當大。
首先:擴容比較困難,擴容導致的slot遷移在大QPS壓力下,導致客戶端收到大量MOVED返回,最終導致業務端大量報錯;
其次:擴容時間非常長,從244個節點擴容到272個節點,花費了我們一個星期時間,浪費了我們很多人力資源。

逐漸地我們形成了一套Redis-Cluster的應用最佳實踐
首先、嚴格控制Redis-Cluster叢集規模,主節點不超過100個。
其次、前期我們通過在業務端做資料切割,將資料分佈到不同的Redis-Cluster叢集;逐漸地公司通過自研JCache元件實現巨集叢集,將多個原生的Redis-Cluster組合成一個巨集叢集;在JCache做基於Key規則的hash,相當於多了一層代理。當然,這樣也帶來一些新的問題需要解決,比如後端Redis-Cluster的分裂和資料重新分片的問題,也增加了JCache的複雜度。
JCache 巨集叢集方案:

監控同樣是使用Exporter收集資料到Prometheus,這塊生態十分完善,直接複用現成的方案即可。


我們針對Redis設定瞭如下的告警規則:
1、記憶體使用率告警(每個 redis 應用自定義,預設 90%)
2、客戶端連線數告警(預設 2000)
3、redis 例項 down 告警
4、哨兵發生主從切換告警
5、應用整體 qps 閾值告警
6、特定 redis key 監控

效能優化:
1、關閉 THP
2、高危命令遮蔽(keys/flushall/flushdb 等)
3、部分資料頻繁過期的 Redis 應用,通過調整 hz 引數,加快過期 key 清理,儘快回收記憶體,有一些從預設每秒清理10次提高到100次,但是在大QPS請求下,會有效能影響
4、對部分記憶體需求高,效能要求稍低的 Redis 應用,通過調整資料的底層儲存結構,來節省記憶體,如調整hash-max-ziplist-entries/hash-max-ziplist-value

三、Pika實踐
Pika是國內開源的一套相容Redis協議的KV儲存,底層基於RocksDB儲存引擎,支援多執行緒,屬於磁碟KV儲存系統,比較適用於資料量特別大(例如TB級別)但是QPS要求不是特別高的場景。
極光 Pika 規模

Pika 當前資料量大約在 160T 左右。
效能較高
從我們使用NVMe SSD作為儲存介質實測下來,單機(8核32G)峰值達到18W QPS是沒有問題的,實際使用場景下峰值QPS可以達到10W而不影響業務。
當前公司自建 IDC 使用 NVMe SSD 最大的 ops 在 7.6W 左右

生態不算成熟
國內開源軟體,受眾不算大,軟體不是特別成熟,功能迭代變化較快,從2.X版本快速迭代到3.X版本,根據社群反饋而做了很多改進,目前我們基本穩定使用3.2.X的版本。
注:新應用基本都是基於 3.2.x 版本,還有部分遺留的歷史應用由於資料比較重要,暫時沒有升級
最近一年因為專案變更,Pika似乎捐獻給了國內某個開源基金會,不再由360公司繼續負責維護,從QQ群的反饋來看,核心開發人員似乎越來越少,專案前景有一點暗淡。這也是很多小眾開源軟體的常見問題,軟體本身很容易因為公司政策或者某些核心人員的變動而受到較大影響。

Pika最近一次發版本還是在 2020年 12 月,已經快過去一年時間了。
代理層
因為Pika只有主從模式,而我們的資料量動不動就好幾個T,QPS 數十萬,所以我們在實際使用時需要在前面加了一層代理層來做hash分片工作。目前單個例項最大達到了2T,實際QPS達到10萬,讀寫例項比例1:3,滿足寫少讀多的場景。

標配SSD
無論從官方建議還是實際使用,Pika的磁碟我們都標配NVMe SSD磁碟,相比普通SSD磁碟,提供更高的IOPS和吞吐能力,更低的讀寫延遲。Pika生產環境,NVMe SSD我們峰值IOPS可以達到5萬,而普通的SAS SSD磁碟也就1萬,效能提升還是很明顯的,對比價格的區別,效能提升非常多,更不用說相比記憶體了。

串聯主從問題
Redis可以支援和實現主-從-從的串聯關係,我們在使用Pika的時候也做過類似的部署,結果出現了嚴重問題,導致我們丟失了資料。Pika在串聯主從這種模式下對於資料同步狀態的管理十分簡單粗暴,只能看到slave和master已建立連線,但是資料是否同步完畢、是否有資料缺失都需要應用層去處理。這也是後面我們研究程式碼得出來的,一方面是文件的缺失,另一方面也說明了在使用開源軟體時不要理所當然地認為是怎麼樣,而是要經過嚴格的確認和測試,否則帶來的代價是非常大的。
注:Pika從 3.2.X 版本後就不再支援串聯主從的設定了,所有Slave都必須從Master同步資料,會對Master節點造成一定的讀壓力。
監控和告警
監控資訊還是可以通過Exporter蒐集並上傳到Prometheus,比較簡單清晰


Pika的告警規則設定如下:
1、Pika 例項程式告警
2、Pika 連線數告警
3、哨兵主從切換告警
4、JCache 慢查詢告警
5、Pika master 寫資料失敗告警
效能引數:
1、auto-compact 自動壓縮引數,針對存在大量過期資料的應用
2、root-connection-num 保證客戶端把連線數佔滿後仍然能通過 pika 本地連線上
3、壓縮演算法改為 lz4,效能好,壓縮比高

四、後續規劃
極光目前的KV儲存經歷了這麼多年的演進,滿足當前需求是足夠的,但是仍然存在擴容不方便、不平滑,大規模叢集效能瓶頸、價效比等問題;未來將重點投入在對業務的賦能上,將KV儲存做成一套適應性更強、更靈活的儲存服務,可能考慮引入類似存算分離、冷熱分層等技術,在擴縮容、效能優化、價效比等維度上更上一層樓。

相關文章