Redis 集羣搭建很 easy

前言

哨兵模式雖然讓讀寫分離更加高可用,但單臺服務器由於本身的內存和 CPU 瓶頸,對於高併發和大數據業務的應用場景還是遠遠不能滿足;對於這種情況,有點經驗的小夥伴會毫不猶豫的想到集羣,搞他好幾個節點,負載均衡再加上故障轉移,豈不美哉。是的,就是這個理,接下來玩玩。

正文

集羣,相信這個詞小夥伴應該聽的耳朵起繭子了吧;多搞幾臺服務器,讓請求 / 命令平均分發到各個服務器,避免單臺服務器承載過大壓力;對於 Redis 集羣來說,爲了實現自動故障轉移,還需要在每個主節點上增加一個或多個從節點,當主節點發生故障時,從節點自動補上,實現高可用。

總的來說,Redis 集羣有以下作用:

老規矩不變,一邊實操一邊總結,接下來搭建一個 3 主 3 從的集羣,這是最簡單的。Redis 集羣中最少需要 3 個主節點,再加上爲了實現高可用,每個主節點至少得跟一個從節點,不然一個主節點掛了,找不到完整的數據,整個集羣就不能用了;至於爲什麼會找不到完整的數據,下面會聊到。

接下來要搭建的集羣環境如下:

簡要說明:

這裏集羣方案使用 redis-cli 自動指定主從關係 (小夥伴的主從關係可能會和我這不一樣哦),也可以手動指定;反正思路都一樣;

以下演示在同一臺機器上,通過端口區分各個節點;在實際開發中,一般都是用不同的服務器。

案例演示

  1. 準備六個節點的配置文件,開啓集羣相關配置

    拷貝最初默認的配置文件,然後進行更改,主要更改以下項:

    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-enabledcluster-config-file 是集羣配置的重點。

  2. 啓動六個節點,剛開始各個節點是相互獨立的

    準備好配置文件之後,就可以使用 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,集羣的關鍵,槽也還沒有分配;那接下來肯定是要將各節點的集羣關係搞起來;

  3. 建立節點集羣關係

    由於我使用的 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: 節點端口,一般前面的是主節點,後面的是從節點;

    如果同意集羣方案,然後就開始進行相關操作,如下:

    同樣,可以連接到任意一個節點,查看集羣情況,如下:

    注:關於主從節點之間的主從複製過程就不在這說了,和之前說過的主從複製一樣;

  4. 演示訪問操作

    使用 redis-cli 連接任意節點寫入數據,如果不指定集羣連接的話,會寫入數據失敗,如下:

    由於集羣環境下,數據的存儲位置是根據 Key 來計算而來的 (這裏牽涉到一致性哈希算法),使得數據可以均勻分配到各節點上,所以在 redis-cli 連接的時候需要指定集羣模式,如下:

    如上圖所示,指定集羣模式之後就可以正常存取了;

  5. 故障演示

    既然集羣環境,肯定少不了要好好測測;

    模擬從節點掛掉

    找個從節點停掉試試,這裏停掉 6371 節點,根據創建集羣信息知道,它的主節點是 6390;

    主節點顯示從節點斷開連接,看看它的主節點反應:

    其他集羣節點只是將從節點標記爲 failing 狀態,即下線狀態,如下:

    對於存取數據也不受影響,這裏就不截圖了,小夥伴自行嘗試吧;

    當故障的從節點 6371 重新連上時,主節點恢復主從關係,並進行主從複製操作;其他集羣節點會清除原來標記的下線狀態,將其改爲上線;

    模擬主節點掛掉

    這裏就手動將 6390 這個節點停掉,會有怎樣的反應呢?

    自身從節點會每隔一秒檢測連接,如果超時 (默認是 15 秒),會選舉從節點做爲集羣的主節點來提供服務,如下圖:

    數據存取最終還是不受影響;

    對於其他集羣節點,將故障節點標記爲 failing,讓新上任的主節點提供服務,如下圖:

    存取數據也是不受影響的;

    掛掉的主節點 6390 如果恢復,那它只能變爲 6371 的從節點啦,並進行相關主從複製操作;而集羣的其他節點只是將其原有的 Fail 狀態清除,表示可以正常連接;

Redis 集羣就是這樣簡單,只要思路對,就是手工活;小夥伴可以編寫腳本自動執行哦;

接下來說說集羣數據的存儲;

數據存儲簡單分析

在 Redis 集羣環境中,數據的存儲位置是根據對 Key 的 Hash 計算進行指定的;Redis 集羣爲了在節點改變時保證數據分佈均勻,引入了槽 (slot) 作爲遷移的基本單位,槽解耦了數據和實際節點的關係,使得實際節點數的改變對系統影響較小;

在整個集羣中,槽 (slot) 總共有 16384,會將其均勻分配到集羣的主節點上,其中每一份槽對應一個存儲空間 (這裏的存儲空間可以理解爲一個容器,是可以存很多數據的),以上集羣環境的槽分配如下:

存儲數據的過程,如下:

連接 6380 主節點,執行如下操作:

具體過程如下:

簡要說明:

  1. 客戶端發起命令;

  2. 服務器將 Key 進行 CRC16 計算,並與總槽位計算出 Key 需要存儲的位置;

  3. 這裏模擬的 Key 爲 zoe,計算出的槽位爲 14588,不在 6380 這個節點上,集羣節點會將其重定向到對應槽位的節點上;

  4. 然後找到 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

參數說明:

現在還差槽分配了,如果需要直接將 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 指分配的槽數

這裏就不截圖演示了,留給小夥伴自己動手操作吧;

刪除節點

  1. 先對節點進行分片工作,防止數據丟失,即將指定節點上的槽分配到其他節點;
    ./redis-cli --cluster reshard 要刪除節點ip:port

  2. 移除節點,推薦先刪除從節點,再刪除主節點;

    ./redis-cli --cluster del-node 節點ip:port 節點id

集羣配置項

總結

到這集羣的搭建就完啦,本來想着寫着很簡單的,沒想到又幹了 4000 字;對於集羣,使用有一些限制,比如 Keys 命令只能針對當前節點,需要針對多節點的情況進行處理;集羣中各節點只支持 db0 數據庫,其他數據庫不支持等等;所以使用要注意哦,後續抽時間單獨整理一篇注意事項吧,篇幅有點長,不繼續聊啦;  下篇說說熟悉的緩存穿透、緩存擊穿、緩存雪崩吧;

程序員徐 Sir

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/_gz9Tr7weU5dtRXAgROvqQ