[TOC]
1. Redis集群介紹
Redis 集群是一個提供在多個Redis間節(jié)點間共享數(shù)據(jù)的程序集。
Redis集群并不支持處理多個keys的命令,因為這需要在不同的節(jié)點間移動數(shù)據(jù),從而達不到像Redis那樣的性能,在高負載的情況下可能會導(dǎo)致不可預(yù)料的錯誤.
Redis 集群通過分區(qū)來提供一定程度的可用性,在實際環(huán)境中當(dāng)某個節(jié)點宕機或者不可達的情況下繼續(xù)處理命令. Redis 集群的優(yōu)勢:
- 自動分割數(shù)據(jù)到不同的節(jié)點上挟纱。
- 整個集群的部分節(jié)點失敗或者不可達的情況下能夠繼續(xù)處理命令撕氧。
2. Redis 集群的數(shù)據(jù)分片
Redis 集群沒有使用一致性hash, 而是引入了 哈希槽的概念.
Redis 集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽.集群的每個節(jié)點負責(zé)一部分hash槽,舉個例子,比如當(dāng)前集群有3個節(jié)點,那么:
- 節(jié)點 A 包含 0 到 5500號哈希槽.
- 節(jié)點 B 包含5501 到 11000 號哈希槽.
- 節(jié)點 C 包含11001 到 16384號哈希槽.
這種結(jié)構(gòu)很容易添加或者刪除節(jié)點. 比如如果我想新添加個節(jié)點D, 我需要從節(jié)點 A, B, C中得部分槽到D上. 如果我想移除節(jié)點A,需要將A中的槽移到B和C節(jié)點上,然后將沒有任何槽的A節(jié)點從集群中移除即可. 由于從一個節(jié)點將哈希槽移動到另一個節(jié)點并不會停止服務(wù),所以無論添加刪除或者改變某個節(jié)點的哈希槽的數(shù)量都不會造成集群不可用的狀態(tài).
3. Redis 集群的主從復(fù)制模型
為了使在部分節(jié)點失敗或者大部分節(jié)點無法通信的情況下集群仍然可用,所以集群使用了主從復(fù)制模型,每個節(jié)點都會有N-1個復(fù)制品.
在我們例子中具有A核行,B牢硅,C三個節(jié)點的集群,在沒有復(fù)制模型的情況下,如果節(jié)點B失敗了,那么整個集群就會以為缺少5501-11000這個范圍的槽而不可用.
然而如果在集群創(chuàng)建的時候(或者過一段時間)我們?yōu)槊總€節(jié)點添加一個從節(jié)點A1芝雪,B1减余,C1,那么整個集群便有三個master節(jié)點和三個slave節(jié)點組成,這樣在節(jié)點B失敗后惩系,集群便會選舉B1為新的主節(jié)點繼續(xù)服務(wù)位岔,整個集群便不會因為槽找不到而不可用了
不過當(dāng)B和B1 都失敗后,集群是不可用的.
4. Redis 一致性保證
Redis 并不能保證數(shù)據(jù)的強一致性. 這意味這在實際中集群在特定的條件下可能會丟失寫操作.
第一個原因是因為集群是用了異步復(fù)制. 寫操作過程:
- 客戶端向主節(jié)點B寫入一條命令.
- 主節(jié)點B向客戶端回復(fù)命令狀態(tài).
- 主節(jié)點將寫操作復(fù)制給他得從節(jié)點 B1, B2 和 B3.
主節(jié)點對命令的復(fù)制工作發(fā)生在返回命令回復(fù)之后堡牡, 因為如果每次處理命令請求都需要等待復(fù)制操作完成的話抒抬, 那么主節(jié)點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權(quán)衡。 注意:Redis 集群可能會在將來提供同步寫的方法悴侵。 Redis 集群另外一種可能會丟失命令的情況是集群出現(xiàn)了網(wǎng)絡(luò)分區(qū)瞧剖, 并且一個客戶端與至少包括一個主節(jié)點在內(nèi)的少數(shù)實例被孤立。
舉個例子 假設(shè)集群包含 A 可免、 B 抓于、 C 、 A1 浇借、 B1 捉撮、 C1 六個節(jié)點, 其中 A 妇垢、B 巾遭、C 為主節(jié)點, A1 闯估、B1 灼舍、C1 為A,B涨薪,C的從節(jié)點骑素, 還有一個客戶端 Z1 假設(shè)集群中發(fā)生網(wǎng)絡(luò)分區(qū),那么集群可能會分為兩方刚夺,大部分的一方包含節(jié)點 A 献丑、C 末捣、A1 、B1 和 C1 创橄,小部分的一方則包含節(jié)點 B 和客戶端 Z1 .
Z1仍然能夠向主節(jié)點B中寫入, 如果網(wǎng)絡(luò)分區(qū)發(fā)生時間較短,那么集群將會繼續(xù)正常運作,如果分區(qū)的時間足夠讓大部分的一方將B1選舉為新的master箩做,那么Z1寫入B中得數(shù)據(jù)便丟失了.
注意, 在網(wǎng)絡(luò)分裂出現(xiàn)期間妥畏, 客戶端 Z1 可以向主節(jié)點 B 發(fā)送寫命令的最大時間是有限制的邦邦, 這一時間限制稱為節(jié)點超時時間(node timeout), 是 Redis 集群的一個重要的配置選項.
5. 搭建并使用Redis集群
搭建集群的第一件事情我們需要一些運行在 集群模式的Redis實例. 這意味這集群并不是由一些普通的Redis實例組成的咖熟,集群模式需要通過配置啟用圃酵,開啟集群模式后的Redis實例便可以使用集群特有的命令和特性了.
配置文件
下面是一個最少選項的集群的配置文件:
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
文件中的 cluster-enabled 選項用于開實例的集群模式, 而 cluster-conf-file 選項則設(shè)定了保存節(jié)點配置文件的路徑馍管, 默認值為 nodes.conf.節(jié)點配置文件無須人為修改郭赐, 它由 Redis 集群在啟動時創(chuàng)建, 并在有需要時自動進行更新确沸。
在之前的redis的哨兵模式中捌锭,沒有實現(xiàn)集群,今天罗捎,在哨兵模式的基礎(chǔ)上繼續(xù)观谦。
首先,從redis的github上下載代碼桨菜,主要是獲取redis.conf
然后上傳到服務(wù)器中:
然后拷貝兩份配置文件(防止redis,conf被污染)豁状,并給與權(quán)限
配置集群
接下來,修改配置文件
開啟集群模式
指定配置文件
集群節(jié)點超時時間
==這里有一個比較坑的地方倒得,cluster-config-file
這里不配置泻红,因為我們使用docker啟動,在啟動的時候會指定配置文件的==霞掺,否則會拋出異常:Unrecoverable error: corrupted cluster config file.
docker啟動
接著谊路,使用docker啟動
docker run -d -p 6379:6379 -v /redis/redis_1.conf:/usr/local/etc/redis/redis.conf --name=master_c_1 redis redis-server /usr/local/etc/redis/redis.conf
接下來創(chuàng)建從節(jié)點
集群客戶端
在redis 5.x之后,就不推薦使用redis-trib.rb
了菩彬,而是使用redis-cli --cluster
的命令缠劝。
但是redis高版本,可以使用create-cluster腳本
查看其REDAME:
將腳本放到服務(wù)器中(這個腳本是個linux的腳本)
創(chuàng)建集群
因為目錄結(jié)構(gòu)已經(jīng)不正確了骗灶,所以惨恭,我們研究下這個腳本里面都干了什么吧
和我們之前在docker那里的命令一模一樣。
創(chuàng)建集群使用docker容器里面的redis-cli耙旦。
docker run -it --rm redis redis-cli --cluster create 10.0.228.117:6379 10.0.228.117:6380 10.0.228.117:6381 10.0.228.117:6382 --cluster-replicas 1
提示6379脱羡,也就是master_c_1不是集群模式啟動的?
明明是集群模式啟動的啊。
想想轻黑,應(yīng)該是配置不對吧。
應(yīng)該是ip綁定了琴昆,不應(yīng)該綁定ip.
果真如此氓鄙,不僅僅綁定了IP,還使用了保護模式业舍。抖拦。。舷暮。态罪。太粗心了。綁定0.0.0.0表示任何IP都可以訪問
重啟下面,重試复颈。
至少需要6臺機器,我擦
(因為redis集群使用流言協(xié)議進行交換數(shù)據(jù)沥割,流言協(xié)議的裁定需要使用過半原則耗啦。所以最少是3臺master(1個無法實現(xiàn)流言協(xié)議,2個無法實現(xiàn)過半原則)机杜,指定1個副本帜讲,就是至少6臺機器)
在增加一個主節(jié)點和一個從節(jié)點吧。
重新創(chuàng)建集群
又沒成功椒拗,從輸出來看似将,應(yīng)該是容器內(nèi)無法解析IP,那么只能在啟動的時候制動hostname了
我真是太能折騰了蚀苛。在验。
docker ps|grep redis|awk '{print $1}'|xargs docker rm
docker run -d --rm --network=host -v /redis/redis_1.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_1 --name=master_c_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6379
docker run -d --rm --network=host -v /redis/redis_2.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_2 --name=master_c_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6380
docker run -d --rm --network=host -v /redis/redis_3.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_3 --name=master_c_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6381
docker run -d --rm --network=host -v /redis/slave_1.conf:/usr/local/etc/redis/redis.conf --hostname=slave_1 --name=slave_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6382
docker run -d --rm --network=host -v /redis/slave_2.conf:/usr/local/etc/redis/redis.conf --hostname=slave_2 --name=slave_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6383
docker run -d --rm --network=host -v /redis/slave_3.conf:/usr/local/etc/redis/redis.conf --hostname=slave_3 --name=slave_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6384
然后創(chuàng)建集群
終于成功了(都快哭了)
==這里必須使用docker的host網(wǎng)絡(luò)模式,因為redis集群不支持docker的port mapping.==
使用這個命令看看吧
使用
嘗試插入不同的數(shù)據(jù):
出現(xiàn)(error) MOVED xxxxxx
==原因:redis-cli需要以集群模式啟動==
6. 集群命令 -- cluster
info
查看集群信息
cluster info
-
cluster_state
:ok
狀態(tài)表示集群可以正常接受查詢請求枉阵。fail
狀態(tài)表示译红,至少有一個哈希槽沒有被綁定(說明有哈希槽沒有被綁定到任意一個節(jié)點),或者在錯誤的狀態(tài)(節(jié)點可以提供服務(wù)但是帶有FAIL 標(biāo)記)兴溜,或者該節(jié)點無法聯(lián)系到多數(shù)master節(jié)點侦厚。. -
cluster_slots_assigned
: 已分配到集群節(jié)點的哈希槽數(shù)量(不是沒有被綁定的數(shù)量)。16384個哈希槽全部被分配到集群節(jié)點是集群正常運行的必要條件. -
cluster_slots_ok
: 哈希槽狀態(tài)不是FAIL
和PFAIL
的數(shù)量. -
cluster_slots_pfail
: 哈希槽狀態(tài)是PFAIL
的數(shù)量拙徽。只要哈希槽狀態(tài)沒有被升級到FAIL
狀態(tài)刨沦,這些哈希槽仍然可以被正常處理。PFAIL
狀態(tài)表示我們當(dāng)前不能和節(jié)點進行交互膘怕,但這種狀態(tài)只是臨時的錯誤狀態(tài)想诅。 -
cluster_slots_fail
: 哈希槽狀態(tài)是FAIL
的數(shù)量。如果值不是0,那么集群節(jié)點將無法提供查詢服務(wù)来破,除非cluster-require-full-coverage
被設(shè)置為no
. -
cluster_known_nodes
: 集群中節(jié)點數(shù)量篮灼,包括處于握手
狀態(tài)還沒有成為集群正式成員的節(jié)點. -
cluster_size
: 至少包含一個哈希槽且能夠提供服務(wù)的master節(jié)點數(shù)量. -
cluster_current_epoch
: 集群本地Current Epoch
變量的值。這個值在節(jié)點故障轉(zhuǎn)移過程時有用徘禁,它總是遞增和唯一的诅诱。 -
cluster_my_epoch
: 當(dāng)前正在使用的節(jié)點的Config Epoch
值. 這個是關(guān)聯(lián)在本節(jié)點的版本值. -
cluster_stats_messages_sent
: 通過node-to-node二進制總線發(fā)送的消息數(shù)量. -
cluster_stats_messages_received
: 通過node-to-node二進制總線接收的消息數(shù)量.
nodes
查看節(jié)點信息
cluster nodes
每行組成:
<id> <ip:port> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>
每項的含義如下:
id
: 節(jié)點ID,是一個40字節(jié)的隨機字符串,這個值在節(jié)點啟動的時候創(chuàng)建送朱,并且永遠不會改變(除非使用CLUSTER RESET HARD
命令)娘荡。ip:port
: 客戶端與節(jié)點通信使用的地址.-
flags
: 逗號分割的標(biāo)記位,可能的值有:myself
,master
,slave
,fail?
,fail
,handshake
,noaddr
,noflags
:各flags的含義 (上面所說數(shù)據(jù)項3):
-
myself
: 當(dāng)前連接的節(jié)點. -
master
: 節(jié)點是master. -
slave
: 節(jié)點是slave. -
fail?
: 節(jié)點處于PFAIL
狀態(tài)驶沼。 當(dāng)前節(jié)點無法聯(lián)系炮沐,但邏輯上是可達的 (非FAIL
狀態(tài)). -
fail
: 節(jié)點處于FAIL
狀態(tài). 大部分節(jié)點都無法與其取得聯(lián)系將會將改節(jié)點由PFAIL
狀態(tài)升級至FAIL
狀態(tài)。 -
handshake
: 還未取得信任的節(jié)點回怜,當(dāng)前正在與其進行握手. -
noaddr
: 沒有地址的節(jié)點(No address known for this node). -
noflags
: 連個標(biāo)記都沒有(No flags at all).
-
master
: 如果節(jié)點是slave大年,并且已知master節(jié)點,則這里列出master節(jié)點ID,否則的話這里列出”-“鹉戚。ping-sent
: 最近一次發(fā)送ping的時間鲜戒,這個時間是一個unix毫秒時間戳,0代表沒有發(fā)送過.pong-recv
: 最近一次收到pong的時間抹凳,使用uni`x時間戳表示.config-epoch
: 節(jié)點的epoch值(or of the current master if the node is a slave)遏餐。每當(dāng)節(jié)點發(fā)生失敗切換時,都會創(chuàng)建一個新的赢底,獨特的失都,遞增的epoch。如果多個節(jié)點競爭同一個哈希槽時幸冻,epoch值更高的節(jié)點會搶奪到粹庞。link-state
: node-to-node集群總線使用的鏈接的狀態(tài),我們使用這個鏈接與集群中其他節(jié)點進行通信.值可以是connected
和disconnected
.slot
: 哈希槽值或者一個哈希槽范圍. 從第9個參數(shù)開始洽损,后面最多可能有16384個 數(shù)(limit never reached)庞溜。代表當(dāng)前節(jié)點可以提供服務(wù)的所有哈希槽值。如果只是一個值,那就是只有一個槽會被使用碑定。如果是一個范圍流码,這個值表示為起始槽-結(jié)束槽
,節(jié)點將處理包括起始槽和結(jié)束槽在內(nèi)的所有哈希槽延刘。
replocas
cluster replicas <node-id>
該命令會列出指定主節(jié)點的輔助副本節(jié)點漫试,輸出格式同命令CLUSTER NODES
.
若特定節(jié)點狀態(tài)未知,或在接收命令節(jié)點的節(jié)點信息表中碘赖,該節(jié)點不是主節(jié)點驾荣,則命令失敗.
slaves
cluster slaves <node-id>
該命令會列出指定master節(jié)點所有slave節(jié)點外构,格式同CLUSTER NODES
當(dāng)指定節(jié)點未知或者根據(jù)接收命令的節(jié)點的節(jié)點信息表指定節(jié)點不是主節(jié)點,命令執(zhí)行錯誤播掷。
slots
cluster slots
CLUSTER SLOTS
命令返回哈希槽和Redis實例映射關(guān)系审编。這個命令對客戶端實現(xiàn)集群功能非常有用,使用這個命令可以獲得哈希槽與節(jié)點(由IP和端口組成)的映射關(guān)系歧匈,這樣割笙,當(dāng)客戶端收到(用戶的)調(diào)用命令時,可以根據(jù)(這個命令)返回的信息將命令發(fā)送到正確的Redis實例.
(嵌套對象)結(jié)果數(shù)組每一個(節(jié)點)信息:
- 哈希槽起始編號
- 哈希槽結(jié)束編號
- 哈希槽對應(yīng)master節(jié)點眯亦,節(jié)點使用IP/Port表示
- master節(jié)點的第一個副本
每個結(jié)果包含該哈希槽范圍的所有存活的副本,沒有存活的副本不會返回.
(每個節(jié)點信息的)第三個(行)對象一定是IP/Port形式的master節(jié)點般码。之后的所有IP/Port都是該哈希槽范圍的Redis副本妻率。
如果一個集群實例中的哈希槽不是連續(xù)的(例如1-400,900,1800-6000),那么哈希槽對應(yīng)的master和replica副本在這些不同的哈希槽范圍會出現(xiàn)多次板祝。
count-failure-reports
cluster count-filure-reports <node-id>
這個命令返回指定節(jié)點的故障報告個數(shù)宫静,故障報告是Redis Cluster用來使節(jié)點的PFAIL
狀態(tài)(這意味著節(jié)點不可達)晉升到FAIL
狀態(tài)而的方式谭网,這意味著集群中大多數(shù)的主節(jié)點在一個事件窗口內(nèi)同意節(jié)點不可達摊鸡。
因為redis使用==流言模式==,所以需要記錄報告的異常次數(shù)蝇摸。
- 一個節(jié)點會用
PFAIL
標(biāo)記一個不可達時間超過配置中的超時時間的節(jié)點橘洞,這個超時時間是 Redis Cluster 配置中的基本選項捌袜。 - 處于
PFAIL
狀態(tài)的節(jié)點會將狀態(tài)信息提供在心跳包的流言(gossip)部分。 - 每當(dāng)一個節(jié)點處理來自其他節(jié)點的流言(gossip)包時炸枣,該節(jié)點會建立故障報告(如果需要會刷新TTL)虏等,并且會記住發(fā)送消息包的節(jié)點所認為處于
PFAIL
狀態(tài)下的其他節(jié)點。 - 每個故障報告的生存時間是節(jié)點超時時間的兩倍适肠。
- 如果在一段給定的事件內(nèi)霍衫,一個節(jié)點被另一個節(jié)點標(biāo)記為
PFAIL
狀態(tài),并且在相同的時間內(nèi)收到了其他大多數(shù)主節(jié)點關(guān)于該節(jié)點的故障報告(如果該節(jié)點是主節(jié)點包括它自己)侯养,那么該節(jié)點的故障狀態(tài)會從PFAIL
晉升為FAIL
敦跌,并且會廣播一個消息,強制所有可達的節(jié)點將該節(jié)點標(biāo)記為FAIL
逛揩。
countkeysinslot
cluster countkeysinslot slot
count keys in sloot
查詢指定slot中key的數(shù)量
這個命令和keyslot配合使用柠傍。
==如果指定的hash slot不在客戶端連接的節(jié)點上,返回0.==
getkeysinslot
獲取指定hash slot中全部的key.
cluster getkeysinslot slot count
keyslot
cluster keyslot key
查詢指定key的hash slot
可以和countkeysinslot配合使用息尺。
failover
cluster failover [Force|Takeover]
該命令只能在群集slave節(jié)點執(zhí)行携兵,讓slave節(jié)點進行一次人工故障切換。
人工故障切換是預(yù)期的操作搂誉,而非發(fā)生了真正的故障徐紧,目的是以一種安全的方式(數(shù)據(jù)無丟失)將當(dāng)前master節(jié)點和其中一個slave節(jié)點(執(zhí)行cluster-failover的節(jié)點)交換角色。
流程如下:
- 當(dāng)前slave節(jié)點告知其master節(jié)點停止處理來自客戶端的請求
- master 節(jié)點將當(dāng)前replication offset 回復(fù)給該slave節(jié)點
- 該slave節(jié)點在未應(yīng)用至replication offset之前不做任何操作,以保證master傳來的數(shù)據(jù)均被處理并级。
- 該slave 節(jié)點進行故障轉(zhuǎn)移拂檩,從群集中大多數(shù)的master節(jié)點獲取epoch,然后廣播自己的最新配置
- 原master節(jié)點收到配置更新:解除客戶端的訪問阻塞嘲碧,回復(fù)重定向信息稻励,以便客戶端可以和新master通信。
當(dāng)該slave節(jié)點(將切換為新master節(jié)點)處理完來自master的所有復(fù)制愈涩,客戶端的訪問將會自動由原master節(jié)點切換至新master節(jié)點.
-
FORCE 選項:slave節(jié)點不和master協(xié)商(master也許已不可達)望抽,從上如4步開始進行故障切換。當(dāng)master已不可用履婉,而我們想要做人工故障轉(zhuǎn)移時煤篙,該選項很有用。
但是毁腿,即使使用FORCE選項辑奈,我們依然需要群集中大多數(shù)master節(jié)點有效,以便對這次切換進行驗證已烤,同時為將成為新master的salve節(jié)點生成新的配置epoch鸠窗。
-
TAKEOVER 選項: 忽略群集一致驗證的的人工故障切換
有時會有這種情況,群集中master節(jié)點不夠,我們想在未和群集中其余master節(jié)點驗證的情況下進行故障切換胯究。 實際用途舉例:群集中主節(jié)點和從節(jié)點在不同的數(shù)據(jù)中心稍计,當(dāng)所有主節(jié)點down掉或被網(wǎng)絡(luò)分區(qū)隔離,需要用該參數(shù)將slave節(jié)點 批量切換為master節(jié)點裕循。
選項 TAKEOVER 實現(xiàn)了FORCE的所有功能丙猬,同時為了能夠進行故障切換放棄群集驗證。當(dāng)slave節(jié)點收到命令CLUSTER FAILOVER TAKEOVER
會做如下操作:
- 獨自生成新的
configEpoch
,若本地配置epoch非最大的费韭,則取當(dāng)前有效epoch值中的最大值并自增作為新的配置epoch - 將原master節(jié)點管理的所有哈希槽分配給自己茧球,同時盡快分發(fā)最新的配置給所有當(dāng)前可達節(jié)點,以及后續(xù)恢復(fù)的故障節(jié)點星持,期望最終配置分發(fā)至所有節(jié)點
注意:TAKEOVER 違反Redis群集最新-故障轉(zhuǎn)移-有效 原則抢埋,因為slave節(jié)點產(chǎn)生的配置epoch 會讓正常產(chǎn)生的的配置epoch無效
- 使用TAKEOVER 產(chǎn)生的配置epoch 無法保證時最大值,因為我們是在少數(shù)節(jié)點見生成epoch督暂,并且沒有使用信息交互來保證新生成的epoch值最大揪垄。
- 如果新生成的配置epoch 恰巧和其他實例生成的發(fā)生沖突(epoch相同),最終我們生成的配置epoch或者其他實例生成的epoch逻翁,會通過使用配置epoch沖突解決算法 舍棄掉其中一個饥努。
因為這個原因,選擇TAKEOVER需小心使用.
delslots
cluster delslots <hash-slots>
在Redis Cluster中八回,每個節(jié)點都會知道哪些主節(jié)點正在負責(zé)哪些特定的哈希槽
DELSLOTS
命令使一個特定的Redis Cluster節(jié)點去忘記一個主節(jié)點正在負責(zé)的哈希槽酷愧,這些哈希槽通過參數(shù)指定驾诈。
說白了就是使指定的hash slot從集群中解綁
在已經(jīng)接收到DELSLOTS
命令的節(jié)點環(huán)境中,并且因此已經(jīng)去除了指定哈希槽的關(guān)聯(lián)溶浴,我們認為這些哈希槽是未綁定的 乍迄。請注意,當(dāng)一個節(jié)點還沒有被配置去負責(zé)他們(可以通過ADDSLOTS
完成槽的分配)并且如果該節(jié)點沒有收到關(guān)于誰擁有這些哈希槽的消息時(節(jié)點通過心跳包或者更新包獲取消息)士败,這些未綁定的哈希槽是自然而然本來就存在的闯两。
如果一個節(jié)點認為一些哈希槽是未綁定的,但是從其他節(jié)點接收到一個心跳包谅将,得知這些哈希槽已經(jīng)被其他節(jié)點負責(zé)漾狼,那么會立即確立其關(guān)聯(lián)關(guān)系。而且饥臂,如果接收到一個心跳包或更新包的配置紀(jì)元比當(dāng)前節(jié)點的大邦投,那么會重新建立關(guān)聯(lián)。
- 命令只在參數(shù)指定的哈希槽已經(jīng)和某些節(jié)點關(guān)聯(lián)時有效擅笔。
- 如果同一個哈希槽被指定多次,該命令會失敗屯援。
- 命令執(zhí)行的副作用是猛们,因為不在負責(zé)哈希槽,節(jié)點可能會進入下線狀態(tài)狞洋。
10000這個hash slot已經(jīng)從集群中解綁了.
==請注意弯淘,如果解綁的hash slot在一定時間內(nèi)沒有被重新分配,那么會因集群間心跳包傳輸吉懊,當(dāng)前節(jié)點重新獲得移除的hash slot.==
此命令和addslots配合使用庐橙,實現(xiàn)人工分配hash slot.
addslots
cluster addslots <hash-slots>
指定命令接收節(jié)點,分配指定的slot集合
這個命令是用于修改某個節(jié)點上的集群配置借嗽。具體的說它把一組hash slots分配給接收命令的節(jié)點态鳖。 如果命令執(zhí)行成功,節(jié)點將指定的hash slots映射到自身恶导,節(jié)點將獲得指定的hash slots浆竭,同時開始向集群廣播新的配置。
需要注意:
- 該命令只有當(dāng)所有指定的slots在接收命令的節(jié)點上還沒有分配得的情況下生效惨寿。節(jié)點將 拒絕接納已經(jīng)分配到其他節(jié)點的slots(包括它自己的)邦泄。
- 同一個slot被指定多次的情況下命令會失敗。
- 執(zhí)行這個命令有一個副作用裂垦,如果slot作為其中一個參數(shù)設(shè)置為
importing
顺囊,一旦節(jié)點向自己分配該slot(以前未綁定)這個狀態(tài)將會被清除。
saveconfig
cluster saveconfig
強制保存配置nodes.conf
至磁盤蕉拢。
該命令主要用于nodes.conf
節(jié)點狀態(tài)文件丟失或被刪除的情況下重新生成文件特碳。當(dāng)使用CLUSTER
命令 對群集做日常維護時诚亚,該命令可以用于保證新生成的配置信息會被持久化到磁盤。當(dāng)然测萎,這類命令應(yīng)該設(shè)置定時調(diào)用 將配置信息持久化到磁盤亡电,保證系統(tǒng)重啟之后狀態(tài)信息還是正確的。
reset
cluster reset [HARD|SOFT]
根據(jù)reset的類型配置hard或者soft 硅瞧,Reset 一個Redis群集節(jié)點可以選擇十分極端或極端的方式份乒。 注意該命令在主節(jié)點hold住一個或多個keys的時候無效,在這種情況下腕唧,如果要徹底reset一個master或辖, 需要將它的所有key先移除,如先使用FLUSHALL
枣接,在使用CLUSTER RESET
節(jié)點上的效果如下:
- 群集中的節(jié)點都被忽略
- 所有已分派/打開的槽會被reset颂暇,以便slots-to-nodes對應(yīng)關(guān)系被完全清除
- 如果節(jié)點是slave,它會被切換為(空)master但惶。它的數(shù)據(jù)集已被清空耳鸯,因此最后也會變成一個空master。
- Hard reset only:生成新的節(jié)點ID
- 變量
currentEpoch
和configEpoch
被設(shè)置為0 - 新配置被持久化到節(jié)點磁盤上的群集配置信息文件中
當(dāng)需要為一個新的或不同的群集提供一個新的群集節(jié)點是可使用該命令膀曾,同時它也在Redis群集測試框架中被廣泛使用县爬,它用于 在每個新的測試單元啟動是初始化群集狀態(tài)。
如果reset類型沒有指定添谊,使用默認值soft
hard:
soft
沒看出這兩個有什么區(qū)別财喳。
reset會清楚master中的數(shù)據(jù):
因為reset改變了id,所以斩狱,在其他redis節(jié)點中耳高,原有的兩個被標(biāo)識為未知的了。(流言開始)
如果過一段時間所踊,流言得到確認泌枪,就會移除未知節(jié)點。
set-config-epoch
cluster set-config-epoch <config-epoch>
該命令為一個全新的節(jié)點設(shè)置指定的config epoch,僅在如下情況下有效:
- 節(jié)點的節(jié)點信息表為空
- 節(jié)點的當(dāng)前config epoch為0
這些先決條件是需要的秕岛,因為通常情況下工闺,人工修改一個節(jié)點的配置epoch是不安全的,我們想保證一點:在 獲取哈希槽的所有權(quán)時瓣蛀,擁有更高配置epoch值的節(jié)點獲勝陆蟆。
但是該規(guī)則也有一個例外,在群集創(chuàng)建的時候惋增,Redis群集配置epoch沖突解決算法會解決 群集啟動時新的節(jié)點配置成相同配置epoch的問題叠殷,但是這個處理過程很慢,為了保證不管發(fā)生任何情況,都不會有兩個節(jié)點擁有相同的配置epoch诈皿。
因此林束,當(dāng)一個新群集創(chuàng)建的時候像棘,使用命令CONFIG SET-CONFIG-EPOCH
為每個一個節(jié)點分派漸進的配置epoch,然后再加入群集壶冒。
meet
cluster meet <ip> <port>
CLUSTER MEET
命令被用來連接不同的開啟集群支持的 Redis 節(jié)點缕题,以進入工作集群。
基本的思想是每個節(jié)點默認都是相互不信任的胖腾,并且被認為是未知的節(jié)點烟零,以便萬一因為系統(tǒng)管理錯誤或地址被修改,而不太可能將多個不同的集群節(jié)點混成一個集群咸作。
請注意锨阿,Redis Cluster 需要形成一個完整的網(wǎng)絡(luò)(每個節(jié)點都連接著其他每個節(jié)點),但是為了創(chuàng)建一個集群记罚,不需要發(fā)送形成網(wǎng)絡(luò)所需的所有CLUSTER MEET
命令墅诡。發(fā)送CLUSTER MEET
消息以便每個節(jié)點能夠到達其他每個節(jié)點只需通過一條已知的節(jié)點鏈就足夠了。由于在心跳包中會交換 gossip 信息桐智,將會創(chuàng)建節(jié)點間缺失的鏈接末早。
所以,如果我們通過CLUSTER MEET
鏈接節(jié)點 A 和節(jié)點 B 说庭,并且節(jié)點 B 和 C 有鏈接然磷,那么節(jié)點 A 和節(jié)點 C 會發(fā)現(xiàn)他們握手和創(chuàng)建鏈接的方法。
**實現(xiàn)細節(jié):MEET 和 PING 包****
當(dāng)一個給定的節(jié)點接收到一個CLUSTER MEET
消息時口渔,命令中指定的節(jié)點仍然不知道我們發(fā)送了命令,所以為了使節(jié)點強制將接收命令的節(jié)點將它作為信任的節(jié)點接受它穿撮,它會發(fā)送MEET
包而不是PING
包缺脉。兩個消息包有相同的格式,但是MEET
強制使接收消息包的節(jié)點確認發(fā)送消息包的節(jié)點為可信任的悦穿。
我們新增一個redis實例攻礼,然后用meet加入集群:
然后加入
setSlot
MIGRATING
子命令:將一個哈希槽設(shè)置為migrating 狀態(tài)(導(dǎo)出)IMPORTING
子命令:將一個哈希槽設(shè)置為importing 狀態(tài)(倒入)STABLE
子命令:從哈希槽中清除導(dǎo)入和遷移狀態(tài)NODE
子命令:將一個哈希槽綁定到另一個不同的節(jié)點
migrating
cluster setslot <slot> migrating <dest-node-id>
該子命令將一個槽設(shè)置為migrating狀態(tài).為了可以將一個哈希槽設(shè)置成這種狀態(tài),收到命令的節(jié)點必須是該哈希槽的所有者栗柒,否則報錯
importing
cluster setslot <slot> importing <source-node-id>
該子命令是MIGRATING
的反向操作礁扮,將keys從指定源節(jié)點導(dǎo)入目標(biāo)節(jié)點。該命令僅能在目標(biāo)節(jié)點不是指定槽的所有者時生效瞬沦。
stable
cluster setslot <slot> stable
該子命令僅用于清理槽中遷移中/導(dǎo)入中的狀態(tài)太伊。它主要用于修復(fù)群集在使用·redis-trip fix· 卡在一個錯誤狀態(tài)的問題。
node
cluster setslot <slot> node <node-id>
子命令NODE
使用方法最復(fù)雜逛钻,它后接指定節(jié)點的哈希槽僚焦,該命令僅在特定情況下有效,并且不同的槽狀態(tài)會有不同的效果.
如果slot是migrating曙痘,那么該操作是將命令接收者的slot分配出去
如果slot是importing芳悲,那么該操作是將其他slot分配給命令接受者
replicate
cluster replcate <node-id>
該命令重新配置一個節(jié)點成為指定master的salve節(jié)點立肘。 如果收到命令的節(jié)點是一個empty master,那么該節(jié)點的角色將由master切換為slave名扛。
一旦一個節(jié)點變成另一個master節(jié)點的slave谅年,無需通知群集內(nèi)其他節(jié)點這一變化:節(jié)點間交換 信息的心跳包會自動將新的配置信息分發(fā)至所有節(jié)點。
我們在新增一個節(jié)點:
此時6386是master肮韧,我們要讓6386成為6385的slave
得益于redis集群的通信融蹂,其他節(jié)點也得到了相同的信息
forget
cluster forget <node-id>
該命令可以從收到命令的Redis群集節(jié)點的節(jié)點信息列表中移除指定ID的節(jié)點。 換句話說惹苗,從收到命令的Redis群集節(jié)點的nodes table中刪除指定節(jié)點殿较。
該命令不是將待刪除節(jié)點的信息簡單從內(nèi)部配置中簡單刪除,它同時實現(xiàn)了禁止列表功能:不允許已刪除 的節(jié)點再次被添加進來桩蓉,否則已刪除節(jié)點會因為處理其他節(jié)點心跳包中的gossip section時被再次添加淋纲。
命令CLUSTER FORGET
為每個節(jié)點實現(xiàn)了包含超時時間的禁止列表
因此我們命令實際的執(zhí)行情況如下:
- 從收到命令節(jié)點的節(jié)點信息列表中刪除待刪除節(jié)點的節(jié)點信息。
- 已刪除的節(jié)點的節(jié)點ID被加入禁止列表院究,保留1分鐘
- 收到命令的節(jié)點洽瞬,在處理從其他節(jié)點發(fā)送過來的gossip sections 會跳過所有在禁止列表中的節(jié)點。
這樣业汰,我們就有60秒的時間窗口來通知群集中的所有節(jié)點伙窃,我們想要刪除某個節(jié)點。
7. 集群命令--redis-cli
create
redis-cli --cluster create <ip1:port1> ... --cluster-replicas <args>
創(chuàng)建集群
見第5小節(jié)样漆。为障。
info
redis-cli --cluster info <集群內(nèi)任一ip:port>
獲取集群信息
check
redis-cli --cluster check <集群內(nèi)任一ip:port>
檢查集群
報錯提示我們的集群內(nèi)每一個節(jié)點的配置文件不同。
還記得我們啟動的命令嗎:
docker run -d --rm --network=host -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_4 --name=master_c_4 redis redis-server /usr/local/etc/redis/redis.conf --port 6385
我們傳入了一個配置文件放祟,但是我們在配置文件中指定的配置文件是nodes.conf
我們將這個配置定為同樣的配置:
創(chuàng)建每個節(jié)點的nodes.conf的目錄
然后重新創(chuàng)建全部的集群節(jié)點:
docker ps|grep redis|awk '{print $1}'|xargs docker stop
docker run -d --rm --network=host -v /redis/master_c_1/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_1 --name=master_c_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6379
docker run -d --rm --network=host -v /redis/master_c_2/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_2 --name=master_c_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6380
docker run -d --rm --network=host -v /redis/master_c_3/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_3 --name=master_c_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6381
docker run -d --rm --network=host -v /redis/slave_1/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_1 --name=slave_1 redis redis-server /usr/local/etc/redis/redis.conf --port 6382
docker run -d --rm --network=host -v /redis/slave_2/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_2 --name=slave_2 redis redis-server /usr/local/etc/redis/redis.conf --port 6383
docker run -d --rm --network=host -v /redis/slave_3/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_3 --name=slave_3 redis redis-server /usr/local/etc/redis/redis.conf --port 6384
docker run -d --rm --network=host -v /redis/master_c_4/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=master_c_4 --name=master_c_4 redis redis-server /usr/local/etc/redis/redis.conf --port 6385
docker run -d --rm --network=host -v /redis/slave_4/:/redis/cluster/ -v /redis/redis_cluster.conf:/usr/local/etc/redis/redis.conf --hostname=slave_4 --name=slave_4 redis redis-server /usr/local/etc/redis/redis.conf --port 6386
創(chuàng)建集群:
檢測:
fix
redis-cli --cluster fix <集群內(nèi)任一ip:port>
檢測出錯了鳍怨,可以使用這個命令處理
修復(fù)的結(jié)果就是將全部的slot分配給第一個機器
reshard
redis-cli --cluster reshared <集群內(nèi)任一ip:port>
可選參數(shù):
--cluster-from
--cluster-to
--cluster-slots
--cluster-yes
--cluster-timeout
--cluster-pipeline
--cluster-replace
[root@master1 ~]# redis-cli --cluster reshard 192.168.100.41:6379
How many slots do you want to move (from 1 to 16384)? 4096 '//要遷移多少個槽'
What is the receiving node ID? 99521b7fd126b694bcb9a22ffa5a490f31f66543 '//遷移到哪個節(jié)點,數(shù)據(jù)節(jié)點id'
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
'//要求輸入源節(jié)點的id,這里因為原本有三個節(jié)點跪妥,輸入done表示結(jié)束'
Source node #1: 7f112f82bcf28a5d0627ea81b48cb76f4ea8605d
Source node #2: df195a34a91d756157a0fda7c71e99d5bd8fad09
Source node #3: a233a23541f431107fed79908318394d8bb30b51
Source node #4: done
'//最后會有一個遷移方案鞋喇,輸入yes表示同意,遷移開始眉撵。輸入no表示不同意侦香,重新設(shè)置遷移方案。'
'//確認是否遷移成功'
[root@master1 ~]# redis-cli -h 192.168.100.41 -p 6379
192.168.100.41:6379> cluster nodes
...省略內(nèi)容
遷移slot
發(fā)現(xiàn)只有一個機器纽疟,不夠用罐韩,現(xiàn)在每一個機器都是隔離的:
我們將其連接起來
我們設(shè)置主從節(jié)點
遷移slot
rebalance
redis-cli --cluster rebalance <集群內(nèi)任一ip:port>
自動平衡hash slot
del-node
redis-cli --cluster del-node <集群內(nèi)ip:port> <node>
刪除節(jié)點
add-node
redis-cli --cluster add-node <集群外的ip:port> <集群內(nèi)任一ip:port>
不知道為什么--cluster-master-id
沒生效
import
redis-cli --cluster import <集群外ip:port>
將redis實例倒入集群(倒入數(shù)據(jù))
[ERR] The source node should not be a cluster node.
因為6386也是一個集群節(jié)點,cluster-enabled=true
新建一個redis實例污朽,使用默認配置伴逸。
然后倒入