背景
Pika是一個可持久化的大容量redis儲存服務,相容string、hash、list、zset、set的絕大部分介面(相容詳情),解決redis由於儲存資料量巨大而導致記憶體不夠用的容量瓶頸。使用者可以不修改任何程式碼從redis遷移到pika服務。具有良好的相容性和穩定性,被360公司內部使用超過3000例項,github社群超過3.8K star。由於單機pika容量受限於單塊硬碟容量的大小,360公司業務和社群對分散式pika叢集的需求越來越強烈,因此我們推出了原生分散式pika叢集,釋出pika版本v3.4。與pika+codis叢集方案相比,codis對pika建立和管理slot操作的支援並不友好,需要運維人員大量介入。而pika原生叢集則不需要額外部署codis-proxy模組。
叢集部署結構
以3個pika節點的叢集為例,叢集部署結構如上圖所示:
- 部署Etcd叢集作為pika manager的元資訊儲存。
- 3臺物理機上分別部署pika manager,並配置好Etcd的服務埠。Pika manager會向etcd註冊,並爭搶成為leader。叢集中有且只有一個pika manager能夠成為leader並向etcd中寫入叢集資料。
- 3臺物理機上分別部署pika節點,然後把pika節點的資訊新增到pika manager中。
- 為了負載均衡,把pika的服務埠註冊到LVS中。
資料分佈
為了對資料按照業務進行隔離,Pika叢集引入table的概念,不同的業務資料儲存在不同的table中。業務資料按照key的hash值儲存到對應的slot上面。每一個slot會有多個副本,從而形成一個replication group。replication group中的所有slot副本具有相同的slot ID,其中一個slot副本是leader,其他副本為follower。為了保證資料的一致性,只有leader提供讀寫服務。可以使用pika manager對slot進行排程遷移,使資料和讀寫壓力均勻的分散到整個pika叢集中,從而保證了整個叢集資源的充分利用並且可以根據業務壓力和儲存容量的需要進行水平擴容和縮容。
pika使用rocksdb作為儲存引擎,每個slot會建立對應的rocksdb。pika中的每個slot都支援讀寫redis 5種資料結構。因此資料遷移的時候會特別方便,只需遷移pika中的slot即可。但同時也存在資源佔用過多的問題。目前的pika在建立slot的時候會預設建立5個rocksdb,分別來儲存5種資料結構。在table中含有大量slot或者建立大量table的時候會使單個pika節點含有多個slot,進而建立過多的rocksdb例項,佔用了過多系統資源。在後續版本中一方面會支援建立slot的時候根據業務需要建立一種或多種資料結構,另一方面會持續對pika中的blackwidow介面層進行優化,減少對rocksdb的使用。
資料處理
- 當pika節點接收到使用者請求時,解析層處理解析redis協議,並把解析好的結果交給router層進行判斷。
- router根據key的hash結果找到key對應的slot,並判斷slot是否在本地節點上。
- 如果key所在的slot在其他節點,則根據請求建立一個task放入佇列中,並把請求轉發給peer節點來處理。當task接收到請求的處理結果後把請求返回給客戶端。
- 如果key所在的slot屬於本地節點,就直接本地處理請求並返回給客戶端。
- 對於需要本地處理的寫請求,先通過replication manager模組寫binlog,非同步複製到其他slot副本。process layer根據一致性的要求,寫入leader slot。其中blackwidow是對rocksdb的介面封裝。
我們把proxy內嵌的pika中,不需要單獨部署。與redis cluster相比,客戶端不需要感知proxy的存在,只需像使用單機一樣使用叢集。可以把pika節點的服務埠掛載到LVS中,實現壓力在整個叢集的負載均衡。
日誌複製
pika中replication manager模組負責日誌的主從同步。為了相容redis,pika支援非一致日誌複製,leader slot直接在db中寫入資料而無需等待從follower slot的ack應答。同時也支援raft一致性協議方式的日誌複製,需要滿足收到大多數副本的ack才寫入db。
非一致日誌複製
在非一致場景下處理流程如下:
- 處理執行緒接收到客戶端的請求,直接加鎖後寫入binlog和並操作db。
- 處理執行緒返回客戶端response。
- 輔助執行緒傳送BinlogSync同步請求給follower slot,同步日誌。
- follower slot返回BinlogSyncAck報告同步情況。
一致性日誌複製
在一致性日誌複製場景下:
- 處理執行緒把客戶端請求寫入binlog檔案
- 通過傳送BinlogSync請求向從庫同步
- 從庫返回BinlogSyncAck報告同步狀況
- 檢查從庫應答滿足大多數後將相應的請求寫入db
- 將response返回客戶端
叢集後設資料處理
我們在codis-dashboard的基礎上二次開發了pika manager(簡稱PM),作為整個叢集的全域性控制節點,用來部署和排程管理叢集。PM裡儲存了整個叢集的後設資料及路由資訊。
- 增加了叢集建立多表的功能,方便業務根據表的不同來實現業務資料隔離。
- 支援建立表時指定slot數目和副本數目,方便運維根據業務的規模和故障容忍度建立table。
- 從邏輯上把group的概念改為replication group,使得原來的程式級別的資料和日誌複製轉變為slot級別的複製。
- 支援建立table時建立密碼來隔離業務的使用。客戶端只需要執行auth和select語句就可以認證並對指定的table進行操作。
- 支援slot遷移,方便根據業務需求進行擴容和縮容。
- 整合哨兵模組,PM會不斷的向叢集中的pika節點傳送心跳,監測存活狀態。當PM發現leader slot down時,會自動提升binlog偏移最大的slave slot為leader。
- 儲存後端支援後設資料寫入etcd,保證後設資料的高可用。
- pika manager通過不斷向etcd爭搶鎖來成為leader,來實現pika manager的高可用。
後記
pika原生叢集的推出解決了單機pika受限於磁碟容量的限制,可以按照業務的需求進行水平擴容。但仍然有一些缺陷,如基於raft的內部自動選主功能的缺失,基於range的資料分佈,及監控資訊的展板等功能。後續版本我們會一一解決這些問題。