Redis Cluster一窺

Redis Cluster

什么是Redis Cluster

Redis Cluster讓多個Redis節(jié)點以集群的方式存儲數(shù)據(jù),數(shù)據(jù)會自動分片保存。
在提供分區(qū)的情況下,Redis Cluster可以保證一定程度的可用性,即在一個節(jié)點掛掉的情況下,整個集群依然可以正常提供服務。但是出現(xiàn)大多數(shù)master節(jié)點都掛的情況時,整個集群也會一起掛掉。

綜上,Redis Cluster提供了兩個特性:
1、數(shù)據(jù)的自動分區(qū)存儲
2、高可用性。即部分節(jié)點掛掉不影響集群的可用性。

TCP端口

每個Redis Cluster節(jié)點會占用兩個TCP端口,一個監(jiān)聽客戶端的請求,默認是6379,另外一個在前一個端口加上10000,比如16379,來監(jiān)聽數(shù)據(jù)的請求。

節(jié)點和節(jié)點之間會監(jiān)聽第二個端口,用一套二進制協(xié)議來通信。
節(jié)點之間會通過套協(xié)議來進行失敗檢測,配置更新,failover認證等等。
為了保證節(jié)點之間正常的訪問,需要注意防火墻的配置。

數(shù)據(jù)分片

Redis 集群沒有并使用傳統(tǒng)的一致性哈希來分配數(shù)據(jù),而是采用另外一種叫做哈希槽的方式來分配。
Redis Cluster默認分配了16384個槽,在分配的時候,會采用根據(jù)CRC16(key) % 16384的計算結(jié)果來將數(shù)據(jù)分配到節(jié)點上。
Redis Cluster中的每個節(jié)點會負責存儲數(shù)據(jù)槽的一個子集,假設有三個節(jié)點

  1. A節(jié)點存儲0到5500
  2. B節(jié)點存儲5501到11000
  3. C節(jié)點存儲11001到16383
    根據(jù)上面的公式計算的結(jié)果,如果大于0小于5500,那么數(shù)據(jù)將被存儲到A節(jié)點上。

這樣的特性使得增加或者刪除節(jié)點非常得容易。假如要加入節(jié)點D,只需要將A,B,C的部分槽轉(zhuǎn)移到D上;同理,要刪除C,只需要將C的槽轉(zhuǎn)移到A和B上,當C節(jié)點的數(shù)據(jù)被轉(zhuǎn)移,清空后,就可以刪除C節(jié)點了。

在移動哈希槽的時候,不需要停機維護。

如果一個指令涉及到多個key時,只要這些key屬于同一個槽,Redis Cluster允許同時操作他們。用戶可以通過hash tags強制將多個key歸到一個槽中。

主從模式

Redis Cluster支持主從模式,從節(jié)點會保存主節(jié)點的全部數(shù)據(jù)
在上面的例子中,假設B節(jié)點掛了,那么5501-11000的槽將不能夠提供服務。
現(xiàn)在給上面的節(jié)點添加一個從節(jié)點,那么我們將有A,B,C,A1,B1,C1六個節(jié)點。
當B節(jié)點掛掉,B1將會升級為主節(jié)點,系統(tǒng)的可用性將不受到影響。
但是,如果B和B1節(jié)點同時掛掉的話,集群依然會掛掉。

數(shù)據(jù)一致性

Redis Cluster不會保證數(shù)據(jù)的強一致性。在部分場景下可能會出現(xiàn)數(shù)據(jù)丟失的現(xiàn)象。
會丟數(shù)據(jù)的第一個原因是Redis Cluster中主節(jié)點異步向從節(jié)點拷貝數(shù)據(jù)。
在客戶寫入數(shù)據(jù)時,會經(jīng)過下面的過程。

  1. 寫到主節(jié)點B
  2. 主節(jié)點B返回"OK"
  3. 主節(jié)點將數(shù)據(jù)復制到從節(jié)點B1,B2,B3

可以看到,主節(jié)點B在向客戶返回"OK"的之前,并不會等待B1,B2,B3確認寫入的回應。這樣主要是為了性能的考慮,不能讓客戶等待太長時間。
假設一種情況,client寫入數(shù)據(jù),節(jié)點B確認這次寫入,但是在步驟3之前掛掉了,B1成為了新的主節(jié)點。那么這次寫入就永遠失效了。

可以看到Redis的高性能也是需要一定的代價的。Redis Cluster采取的方案實際上是數(shù)據(jù)一致性和高性能的折衷。

Redis Cluster支持同步寫入,見WAIT操作,這樣會降低丟數(shù)據(jù)的可能性,但是在復雜的情況下,還是可能出現(xiàn)從節(jié)點沒有接到寫入,然后成為主節(jié)點。

假設有A,B,C,A1,B1,C1六個節(jié)點,三主三從,現(xiàn)在有一個客戶Z1。
現(xiàn)在網(wǎng)絡出現(xiàn)隔離,A,C,A1,B1,C1之間是聯(lián)通的;Z1和B是聯(lián)通的。Z1向B寫入成功,如果網(wǎng)絡很快恢復,那么一切正常,但是沒有很快恢復的情況下,B1會成為新的主節(jié)點,Z1向B的寫入就丟失了。

上面說了這么多,總結(jié)一句話,
<strong><big>即使有了集群,也不能將Redis用做高可靠性的存儲。</big></strong>

部署相關

配置選項

  1. cluster-enabled<yes/no> 如果設置為yes,redis實例會開啟cluster模式;如果設置為no,standalone模式
  2. cluster-config-file<filename>
  3. cluster-node-timeout<milliseconds> 一個節(jié)點被判定為掛掉的最大時間
  4. **cluster-slave-validity-factor <factor>
    **:如果設置為0,從節(jié)點會一直failover主節(jié)點
  5. **cluster-migration-barrier <count>
    **:主節(jié)點對應最小從節(jié)點的個數(shù)
  6. **cluster-require-full-coverage <yes/no>
    **:如果設為yes,一旦部分哈希槽不能訪問到,集群會停止接受寫入;如果設為no,即使在部分哈希槽不能被訪問到的情況下,集群依然后接受寫入。

創(chuàng)建集群

我用的是mac系統(tǒng),其他類unix系統(tǒng)應該差不多。
先裝一些工具軟件,下載一下源碼。redis的使用的第三方庫的源碼都包含在項目中了,這簡直是編譯安裝的福音。

brew install ruby
brew install gem
gem install redis
git clone https://github.com/antirez/redis
cd redis
make

然后進入目錄utils/create-cluster,執(zhí)行命令

./create-cluster start

看到輸出,建立了6個單獨的實例。

Starting 30001
Starting 30002
Starting 30003
Starting 30004
Starting 30005
Starting 30006

執(zhí)行命令

./create-cluster create

看到輸出

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:30001
127.0.0.1:30002
127.0.0.1:30003
Adding replica 127.0.0.1:30004 to 127.0.0.1:30001
Adding replica 127.0.0.1:30005 to 127.0.0.1:30002
Adding replica 127.0.0.1:30006 to 127.0.0.1:30003
M: 6687e151e76830f8544ab9527bbb65b8d9063de4 127.0.0.1:30001
   slots:0-5460 (5461 slots) master
M: ea2e8ab4d48f5b0a1527dc0ac6d4f14e80f6aca0 127.0.0.1:30002
   slots:5461-10922 (5462 slots) master
M: 4a808670aae774e49343aac8526b641d5aa79de8 127.0.0.1:30003
   slots:10923-16383 (5461 slots) master
S: cee189bce870d87c318840a1e6a2d5045806acba 127.0.0.1:30004
   replicates 6687e151e76830f8544ab9527bbb65b8d9063de4
S: 68838ae12c64ccfccfe55b607a99454678d35ea4 127.0.0.1:30005
   replicates ea2e8ab4d48f5b0a1527dc0ac6d4f14e80f6aca0
S: 075ced4cef8e8ec06076b5193efb81812d72dc1b 127.0.0.1:30006
   replicates 4a808670aae774e49343aac8526b641d5aa79de8
Can I set the above configuration? (type 'yes' to accept): yes

輸入yes后,建立集群
可以看到30001,30002,30003作為主節(jié)點
30004,30005,30006分別作為其從節(jié)點。

執(zhí)行腳本

來看一下代碼

start

在執(zhí)行start指令的時候,實際上是執(zhí)行了下面的操作。

../../src/redis-server --port $PORT --cluster-enabled yes --cluster-config-file nodes-${PORT}.conf --cluster-node-timeout $TIMEOUT --appendonly yes --appendfilename appendonly-${PORT}.aof --dbfilename dump-${PORT}.rdb --logfile ${PORT}.log --daemonize yes

可以看到##配置選項里面項目都設置了一個值,來看一下--cluster-config-file這個配置里的文件長啥樣。挑一個主節(jié)點看看

cat nodes-30003.conf
ea2e8ab4d48f5b0a1527dc0ac6d4f14e80f6aca0 127.0.0.1:30002 master - 0 1473069793428 2 connected 5461-10922
4a808670aae774e49343aac8526b641d5aa79de8 127.0.0.1:30003 master - 0 1473069793529 3 connected 10923-16383
075ced4cef8e8ec06076b5193efb81812d72dc1b 127.0.0.1:30006 slave 4a808670aae774e49343aac8526b641d5aa79de8 0 1473069793428 6 connected
cee189bce870d87c318840a1e6a2d5045806acba 127.0.0.1:30004 slave 6687e151e76830f8544ab9527bbb65b8d9063de4 0 1473069793428 4 connected
6687e151e76830f8544ab9527bbb65b8d9063de4 127.0.0.1:30001 myself,master - 0 0 1 connected 0-5460
68838ae12c64ccfccfe55b607a99454678d35ea4 127.0.0.1:30005 slave ea2e8ab4d48f5b0a1527dc0ac6d4f14e80f6aca0 0 1473069793024 5 connected
vars currentEpoch 6 lastVoteEpoch 0

再挑一個從節(jié)點看看

cat nodes-30006.conf
4a808670aae774e49343aac8526b641d5aa79de8 127.0.0.1:30003 master - 0 1473069792576 3 connected 10923-16383
cee189bce870d87c318840a1e6a2d5045806acba 127.0.0.1:30004 myself,slave 6687e151e76830f8544ab9527bbb65b8d9063de4 0 0 4 connected
68838ae12c64ccfccfe55b607a99454678d35ea4 127.0.0.1:30005 slave ea2e8ab4d48f5b0a1527dc0ac6d4f14e80f6aca0 0 1473069793485 5 connected
ea2e8ab4d48f5b0a1527dc0ac6d4f14e80f6aca0 127.0.0.1:30002 master - 0 1473069793079 2 connected 5461-10922
075ced4cef8e8ec06076b5193efb81812d72dc1b 127.0.0.1:30006 slave 4a808670aae774e49343aac8526b641d5aa79de8 0 1473069792578 3 connected
6687e151e76830f8544ab9527bbb65b8d9063de4 127.0.0.1:30001 master - 0 1473069793079 1 connected 0-5460
vars currentEpoch 6 lastVoteEpoch 0

可以看到這里面維護了一個狀態(tài)表,紀錄了所有節(jié)點的
信息,狀態(tài)等等。這個文件會將集群的信息保存下來,用于集群下次的啟動,根據(jù)節(jié)點收到的信息,這個文件會經(jīng)常改變,并保存。

create

執(zhí)行create指令時,實際上是執(zhí)行了下面的操作

../../src/redis-trib.rb create --replicas 1  127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006

redis-trib.rb是redis作者寫的一個工具。

用用看

redis-cli -c -p 30001
127.0.0.1:30001> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:30003
OK
127.0.0.1:30003> set hello world
-> Redirected to slot [866] located at 127.0.0.1:30001
OK
127.0.0.1:30001> get foo
-> Redirected to slot [12182] located at 127.0.0.1:30003
"bar"
127.0.0.1:30003> get hellp
-> Redirected to slot [8380] located at 127.0.0.1:30002
(nil)
127.0.0.1:30002> get hello
-> Redirected to slot [866] located at 127.0.0.1:30001
"world"
127.0.0.1:30001>

可以看到,集群會根據(jù)key值所在的槽重定向至對應的節(jié)點。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • redis集群分為服務端集群和客戶端分片,redis3.0以上版本實現(xiàn)了集群機制,即服務端集群,3.0以下使用客戶...
    hadoop_null閱讀 1,679評論 0 6
  • 本文是對Redis的集群部署模式一個學習總結(jié),共包括如下章節(jié)內(nèi)容: 概述 主從集群模式 “哨兵”集群模式 Clus...
    我是老薛閱讀 1,078評論 0 4
  • 前言 Redis 是我們目前大規(guī)模使用的緩存中間件,由于它強大高效而又便捷的功能,得到了廣泛的使用。單節(jié)點的Red...
    Kevin_ZGJ閱讀 11,857評論 19 133
  • 零、redis集群解決方案 1.Twitter開發(fā)的twemproxy2.豌豆莢開發(fā)的codis3.redis官方...
    空杯成長筆記閱讀 4,796評論 0 1
  • 前面我們介紹了國人自己開發(fā)的Redis集群方案——Codis,Codis友好的管理界面以及強大的自動平衡槽位的功能...
    Jackeyzhe閱讀 2,171評論 0 3

友情鏈接更多精彩內(nèi)容