Redis是什么
Redis是現在最受歡迎的NoSQL數據庫之一,Redis是一個使用ANSI C編寫的開源、包含多種數據結構、支持網絡、基於內存、可選持久性的鍵值對存儲數據庫,其具備如下特性:
· 基於內存運行,性能高效
· 支持分布式,理論上可以無限擴展
· key-value存儲系統
· 開源的使用ANSI C語言編寫、遵守BSD協議、支持網絡、可基於內存亦可持久化的日志型、Key-Value數據庫,並提供多種語言的API
Ⅰ-主從(master-salver)2.8之前
redis同mysql一樣,雖然讀寫都很快,但是也會產生讀寫壓力大的情況。為了分擔讀的壓力,Redis支持主從復制,master進行寫操作,slave進行讀操作。Redis的主從結構可以采用一主多從或者級聯結構,Redis主從復制可以根據是否是全量分為全量同步和增量同步
Ⅱ-哨兵(sentinel)2.8之后
由於redis單一的主從復制模式下,容災性較差,當集群中master由於故障下線了,那么slaver因為沒有master而同步中斷,因而需要人工進行故障轉移工作。
Redis在2.8之后的版本提供了一種高可用的方案——哨兵模式(Sentinel),由一個或者多個哨兵節點組成Sentinel系統用於監聽一個或多個redis集群,監聽群內主節點以及其從節點服務提供狀態,並且當監聽的redis集群中master下線后,從master的從屬節點中選舉出新的master並維護新的主從關系。
注:哨兵監視redis集群的同時,哨兵節點之間也會相互監聽。

哨兵模式過程
1、監聽
sentinel在監聽redis的集群過程中會周期性的對redis集群發送指令進行狀態監控
| 周期 |
消息類型 |
動作 |
方向 |
作用 |
| 10s |
info命令 |
哨兵每隔10s向監聽的redis集群所有節點發送info命令 |
sentinel --> master sentinel --> slave |
1、通過info指令定期更新當前節點最新的節點信息 2、發現新加入的slave節點,確認其主從關系 |
| 2s |
sentinel:hello訂閱 |
master節點上會發布一個由哨兵訂閱的頻道,哨兵每隔2s發送自己的信息以及主節點判斷到頻道上 |
sentinel --> master |
1、所有的sentinel都會訂閱該頻道,sentinel通過該頻道相互發現,同時建立連接與監聽 2、sentinel之間會交換對主節點的狀態,為后續領導選舉與客觀下線做准備 |
| 1s |
PING - PONG |
每1s會對每個master、slave、sentinel發送心跳包 |
sentinel --> master sentinel --> slave sentinel --> sentinel |
1、實現了對每個節點的監控,是sentinel對節點判斷是否下線的依據 |
2、主觀下線與客觀下線
sentinel集群在監聽redis集群的過程中,每個哨兵會對master發送心跳PING來確認master的存活,如果master在“一定時間范圍”內不回應PONG,或者回應了一個錯誤的消息,該sentinel會認為當前集群的master已經無法使用(主觀下線),並同時向sentinel集群中的其他節點發送sentinel ismaster-down-by-addr命令詢問其他節點對主機的狀態判斷,當超過一定數量的sentinel確認master已經無法使用,這時候master下線的判定就認為是客觀的。
注:客觀下線后故障轉移決定需要由sentinel中的leader進行裁決,sentinel在發送is-master-down-by-addr的同時使用Raft實現leader選舉

3、領導者選舉
1)每個在線的Sentinel節點都有資格成為領導者,當它確認主節點主觀下線時候,會向其他Sentinel節點發送sentinel is-master-down-by-addr命令, 要求將自己設置為領導者
2)收到命令的Sentinel節點,如果沒有同意過其他Sentinel節點的sentinel is-master-down-by-addr命令,將同意該請求,否則拒絕
3)如果該Sentinel節點發現自己的票數已經大於等於max(quorum,num(sentinels)/2+1),那么它將成為領導者
4)如果此過程沒有選舉出領導者,將進入下一次選舉
4、故障轉移
故障轉移就是當master宕機,sentinel集群會在redis集群中,自動選擇一個合適的slave節點來升級為master節點的操作,不需要人工故障轉移。
1、篩選slave成為master
(1)過濾掉無法使用的slave(主觀下線,斷線)未回復Sentinel節點Pong相應的節點;
(2)選擇slave-priority最大的從節點(可能存在多個相同大小),如果只存在一個,則完成選擇,否則繼續;
slave-priority值在redis啟動文件中配置,用於決定故障轉移優先級,以及數據備份時的備份順序;
(3)選擇復制偏移量最大的從節點(復制最完整的)如果存在,則完成選擇,否則繼續;
redis集群中slave從master同步時,每台slave進與redis同步並非完全同步,不同slave同步master的進度可能不一致,在info relication中存在一項參數 master_repl_offset(復制偏移量)來表記錄主從同步的程度,每完成一次同步此值會進行累加,從多個slave中選擇偏移量最大的slave則能選出復制maste最完整的主機;
作用:通過對比主從節點的復制偏移量,可以判斷主從節點數據是否一致。可以通過主節點的統計信息,計算出master_repl_offset-slave_offset字節量,判斷主從節點復制相差的數據量,根據這個差值判定當前復制的健康度。如果主從之間復制偏移量相差較大,則可能是網絡延遲或命令阻塞等原因引起
(4)選擇runid(服務器運行的唯一ID)最小的從節點;
2、對新master發送 slaveof no one 指令,停止其主從復制
3、修改程序段連接到新的master
4、向集群中其他slave發送指令修改為新master的從機
5、原master重啟后修改為新master的slave

缺點:
1、如果是從節點下線了,sentinel是不會對其進行故障轉移的,連接從節點的客戶端也無法獲取到新的可用從節點
2、較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。
3、集群中只有一個主節點,當寫操作並發量特別大的時候,並無法緩解寫操作的壓力
Ⅲ-集群(cluster)3.0之后
為了解決Redis高可用模式下集群動態擴容困難、寫操作並發瓶頸問題,在3.0之后redis推出了Redis-Cluster集群模式。
redis-cluster采用無中心結構,每個節點保存各自的數據和整個集群的狀態,每個節點都和其他所有節點連接,客戶端連接任意主節點可以對整個集群中數據進行讀寫,所有的slave節點僅用於數據備份與故障轉移。

raft集群至少需要奇數個節點,所以至少需要3台redis作為集群中的master節點,而為了實現高可用(避免掛一台導賬集群無法使用)每個master至少需要一個slave來進行主從復制,所以一個redis-Cluster集群至少需要六台機器。
分布式存儲
redis-Cluster集群采用分布式存儲的機制,每個master以及其slave只存儲自己節點下的數據,客戶端與任意master節點進行讀寫操作,會通過cluster的集群算法路由到對應的機器上【一致性哈希算法】。
一致性哈希算法簡單的來說就是,redis-cluster把所有的redis節點映射到[0-16383]slot上(不一定是平均分配,圖示中物理機的哈希值為5461、10922、16383),每一次讀寫操作集群會計算key的哈希值,然后根據哈希值選擇對應機器進行讀寫。
將[0-16383]slot進行首尾相連,形成哈希環,對於每個redis節點會分配到一個值,該節點就負責自己節點值到上一節點值的所有slot值數據的存儲。
當集群要對一個key進行讀寫的時候,將key值計算出來的hash值向16384進行取模,將模值放入哈希環,並向后尋找第一個redis的slot值,然后將key值存入redis上。

通過這種方式,能夠保證集群中存在多台master同時進行寫操作,極大的降低了單節點高並發寫的壓力。
動態擴容
redis-cluster集群的一致性哈希算法支持動態擴容。動態擴容在一致性算法中涉及到兩個問題,slot桶的重新分配、數據轉移。

上圖所示是一個3節點redis-cluster集群里,redsi節點與key在哈希環上的映射關系,可以看出1、2兩個key會存儲在redis1上,3、4、5、6四個key會存儲在redis2上,而redis3只存儲了key7。當我們需要往集群中新增一台redis,如果改變了全部redis分配的slot,那么數據的轉移會涉及到整個集群, 那將是災難性的。
在一致性哈希算法下,會將新的redis節點計算出哈希值,放入哈希環中,這時,redis2中H(key)<=7866的所有key值會進行轉移,轉移到redis4中;而當我們需要在新集群中刪除掉其中一台redis2,redis2中的所有key將會根據算法遷移到redis3上進行存儲;

一致性哈希算法在保持了單調性的同時,還是數據的遷移達到了最小,這樣的算法對分布式集群來說是非常合適的,避免了大量數據遷移,減小了服務器的的壓力;
故障發現與故障轉移
Cluster集群在運行時所有的redis節點之間會通過ping/pong消息實現節點通信,消息不但傳輸節點槽信息,也能傳播節點狀態:主從狀態,節點故障等。
當集群中某一個節點出現問題時,集群會通過消息進行發現。與sentinel模式相同,節點故障在集群中也會經過主觀下線、客觀下線的過程,但是cluster集群中,並不需要sentinel來進行節點監控與故障轉移,而是由集群中的master們來處理的。
