分布式技術(shù)原理與實戰(zhàn)45講--第38講:緩存高可用:緩存如何保證高可用
上一課時提到了緩存集群的負(fù)載均衡策略,保證緩存服務(wù)的高可用,集群策略是最常用的,這一課時,我們以 Redis 為例,分析一下單點緩存如何擴(kuò)展到集群,以及集群部署的幾種常見模式。
Redis 的主從復(fù)制
集群實現(xiàn)依靠副本,而副本技術(shù)有個非常關(guān)鍵的一點,那就是各個副本之間的快速數(shù)據(jù)同步,也就是我們常說的主從復(fù)制。
主從復(fù)制技術(shù)在關(guān)系型數(shù)據(jù)庫、緩存等各類存儲節(jié)點中都有比較廣泛的應(yīng)用。Redis 的主從復(fù)制,可以將一臺服務(wù)器的數(shù)據(jù)復(fù)制到其他節(jié)點,在 Redis 中,任何節(jié)點都可以成為主節(jié)點,通過 Slaveof 命令可以開啟復(fù)制。
主從復(fù)制一方面可以作為數(shù)據(jù)備份,通過實現(xiàn)主從節(jié)點之間的最終數(shù)據(jù)一致性,保證數(shù)據(jù)盡量不丟失。除了數(shù)據(jù)備份,從節(jié)點還可以擴(kuò)展主節(jié)點的讀請求支持能力,實現(xiàn)讀寫分離,主節(jié)點作為寫節(jié)點,從節(jié)點支持讀請求。當(dāng)主節(jié)點的系統(tǒng)水位不能承擔(dān)前臺業(yè)務(wù)請求并發(fā)量時,可以將請求路由到從節(jié)點,實現(xiàn)集群內(nèi)的動態(tài)均衡。
有了主從復(fù)制,現(xiàn)在請你思考一個問題,Redis 的主從復(fù)制如何選舉呢?
我們先來了解下 MySQL 的選主,也就是故障轉(zhuǎn)移機(jī)制,和主從機(jī)器之間的數(shù)據(jù)同步方式有很大關(guān)系,同步方式包括半同步、全同步,關(guān)于 GTID 的復(fù)制等方式,MySQL 缺少一個選舉決策的節(jié)點,一般是人工干預(yù)選主流程,感興趣的同學(xué)可以查閱相關(guān)資料了解一下。
我們再來看一下 Redis 的主從配置,正常情況下,當(dāng)主節(jié)點發(fā)生故障宕機(jī),需要運(yùn)維工程師手動從從節(jié)點服務(wù)器列表中,選擇一個晉升為主節(jié)點,并且需要更新上游客戶端的配置,這種方式顯然是非常原始的,我們希望有一個機(jī)制,可以自動實現(xiàn) Failover,也就是 自動故障轉(zhuǎn)移 。
在 Redis 集群中,依賴 Sentinel,就可以實現(xiàn)上面的需求。
Redis Sentinel——Redis 哨兵
Redis Sentinel 就是我們常說的 Redis 哨兵機(jī)制,也是官方推薦的高可用解決方案,上面我們提到的主從復(fù)制場景,就可以依賴 Sentinel 進(jìn)行集群監(jiān)控。
Redis-Sentinel 是一個獨立運(yùn)行的進(jìn)程,假如主節(jié)點宕機(jī),它還可以進(jìn)行主從之間的切換。主要實現(xiàn)了以下的功能:
不定期監(jiān)控 Redis 服務(wù)運(yùn)行狀態(tài)
發(fā)現(xiàn) Redis 節(jié)點宕機(jī),可以通知上游的客戶端進(jìn)行調(diào)整
當(dāng)發(fā)現(xiàn) Master 節(jié)點不可用時,可以選擇一個 Slave 節(jié)點,作為新的 Master 機(jī)器,并且更新集群中的數(shù)據(jù)同步關(guān)系
現(xiàn)在思考一個場景,我們使用 Sentinel 來管理 Redis 集群高可用,假如 Sentinel 宕機(jī),那么整個系統(tǒng)還可以按照預(yù)期的方式運(yùn)行嗎?
答案是否定的,很明顯,Sentinel 也存在單點問題,如果 Sentinel 宕機(jī),高可用也就無法實現(xiàn)了,所以,Sentinel 必須支持集群部署。
實際上,Redis Sentine 方案是一個包含了多個 Sentinel 節(jié)點,以及多個數(shù)據(jù)節(jié)點的分布式架構(gòu)。除了監(jiān)控 Redis 數(shù)據(jù)節(jié)點的運(yùn)行狀態(tài),Sentinel 節(jié)點之間還會互相監(jiān)控,當(dāng)發(fā)現(xiàn)某個 Redis 數(shù)據(jù)節(jié)點不可達(dá)時,Sentinel 會對這個節(jié)點做下線處理,如果是 Master 節(jié)點,會通過投票選擇是否下線 Master 節(jié)點,完成故障發(fā)現(xiàn)和故障轉(zhuǎn)移。
Sentinel 在操作故障節(jié)點的上下線時,還會通知上游的業(yè)務(wù)方,整個過程不需要人工干預(yù),可以自動執(zhí)行。
Redis Cluster 集群
Redis Cluster 是官方的集群方案,是一種無中心的架構(gòu),可以整體對外提供服務(wù)。

為什么是無中心呢?因為在 Redis Cluster 集群中,所有 Redis 節(jié)點都可以對外提供服務(wù),包括路由分片、負(fù)載信息、節(jié)點狀態(tài)維護(hù)等所有功能都在 Redis Cluster 中實現(xiàn)。
Redis 各實例間通過 Gossip 通信,這樣設(shè)計的好處是架構(gòu)清晰、依賴組件少,方便橫向擴(kuò)展,有資料介紹 Redis Cluster 集群可以擴(kuò)展到 1000 個以上的節(jié)點。
Redis Cluster 另外一個好處是客戶端直接連接服務(wù)器,避免了各種 Proxy 中的性能損耗,可以最大限度的保證讀寫性能。
除了 Redis Cluster,另外一個應(yīng)用比較多的是 Codis 方案,Codis 是國內(nèi)開源的一個 Redis 集群方案,其作者是個大牛,也是一位技術(shù)創(chuàng)業(yè)者,不知道你有沒有聽過最近幾年比較火的分布式關(guān)系型數(shù)據(jù)庫 TiDB,就來自于作者的公司 PingCAP。
Codis 的實現(xiàn)和 Redis Cluster 不同,是一個“中心化的結(jié)構(gòu)”,同時添加了 Codis Proxy 和 Codis Manager。Codis 設(shè)計中,是在 Proxy 中實現(xiàn)路由、數(shù)據(jù)分片等邏輯,Redis 集群作為底層的存儲引擎,另外通過 ZooKeeper 維護(hù)節(jié)點狀態(tài),可以參考下面這張 Codis 的官方架構(gòu)圖:

之所以提到 Codis,是因為 Codis 和官方的 Redis Cluster 實現(xiàn)思路截然不同,使用 Redis Cluster 方式,數(shù)據(jù)不經(jīng)過 Proxy 層,直接訪問到對應(yīng)的節(jié)點。
Codis 和 Redis Cluster 的集群細(xì)節(jié)比較復(fù)雜,這里不展開討論,只要簡單了解即可,你也可以在課后分別去官網(wǎng)深入了解。就我自己而言,Codis 的監(jiān)控和數(shù)據(jù)遷移更加簡便,感覺 Codis 的設(shè)計更加合理,不過也是見仁見智,歡迎分享你的思考。
Redis Cluster 劃分了 16384 個槽位,每個節(jié)點負(fù)責(zé)其中的一部分?jǐn)?shù)據(jù),都會存儲槽位的信息,當(dāng)客戶端鏈接時,會獲得槽位信息。如果需要訪問某個具體的數(shù)據(jù) Key,就可以根據(jù)本地的槽位來確定需要連接的節(jié)點。
關(guān)于 Redis Cluster 為什么是 16384 個槽位,網(wǎng)上也有很多討論,Redis 的作者也給出了他的思考, 感興趣的可點擊這里查看。
總結(jié)
這一課時和你分享了 Redis 集群高可用的幾種配置方式,包括主從復(fù)制、Redis 的哨兵機(jī)制,簡單介紹了 Redis Cluster 和 Codis 的集群方式。
Redis 高可用集群也經(jīng)歷了一個發(fā)展過程,從早期社區(qū)中 Twitter 開源的 Proxy 方案,到現(xiàn)在官方的 Redis Cluster 集群方案,中間還有很多公司或者組織貢獻(xiàn)了開源方案,比如開源的 Codis、阿里云的 Redis Labs 等。
在我的工作中,一直是應(yīng)用 Twitter 的代理方案,后面就是公司內(nèi)部開發(fā)的一些中間件,在你的工作中應(yīng)用了哪些集群方案呢?歡迎留言進(jìn)行分享。