Redis3.0的主從、叢集高可用
- 安裝Redis3.0 yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc+±devel tcl
mkdir -p /usr/local/src/redis
cd /usr/local/src/redis
tar -xvf redis-3.0.2.tar.gz
cd redis-3.0.2
make
make test #這個就不要執行了,需要很長時間
make install
cp redis.conf /etc/
vi /etc/redis.conf
修改如下,預設為no
daemonize yes
#啟動
redis-server /etc/redis.conf
#測試
redis-cli
- 主從複製(讀寫分離) 主從複製的好處有2點:
1、 避免redis單點故障
2、 構建讀寫分離架構,滿足讀多寫少的應用場景
2.1. 主從架構
2.1.1. 啟動例項 建立6379、6380、6381目錄,分別將安裝目錄下的redis.conf拷貝到這三個目錄下。
分別進入這三個目錄,分別修改配置檔案,將埠分別設定為:6379(Master)、6380(Slave)、6381(Slave)。同時要設定pidfile檔案為不同的路徑。
分別啟動三個redis例項:
2.1.2. 設定主從 在redis中設定主從有2種方式:
1、 在redis.conf中設定slaveof
a) slaveof
2、 使用redis-cli客戶端連線到redis服務,執行slaveof命令
a) slaveof
第二種方式在重啟後將失去主從複製關係。
檢視主從資訊:INFO replication
主:
role:角色
connected_slaves:從庫數量
slave0:從庫資訊
從:
2.1.3. 測試 在主庫寫入資料:
在從庫讀取資料:
2.2. 主從從架構
2.2.1. 啟動例項
設定主從:
設定從從:
2.2.2. 測試 在主庫設定資料:
在6380獲取資料:
在6381獲取資料:
2.3. 從庫只讀 預設情況下redis資料庫充當slave角色時是隻讀的不能進行寫操作。
可以在配置檔案中開啟非只讀:slave-read-only no
2.4. 複製的過程原理 1、 當從庫和主庫建立MS關係後,會向主資料庫傳送SYNC命令;
2、 主庫接收到SYNC命令後會開始在後臺儲存快照(RDB持久化過程),並將期間接收到的寫命令快取起來;
3、 當快照完成後,主Redis會將快照檔案和所有快取的寫命令傳送給從Redis;
4、 從Redis接收到後,會載入快照檔案並且執行收到的快取的命令;
5、 之後,主Redis每當接收到寫命令時就會將命令傳送從Redis,從而保證資料的一致;
2.5. 無磁碟複製 通過前面的複製過程我們瞭解到,主庫接收到SYNC的命令時會執行RDB過程,即使在配置檔案中禁用RDB持久化也會生成,那麼如果主庫所在的伺服器磁碟IO效能較差,那麼這個複製過程就會出現瓶頸,慶幸的是,Redis在2.8.18版本開始實現了無磁碟複製功能(不過該功能還是處於試驗階段)。
原理:
Redis在與從資料庫進行復制初始化時將不會將快照儲存到磁碟,而是直接通過網路傳送給從資料庫,避免了IO效能差問題。
開啟無磁碟複製:repl-diskless-sync yes
2.6. 複製架構中出現宕機情況,怎麼辦? 如果在主從複製架構中出現宕機的情況,需要分情況看:
1、 從Redis宕機
a) 這個相對而言比較簡單,在Redis中從庫重新啟動後會自動加入到主從架構中,自動完成同步資料;
b) 問題? 如果從庫在斷開期間,主庫的變化不大,從庫再次啟動後,主庫依然會將所有的資料做RDB操作嗎?還是增量更新?(從庫有做持久化的前提下)
i. 不會的,因為在Redis2.8版本後就實現了,主從斷線後恢復的情況下實現增量複製。
2、 主Redis宕機
a) 這個相對而言就會複雜一些,需要以下2步才能完成
i. 第一步,在從資料庫中執行SLAVEOF NO ONE命令,斷開主從關係並且提升為主庫繼續服務;
ii. 第二步,將主庫重新啟動後,執行SLAVEOF命令,將其設定為其他庫的從庫,這時資料就能更新回來;
b) 這個手動完成恢復的過程其實是比較麻煩的並且容易出錯,有沒有好辦法解決呢?當前有的,Redis提高的哨兵(sentinel)的功能。
- 哨兵(sentinel) 3.1. 什麼是哨兵 顧名思義,哨兵的作用就是對Redis的系統的執行情況的監控,它是一個獨立程序。它的功能有2個:
1、 監控主資料庫和從資料庫是否執行正常;
2、 主資料出現故障後自動將從資料庫轉化為主資料庫;
3.2. 原理 單個哨兵的架構:
多個哨兵的架構:
多個哨兵,不僅同時監控主從資料庫,而且哨兵之間互為監控。
3.3. 環境 當前處於一主多從的環境中:
3.4. 配置哨兵 啟動哨兵程序首先需要建立哨兵配置檔案:
vim sentinel.conf
輸入內容:
sentinel monitor taotaoMaster 127.0.0.1 6379 1
說明:
taotaoMaster:監控主資料的名稱,自定義即可,可以使用大小寫字母和“.-_”符號
127.0.0.1:監控的主資料庫的IP
6379:監控的主資料庫的埠
1:最低通過票數
啟動哨兵程序:
redis-sentinel ./sentinel.conf
由上圖可以看到:
1、 哨兵已經啟動,它的id為9059917216012421e8e89a4aa02f15b75346d2b7
2、 為master資料庫添加了一個監控
3、 發現了2個slave(由此可以看出,哨兵無需配置slave,只需要指定master,哨兵會自動發現slave)
3.5. 從資料庫宕機
kill掉2826程序後,30秒後哨兵的控制檯輸出:
2989:X 05 Jun 20:09:33.509 # +sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379
說明已經監控到slave宕機了,那麼,如果我們將3380埠的redis例項啟動後,會自動加入到主從複製嗎?
2989:X 05 Jun 20:13:22.716 * +reboot slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379
2989:X 05 Jun 20:13:22.788 # -sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379
可以看出,slave從新加入到了主從複製中。-sdown:說明是恢復服務。
3.6. 主庫宕機 哨兵控制檯打印出如下資訊:
2989:X 05 Jun 20:16:50.300 # +sdown master taotaoMaster 127.0.0.1 6379 說明master服務已經宕機
2989:X 05 Jun 20:16:50.300 # +odown master taotaoMaster 127.0.0.1 6379 #quorum 1/1
2989:X 05 Jun 20:16:50.300 # +new-epoch 1
2989:X 05 Jun 20:16:50.300 # +try-failover master taotaoMaster 127.0.0.1 6379 開始恢復故障
2989:X 05 Jun 20:16:50.304 # +vote-for-leader 9059917216012421e8e89a4aa02f15b75346d2b7 1 投票選舉哨兵leader,現在就一個哨兵所以leader就自己
2989:X 05 Jun 20:16:50.304 # +elected-leader master taotaoMaster 127.0.0.1 6379 選中leader
2989:X 05 Jun 20:16:50.304 # +failover-state-select-slave master taotaoMaster 127.0.0.1 6379 選中其中的一個slave當做master
2989:X 05 Jun 20:16:50.357 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379 選中6381
2989:X 05 Jun 20:16:50.357 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379 傳送slaveof no one命令
2989:X 05 Jun 20:16:50.420 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379 等待升級master
2989:X 05 Jun 20:16:50.515 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster 127.0.0.1 6379 升級6381為master
2989:X 05 Jun 20:16:50.515 # +failover-state-reconf-slaves master taotaoMaster 127.0.0.1 6379
2989:X 05 Jun 20:16:50.566 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379
2989:X 05 Jun 20:16:51.333 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379
2989:X 05 Jun 20:16:52.382 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6379
2989:X 05 Jun 20:16:52.438 # +failover-end master taotaoMaster 127.0.0.1 6379 故障恢復完成
2989:X 05 Jun 20:16:52.438 # +switch-master taotaoMaster 127.0.0.1 6379 127.0.0.1 6381 主資料庫從6379轉變為6381
2989:X 05 Jun 20:16:52.438 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster 127.0.0.1 6381 新增6380為6381的從庫
2989:X 05 Jun 20:16:52.438 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381 新增6379為6381的從庫
2989:X 05 Jun 20:17:22.463 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381 發現6379已經宕機,等待6379的恢復
可以看出,目前,6381位master,擁有一個slave為6380.
接下來,我們恢復6379檢視狀態:
2989:X 05 Jun 20:35:32.172 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381 6379已經恢復服務
2989:X 05 Jun 20:35:42.137 * +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster 127.0.0.1 6381 將6379設定為6381的slave
3.7. 配置多個哨兵 vim sentinel.conf
輸入內容:
sentinel monitor taotaoMaster 127.0.0.1 6381 2
sentinel monitor taotaoMaster2 127.0.0.1 6381 1
3451:X 05 Jun 21:05:56.083 # +sdown master taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:56.083 # +odown master taotaoMaster2 127.0.0.1 6381 #quorum 1/1
3451:X 05 Jun 21:05:56.083 # +new-epoch 1
3451:X 05 Jun 21:05:56.083 # +try-failover master taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:56.086 # +vote-for-leader 3f020a35c9878a12d2b44904f570dc0d4015c2ba 1
3451:X 05 Jun 21:05:56.086 # +elected-leader master taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:56.086 # +failover-state-select-slave master taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:56.087 # +sdown master taotaoMaster 127.0.0.1 6381
3451:X 05 Jun 21:05:56.189 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:56.189 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:56.252 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:57.145 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:57.145 # +failover-state-reconf-slaves master taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:57.234 * +slave-reconf-sent slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:58.149 * +slave-reconf-inprog slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:58.149 * +slave-reconf-done slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:58.203 # +failover-end master taotaoMaster2 127.0.0.1 6381
3451:X 05 Jun 21:05:58.203 # +switch-master taotaoMaster2 127.0.0.1 6381 127.0.0.1 6380
3451:X 05 Jun 21:05:58.203 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ taotaoMaster2 127.0.0.1 6380
3451:X 05 Jun 21:05:58.203 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ taotaoMaster2 127.0.0.1 6380
- 叢集 即使有了主從複製,每個資料庫都要儲存整個叢集中的所有資料,容易形成木桶效應。
使用Jedis實現了分片叢集,是由客戶端控制哪些key資料儲存到哪個資料庫中,如果在水平擴容時就必須手動進行資料遷移,而且需要將整個叢集停止服務,這樣做非常不好的。
Redis3.0版本的一大特性就是叢集(Cluster),接下來我們一起學習叢集。
4.1. 架構
(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進位制協議優化傳輸速度和頻寬.
(2)節點的fail是通過叢集中超過半數的節點檢測失效時才生效.
(3)客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連線叢集所有節點,連線叢集中任何一個可用節點即可
(4)redis-cluster把所有的物理節點對映到[0-16383]slot(插槽)上,cluster 負責維護node<->slot<->value
4.2. 修改配置檔案 1、 設定不同的埠,6379、6380、6381
2、 開啟叢集,cluster-enabled yes
3、 指定叢集的配置檔案,cluster-config-file “nodes-xxxx.conf”
4.3. 建立叢集 4.3.1. 安裝ruby環境 因為redis-trib.rb是有ruby語言編寫的所以需要安裝ruby環境。
yum -y install zlib ruby rubygems
gem install redis
手動安裝:
rz上傳redis-3.2.1.gem
gem install -l redis-3.2.1.gem
4.3.2. 建立叢集 首先,進入redis的安裝包路徑下:
cd /usr/local/src/redis/redis-3.0.1/src/
執行命令:
./redis-trib.rb create --replicas 0 192.168.56.102:6379 192.168.56.102:6380 192.168.56.102:6381
–replicas 0:指定了從資料的數量為0
注意:這裡不能使用127.0.0.1,否則在Jedis客戶端使用時無法連線到!
redis-trib用法:
4.3.3. 測試
什麼情況??(error) MOVED 7638 127.0.0.1:6380
因為abc的hash槽資訊是在6380上,現在使用redis-cli連線的6379,無法完成set操作,需要客戶端跟蹤重定向。
redis-cli -c
看到由6379跳轉到了6380,然後再進入6379看能否get到資料
還是被重定向到了6380,不過已經可以獲取到資料了。
4.4. 使用Jedis連線到叢集 新增依賴,要注意jedis的版本為2.7.2
說明:這裡的jc不需要關閉,因為內部已經關閉連線了。
4.5. 插槽的分配 通過cluster nodes命令可以檢視當前叢集的資訊:
該資訊反映出了叢集中的每個節點的id、身份、連線數、插槽數等。
當我們執行set abc 123命令時,redis是如何將資料儲存到叢集中的呢?執行步驟:
1、 接收命令set abc 123
2、 通過key(abc)計算出插槽值,然後根據插槽值找到對應的節點。(abc的插槽值為:7638)
3、 重定向到該節點執行命令
整個Redis提供了16384個插槽,也就是說叢集中的每個節點分得的插槽數總和為16384。
./redis-trib.rb 指令碼實現了是將16384個插槽平均分配給了N個節點。
注意:如果插槽數有部分是沒有指定到節點的,那麼這部分插槽所對應的key將不能使用。
4.6. 插槽和key的關係 計算key的插槽值:
key的有效部分使用CRC16演算法計算出雜湊值,再將雜湊值對16384取餘,得到插槽值。
什麼是有效部分?
1、 如果key中包含了{符號,且在{符號後存在}符號,並且{和}之間至少有一個字元,則有效部分是指{和}之間的部分;
a) key={hello}_tatao的有效部分是hello
2、 如果不滿足上一條情況,整個key都是有效部分;
a) key=hello_taotao的有效部分是全部
4.7. 新增叢集節點 再開啟一個例項的埠為6382
執行指令碼:
./redis-trib.rb add-node 192.168.56.102:6382 192.168.56.102:6379
已經新增成功!檢視叢集資訊:
發現沒有插槽數。
接下來需要給6382這個服務分配插槽,將6379的一部分(1000個)插槽分配給6382:
檢視節點情況:
4.8. 刪除叢集節點 想要刪除叢集節點中的某一個節點,需要嚴格執行2步:
1、 將這個節點上的所有插槽轉移到其他節點上;
a) 假設我們想要刪除6380這個節點
b) 執行指令碼:./redis-trib.rb reshard 192.168.56.102:6380
c) 選擇需要轉移的插槽的數量,因為6380有5128個,所以轉移5128個
d) 輸入轉移的節點的id,我們轉移到6382節點:82ed0d63cfa6d19956dca833930977a87d6ddf7
e) 輸入插槽來源id,也就是6380的id
f) 輸入done,開始轉移
g) 檢視叢集資訊,可以看到6380節點已經沒有插槽了。
2、 使用redis-trib.rb刪除節點
a) ./redis-trib.rb del-node 192.168.56.102:6380 4a9b8886ba5261e82597f5590fcdb49ea47c4c6c
b) del-node host:port node_id
c)
d) 檢視叢集資訊,可以看到已經沒有6380這個節點了。
4.9. 故障轉移 如果叢集中的某一節點宕機會出現什麼狀況?我們這裡假設6381宕機。
我們嘗試連線下叢集,並且檢視叢集資訊,發現6381的節點斷開連線:
我們嘗試執行set命令,結果發現無法執行:
什麼情況?叢集不可用了?? 這叢集也太弱了吧??
4.9.1. 故障機制 1、 叢集中的每個節點都會定期的向其它節點發送PING命令,並且通過有沒有收到回覆判斷目標節點是否下線;
2、 叢集中每一秒就會隨機選擇5個節點,然後選擇其中最久沒有響應的節點放PING命令;
3、 如果一定時間內目標節點都沒有響應,那麼該節點就認為目標節點疑似下線;
4、 當叢集中的節點超過半數認為該目標節點疑似下線,那麼該節點就會被標記為下線;
5、 當叢集中的任何一個節點下線,就會導致插槽區有空檔,不完整,那麼該叢集將不可用;
6、 如何解決上述問題?
a) 在Redis叢集中可以使用主從模式實現某一個節點的高可用
b) 當該節點(master)宕機後,叢集會將該節點的從資料庫(slave)轉變為(master)繼續完成叢集服務;
4.9.2. 叢集中的主從複製架構 架構:
出現故障:
4.9.3. 建立主從叢集 需要啟動6個redis例項,分別是:
6379(主) 6479(從)
6380(主) 6480(從)
6381(主) 6481(從)
啟動redis例項:
cd 6379/ && redis-server ./redis.conf && cd …
cd 6380/ && redis-server ./redis.conf && cd …
cd 6381/ && redis-server ./redis.conf && cd …
cd 6479/ && redis-server ./redis.conf && cd …
cd 6480/ && redis-server ./redis.conf && cd …
cd 6481/ && redis-server ./redis.conf && cd …
建立叢集,指定了從庫數量為1,建立順序為主庫(3個)、從庫(3個):
./redis-trib.rb create --replicas 1 192.168.56.102:6379 192.168.56.102:6380 192.168.56.102:6381 192.168.56.102:6479 192.168.56.102:6480 192.168.56.102:6481
建立成功!檢視叢集資訊:
4.9.4. 測試
儲存、讀取資料OK!
檢視下6480的從庫資料:
看到從6480檢視資料也是被重定向到6380.
說明叢集一切執行OK!
4.9.5. 測試叢集中slave節點宕機 我們將6480節點kill掉,檢視情況。
檢視叢集情況:
發現6480節點不可用。
那麼整個叢集可用嗎?
發現叢集可用,可見從資料庫宕機不會影響叢集正常服務。
恢復6480服務:
測試6480中的資料:
看到已經更新成最新資料。
4.9.6. 測試叢集中master宕機 假設6381宕機:
檢視叢集情況:
發現:
1、6381節點失效不可用
2、6481節點從slave轉換為master
測試叢集是否可用:
叢集可用。
恢復6381:
發現:
1、6381節點可用
2、6481依然是主節點
3、6381成為6481的從資料庫
4.10. 使用叢集需要注意的事項 1、 多鍵的命令操作(如MGET、MSET),如果每個鍵都位於同一個節點,則可以正常支援,否則會提示錯誤。
2、 叢集中的節點只能使用0號資料庫,如果執行SELECT切換資料庫會提示錯誤。