一. 主從復制
1. 含義
在分布式系統中,為了解決單點問題,通常會把數據復制多個副本到其它機器,滿足故障恢復和負載均衡等要求,Redis也是如此,提供了主從復制功能。(redis第一代架構)
實質:一個主服務器(master)對應多個從服務器(slave),主從之間實現數據同步,主服務器負責【寫】,從服務器負責【讀】,另外從服務器通常會配置只支持讀,不支持寫(replica‐read‐only yes)。
PS:主從復制是redis高可用的基礎,后面的Sentinel和Cluster都是在主從復制的基礎上進行升級實現高可用的。
如圖:
2. 常用操作
(1). 建立主從復制
A. 在從節點在配置文件中加入 replicaof {masterHost} {masterPort},隨redis啟動生效。 【配置文件】
B. 在redis-server啟動命令后加入 -slaveof {masterHost} {masterPort} 生效。 【指令】
C. 直接使用命令:slaveof {masterHost}{masterPort} 生效 【指令】
PS:查看復制信息 info replication
(2). 斷開復制
從節點執行指令:slave of no one來斷開與主節點復制關系。
A. 斷開與主節點復制關系。
B. 從節點晉升為主節點。
PS:從節點斷開復制后不會拋棄原有數據,只是無法在獲取主節點的數據變化了。
(3). 切換主節點
從節點執行命令:slaveof {newMasterIp}{newMasterPort}命令即可
A.斷開與舊主節點的復制關系。
B.與新主節點建立復制關系。
C.刪除從節點當前所有數據。
D.對新主節點進行復制操作。
注:線上操作一定要小心,因為切主后會清空之前所有的數據。
分享主從的配置文件:
主服務器不需要做特別配置,正常啟動即可,假設主服務器的地址為: 192.168.0.1:6379 ,下面分享從服務器的配置文件,然后正常啟動即可。
# 實際上就兩句話 replicaof 192.168.0.1 6379 # 從本機6379的redis實例復制數據 replica‐read‐only yes #配置從服務器只讀
3. 主從復制的原理
詳見:https://www.cnblogs.com/yaopengfei/p/13879077.html
4. 弊端分析
主從模式下,master主節點一旦發生故障,則不能提供服務,需要人工修改從節點的配置進行干預,將從節點晉升為主節點(主從架構不能沒有選舉功能!!),同時還需要修改客戶端配置(redis鏈接地址改為原先從節點的地址),非常不友好。
基於此背景,Redis2.8發布了一個穩定版本Sentinel機制(Redis2.6最早推出Sentinel,但存在一些問題)
二.Sentinel 哨兵
1. 含義
Sentinel架構解決redis主從架構人工干預的問題。
Sentinel哨兵是特殊的redis服務,不提供讀寫服務,主要用來監控redis實例節點。哨兵架構下client端第一次從哨兵找出redis的主節點,后續就直接訪問redis的主節點,不會每次都通過sentinel代理訪問redis的主節點,當redis的主節點發生變化,哨兵會第一時間感知到,並且將新的redis主節點通知給client端(這里面redis的client端一般都實現了訂閱功能,訂閱sentinel發布的節點變動消息)
2. 運行原理
可以在一個架構中運行多個Sentinel進程,這些進程采用流言協議(gossip protocols)來接受關於主服務器是否下線的信息,並使用投票協議(agreement protocols)來決定是否執行故障遷移,以及選擇哪個從服務器作為新的主服務器。
Redis的Sentinel系統用於管理多個Redis實例(服務器),該系統執行以下三個任務:
(1). 監控
Sentinel會不斷的定期檢查你的主服務器和從服務器是否運作正常。
(2). 提醒
當被監控的某個Redis服務器出現問題的時候,Sentinel可以通過API向管理員或者其它應用程序發送通知。
(3).自動故障遷移
當一個主服務器不能正常工作的時候,Sentinel會開始一次自動故障遷移工作,它會將失效的主服務器的其中一個從服務器升級為新的主服務器,並讓其它的從服務器改為復制新的主服務器;當客戶端試圖鏈接失效的的主服務器的時候,集群會向客戶端返回新的主服務器的地址,使得集群可以適用新主服務器代替失效服務器。
總結:Redis Sentinel是一個分布式架構,其中包含N個Sentinel節點和N個Redis數據節點,每個Sentinel節點會對數據節點和其它的Sentinel節點進行監控,當發現節點不可用時,會對該節點做下線標識,如果被標識的是主節點,他還會和其它的Sentinel進行“協商”,當大多數節點都認為主節點不可用時候,會選舉出來一個Sentinel節點來完成自動故障轉移工作,同時會將這個變化實時通知給redis客戶端,整個過程是自動的,不需要人工干預,有效的解決了redis高可用的問題。
如下圖:
3. 代碼配置
#1.復制一份sentinel.conf文件 cp sentinel.conf sentinel‐26379.conf #2.將相關配置修改為如下值: port 26379 daemonize yes pidfile "/var/run/redis‐sentinel‐26379.pid" logfile "26379.log" dir "/usr/local/redis‐5.0.3/data" # sentinel monitor <master‐name> <ip> <redis‐port> <quorum>
# quorum是一個數字,指明當有多少個sentinel認為一個master失效時(值一般為:sentinel總數/2 +1),master才算真正失效 (此處的ip和port都要對應redis的master的地址)
sentinel monitor mymaster 192.168.0.60 6379 2
#3.啟動sentinel哨兵實例 src/redis‐sentinel sentinel‐26379.conf #4.查看sentinel的info信息,可以看到Sentinel的info里已經識別出了redis的主從
src/redis‐cli ‐p 26379
info
#5.可以自己再配置兩個sentinel,端口26380和26381,注意上述配置文件里的對應數字都要修改
4. 分析
優勢:
當主節點出現故障時,redis sentinel能自動完成故障發現和故障轉移,並通知客戶端從而實現真正的高可用。
設置多個Sentinel節點的好處:①對節點的故障判斷是由多個節點完成的,可以有效的防止誤判。 ② 多個Sentinel節點,即使出現了個別節點不可用,也不會影響客戶端的訪問。
弊端:
(1). 配置相對復雜。
(2). 雖然解決了第一代中主掛全掛的問題,但所有的寫壓力都在一個master上,且宕機的時候,slave頂上去的這個切換期間,整個服務停止,從而影響項目的正常運行。而且就一個master,單個節點的極限並發也就10萬左右了。
從而引出Redis第三代架構,Redis Cluster,多個master節點,且無中心節點,可以盡情的橫向擴展。
5. 哨兵leader選舉流程
當一個master服務器被某sentinel視為客觀下線狀態后,該sentinel會與其他sentinel協商選出sentinel的leader進行故障轉移工作。每個發現master服務器進入客觀下線的sentinel都可以要求其他sentinel選自己為sentinel的leader,選舉是先到先得。同時每個sentinel每次選舉都會自增配置紀元(選舉周期),每個紀元中只會選擇一個sentinel的leader。如果所有超過一半的sentinel選舉某sentinel作為leader。之后該sentinel進行故障轉移操作,從存活的slave中選舉出新的master,這個選舉過程跟集群的master選舉很類似。
哨兵集群只有一個哨兵節點,redis的主從也能正常運行以及選舉master,如果master掛了,那唯一的那個哨兵節點就是哨兵leader了,可以正常選舉新master。
不過為了高可用一般都推薦至少部署三個哨兵節點。為什么推薦奇數個哨兵節點原理跟集群奇數個master節點類似。
三. Redis Cluster
1. 前言
在Redis Cluster出現之前,業界普遍使用的Redis多實例集群的方式主要是以下兩類方案:
(1). 客戶端分片方案
A. 哈希取模:hash(key)% N,hash代表一種散列算法,N代表redis服務器的數量。這種算法實現起來非常簡單,但是缺點也是非常明顯的,當服務器數量N增加或者減少的時候,原先的緩存數據定位幾乎失效,緩存數據定位失效意味着要到數據庫重新查詢,這對於高並發的系統來說是致命的。
B. 一致性哈希算法:將key和server都進行hash,分配在閉環上,采用臨近原則,key 找 離它最近的server節點進行存儲。 詳細參考:https://blog.csdn.net/maihilton/article/details/81979361
剖析:客戶端分片的方案,優點是分區邏輯可控;缺點是需要自己處理數據路由、高可用、故障轉移等,而且即使采用一致性哈希算法,還是會存在少量key匹配不到丟失的情況,需要做鍵值的遷移。
客戶端分區 和 服務端分區對比:
客戶端sharding技術其優勢在於服務端的Redis實例彼此獨立,相互無關聯,每個Redis實例像單服務器一樣運行,非常容易線性擴展,系統的靈活性很強。其不足之處在於:
由於sharding處理放到客戶端,規模進步擴大時給運維帶來挑戰。 服務端Redis實例群拓撲結構有變化時,每個客戶端都需要更新調整。連接不能共享,當應用規模增大時,資源浪費制約優化。
服務端sharding的Redis Cluster其優勢在於服務端Redis集群拓撲結構變化時,客戶端不需要感知,客戶端像使用單Redis服務器一樣使用Redis集群,運維管理也比較方便。
(2). 代理方案
使用代理中間件:twemproxy
Twemproxy是一種代理分片機制,由Twitter開源。Twemproxy作為代理,可接受來自多個程序的訪問,按照路由規則,轉發給后台的各個Redis服務器,再原路返回。該方案很好的解決了單個Redis實例承載能力的問題。當然,Twemproxy本身也是單點,需要用Keepalived做高可用方案。通過Twemproxy可以使用多台服務器來水平擴張redis服務,可以有效的避免單點故障問題。雖然使用Twemproxy需要更多的硬件資源和在redis性能有一定的損失(twitter測試約20%),但是能夠提高整個系統的HA也是相當划算的。不熟悉twemproxy的同學,如果玩過nginx反向代理或者mysql proxy,那么你肯定也懂twemproxy了。其實twemproxy不光實現了redis協議,還實現了memcached協議,什么意思?換句話說,twemproxy不光可以代理redis,還可以代理memcached。
參考:https://www.cnblogs.com/gomysql/p/4413922.html
https://www.cnblogs.com/kuncy/p/9903482.html
2. Redis Cluster介紹
該模式是由多個主從節點群組成的分布式服務集群,它具有復制、高可用和分片特性。Redis Cluster不需要Sentinel-哨兵也能完成節點移除和故障轉移工作。需要將每個節點設置成集群模式,這種集群沒有中心節點,可水平擴展,根據官方文檔成可以線性擴展到1000個節點,redis集群的性能和高可用性均優於之前的哨兵模式,且集群的配置非常簡單。
如圖:
剖析:
多個master平行節點,分攤了寫的壓力,且無論是master還是slave水平都可以擴展很多。
但也有弊端,假設1個master和下面的slave全部掛掉,那么分配在該master節點中的槽位對應的key將失效,無法獲取,新的請求進來,經過 crc16(key) % 16384 計算,如果slot在這個掛掉的master上,則寫入操作也無法進行。(此處的演示詳見cluster搭建章節 https://www.cnblogs.com/yaopengfei/p/13856347.html)
3. Redis Cluster通信流程
總結一句話:集群中的每個節點都會單獨開辟一個Tcp通道,用於節點之間通信,通信端口為:原基礎端口+10000,比如redis的端口為6379,那么他的通信端口就是16379。
(1). 在分布式存儲中需要提供維護節點元數據信息的機制,所謂元數據指:節點負責哪些數據,是否出現故障燈狀態信息,redis集群采用Gossip(流言)協議,Gossip協議工作原理就是節點彼此不斷交換信息,一段時間后,所有的節點都會知道集群的完整信息,類似流言傳播。
通信過程如下:
A. 集群中的每個節點都會單獨開辟一個Tcp通道,用於節點之間通信,通信端口為:原基礎端口+10000,比如redis的端口為6379,那么他的通信端口就是16379
B. 每個節點在固定周期內通過特定規則選擇結構節點發送ping消息
C. 接收到ping消息的節點用pong消息作為響應。集群中每個節點通過一定規則挑選要通信的節點,每個節點可能知道全部節點,也可能僅知道部分節點,只有這些節點彼此可以正常通信,最終才會達成一致的狀態,當節點出現故障,新節點介入,主角色變化等,它能夠不斷的ping/pong消息,從而達到同步的目的。
(2). Gossip協議詳解
Gossip協議的職責就是信息交換,信息交換的載體就是節點之間彼此發送的Gossip消息。常見的Gossip消息分為:ping pong meet fail等
A. meet消息:用於通知新節點的加入,消息發送者通知接收者加入當前集群,mmet消息通信正常完成后,接收節點會加入到集群中並進行周期性的ping、pong信息交換。
B. ping消息:集群內部交換最頻繁的消息,集群內每個節點每秒都向多個其它節點發送ping消息,用於檢測節點是否在線和彼此交換信息。
C. pong消息:當接收到ping、meet消息時,作為響應消息回復給發送發確認消息可以正常通信,節點也可以向集群內廣播自身的pong消息來通知整個集群對自身狀態進行更新。
D. fail消息:當節點判定集群內另一個節點下線時,會向集群內廣播一個fail消息,其它節點收到fail消息猴,把對應節點更新為下線狀態。
如下圖:
4. Redis Cluster路由機制
(1). Moved重定向
A. 普通連接
如果指令在這個node上,則處理指令;如果不在這個node上,則redis會返回給客戶端MOVED重定向錯誤,通知客戶端重新請求正確的node,這個過程稱為MOVED重定向。
重定向信息中包含了key, slot,node的地址,根據這些信息,客戶端就可以去請求正確的node,流程圖如下:
./redis-cli -h 192.168.137.201 -p 6380 -a 123456
測試:在已經搭建好的redis cluster下,6379、6380、6381是master節點,下面通過普通連接(沒有-c),連接到6380端口上,進行數據的寫入命令,
(2).集群的模式連接
在使用redis-cli時,可以加入 -c 參數,支持自動重定向,簡化手動發起重定向的操作,這里redis-cli自動幫我們連接到了正確的node, 這個過程是redis-cli內部維護的,他先收到了MOVED信息,然后向新node發起請求。
./redis-cli -c -h 192.168.137.201 -p 6380 -a 123456
測試:在已經搭建好的redis cluster下,6379、6380、6381是master節點,下面通過集群的連接方式,連接到6380端口上,進行數據的寫入命令,
(2). ASK重定向
redis cluster除了moved重定向,還有ask重定向。ask重定向代表的狀態比較特別,它是當slot處於遷移狀態時才會發生。例如:一個slot存在三個key,分別為k1、k2、k3,假設此時slot正在處於遷移狀態,k1已經遷移到了目標節點,此時如果在源節點獲取k1,則會報出ask重定向錯誤。
5. Redis Cluster 分片機制
在Redis Cluster中,Redis 為了更好的分配存儲數據,引入槽位的概念(slot),Redis Cluster共有16384個槽位,在創建集群的時候,這些槽位會平均分給每個master節點,當key進來的時候,會對key進行一定處理,計算出slot值,然后分配到該值對應16384個slot中的某個slot所在的redis的master節點上,這里采用的hash算法為:CRC16(key) % 16384,這就是Redis Cluster的分片機制。
如圖:
注意:分片機制是一種Redis服務端的路由規則,是為了解決Redis分布式部署下Key的分配存儲位置問題,為了分攤高並發下寫的壓力,並不是1個槽位只能存1個key,槽位與能存儲Key的個數沒有任何關系,Redis Cluster是一種服務器端分片的技術。
測試:已經搭建好redis cluster,6379 6380 6381是三個master節點,6382 6383 6384 分別是三個master對應slave節點。
(1). 查看slots分配情況
(2). 查看寫入數據時候的跳轉機制,自動匹配對應的槽位,進行寫操作
(3). 連接從節點,獲取數據,還是會重定向到主節點進行獲取。
注:redis cluster中的slave節點上沒有slot槽位,不對外提供服務,只是為了備份數據,當master宕機的時候,slave會頂替上去成為master節點,即使客戶端訪問從節點(讀或寫),redis內部也會重定向到主節點。
6. 集群選舉原理分析
當slave發現自己的master變為FAIL狀態時,便嘗試進行Failover,以期成為新的master。由於掛掉的master可能會有多個slave,從而存在多個slave競爭成為master節點的過程, 其過程如下:
(1). slave發現自己的master變為FAIL
(2). 將自己記錄的集群currentEpoch加1,並廣播FAILOVER_AUTH_REQUEST 信息
(3). 其他節點收到該信息,只有master響應,判斷請求者的合法性,並發送FAILOVER_AUTH_ACK,對每一個epoch只發送一次ack
(4). 嘗試failover的slave收集master返回的FAILOVER_AUTH_ACK
(5). slave收到超過半數master的ack后變成新Master (這里解釋了集群為什么至少需要三個主節點,如果只有兩個,當其中一個掛了,只剩一個主節點是不能選舉成功的)
(6). 廣播Pong消息通知其他集群節點。
補充:
從節點並不是在主節點一進入 FAIL 狀態就馬上嘗試發起選舉,而是有一定延遲,一定的延遲確保我們等待FAIL狀態在集群中傳播,slave如果立即嘗試選舉,其它masters或許尚未意識到FAIL狀態,可能會拒絕投票
•延遲計算公式:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
•SLAVE_RANK:表示此slave已經從master復制數據的總量的rank。Rank越小代表已復制的數據越新。這種方式下,持有最新數據的slave將會首先發起選舉(理論上)。
7. 靈魂拷問
(1). 網絡抖動的解決方案?
真實世界的機房網絡往往並不是風平浪靜的,它們經常會發生各種各樣的小問題。比如網絡抖動就是非常常見的一種現象,突然之間部分連接變得不可訪問,然后很快又恢復正常。
為解決這種問題,Redis Cluster 提供了一種選項cluster-node-timeout,表示當某個節點持續 timeout 的時間失聯時,才可以認定該節點出現故障,需要進行主從切換。如果沒有這個選項,網絡抖動會導致主從頻繁切換 (數據的重新復制)。
(2). 集群是否完整才能對外提供服務 ?
當redis.conf的配置cluster-require-full-coverage為no時,表示當負責一個插槽的主庫下線且沒有相應的從庫進行故障恢復時,集群仍然可用,如果為yes則集群不可用。
(3). Redis集群為什么至少需要三個master節點,並且推薦節點數為奇數?
因為新master的選舉需要大於半數的集群master節點同意才能選舉成功,如果只有兩個master節點,當其中一個掛了,是達不到選舉新master的條件的。
奇數個master節點可以在滿足選舉該條件的基礎上節省一個節點,比如三個master節點和四個master節點的集群相比,大家如果都掛了一個master節點都能選舉新master節點,如果都掛了兩個master節點都沒法選舉新master節點了,所以奇數的master節點更多的是從節省機器資源角度出發說的。
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。