Redis 集羣搭建很 easy
前言
哨兵模式雖然讓讀寫分離更加高可用,但單臺服務器由於本身的內存和 CPU 瓶頸,對於高併發和大數據業務的應用場景還是遠遠不能滿足;對於這種情況,有點經驗的小夥伴會毫不猶豫的想到集羣,搞他好幾個節點,負載均衡再加上故障轉移,豈不美哉。是的,就是這個理,接下來玩玩。
正文
集羣,相信這個詞小夥伴應該聽的耳朵起繭子了吧;多搞幾臺服務器,讓請求 / 命令平均分發到各個服務器,避免單臺服務器承載過大壓力;對於 Redis 集羣來說,爲了實現自動故障轉移,還需要在每個主節點上增加一個或多個從節點,當主節點發生故障時,從節點自動補上,實現高可用。
總的來說,Redis 集羣有以下作用:
-
多主節點的實現可以應對高併發場景,併發量增大,節點可以隨時擴展滿足需求;
-
多主節點的實現可以存儲更多的數據,因爲數據均勻分佈到各個節點;
-
多主節點搭配多從節點的實現讓高可用更加穩定,即當有主節點發生故障時,對應下面的從節點會升級爲主節點,正常提供功能;
老規矩不變,一邊實操一邊總結,接下來搭建一個 3 主 3 從的集羣,這是最簡單的。Redis 集羣中最少需要 3 個主節點,再加上爲了實現高可用,每個主節點至少得跟一個從節點,不然一個主節點掛了,找不到完整的數據,整個集羣就不能用了;至於爲什麼會找不到完整的數據,下面會聊到。
接下來要搭建的集羣環境如下:
簡要說明:
-
6370 爲主節點,6381 爲 6370 的從節點;
-
6380 爲主節點,6391 爲 6380 的從節點;
-
6390 爲主節點,6371 爲 6390 的從節點;
-
在集羣環境中主節點之間是相互通訊的 (這裏沒有哨兵),每一個節點都是數據節點;
這裏集羣方案使用 redis-cli 自動指定主從關係 (小夥伴的主從關係可能會和我這不一樣哦),也可以手動指定;反正思路都一樣;
以下演示在同一臺機器上,通過端口區分各個節點;在實際開發中,一般都是用不同的服務器。
案例演示
-
準備六個節點的配置文件,開啓集羣相關配置;
拷貝最初默認的配置文件,然後進行更改,主要更改以下項:
port 6370 # 指定Redis節點端口 pidfile /var/run/redis_6370.pid # 指定對應進程文件 dbfilename dump6370.rdb # 每個節點的rdb持久化文件 cluster-enabled yes # 開啓集羣,這個比較重要 cluster-config-file nodes-6370.conf #指定每個節點的集羣配置文件,這個比較重要
以上配置文件內容在其他節點 (6370,6371,6380,6381,6390,6391) 都需要進行修改,只是將其中 6370 改爲對應節點的端口即可,目的就是爲了不同節點使用不同端口並區分用到的不同文件即可;比如需要修改 6371 節點的配置文件如下:
port 6371 # 指定Redis節點端口 pidfile /var/run/redis_6371.pid # 指定對應進程文件 dbfilename dump6371.rdb # 每個節點的rdb持久化文件 cluster-enabled yes # 開啓集羣,這個比較重要 cluster-config-file nodes-6371.conf #指定每個節點的集羣配置文件,這個比較重要
其中 cluster-enabled 和 cluster-config-file 是集羣配置的重點。
-
啓動六個節點,剛開始各個節點是相互獨立的;
準備好配置文件之後,就可以使用 redis-server 指定配置文件啓動節點啦,如果節點多,小夥伴可以編寫腳本哦;
./redis-server ZoeCluster/redis6370.conf # 啓動6370節點 ./redis-server ZoeCluster/redis6371.conf # 啓動6371節點 ./redis-server ZoeCluster/redis6380.conf # 啓動6380節點 ./redis-server ZoeCluster/redis6381.conf # 啓動6381節點 ./redis-server ZoeCluster/redis6390.conf # 啓動6390節點 ./redis-server ZoeCluster/redis6391.conf # 啓動6391節點
啓動效果如下:
這樣只是將各個節點啓動起來,集羣關係還沒創建呢,如果不信,可以使用 redis-cli 連接任意一個節點查看集羣信息,如下:
如上圖,cluster-size 爲 0,集羣的關鍵,槽也還沒有分配;那接下來肯定是要將各節點的集羣關係搞起來;
-
建立節點集羣關係
由於我使用的 Redis 版本是 5.0,直接可以使用 redis-cli 就可以進行集羣搭建,在此版本之前都推薦使用 redis-trib.rb 進行相關操作,這個是一個 Ruby 腳本,需要安裝相關環境,小夥伴可以下來嘗試;
使用命令如下:
./redis-cli --cluster create --cluster-replicas 1 127.0.0.1:6370 127.0.0.1:6380 127.0.0.1:6390 127.0.0.1:6371 127.0.0.1:6381 127.0.0.1:6391
參數簡介:
-- cluster : 指定是用於創建集羣環境;
-a:密碼,即如果有密碼,可以通過 - a 傳參,這裏沒有設置密碼;
--cluster-replicas:這裏設置爲 1, 用於配置主節點上的從節點數,1 就代表一主一從,2 就代表一主二從,依次類推;
後面的是節點 IP: 節點端口,一般前面的是主節點,後面的是從節點;
如果同意集羣方案,然後就開始進行相關操作,如下:
同樣,可以連接到任意一個節點,查看集羣情況,如下:
注:關於主從節點之間的主從複製過程就不在這說了,和之前說過的主從複製一樣;
-
演示訪問操作;
使用 redis-cli 連接任意節點寫入數據,如果不指定集羣連接的話,會寫入數據失敗,如下:
由於集羣環境下,數據的存儲位置是根據 Key 來計算而來的 (這裏牽涉到一致性哈希算法),使得數據可以均勻分配到各節點上,所以在 redis-cli 連接的時候需要指定集羣模式,如下:
如上圖所示,指定集羣模式之後就可以正常存取了;
-
故障演示
既然集羣環境,肯定少不了要好好測測;
模擬從節點掛掉
找個從節點停掉試試,這裏停掉 6371 節點,根據創建集羣信息知道,它的主節點是 6390;
主節點顯示從節點斷開連接,看看它的主節點反應:
其他集羣節點只是將從節點標記爲 failing 狀態,即下線狀態,如下:
對於存取數據也不受影響,這裏就不截圖了,小夥伴自行嘗試吧;
當故障的從節點 6371 重新連上時,主節點恢復主從關係,並進行主從複製操作;其他集羣節點會清除原來標記的下線狀態,將其改爲上線;
模擬主節點掛掉
這裏就手動將 6390 這個節點停掉,會有怎樣的反應呢?
自身從節點會每隔一秒檢測連接,如果超時 (默認是 15 秒),會選舉從節點做爲集羣的主節點來提供服務,如下圖:
數據存取最終還是不受影響;
對於其他集羣節點,將故障節點標記爲 failing,讓新上任的主節點提供服務,如下圖:
存取數據也是不受影響的;
掛掉的主節點 6390 如果恢復,那它只能變爲 6371 的從節點啦,並進行相關主從複製操作;而集羣的其他節點只是將其原有的 Fail 狀態清除,表示可以正常連接;
Redis 集羣就是這樣簡單,只要思路對,就是手工活;小夥伴可以編寫腳本自動執行哦;
接下來說說集羣數據的存儲;
數據存儲簡單分析
在 Redis 集羣環境中,數據的存儲位置是根據對 Key 的 Hash 計算進行指定的;Redis 集羣爲了在節點改變時保證數據分佈均勻,引入了槽 (slot) 作爲遷移的基本單位,槽解耦了數據和實際節點的關係,使得實際節點數的改變對系統影響較小;
在整個集羣中,槽 (slot) 總共有 16384,會將其均勻分配到集羣的主節點上,其中每一份槽對應一個存儲空間 (這裏的存儲空間可以理解爲一個容器,是可以存很多數據的),以上集羣環境的槽分配如下:
存儲數據的過程,如下:
連接 6380 主節點,執行如下操作:
具體過程如下:
簡要說明:
-
客戶端發起命令;
-
服務器將 Key 進行 CRC16 計算,並與總槽位計算出 Key 需要存儲的位置;
-
這裏模擬的 Key 爲 zoe,計算出的槽位爲 14588,不在 6380 這個節點上,集羣節點會將其重定向到對應槽位的節點上;
-
然後找到 6371 上的 14588 槽位進行數據存儲;(注,這裏的 6371 已經是主節點了,因爲上面做過一次故障轉移模擬);
那集羣節點是如何知道其他節點的槽範圍和其他信息呢?
那是因爲各節點之間有通訊,通訊端口是對應的 redis 端口 + 10000,比如節點 6371 的集羣通訊端口爲 16371(如果多臺機器,別忘了防火牆放開這個端口哦),可以通過 cluster nodes 看到,如下:
並且將各節點的信息保存在自己對應的集羣配置文件中,這個集羣文件名是通過配置項 cluster-config-file 指定的,在集羣節點啓動時會檢查該文件是否存在,如果不存在,會自動創建,如果存在,就加載裏面的相關配置信息;裏面有哪些信息,隨便找個節點的配置文件看一下:
如上圖所示,各節點的配置文件中記錄了其他節點的主從關係,分配的槽位,各節點的狀態;這樣的話,集羣關係就算重新啓動也還存在。
集羣伸縮 (節點增刪) 演示
在實際應用場景中,會根據業務需要,對集羣進行伸縮,即節點的增刪;業務併發大了加節點進行擴展, 節點需要調整時可能需要進節點刪除;
加節點
這裏進行節點擴展,加一個 6360 主節點,6361 作爲 6360 的從節點;參照以上集羣搭建時配置文件更改,然後將其都啓動,如下:
6360 節點
port 6360 # 指定Redis節點端口
pidfile /var/run/redis_6360.pid # 指定對應進程文件
dbfilename dump6360.rdb # 每個節點的rdb持久化文件
cluster-enabled yes # 開啓集羣,這個比較重要
cluster-config-file nodes-6360.conf #指定每個節點的集羣配置文件,這個比較重要
6361 節點
port 6361 # 指定Redis節點端口
pidfile /var/run/redis_6361.pid # 指定對應進程文件
dbfilename dump6361.rdb # 每個節點的rdb持久化文件
cluster-enabled yes # 開啓集羣,這個比較重要
cluster-config-file nodes-6361.conf #指定每個節點的集羣配置文件,這個比較重要
兩個節點都啓動,然後將 6360 加入到集羣主節點中,執行以下命令:
./redis-cli --cluster add-node 127.0.0.1:6360 127.0.0.1:6370
注:其中 127.0.0.1:6360 是需要加入的新增節點,127.0.0.1:6370 是現有集羣中的任意一個節點;
可以通過以下命令檢測集羣狀態,如下:
./redis-cli --cluster check 127.0.0.1:6370 # 後面的地址是任意的集羣節點
可以看到 6360 已經加入到集羣環境中,但現在還沒有從節點和槽分配,所以接下來先將 6361 作爲 6360 的從節點加入,如下:
./redis-cli --cluster add-node --cluster-slave --cluster-master-id eaa814dc56beb0d5edb6a4fbb14f1384e78d4764 127.0.0.1:6361 127.0.0.1:6370
參數說明:
-
--cluster-slave : 意思就是加入的是從節點;
-
--cluster-master-id:後面緊跟主節點的 id,這裏就是 6360 的節點 id;通過 cluster nodes 可以查看到節點 id;
-
127.0.0.1:6361:需要加入的從節點;
-
127.0.0.1:6370:現有集羣的任意主節點;
現在還差槽分配了,如果需要直接將 16384 個槽平均分配到所有節點話,直接執行以下命令即可:
./redis-cli --cluster rebalance --cluster-threshold 1 --cluster-use-empty-masters 127.0.0.1:6370
使用命令./redis-cli --cluster check 127.0.0.1:6370 查看分配結果,如下圖,只截了部分:
如果不想均勻分配,根據自定義需要進行配置,可以執行以下命令,會提示一步一步配置;
./redis-cli --cluster reshard 127.0.0.1:6360 #後面是新加入的主節點
# 也可以執行以下指令直接配置想要的數據
./redis-cli --cluster reshard --cluster-from all --cluster-to 需要分配槽的節點id --cluster-slots 1000 --cluster-yes 127.0.0.1:6370 # 1000 指分配的槽數
這裏就不截圖演示了,留給小夥伴自己動手操作吧;
刪除節點
-
先對節點進行分片工作,防止數據丟失,即將指定節點上的槽分配到其他節點;
./redis-cli --cluster reshard 要刪除節點ip:port
-
移除節點,推薦先刪除從節點,再刪除主節點;
./redis-cli --cluster del-node 節點ip:port 節點id
集羣配置項
-
cluster-enabled(是否開啓集羣模式):設置爲 yes,將該節點開啓爲集羣模式;
-
cluster-config-file(設置每個集羣節點對應的配置文件名稱):文件是自動生成的,不用手動創建;
-
cluster-node-timeout(設置超時時間,即集羣節點不可用的最大時間,如果超過這個時間就認爲該節點不可用):默認爲 15000(以毫秒爲單位);
-
cluster-migration-barrier(配置一個主機最少可用的從機的個數):默認是 1, 表示一個主機的從機遷移之後,至少得有一個從機可用,否則不進行節點遷移;
-
cluster-require-full-coverage(配置集羣服務的可用性):默認 yes 開啓,即集羣沒完全覆蓋所有 slot,集羣就掛了;設置爲 no,就算槽沒有全分配,也能提供服務,需要自己保證槽分配;
總結
到這集羣的搭建就完啦,本來想着寫着很簡單的,沒想到又幹了 4000 字;對於集羣,使用有一些限制,比如 Keys 命令只能針對當前節點,需要針對多節點的情況進行處理;集羣中各節點只支持 db0 數據庫,其他數據庫不支持等等;所以使用要注意哦,後續抽時間單獨整理一篇注意事項吧,篇幅有點長,不繼續聊啦; 下篇說說熟悉的緩存穿透、緩存擊穿、緩存雪崩吧;
程序員徐 Sir
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/_gz9Tr7weU5dtRXAgROvqQ