1. 程式人生 > >Redis筆記(二、Redis單例項到叢集)

Redis筆記(二、Redis單例項到叢集)

Redis 部署方案
單節點
預設情況下Redis 為單示例模式,安裝簡單,使用也便捷. 生產環境中存在單節點問題,受限於單機的記憶體,不具備擴充套件的能力。
Redis 安裝
1.下載安裝包https://redis.io 下載最最新版本
2.解壓縮tar -zxf redis-3.0.1.tar.gz
3.cd redis-3.0.1 ;make install;
4.修改配置檔案配置守護後臺執行
vi redis.conf; daemonize yes
5.啟動Redis
redis-server   /app/redis-3.0.1/redis.conf
6.使用redis-cli 環境連線,預設的埠為6379,不修改可以不填
redis-cli  -p 6379
 

7.安裝完畢後可使用Java客戶端實現Jedis來操作Redis.指令可參考官網文件和Jedis Api.
Redis 主從複製
預備知識
主從架構--> 主[Master],從[Slave]
基於Redis的複製特性,允許Slave節點從Master節點中精確進行資料複製,類似於關係型資料庫Oracle\Mysql的資料複製.連結斷開時Slave節點自動重連到Master節點,始終嘗試進行精確資料複製.有以下三種複製策略.
主從節點狀態良好-->主節點發送一系列的命令到從節點保持對從節點的更新[寫入\過期\刪除]等
主從網路中斷-->從節點重新連上後先試圖同步自網路斷開期間錯過的資料流.
區域性同步不可用-->從節點要求重新同步,執行更復雜的操作,主節點建立所有資料的完整快照併發送到從節點,並在資料集更改時繼續傳送命令流.
Redis 預設使用非同步複製,從節點非同步確認接收到來自於主節點的資料.
客戶端可以使用WAIT命令請求同步複製某些資料,只能確保在另一個Redis例項中有指定數量的公認副本.在故障轉移期間由於不同原因造成的故障轉移,或者依賴於Redis永續性的配置,仍然可能在故障期間丟失資料.
Redis 複製採用非同步方式,從節點非同步的確認回覆主節點同步到從節點的資料量
一個Master可以有多個Slaves
Slaves 節點也可以擁有Slaves節點
Master節點上覆制是非阻塞的
複製很大程度上也是非阻塞的
複製可用於擴充套件伸縮性,也可用於為只讀查詢提供多個Slave
可以使用複製來避免主節點向磁碟寫入資料,***   -->實驗特性

主節點關閉持久化時安全複製
主從模式中建議對主從都進行持久化,當由於磁碟緩慢導致延遲的時候這是不可取的,如果對主節點採用非持久化則應該配置在機器重啟後避免主節點自動重啟.
以下故障模式,資料將從主從以及所有從節點中刪除
A作為主節點關閉其持久化,B、C作為A的從節點.
節點A奔潰,系統重啟後A節點配置了自動重啟,由於關閉了持久化,導致A節點以一個空的資料集啟動.
節點B\C從A節點複製資料,從而銷燬自己的資料副本.資料丟失!
複製的工作原理
Master節點儲存了副本的ID,一個大的隨機字串,用於標記資料集傳送情況,主節點持有傳送給從節點的複製流的偏移,主節點將對新資料集的修改更新到從節點,偏移量由主節點進行維護,偏移量保持遞增的   -->  [Replication ID, offset]
定義主節點資料集的版本
Slave連線到Master時使用自己的PSYNC命令傳送舊的在Master中的複製ID,和自己當前消費的偏移量,通過這種方式Master只需傳送所需的增量部分,如果Master快取區沒有足夠的backlog,或者Slave引用了一個過期的偏移,這種情況下從頭開始獲取資料集的完整副本.
完整的資料同步過程:
Master啟動一個後臺程序將資料寫入並生成RDB檔案,並開始快取從客戶端收到的所有的寫命令,後臺程序儲存完成後,Master將資料庫檔案傳輸給Slave節點,Slave將資料儲存在磁碟上載入到內從中.Master向Slave傳送快取的命令,複製正常執行.
無磁碟複製
2.8.18後的版本支援直接將RDB檔案傳送到Slave節點從而繞靠緩慢的磁碟同步.
見redis.conf配置
主從複製配置
在Slave節點中配置 slaveof 192.168.1.1 6379
其它引數見redis.conf說明
只讀的副本
預設情況下副本為只讀的 -->slave-read-only 選項控制 -->可以通過進一步的禁用Redis命令來提高只讀的安全性[網路不一定被禁用-->Redis-cli可訪問].
可寫的Slave是本地化的,其寫指令不具備傳播性.
Master-Slave許可權驗證
Master可要求Slave認證
只在滿足最小副本數時寫
Redis2.8+可以配置只有至少N個Slave節點連線到主伺服器的情況下才允許Master執行寫操作.
原理
Reids 每秒向Master伺服器傳送ping訊號,並確認複製流的數量.
Master記錄Slave傳送ping訊號的時間作為最後的心跳時間.
使用者可配置最小Master數量,以及不得大於的最大延遲時間
min-slaves-to-write-->Master寫要求的最小Slaves數量
min-slaves-max-lag-->Slave ping請求的最大延遲時間
Redis Replication 處理Keys過期
Keys的過期依賴於節點計算過期時間的能力.即使使用Lua 指令碼修改這些Keys Redis也可以正確的處理Keys的過期
Reidis 不依賴於Master\Slave的時鐘同步
1.Slaves 不過期keys,相反等待master將keys過期,當Master中的一個key過期[或者被LRU淘汰],會生成一個DEL 命令傳送給所有的Slaves.
2.Master不能實時提供DEL 指令,Slaves使用自己的邏輯時鐘檢查併為只讀操作報告Key並不存在,這樣不違反資料一致性[Slave隨後將收到DEL指令],通過這種邏輯,Slave避免過期的key任然存在並被客戶端感知。
3.Lua Scripting 執行期間不執行任何keys過期操作,Lua 執行期間Master中時間被凍結,給定的key只處於存在和不存在狀態,Lua指令碼被完全複製到Slaves中執行.
如果一個Slave被提升為Master,將開始獨立過期Keys,不在依賴於Master
Info & Role
info-->info [replication]-->顯示覆制相關的資訊
rele-->顯示當前節點的角色資訊
Redis 持久化

Reids為內從資料庫,執行時資料被載入到記憶體中加速讀寫速度,Redis提供了一定的策略用於資料的持久化,防止資料丟失.
RDB在指定時間間隔持續性的建立資料集在指定時間點的快照
AOF[Append-only file]記錄服務記錄接收到的每一個寫操作,在服務意外重啟後進行資料集重建.AOF記錄的格式為Redis協議相同-->資料量非常大的情況下快速重建資料集
Redis 允許禁用永續性,
同一Reids示例,可以結合RDB和AOF,這種情況下AOF檔案將被用來重建完整資料集 -->AOF檔案儲存的是最完整的
RDB優勢
非常緊湊的單檔案時間節點表示,指定時間間隔進行資料快照.
非常適於災備恢復,將單一壓縮檔案傳輸到遠端資料中心.
使Redis效能最大化,快照由獨立執行緒維護
允許更快速的重新啟動大型叢集
RDB劣勢
不能將資料丟失的機率降低到0,
需要子程序fork()完成快照任務,資料集很大的話可能會耗費大量時間
AOF優勢
使Redis持久化更有保證,可以有不同的同步策略,[不同步,每秒,每次查詢],預設每秒同步一次到磁碟,重新整理使用後臺執行緒執行,不影響寫入,預設的配置最多損失1S的寫入.
AOF是附加日誌檔案,如果斷電不用查詢,不會出現損壞問題,Redis提供了AOF檔案修復工具,
當AOF檔案過大的時候Redis會自動重寫它,重寫是完全安全的,Redis 繼續追加到舊檔案,會建立一個能容下當前資料集的最小檔案,一旦第二個檔案準備好Redis交換兩檔案.開始追加到新的檔案.
AOF易於理解,包含了一個一個的操作日誌.AOF檔案可以被匯出.
AOF缺點
對於同一資料集,AOF通常被RDB大
按精確的語意AOF比RDB慢
罕見的BUG[BRPOPLPUSH導致AOF產生不能在重新載入時複製完全相同的資料集]
快照
預設情況下Reids的快照檔名為dump.rdb,可以配置Redis在N秒有M個變化就執行快照.或者手動呼叫SAVA \BGSAVE 命令
fork()子程序-->寫新的快照檔案-->替換舊的快照檔案
追加檔案
完全持久化的保證,使用一下配置啟用
appendonly yes
日誌重寫
Redis支援在不中斷響應的情況下重寫AOF日誌檔案,2.4+可自動觸發日誌重寫.
Redis可配置AOF快取重新整理到磁碟的策略:
每個命令都重新整理到磁碟 --> Very very slow  very safe.
每秒重新整理一次--> 足夠塊,災難時可能丟失1S的資料
從不重新整理-->
AOF檔案修復
建立AOF檔案的備份,--> redis-check-aof --fix 修復--> diff -u 檢視區別 -->使用修復的檔案重啟叢集
日誌重寫工作原理
fork()子程序
子程序寫新的AOF檔案到快取目錄,
父程序在記憶體中快取所有新的更改,(同時在舊檔案總寫入更改)
子程序重寫完成後,父程序收到訊號,在新的檔案末尾追加緩衝區的內容
重寫完成,開始將新資料新增到新檔案中.
備份Redis 資料
直接定期的備份RDB檔案即可.
災備
將RDB定期上傳雲端儲存
定期上傳遠端儲存
Redis HA

Reids Sentinel(哨兵)用來為Redis提供高可用特性,Sentinel還提供了監控\通知\為客戶端提供配置等特性.
監控--> Sentinel不斷檢查Redis Master例項的工作狀態
通知-->Sentinel通過API方式通知系統管理員\其它的計算機程式-->Redis例項故障
自動故障轉移-->Master節點故障後,Sentinel可以啟動故障轉移過程,將一個Slave提升為Master,其它的Slave也修改使用行的Master來複制資料,並且告知使用Redis服務期的應用程式使用新的地址.
提供配置-->充當發現客戶端的角色,客戶端連線到Sentinel-->請求當前Redis Master節點的地址,如果發生故障轉移將報告客戶端新的Master地址。
Sentinel 分散式特性
Redis Sentinel 是一個分散式系統,Sensinel可以同時執行多個例項之間互相協調
多個Sensinel 同時確認一個給定的Master是否故障,確認後執行故障檢測-->降低誤報概率
即使不是所有的Sentinel都正常工作,也可以使系統更強壯
Sentinel入門
基礎知識
1.Sentinel支援分散式部署,使用最好三個以上的Sentinel節點
2.Sentinel應該以獨立的虛擬機器或者計算機進行隔離 -->獨立失敗
3.Sentinel +Redis 分散式部署不能保證在故障期間保留Master已經確認的寫入,由於Redis使用非同步複製
4.客戶端需要支援Sentinel連線
5.配置需要在開發環境中配置測試好在上線
6.涉及Docker, 或者其它網路地址轉換或埠對映的時候需要謹慎配置
建立Sentinel
最新版本為Sentinel2 -->使用更強大和簡單的預測演算法重寫最初的Sentinel實現.
使用2.8+版本.
執行Sentinel
兩種啟動方式
redis-sentinel /path/to/sentinel.conf-->
redis-server /path/to/sentinel.conf --sentinel-->
Sentinel執行時必須使用自己的配置檔案,預設情況下Sentinel監聽26379埠,
配置Sentinel
參考Reids提供的預設的Sentinel的配置檔案sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
指定監控的Master,給不同的Master一個指定的名字,不需要配置Slave節點[由Sentinel自動發現]
Sentinel自動發現並更新配置,並提供相關Slave的資訊(重啟時保留),每次故障轉移一個Slave被提升為Master,每發現一個新的哨兵都會重寫配置檔案.
配置Sentinel監控
sentinel monitor <master-group-name> <ip> <port> <quorum>-->第一個引數指定Master的名字-->第二個指定Master的IP-->第三個指定Master的埠
quorum指的是需要判定Master不可用的Sentinel的數量,該引數只是用於檢測故障,為執行故障轉移其中一個Sentinel將被選舉為Leader執行故障轉移.Leader通過選舉投票產生,負責執行故障轉移的Sentinel至少要獲得半數以上Senginel的投票.
其它配置
sentinel <option_name> <master_name> <option_value>,
down-after-milliseconds-->毫秒,超過該時間若收不到Master的ping訊號或者收到一個錯誤,則Sentinel認為Master節點失敗.
parallel-syncs-->設定在失敗後有多少個Slave可以同步新的Master的資料
Sentinal標準配置

 如上所示,有三個隔離的節點,一個節點部署Master+Sentinel,另外兩節點部署Slave+Sentinel.

M1故障-->S2+S3判定M1故障-->進行故障轉移-->客戶端正常訪問 -->可能會存在以下情況


由於網路分割槽M1S1被隔離,R2被提升為Master客戶端C1任然和M1在同一個網路分割槽,C1寫入的這部分資料將永久丟失. 可通過一下配置來儘可能的避免:

min-slaves-to-write 1-->至少需要一個Slave可用

min-slaves-max-lag 10-->Slave超時時間

Sentinal在客戶端
如果只有兩個節點,一個Master一個Slave,可以將Sentinel放在客戶端 -->quorum = 2
 
Sentinel和客戶端在一起,大多數客戶端都能連線到Master就沒什麼問題,M1故障可進行自動故障轉移,
Sentinel和客戶端繫結在一起,客戶機和M1網路斷開Sentinel無法進行設定.
混合設定
如果客戶端數量少於三個,可以使用混合設定.

案例

A節點-->Master+Sentinel
B 節點-->Slave+Sentinel
C 節點-->Slave+Sentinel
A配置
1.redis.conf -->
min-slaves-to-write 1
min-slaves-max-lag 10
2.sentinel.conf-->
port 26379
sentinel monitor mymaster 111.111.111.224 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 2
4.啟動Redis  &Sentinel
redis-server  /app/redis-3.0.1/redis.conf
redis-server  /app/redis-3.0.1/sentinel.conf  --sentinel 或者
redis-sentinel  /app/redis-3.0.1/sentinel.conf
B配置
1.redis.conf
slaveof 111.111.111.224 6379
slave-read-only yes
2.sentinel.conf
port 26379
sentinel monitor mymaster 111.111.111.224 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 2
3.啟動Redis&Sentinal
redis-server /app/redis-3.0.1/redis.conf
redis-sentinel  /app/redis-3.0.1/sentinel.conf
C配置
1.redis.conf
slaveof 111.111.111.224 6379
slave-read-only yes
2.sentinel.conf
port 26379
sentinel monitor mymaster 111.111.111.224 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 2
3.啟動Redis&Sentinal
redis-server /app/redis-3.0.1/redis.conf
redis-sentinel  /app/redis-3.0.1/sentinel.conf
檢視Sentinel狀態
使用Redis-cli連線Sentinel
redis-cli  -p 26379
1.檢視指定master的狀態,--> sentinel master mymaster
 
2.檢視Slave狀態 --> SENTINEL slaves mymaster
 
3.檢視Sentinel狀態 --> SENTINEL sentinels mymaster
 
4.獲取當前主機的地址 --> SENTINEL get-master-addr-by-name mymaster
5.其它命令
redis-cli  -p 6379 DEBUG sleep 50-->阻塞當前節點50秒

Redis 叢集
3.0+
Redis叢集解決方案-->資料自動分佈在多個Redis節點中共享,Redis叢集為Redis節點提供了一定的可用性,大多數節點不可用時叢集故障.
多個節點之間自動分割資料的能力.
節點的子集或者部分出現通訊故障時,能夠繼續操作.
Redis 叢集TCP埠
每個Redis叢集節點都需要開啟兩個TCP埠,一個用於給客戶端連線[6379],和一個數據埠[連線埠+10000]用於叢集的資料匯流排,是一個使用二進位制協議的點到點的通訊協議.匯流排用於故障檢測、配置更新、故障轉移授權等.
Redis 叢集資料分片
Redis沒有使用一致性雜湊,使用”hash slot”的概念進行資料切分.Redis 叢集中有16384個雜湊槽,Redis的鍵經過取模對應到16384槽中的一個上.Redis叢集中的每個節點都負責Hash solt中的一個子集[0-16383].
只要所有涉及到單個命令執行(事物、Lua指令碼)的鍵都屬於同一個Hash Solt,那麼Redis叢集就支援多個鍵的操作.使用者可以使用一個名為 hash tags強制多個鍵成為同一個Hash Solt的一部分. hash tags使用{}標識,放在key的最後部分,
Redis 叢集主從模型
Reids叢集使用主從複製,每個Hash Solt 使用一個Master(1)主節點 --> Slaves(N)從節點的主備模型.
Redis 叢集一致性保證
Redis叢集不能保證資料的強一致性,Redis叢集使用非同步的複製方式,允許同步複製,需要在效能和一致性之間取得平衡.
Redis 叢集配置引數
cluster-enabled <yes/no>--> 是否啟用Redis叢集
cluster-config-file <filename>-->叢集自動維護,不需要手動維護
cluster-node-timeout <milliseconds>-->叢集節點最大超時時間,如果主節點超時將被Slave節點替換.
cluster-slave-validity-factor <factor>-->0,Slave將始終嘗試進行故障轉移對應的Master,
如果為正數用來判斷slave與master斷開的時間,如果為正數則Slave節點斷開Master節點的時間大於節點超時時間(cluster-node-timeout)*有效因子(cluster-slave-validity-factor)的值則該節點不能被選為Master節點,防止過期的Slave節點被選為Master而導致資料丟失.
cluster-migration-barrier <count>-->Master的Slave數大於該值時,Slave才能遷移到其它節點.
cluster-require-full-coverage <yes/no> --> 預設yes,只有所有的Hash Solt都被分配出去叢集才允許接受寫入,no允許在Hash Solt沒有完全分配時提供查詢服務,只有部分鍵可以被處理.
建立Redis叢集
以下配置一個Redis叢集,建議至少使用6個節點,三個主節點每個主節點一個從節點.
#後臺執行
daemonize yes
#pid檔案位置
pidfile "/app/redis-3.0.1/7000/redis.pid"
#節點埠
port 7000
#節點日誌檔案位置
logfile "/app/redis-3.0.1/7000/7000.log"
#資料庫數量
databases 1
#快照檔案位置
dbfilename "7000.rdb"
#例項的工作目錄
dir "/app/redis-3.0.1/7000"
#啟用AOF檔案
appendonly yes
#啟用Redis叢集模式
cluster-enabled yes
#叢集節點配置檔案-->不需要手動配置
cluster-config-file nodes.conf
#叢集中節點超時
cluster-node-timeout 5000
下面流程在一個Linux主機上建立一個有6個節點的Redis叢集.
1.mkdir 7000 7001 7002 7003 7004 7005
2.拷貝redis.conf到7000 7001 7002 7003 7004 7005目錄參考以上配置修改700*為對應的目錄,其餘保持一致.
3.啟動Redis節點
redis-server  /app/redis-3.0.1/7000/redis.conf
分別啟動6個節點
 
4.通過redis-trib 建立Redis叢集,是一個Ruby程式,需要安裝redis gem去執行redis-trib指令碼.

gem install redis


5.檢查當前叢集狀態
./redis-trib.rb  check localhost:7000

當前叢集16384個槽都未被分配出去


6.建立Redis叢集

./redis-trib.rb  create  --replicas  1  localhost:7000 localhost:7003 localhost:7001 localhost:7004  localhost:7002 localhost:7005 


使用Redis預設的Solt分配方案,叢集建立失敗… 總結下不能使用主機名…


7.刪除節點,同時會將節點下線,在此加入的時候需要將nodes.conf檔案清理掉! 刪除7001,7003,7004,7005節點並清理對應的nodes.conf檔案後重啟.
redis-trib.rb del-node  localhost:7000  32607595f0e718ee97692eb762e9152d38ffbb5a 
8.新增一個節點作為指定節點的Slave,需要使用ip地址而不能使用主機名...
src/redis-trib.rb  add-node --slave --master-id 9d6ebdac22053d5923f193437aa1c8ed806d9f1d  111.111.111.224:7004 111.111.111.224:7000

9.重複上述步驟,知道每個Master都有對應的Salve且所有Hash Solt被分配出去


重新切分叢集
檢視當前節點資訊
redis-cli  -p 7000 cluster nodes
新增一個主節點到叢集
src/redis-trib.rb  add-node --master-id e47fe240eb6aefc8fa0099d6908b6c2cbf0612a2  111.111.111.224:7005 111.111.111.224:7000
自動副本遷移
預設情況下對於一個每個Redis的每個主節點都應該有至少一個副本,當主節點異常後提升副本為主節點,如果發生副本在次異常的場景將導致叢集不可用,或者使用了更多的副本,但是需要更多的資源,Redis 叢集可以實現自動的副本遷移,在叢集內部自動的將副本數多的節點的副本轉移給副本少的節點作為副本,尋求一個平衡,遵循以下規則.
叢集嘗試從副本最多的主節點中遷移副本
為從中獲益,只需要向叢集中的幾個主節點多新增幾個副本即可
使用cluster-migration-barrier進行配置,主節點的備份大於該值其從節點才可以遷移為其它節點[孤立的主節點]的從節點