滿懷憂思,不如先幹再說!
本文章為系列文章,如需系統觀看請按照文章順序閱讀,如有所了解,解決針對性問題,可直接閱讀,謝謝支援!用到Redis版本為5.X
說在前頭
本文涵蓋大量理論和原理性知識,适合收藏反複閱讀
如果純粹搭建叢集,暫且對理論和原理不感興趣,可直接閱讀 【快速配置】章節
為什麼使用叢集
之前我們提到redis可以實作主從複制,但是主從複制是不能實作高可用的,當資料容量或者QPS需要很大時但即使無法滿足需求的。至于Redis Sentinel【哨兵模式】與Redis Cluster【叢集模式】有何差別在文末說明。
并發量
Redsi官方提供的資料為10W/秒,不去計較它的準确性,但是實際使用中是可以完全達到上萬,已經可以滿足我們很大一部分的需求,但是有些業務可能需要更高的QPS,比如百萬級的。
資料量
Redis是基于記憶體的資料庫,機器的記憶體普遍在16~256G之間,如果我們的資料量有500G,比如個性化推薦系統,将使用者相關的資料都存到Redis中。
解決方案
- 配置強悍的機器,超大記憶體,頂級CPU等,但是成本非常高,一台節點總歸有極限。
- 分布式,添加節點。
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%的資料會遷移。
總結:
- 用戶端分片:哈希+取餘
- 節點伸縮:資料節點關系變化,導緻資料遷移,因為要重新計算
- 遷移量和添加節點數量有關:建議翻倍擴容
- 這種方式不建議使用,是一種比較古老的方式,因為當新增節點時會對大量資料造成遷移,如果你的系統很依賴緩存,那麼性能必然會受到影響。
一緻性哈希分區
上邊說到哈希取餘方式如果增加節點對資料造成的遷移比較大,一緻性哈希就是解決了這種問題。我們可以将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叢集中可用的節點。如果用戶端要找的資料在該節點上就會傳回資料,如果不在會響應用戶端新的節點位址,做一個轉發操作,去新的節點上擷取資料。當然這種方式效率不高,當節點多時,命中率不會很高,需要智能用戶端,這個後邊再說。
在分布式模式下節點之間會互相通信 每個節點都負責讀寫,每個節點負責資料的一部分
節點間通信
節點間使用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架構和整個流程,實際應用中使用快捷方式配置即可。
原生配置方式
步驟
- 配置開啟Redis,這種情況每台節點都是獨立的;
- 執行meet操作,讓Redis叢集之間感覺到其他節點的存在;
- 配置設定槽;
- 設定主從關系,我們這裡一共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
檢視狀态指令:
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個小時才找到!
下圖為配置設定槽、配置主從的過程是可以看出來的
檢視叢集情況
可以看出3主3從,操作和之前都一樣
哨兵模式和叢集有何差別
- 哨兵模式需要開啟sentinel程序主要作用是監控Redis節點的運作狀态,如果主資料庫發生故障則切換到從資料庫,sentinel發現master挂掉之後再重新選舉出一個新的master,主要是監控,提醒和故障轉移,實作Redis的高可用;
- 哨兵模式用戶端不會記錄具體的master節點的ip,而是記錄sentinel節點,我們從sentinel節點擷取redis的位址,上節我們用代碼示範過;
- 哨兵模式存儲資料都是全量存儲,每個Redis存儲的都是完整的資料,浪費記憶體而且存在木桶效應,為了最大化利用記憶體,我們可以使用分布式存儲,采用叢集。即每台節點存儲不同的資料,共有16384個slot;
- 叢集最少3主3從,且主從不用配置,叢集會自己配置設定(參考我們的第二種搭建方式);
- 叢集模式為了解決單機Redis容量有限的問題,将資料按照一定的規則配置設定到多台機器,提高并發。
如果不錯記得關注,點贊哦!無償提供程式設計咨詢服務,如有需要可私信