Redis Cluster 集羣模式從零理論配合集羣搭建

點贊多大膽,就有多大產路漫漫其修遠兮,吾將上下而求索獻給每一位技術使用者和愛好者!

乾貨滿滿,擺好姿勢,點贊發車

爲什麼使用集羣

之前我們提到redis可以實現主從複製,但是主從複製是不能實現高可用的,當數據容量或者QPS需要很大時但即使無法滿足需求的。也提到了Redis Sentinel與Redis Cluster有何區別我們在文末說明。

併發量

Redsi官方提供的數據爲10W/秒,我們不去計較它的準確性,但是實際使用中是可以完全達到上萬,已經可以滿足我們很大一部分的需求,但是有些業務可能需要更高的QPS,比如百萬級的。

數據量

Redis是基於內存的數據庫,機器的內存普遍在16~256G之間,如果我們的數據量有500G,比如個性化推薦系統,將用戶相關的數據都存到Redis中。

解決方案

  1. 配置強悍的機器,超大內存,頂級CPU等,但是成本非常高,一臺節點總歸有極限。
  2. 分佈式,添加節點。

Redis在3.0版本之後推出Redis Cluster來滿足我們分佈式的需求

數據分區

我們在學習Redis集羣之前我們先看看數據分區的概念,就是怎麼將所有的數據合理的分配到不同的節點上。常有的分區方式有順序分區哈希分區

順序分區

就是將同一個範圍內的數據存儲到同一個Redis實例中,比如有一張用戶表,我們將ID0-ID10000的,ID-10001-ID20000,以此類推,存儲到同一個實例中。那麼如果我們有些數據不好分區,比如有些ID是隨機數,UUID等等,我們可以使用哈希分區

哈希分區

哈希分區跟範圍分區相比一個明顯的優點是哈希分區適合任何形式的key,而不像順序分區一樣有侷限性,而且分區方法也很簡單,一個公式就可以表達:id=hash(key)%nodes

其中id代表Redis實例的編號,公式描述的是首先根據key和一個hash函數(如crc32函數)計算出一個數值型的,再對Redis節點數取模,取模的目的是計算出我們要將數據存到第幾臺節點上!

節點取餘分區

當我們Redis節點有三臺,但是數據越來越多時,我們會考慮增加節點,這個時候我們建議使用多倍擴容,比如3臺節點我們擴容到4臺那麼80%的數據會切換接點,比如從1到了2節點等現象,數據遷移變化太多,我們如果熙增到6臺節點那麼只有50%的數據會遷移。

總結:

  1. 客戶端分片:哈希+取餘
  2. 節點伸縮:數據節點關係變化,導致數據遷移,因爲要重新計算
  3. 遷移量和添加節點數量有關:建議翻倍擴容
  4. 這種方式不建議使用,是一種比較古老的方式,因爲當新增節點時會對大量數據造成遷移,如果你的系統很依賴緩存,那麼性能必然會受到影響。

一致性哈希分區

上邊我們說到哈希取餘方式如果增加節點對數據造成的遷移比較大,一致性哈希就是解決了這種問題。我們可以將Redis保存數據認爲是一個環形,Hash值有32位,0~2 ^32,將節點的IP+算法確定唯一的哈希值,之後在內存中確定節點的位置,當保存數據時,根據key進行哈希運算,順時針確定掛載到哪臺節點上。圖醜大家見諒,哈哈哈哈嗝~~~!!!

如果集羣需要添加節點,比如在node2和node3之間添加一個node4,數據分佈會變成下圖

我們會發現,數據依然有遷移,本來在node3上的數據一部分遷移到了node4上,但是node1和node2沒有受到影響。如果我們集羣有1000臺,是由原本的取餘分區方式會有80%的數據遷移,爲了避免我們使用雙倍擴容,也就是再添加1000臺節點達到50%數據遷移的效果,很顯然添加這麼多的節點是不合適的!!!這種分區方式在memCache中使用。

Redis哈希槽

上邊我們介紹了順序分區和hash分區,而Redis Cluster並沒有使用其中的任何一種(坑爹呢,上邊叨X叨半天),Redis而是引入了哈希槽的的概念,Redis內置了16384個槽,從0-16383。每個節點都維護一個範圍的哈希槽,當有新的key需要添加時,會使用CRC16算法並且對16384取餘,公式:CRC16(key) & 16384。得到一個值,去找Redis集羣中的節點,看看這個槽是哪個節點維護的,就將key存儲到哪個節點上。

到這裏我們知道有順序分區哈希分區,哈希分區包含節點取餘一致性哈希memCache分佈式使用一致性哈希Redis集羣中使用的是哈希槽的方式存儲數據。 我們接下來說一下Redis集羣的架構搭建方式

Redis集羣架構

單體架構

單體架構如下圖所示,只有一個Redis實例,多個客戶端都在操作同一個Redis,數據存儲量,訪問量,數據備份上都是有問題的

Redis Cluster架構 

說明

下圖是分佈式架構(咋這麼多箭頭,我得了箭頭眩暈症),藍色圓圈是Redis實例,這裏有五個,我們之前說Redis集羣中存儲數據通過槽的概念,會講16384個槽平均到5臺節點上,節點之間看到了有雙向箭頭指向,這代表他們之間是相互通信的,每個節點都知道對應的槽是哪個節點負責。下方的綠色客戶端可以去操作Redis集羣中可用的節點。如果客戶端要找的數據在該節點上就會返回數據,如果不在會響應客戶端新的節點地址,做一個轉發操作,去新的節點上獲取數據。當然這種方式效率不高,當節點多時,命中率不會很高,需要智能客戶端,這個後邊再說。

  1. 在分佈式模式下節點之間會相互通信
  2. 每個節點都負責讀寫,每個節點負責數據的一部分

節點間通信

節點間使用meet命令進行通信,比如A向C發送meet命令,C會反饋給A一個PONG,A給B發送meet,B反饋給A一個PONG,這樣B和C也能得知對方的存在。

節點更多時如下

指派槽

比如我們的Redis Cluster有三臺節點,我們需要給三臺節點分配槽,如下圖,而客戶端則需要使用公式計算結果將key存儲在對應的節點上。

Redis集羣配置和啓動

Redis集羣配置有原生配置、官方提供的ruby插件配置方式和redis5.0之後的快捷配置,我們這裏三種方式我們說明第一種和第三種,原生配置比較麻煩,但是可以讓你體驗到Redis Cluster架構和整個流程,實際應用中使用快捷方式配置即可。

原生配置方式

步驟

  1.  配置開啓Redis,這種情況每臺節點都是獨立的;

  2. 執行meet操作,讓Redis集羣之間感知到其他節點的存在;

  3. 分配槽;

  4. 設置主從關係,我們這裏一共6臺節點,3主3從。

Redis配置和啓動

我們的配置文件從redis-7000.conf到redis-7005.conf,每個配置文件中端口日誌文件名不一樣,只貼出redis-7000.conf配置文件

port 7000
daemonize yes
logfile "7000.log"
dir "/usr/local/redis-5.0.5/data/"
protected-mode no
dbfilename dump-7000.rdb
# 開啓集羣
cluster-enabled yes
# 集羣運行時文件
cluster-config-file nodes-7000.conf
# 是否集羣所有的節點都正常集羣纔可使用,改爲no
cluster-require-full-coverage no

 啓動Redis6個節點,在查看進程,發現端口後邊都有cluster標記

我們隨便進入一個節點添加數據會發現,提示我們集羣下線,沒有提供哈希槽!請回頭看我們的步驟。至此我們第一步和第二步就完成

接下來我們到data目錄下發現有nodes開頭的文件,這就是我們在redis配置文件中配置的,我們輸出一下文件內容,綠色下劃線的分別是該節點的ID和自己的狀態爲master。

meet操作實現節點握手

命令:redis-cli -p port cluster meet 目標節點ip 目標節點port

[root@stt101 conf]# ./redis-cli -p 7000 cluster meet 127.0.0.1 7001
OK
[root@stt101 conf]# ./redis-cli -p 7000 cluster meet 127.0.0.1 7002
OK
[root@stt101 conf]# ./redis-cli -p 7000 cluster meet 127.0.0.1 7003
OK
[root@stt101 conf]# ./redis-cli -p 7000 cluster meet 127.0.0.1 7004
OK
[root@stt101 conf]# ./redis-cli -p 7000 cluster meet 127.0.0.1 7005

查看狀態命令:redis-cli -p 7000 cluster info 發現節點個數爲6個

那麼這裏給大家留個問題,至此我們可否向redis中存儲數據呢? 

指派槽 

集羣規劃爲7000,7001,7002是主節點,7003是7000從節點,7004是7001從節點,7005是7002從節點 

7000:0-5461

7001:5462-10922

7002:10923-16383

分配槽命令:redis-cli -p port cluster addslots slot

我們有16384個槽,一個一個分配是很慢的,所以我們編寫一個腳本來分配!

分配槽腳本

start=$1
end=$2
port=$3
for slot in `seq ${start} ${end}`
do
  echo "slot:${slot}"
  redis-cli -p ${port} cluster addslots ${slot}
done

執行命令

addslots.sh 0 5461 7000 

addslots.sh 5462 10922 7001

addslots.sh 10923 16383 7002 

進入到7000端口實例執行cluster nodes命令看到槽已分配好,大家就可以向Redis中添加數據了 

主從分配

根據指派槽哪裏說得主從關係我們使用以下命令進行分配

命令

redis-cli -p 從節點port cluster replicate 主節點ID

主節點ID就是上圖最前邊的那一串字符

redis-cli -p 7003 cluster replicate cb436d72cee8f6547e0dc002c9342dd27087bdcc 
redis-cli -p 7004 cluster replicate 03717034bca9c03e40cf4c1a4041c94f79e209d8
redis-cli -p 7005 cluster replicate c0167209ceb9fa350704781a1a53432a61f92a8c 

在執行cluster nodes命令會發現已經變成3主3從,如下圖 

 注意:如果啓動集羣模式的客戶端需要使用redis-cli -c -p 7003命令加上了-c參數!

至此我們的原生方式已經搭建完成,很複雜,但是可以看到Redis Cluster的整個實現流程,對大家理解Redis Cluster更有幫助,希望大家可以自己動手跟着做一遍!有問題的可以下方留言! 

快速配置

redis5.0集羣創建方式改爲了C編寫的redis-cli創建,不用再安裝麻煩的ruby了。ruby方式大家感興趣可以到網上搜索,這裏就不說了配置和之前一樣就是將7000端口改爲8000,以此類推爲了區別,大家在配置的時候建議先將redis都停掉,還是3主3從的方式,下邊只貼出8000的配置

配置文件

port 8000
daemonize yes
logfile "8000.log"
dir "/usr/local/redis-5.0.5/data/"
protected-mode no
dbfilename dump-8000.rdb
# 開啓集羣
cluster-enabled yes
# 集羣運行時文件
cluster-config-file nodes-8000.conf
# 是否集羣所有的節點都正常集羣纔可使用,改爲no
cluster-require-full-coverage no
# 節點請求超時時間 
cluster-node-timeout 15000
# 關閉保護模式
protected-mode no

啓動節點

分別啓動6臺節點,查看進程

配置集羣

直接使用以下命令即可,前邊三臺是主節點,後邊三臺是從節點

redis-cli --cluster create 192.168.11.101:8000 192.168.11.101:8001 192.168.11.101:8002 192.168.11.101:8003 192.168.11.101:8004 192.168.11.101:8005 --cluster-replicas 1

 大家這裏一定要注意上邊create創建集羣時,一定要寫具體的節點ip,不要寫127.0.0.1,否則在你使用Java操作Redis Cluster時會去連接127.0.0.1的節點,比如:你在Centos上部署的redis集羣,你的開發環境實在window下,那麼他就會操作你window下的redis,然而並沒有!當時我這裏也是出了問題,搞了將近2個小時才找到,頭疼!之前跟着我博客搭建redis集羣的小夥伴給大家說一聲抱歉,哈哈哈!

下圖爲分配槽、配置主從的過程是可以看出來的

查看集羣情況

 可以看出3主3從,操作和之前都一樣

哨兵模式和集羣有何區別

  1. 哨兵模式需要開啓sentinel進程主要作用是監控Redis節點的運行狀態,如果主數據庫發生故障則切換到從數據庫,sentinel發現master掛掉之後再重新選舉出一個新的master,主要是監控,提醒和故障轉移,實現Redis的高可用;
  2. 哨兵模式客戶端不會記錄具體的master節點的ip,而是記錄sentinel節點,我們從sentinel節點獲取redis的地址,上節我們用代碼演示過;
  3. 哨兵模式存儲數據都是全量存儲,每個Redis存儲的都是完整的數據,浪費內存而且存在木桶效應,爲了最大化利用內存,我們可以使用分佈式存儲,採用集羣。即每臺節點存儲不同的數據,共有16384個slot;
  4. 集羣最少3主3從,且主從不用配置,集羣會自己分配(參考我們的第二種搭建方式);
  5. 集羣模式爲了解決單機Redis容量有限的問題,將數據按照一定的規則分配到多臺機器,提高併發。

我是添添,用你勤勞的雙手點個贊吧,這將是我創作更多優質文章的動力!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章