哨兵主要針對單節點故障無法自動恢復的解決方案,集羣主要針對單節點容量、併發問題、線性可擴展性的解決方案。本文使用官方提供的redis cluster。文末有你們想要的設置ssh背景哦!
本文主要圍繞如下幾個方面介紹集羣
- 集羣簡介
- 集羣作用
- 配置集羣
- 手動、自動故障轉移
- 故障轉移原理
本文實現環境
- centos 7.3
- redis 4.0
- redis工作目錄 /usr/local/redis
- 所有操作均在虛擬機模擬進行
Redis集羣
一、集羣簡介
集羣是爲了解決主從複製中單機內存上限和併發問題,假如你現在的雲服務內存爲256GB,當達到這個內存時redis就沒辦法再提供服務,同時數據量能達到這個地步寫數據量也會很大,容易造成緩衝區溢出,造成從節點無限的進行全量複製導致主從無法正常工作。
那麼我們就需要把單機的主從改爲多對多的方式並且所有的主節點都會連接在一起互相通信。這樣的方式既可以分擔單機內存,也可以分發請求,提高系統的可用性。
如圖:當有大量請求寫入時,不再會單一的向一個主節點發送指令,而會把指令進行分流到各個主節點,達到分擔內存、避免大量請求的作用。
那麼指令是如何進行分流存儲的呢!我們就需要到集羣存儲結構中一探究竟。
二、集羣作用
- 分散單機的存儲能力,同時也可以很方便的實現擴展。
- 分流單機的訪問請求
- 提高系統的可用性
如何理解提高系統的可用性這句話,我們看下圖,當master1宕機後對系統的影響不會那麼大,仍然可以提供正常的服務。
這個時候就會有人問了,當master1宕機後集羣這個時候怎麼工作呀!這個問題會在下文的故障轉移來給你解答。並且在原理篇會對這個問題進行詳解
三、集羣存儲結構
1. 存儲結構
單機的存儲是當用戶發起請求後直接把key存儲到自己的內存即可。
集羣的存儲結構就沒有那麼簡單了,首先當用戶發起一個key指令後需要做的事情。
- 通過CRC16(key)會計算出來一個值
- 用這個值取模16384,會得到一個值,我們就先認爲是28
- 這個值28就是key保存的空間位置
那麼現在問題來了,這個key到底應該存儲在那個redis存儲空間裏邊呢!
其實redis在集羣啓動後就已經把存儲空間劃分了16384
份,每臺主機保存一部分。
這裏需要注意的是我給每個redis存儲空間裏邊的編號就相當於一個小的存儲空間(專業術語“哈希槽”
),你可以理解爲一棟樓裏邊的編號,一棟樓就是redis的整個存儲空間,每個房子的編號就相當於一個存儲空間,這個存儲空間會有一定的區域來保存對應的key,並非上圖取模後的位置。
箭頭指向的28是指的28會存儲在這個區域裏,這個房子有可能會存儲29、30、31等。
此時問題來了,如果新增、減少一臺機器後怎麼辦呢!看圖說話,能用圖說明儘量不去用文字。
在新增一臺機器後,會從其他三個存儲空間中拿出一定的槽分配給新的機器。這裏可以自己設置想給新的機器放多少個槽。
同樣減少一臺機器後會把去掉的槽在重新分配給其它現有的機器跟新增節點一樣,可以指定節點接收槽。
所謂的增節點或去節點就是改變槽所存儲的位置不同。
瞭解了集羣的存儲結構後,我們就需要在對另一個問題進行說明了,集羣是如何設計內部通訊呢!來了一個值,獲取一個key,去哪拿數據,跟着這個問題我們看下文。
2. 通訊設計
集羣中的每個節點會在一定的時期給其它節點發送ping消息,其它節點返回pong作爲響應。經過一段時間後所有節點都會知道集羣全部節點的槽信息。
如下圖有三個節點,那麼就會把16384個哈希槽分成三份。
分別爲0-5500、5501-11000、11001-16384
當用戶發起了一個key的請求,集羣是如何處理請求的呢!
下圖的黑框代表這集羣所有節點的槽信息,裏邊還有很多其它信息。
如圖所示,用戶發起請求key,redis接收後計算key的槽位置,在根據槽位置找出對應的節點
如果訪問的槽就在節點本身,那麼就會直接返回key對應數據。
否則會回覆moved重定向錯誤, 並且給客戶端返回正確的節點。
然後重發key指令
四、配置集羣
1. 修改配置文件
只需要注意咔咔圈中的配置信息即可
- cluster-enabled yes:開啓集羣模式
- cluster-config-file nodes-6379.conf:集羣配置文件
- clustre-node-timeout 10000:節點超時時間,這裏爲了方便測試設置爲10s
2. 構建6個節點的配置文件並全啓動
咔咔給大家提供一個命令可以很方便的替換文件sed 's/6379/6380/g' 6379-redis.conf > 6380-redis.conf
按照這樣的方式創建出來6個不同端口的配置文件
隨便打開一個配置文件查看,檢測是否替換成功
爲了查看日誌信息方便,全部使用前臺啓動。並且查看服務是否都正常啓動,執行命令ps -ef | grep redis
可以看到啓動後多了個cluster標識,代表着都是集羣的一個節點。
所有節點啓動完成,集羣啓動的指令需要基於ruby(咔咔使用redis版本爲4.0)。接下來一起安裝
3. 安裝ruby
執行命令wget https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.1.tar.gz
解壓:tar -xvzf ruby-2.7.1.tar.gz
根據自己下載的版本來解壓
安裝:./configure | make | make install
這三個指令一氣呵成。
查看ruby和gem版本:ruby -v
4. 啓動集羣
集羣的執行命令在/usr/local/redis/src/redis-trib.rb
注意如果需要直接使用redis-trib.rb
命令,需要ln到bin目錄下,否則就必須使用./redis-trib.rb
的方式。
如果按照步驟走,這裏會出現一個錯誤
執行gem install redis
很不幸的是在這裏也會出現錯誤。
隨後需要安裝yum install zlib-devel
和yum install openssl-devel
安裝完成後,在/ruby-2.7.1/ext/openssl
和 /ruby-2.7.1/ext/zlib
分別執行ruby extconf.rb
並且執行make | make install
然後在執行gem install redis
就OK
這時在回頭來執行./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384
信息解讀
創建集羣,並且給6個節點分配哈希槽,後三個節點配置爲前三個節點的從節點
顯示每個節點的哈希槽信息和節點ID,最後一步需要輸入yes
來到data目錄下查看配置文件的變化。配置文件主要信息是每個主節點分的槽
查看主機點的運行日誌
這裏給的主要信息cluster status changed:ok 集羣狀態正常
5. 集羣設置與獲取數據
當直接設置數據會報錯,並且把name這個key進行轉化後的槽位置爲5798 並且給出了ip地址和端口號。
需要使用命令redis-cli -c
在進行設置值的時候提示說重定向到5798的這個槽
接下來進行獲取數據,會自動的切換節點。
五、故障轉移
1. 集羣從節點下線
根據上文集羣啓動信息知道端口6383是6379的從節點。
接下來就是讓6383下線查看6379的日誌信息。
6379會報出連接6383丟失,並且給上標記fail,表示不可用。這個時候集羣還是正常工作的。
總結:從節點下線對集羣沒有影響
當端口6383上線後,所有的節點會把fail的標記清除
2. 集羣主節點下線
手動下線主節點6379,查看從節點6383日誌信息
此時的6383節點會持續連接6379共計10次。那爲什麼是10次呢!
是根據我們配置的參數cluster-node-timeout 10
來決定的,這裏給我們一個信息就是一秒連接一次
直到時間到期後,開始故障轉移。
這時6383在故障轉移選舉中勝任,翻身奴隸把歌唱,成爲了主節點。
此時在查看一下集羣的節點信息,命令cluster nodes
。
會發現這裏竟然存在四個主節點,但是其中一個主節點時下線狀態
6379原主節點上線
6379上線後,同樣所有的節點也會清除fail信息。
並且節點信息也會改變,此時的6379改變爲6383的從節點。
3. 新增主節點
在新增倆個端口6385和6386
執行新增命令./redis-trib.rb add-node 127.0.0.1:6385 127.0.0.1:6379
,這裏發送的就是meet消息
執行add-node命令,第一個參數爲新節點的ip+端口 第二個參數爲已存在集羣中的節點。根據下圖我們就可以看到新增的節點已經存在集羣中了。
注意:雖說6385已經成爲集羣中的節點了,但是跟其它節點有區別。它沒有數據,也就是沒有哈希槽
接下來我們就需要把集羣中的某些哈希槽分配到這個新節點上,分配結束後這個節點纔會成爲真正意義上的主節點
執行命令./redis-trib.rb reshard 127.0.0.1:6385
會提示轉移多少個哈希槽並填寫接收節點的id
最後一步詢問是否從所有節點中轉移:咔咔使用的是all
使用指令:cluster nodes
查看,6385的這個節點就已經擁有三個範圍的哈希槽了
主節點已經新增好了,接下來就需要給6385這個主節點配置一個從節點6386
命令:./redis-trib.rb add-node --slave --master-id dcc0ec4d0c932ac5c35ae76af4f9c5d27a422d9f 127.0.0.1:6386 127.0.0.1:6385
master-id是6385的id,第一個參數爲新節點的ip+端口 第二個爲指定的主節點ip+端口
4. 手動故障遷移
當想對集羣中的主節點進行升級的話可以手動執行故障轉移到從節點,避免集羣可用性受影響。
在從節點執行命令:cluster failover
執行過程
查看節點信息就可以看到6386這個節點已經成爲了主機點。
當給從節點發送cluster failover 指令後,從節點會給主節點發送CLUSTERMSG_TYPE_MFSTART包。從節點請求主節點停止訪問,從而對比兩者的數據偏移量達到一致。
這時客戶端不會連接我們淘汰的主節點,同時主節點向從節點發送複製偏移量,從節點得到複製偏移量後故障轉移開始,接着通知主節點進行配置切換,當客戶端在舊的master上解鎖後重新連接到新的主節點上。
六、故障轉移原理篇
上文中我們測試了故障轉移,主節點下線後從節點變爲主節點,接下來剖析這個過程。
1. 故障發現到確認
集羣中的每個節點會定期的給其它節點發送ping消息,接收方用pong作爲回覆。
如果在cluster-node-timeout的時間內ping消息一直失敗,則會把接收方的節點標記爲pfail狀態也就是主觀下線。
這個下線狀態是不是很熟悉。沒錯,這個跟哨兵判斷主節點是否異常有點相似。當一個哨兵發現主節點有問題時也會標記主節點客觀下線(s_down)。 突然發現跑題了,尷尬…
在提一下哨兵,當一個哨兵認爲主節點異常後標記主觀下線,但是其它哨兵怎麼能會同意,不能你說什麼就是什麼。都會去嘗試連接異常的主節點,當半數以上的哨兵都認爲主節點異常後會直接讓其主節點客觀下線。
同樣集羣也不會因爲一個節點判斷其狀態爲下線就行的,節點直接通過Gossip消息傳播,集羣中節點會不斷收集故障節點的下線反饋並且存儲到本地的故障節點下線報告中。當有半數以上的集羣主節點都標記爲主觀下線後改變狀態爲客觀下線。
最後向集羣廣播一條fail消息,通知所有節點將故障節點標記爲客觀下線。
例如:節點A發送ping到節點B通信異常後標記節點B爲pfail,之後節點A會繼續給節點C發送ping並且攜帶節點B的pfail信息然後節點C將節點B的故障保存到下線報告中。當下線報告數量大於有哈希槽主節點的一半數量以上後就會嘗試客觀下線。
2. 故障恢復(從節點從此翻身奴隸把歌唱)
當故障節點被定義爲客觀下線後,故障節點的所有從節點承擔故障恢復的責任。
故障恢復是從節點通過定時任務發現自己的主機點客觀下線後就會執行故障恢復流程。
1. 資格檢查
所有的從節點都會進行檢查與主節點最後的連接時間,斷線時間大於cluster-node-time*cluster-slave-validity-factor時不具備故障轉移的資格。
2. 準備選舉時間
先說說爲什麼這裏會有一個準備選舉時間。
資格檢查過後存在多個從節點,那麼就需要使用不同的延遲選舉時間來支持優先級。這裏的優先級就是
以複製偏移量爲基準,偏移量越大與故障主節點的延遲越小,那麼就更有機會擁有替換主節點的機會。
主要的作用就是確保數據一致性最好的節點優先發起選舉
3.選舉投票
redis集羣的投票機制沒有采用從節點進行領導選舉,這點切記不要跟哨兵搞混了。集羣的投票機制都是持有槽的主機點進行投票的。
故障節點的從節點會廣播一個FAILOVER_AUTH_REQUEST 數據包給所有的持有槽的主節點請求投票。
當主節點回復FAILOVER_AUTH_ACK投票後在NODE_TIMEOUT * 2的這段時間不能給其它的從節點投票
從節點獲取到半數以上的投票後就會進行故障恢復階段
4. 故障轉移
選舉成功的從節點取消複製變爲主節點
刪除故障節點的槽,並且將故障節點的槽委託到自己身上
向集羣廣播自己的pong消息,通知主機點的改變和接管了故障節點的槽信息。
你們想要的ssh的背景!!!
一篇利用倆個夜晚才弄完的redis哨兵文章,結果你們的關注點卻不在文章本身,啊!小編心很痛
爲了滿足大家的要求,咔咔忍痛說一下如何設置亮瞎的背景。
咔咔使用的工具是xsheel
打開工具選擇選項
接着到查看有個窗口透明就可以設置xsheel透明瞭。
對嘍!你想的沒錯這就是桌面背景,是不是準備開始設置去了。那設置完了回來再把文章看完好嗎?咔咔也需要各路大神給予技術點補充和辨錯。