1.1.1. 13.Redis 集群-Cluster

介绍

Cluster 是官方出的 Redis 集群化解决方案。

它相对于 Codis 不同,它是去中心化的。如图所示,该集群分为三个节点,三个节点负责存储一部分数据,每个节点数据可能各不相同,三个节点互相连接构成一个对等的集群。他们之间通过特殊的二进制协议相互交互集群信息。

Cluster 示意图

Redis Cluster 将所有数据划分为 16384 的 slots(槽),它比 Codis 的 1024 个槽分的更加精细。每个节点负责其中一部分槽位。槽位信息存储在每个节点中,它不像 Codis 需要另外的分布式存储来存储节点槽位信息。

当 Redis Cluster 客户端连接集群时,它会得到一部分集群的槽位配置信息,这样当查询某个 key 时,就可以直接定位目标节点。

Codis 需要通过 proxy 来定位节点。而 Redis Cluster 是直接定位。客户端为了能直接定位某个具体 key 所在的节点,就在客户端缓存了槽位相关信息。同时又因为客户端槽位信息可能和服务器不一致,所以还有纠正机制。

Redis Cluster 的每个节点会将集群信息持久化到配置文件中,所以必须保证配置文件可写,配置文件尽量不依靠人为修改。

比较
节点主从

节点主从

优点:读写分离,增加 salve 可以增加并发读能力。 缺点:master 写能力有瓶颈。slave 虽然没瓶颈但是有维护成本。

hash slot

hash槽

优点:写操作分散到多个节点,提高写的并发。扩容简单。 缺点:每个节点相互监听,高并发读写,任务繁重。当一个节点挂掉,影响系统稳定。

cluster

使用 hash 分逻辑节点,每个在节点内部进行主从部署。这样保证读写分离,又可扩展,也不怕节点挂掉,即高可用。 Center

槽位算法

Cluster 会将 key 值使用 crc16 算法进行 hash 得到一个整数值,然后对这个值进行 16384 取模来得到槽位。

Cluster 还允许用户强制某个 key 挂在特定槽位上,通过在 key 上嵌入 tag 标记,就可以强制 key 所挂的槽位等于 tag 所在的槽位。

跳转

当客户端向一个错误的节点发出指令,该节点发现指令的 key 不属于它管理,这时它会向客户端发送一个特殊的跳转指令,告诉客户端去连接这个节点。

GET x
-MOVED 3999 127.0.0.1:6381

MOVED 后面的 3999 表示对应的 key 的槽位编号,后面的地址表示目标节点地址。MOVED 前面有个减号,表示这时一条错误信息。

客户端收到 MOVED 指令后,会立即纠正本地槽位映射表,后续 key 都将使用新映射表。

迁移

Redis Cluster 提供了工具 redis-trib 让维护人员可以手动调整槽位的分配情况。

迁移过程

Redis 迁移的单位是槽,Redis 一个槽一个槽的迁移。当一个槽正在迁移时,这个槽就出于中间过渡状态。此时这个槽在原节点状态为 「migrating」,在目标节点的状态是 「importing」,表示数据正在流向目标。

迁移工具 redis-trib 步骤:

  1. 首先会在原节点和目标节点设置好中间状态
  2. 然后一次性获取原节点槽位的所有 key 列表(也可以通过 keysinslot 部分获取),再挨个进行迁移。
  3. 每个迁移过程是原节点做为目标节点的「客户端」,原节点对 key 执行 dump 命令得到序列化内容
  4. 然后原节点向目标节点发送 restore 携带序列化的内容作为参数,目标节点反序列化回复到目标节点中
  5. 最后标节点对原节点「客户端」返回 OK,原节点再删除 key。

这就是整个迁移过程。

从源节点获取内容 => 存到目标节点 => 从源节点删除内容。

注意:

  1. 迁移过程是同步的,知道删除原 key 之前,原节点是阻塞的。
  2. 如果迁移过程中发生网络故障,这时两个节点依旧处于中间状态,待下次迁移工具重新连接上时,会提示用户继续进行迁移。
  3. 迁移过程中,key 一般很小,所以迁移很快,不会影响到客户端的正常访问。当 key 很大时,迁移指令会阻塞原节点和目标节点,影响集群的稳定性。所以在日常中要避免较大 key 的产生。
  4. 迁移过程中,客户端访问流程会发生变化,客户端先尝试连接原节点,如果原节点有数据,就直接取出。如果原节点的数据已经消失,则存在两种可能,要么在新节点,要么根本不存在。旧节点不知道是哪种情况,所以它会向客户端返回一个-ASK targetNodeAddr的重定向指令。客户端收到这个重定向指令后,先去目标节点执行一个不带任何参数的asking指令,然后在目标节点再重新执行原先的操作指令。因为在迁移没有完成之前,按理说这个槽位还是不归新节点管理的,如果这个时候向目标节点发送该槽位的指令,节点是不认的,它会向客户端返回一个-MOVED重定向指令告诉它去源节点去执行。如此就会形成 重定向循环。asking指令的目标就是打开目标节点的选项,告诉它下一条指令不能不理,而要当成自己的槽位来处理。
容错

Redis Cluster 可以为每个主节点设置若干个从节点,当主节点出现故障时,集群会自动的将某个从节点提升为主节点。

如果主节点没有从节点,那么当发生故障时,集群将不可用。可以通过 cluster-require-full-coverage 参数来允许部分节点故障,其他节点正常访问。

网络抖动

网络抖动,即突然部分连接不能正常访问了,但是很快有恢复正常。 为了解决这个问题,Redis Cluster 提供了一个参数 cluster-node-timeout。表示某个节点持续 timeout 的时间后,才可认定为故障,需要进行主从切换。

如果没有这个选项,那么由于网络抖动,集群会频繁切换主从。

可能下线 (PFAIL-Possibly Fail) 与确定下线 (Fail)

由于 Cluster 是去中心化的,一个节点认为某个节点已经失联了并不代表所有的节点都认为它失联了。所以集群还要进行协商,当大多数节点认为某个节点失联,才认为该节点需要主从切换来容错。

Redis 集群通过 Gossip 协议来广播自己的状态以及自己对整个集群认知的改变。比如当一个节点认为某个节点已经失联(PFail),它就会向集群广播,其他节点也收到了这条失联消息。当集群中节点认为某个节点的失联的数量(PFail count)达到一定值时,就会标记这个节点失联(Fail),强迫其他节点接受这个事实。并立即对这个节点进行主从切换

安装及使用

基本配置

Redis Cluster 需要 Redis 版本在 3.0 以上。

首先配置全新的(Redis)6 台。(指 dir "/var/lib/redis" 这个目录下,没有 dump.rdb 和 conde-XXXX.conf)

修改其中一台 redis-cluster-6379.conf

port 6379

pidfile "/var/run/redis/redis-server-6379.pid"

logfile "/var/log/redis/redis-server-6379.log"

dbfilename "dump-6379.rdb"
# 开启Cluster
cluster-enabled yes
# 集群配置文件
cluster-config-file nodes-6379.conf
# 集群超时时间
cluster-node-timeout 15000

复制 6 份。

sudo cp redis-cluster-6379.conf redis-cluster-6381.conf
sudo cp redis-cluster-6379.conf redis-cluster-6382.conf
sudo cp redis-cluster-6379.conf redis-cluster-6383.conf
sudo cp redis-cluster-6379.conf redis-cluster-6384.conf
sudo cp redis-cluster-6379.conf redis-cluster-6385.conf
sudo cp redis-cluster-6379.conf redis-cluster-6386.conf

将其中的相关端口修改,然后启动。

sudo redis-server redis-cluster-6381.conf
sudo redis-server redis-cluster-6382.conf
sudo redis-server redis-cluster-6383.conf
sudo redis-server redis-cluster-6384.conf
sudo redis-server redis-cluster-6385.conf
sudo redis-server redis-cluster-6386.conf

然后启动集群,这里有两种方法。

redis-cli 启动

这个方法需要 redis-server 5.0 以上版本,不用安装其他插件。

replicas 后面的参数 1 ,代表 redis 集群主节点和从节点的比值,如主节点 3 个,从节点 3 个,比值就是 1;如主节点 3 个,从节点 6 个,就是 0.5。

vagrant@homestead:/etc/redis$ redis-cli --cluster create 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385 127.0.0.1:6386 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:6385 to 127.0.0.1:6381
Adding replica 127.0.0.1:6386 to 127.0.0.1:6382
Adding replica 127.0.0.1:6384 to 127.0.0.1:6383
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 4f3f01eb51c84b5ef3e81c0fbf55e46c2aa4125d 127.0.0.1:6381
   slots:[0-5460] (5461 slots) master
M: 6dce3bd147bab5fdf7cebe5cf65420b695da8e4a 127.0.0.1:6382
   slots:[5461-10922] (5462 slots) master
M: 5c473eba795c085d5298482adbfc09ad55dfaa38 127.0.0.1:6383
   slots:[10923-16383] (5461 slots) master
S: 7d8b215baa6d7d073381acaa2d69a43644206fed 127.0.0.1:6384
   replicates 6dce3bd147bab5fdf7cebe5cf65420b695da8e4a
S: 77c51a1c66af1f19f1c439c833e8fcafa80afc8a 127.0.0.1:6385
   replicates 5c473eba795c085d5298482adbfc09ad55dfaa38
S: 411c963a3537c6efdb302f91184ed16f34418c4e 127.0.0.1:6386
   replicates 4f3f01eb51c84b5ef3e81c0fbf55e46c2aa4125d
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
......
>>> Performing Cluster Check (using node 127.0.0.1:6381)
M: 4f3f01eb51c84b5ef3e81c0fbf55e46c2aa4125d 127.0.0.1:6381
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 7d8b215baa6d7d073381acaa2d69a43644206fed 127.0.0.1:6384
   slots: (0 slots) slave
   replicates 6dce3bd147bab5fdf7cebe5cf65420b695da8e4a
S: 411c963a3537c6efdb302f91184ed16f34418c4e 127.0.0.1:6386
   slots: (0 slots) slave
   replicates 4f3f01eb51c84b5ef3e81c0fbf55e46c2aa4125d
M: 6dce3bd147bab5fdf7cebe5cf65420b695da8e4a 127.0.0.1:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 77c51a1c66af1f19f1c439c833e8fcafa80afc8a 127.0.0.1:6385
   slots: (0 slots) slave
   replicates 5c473eba795c085d5298482adbfc09ad55dfaa38
M: 5c473eba795c085d5298482adbfc09ad55dfaa38 127.0.0.1:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
redis-trib 启动

需要安装 ruby 环境

sudo apt-get install ruby

sudo apt-get install gems

sudo gem install redis

redis-trib.rb 目录在 /usr/local/redis/src/redis-trib.rb。执行文件后发现,推荐我们使用 redis-cli 来启动,可能是由于我更新了 redis5.0 的缘故。

vagrant@homestead:/etc/redis$ /usr/local/redis/src/redis-trib.rb create --replicas 1 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385 127.0.0.1:6386
WARNING: redis-trib.rb is not longer available!
You should use redis-cli instead.

All commands and features belonging to redis-trib.rb have been moved
to redis-cli.
In order to use them you should call redis-cli with the --cluster
option followed by the subcommand name, arguments and options.

Use the following syntax:
redis-cli --cluster SUBCOMMAND [ARGUMENTS] [OPTIONS]

Example:
redis-cli --cluster create 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385 127.0.0.1:6386 --cluster-replicas 1

To get help about all subcommands, type:
redis-cli --cluster help
测试

使用 redis-cli 连接 6385,-c 表示使用集群模式。

vagrant@homestead:/etc/redis$ redis-cli -c -p 6382
127.0.0.1:6382> set demo hello-world
-> Redirected to slot [903] located at 127.0.0.1:6381
OK
127.0.0.1:6381> get demo
"hello-world"

通过 cluster info 指令,可以看到有 6 个节点,16384 个槽位。

127.0.0.1:6381> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:978
cluster_stats_messages_pong_sent:959
cluster_stats_messages_sent:1937
cluster_stats_messages_ping_received:954
cluster_stats_messages_pong_received:978
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1937

通过 cluster nodes 查看节点,可以看到 6381 6382 6383 三个是主节点,其他为从节点。

127.0.0.1:6381> CLUSTER NODES
5096a076abd4b99d5c07e489109c83be929a4228 127.0.0.1:6382@16382 master - 0 1569570388000 2 connected 5461-10922
a2d9574fba2437b416aecf1d80bc9b422a8cb678 127.0.0.1:6385@16385 slave 5096a076abd4b99d5c07e489109c83be929a4228 0 1569570390638 5 connected
c2ddacc6944d9ffd05ba7286a06e01ec46d76b04 127.0.0.1:6384@16384 slave b17e98228b179ea3b572f6106d2fed6ab75b07f0 0 1569570389000 4 connected
b0a9bce8cb1225dbb7d3a0bef210c3deae55ffc2 127.0.0.1:6383@16383 master - 0 1569570389626 3 connected 10923-16383
b17e98228b179ea3b572f6106d2fed6ab75b07f0 127.0.0.1:6381@16381 myself,master - 0 1569570385000 1 connected 0-5460
147622225bd356f70331e6c67f30e9454de77d5a 127.0.0.1:6386@16386 slave b0a9bce8cb1225dbb7d3a0bef210c3deae55ffc2 0 1569570390000 6 connected

接下来我们使 6381 失效。

vagrant@homestead:/etc/redis$ redis-cli -p 6381 debug segfault
Error: Server closed the connection

稍等片刻,重新连接 6381,并且再次查看集群节点。

vagrant@homestead:/etc/redis$ sudo redis-server redis-cluster-6381.conf
vagrant@homestead:/etc/redis$ redis-cli -c -p 6382
127.0.0.1:6382> cluster nodes
147622225bd356f70331e6c67f30e9454de77d5a 127.0.0.1:6386@16386 slave b0a9bce8cb1225dbb7d3a0bef210c3deae55ffc2 0 1569570753000 6 connected
5096a076abd4b99d5c07e489109c83be929a4228 127.0.0.1:6382@16382 myself,master - 0 1569570754000 2 connected 5461-10922
b17e98228b179ea3b572f6106d2fed6ab75b07f0 127.0.0.1:6381@16381 slave c2ddacc6944d9ffd05ba7286a06e01ec46d76b04 0 1569570755984 7 connected
c2ddacc6944d9ffd05ba7286a06e01ec46d76b04 127.0.0.1:6384@16384 master - 0 1569570754941 7 connected 0-5460
b0a9bce8cb1225dbb7d3a0bef210c3deae55ffc2 127.0.0.1:6383@16383 master - 0 1569570753850 3 connected 10923-16383
a2d9574fba2437b416aecf1d80bc9b422a8cb678 127.0.0.1:6385@16385 slave 5096a076abd4b99d5c07e489109c83be929a4228 0 1569570753000 5 connected

我们可以发现,6381 变成了从节点,6384 变成了主节点。

扩容

新复制两份配置文件,并修改相关值,然后启动

sudo cp redis-cluster-6379.conf redis-cluster-6387.conf
sudo cp redis-cluster-6379.conf redis-cluster-6388.conf

sudo redis-server redis-cluster-6387.conf
sudo redis-server redis-cluster-6388.conf

添加到集群中

redis-cli --cluster add-node 127.0.0.1:6387 127.0.0.1:6381

redis-cli --cluster add-node 127.0.0.1:6388 127.0.0.1:6381、
vagrant@homestead:/etc/redis$ redis-cli --cluster add-node 127.0.0.1:6387 127.0.0.1:6381
>>> Adding node 127.0.0.1:6387 to cluster 127.0.0.1:6381
>>> Performing Cluster Check (using node 127.0.0.1:6381)
M: b1710ed597bbc38e66105b429aced4fbfc04281a 127.0.0.1:6381
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 0a68b1d915956c322119843b1ed848bc95096b0f 127.0.0.1:6383
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 09265af88d3d715803c2d018e97fbe7e0b56c847 127.0.0.1:6386
   slots: (0 slots) slave
   replicates 45cc61a214983f387e1159a9b6a918be6fe36b90
M: 45cc61a214983f387e1159a9b6a918be6fe36b90 127.0.0.1:6382
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 61a48d614c0216765a89b8f7ce2ec999255be333 127.0.0.1:6385
   slots: (0 slots) slave
   replicates b1710ed597bbc38e66105b429aced4fbfc04281a
S: 10d6657b18b4ae6c01ce1fc87b5735e9725dccba 127.0.0.1:6384
   slots: (0 slots) slave
   replicates 0a68b1d915956c322119843b1ed848bc95096b0f
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 127.0.0.1:6387 to make it join the cluster.
[OK] New node added correctly.

此时添加进的两个节点都是 master 节点。

vagrant@homestead:/etc/redis$ redis-cli -c -p 6381
127.0.0.1:6381> cluster nodes
0a68b1d915956c322119843b1ed848bc95096b0f 127.0.0.1:6383@16383 master - 0 1569576631297 3 connected 10923-16383
c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 127.0.0.1:6387@16387 master - 0 1569576627000 7 connected
09265af88d3d715803c2d018e97fbe7e0b56c847 127.0.0.1:6386@16386 slave 45cc61a214983f387e1159a9b6a918be6fe36b90 0 1569576630287 6 connected
b1710ed597bbc38e66105b429aced4fbfc04281a 127.0.0.1:6381@16381 myself,master - 0 1569576629000 1 connected 0-5460
e72718e00fb36c63cd7e04a6e266897c698dddea 127.0.0.1:6388@16388 master - 0 1569576628000 0 connected
45cc61a214983f387e1159a9b6a918be6fe36b90 127.0.0.1:6382@16382 master - 0 1569576627000 2 connected 5461-10922
61a48d614c0216765a89b8f7ce2ec999255be333 127.0.0.1:6385@16385 slave b1710ed597bbc38e66105b429aced4fbfc04281a 0 1569576628092 5 connected
10d6657b18b4ae6c01ce1fc87b5735e9725dccba 127.0.0.1:6384@16384 slave 0a68b1d915956c322119843b1ed848bc95096b0f 0 1569576629176 4 connected

然后我们将 6388 作为 6387 的从节点。首先连接到 6388 节点,指定 6387 为从节点。通过 cluster replicate [id] 这个指令完成。

vagrant@homestead:/etc/redis$ redis-cli -c -p 6388
127.0.0.1:6388> cluster replicate c04144606c0b6c12aaa92f8022e4a6dbe2109ffd
OK
127.0.0.1:6388> cluster nodes
61a48d614c0216765a89b8f7ce2ec999255be333 127.0.0.1:6385@16385 slave b1710ed597bbc38e66105b429aced4fbfc04281a 0 1569576756973 1 connected
e72718e00fb36c63cd7e04a6e266897c698dddea 127.0.0.1:6388@16388 myself,slave c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 0 1569576754000 0 connected
10d6657b18b4ae6c01ce1fc87b5735e9725dccba 127.0.0.1:6384@16384 slave 0a68b1d915956c322119843b1ed848bc95096b0f 0 1569576757984 3 connected
45cc61a214983f387e1159a9b6a918be6fe36b90 127.0.0.1:6382@16382 master - 0 1569576758000 2 connected 5461-10922
c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 127.0.0.1:6387@16387 master - 0 1569576757000 7 connected
0a68b1d915956c322119843b1ed848bc95096b0f 127.0.0.1:6383@16383 master - 0 1569576753000 3 connected 10923-16383
b1710ed597bbc38e66105b429aced4fbfc04281a 127.0.0.1:6381@16381 master - 0 1569576757000 1 connected 0-5460
09265af88d3d715803c2d018e97fbe7e0b56c847 127.0.0.1:6386@16386 slave 45cc61a214983f387e1159a9b6a918be6fe36b90 0 1569576758992 2 connected

然后进行自动槽位迁移

vagrant@homestead:/etc/redis$ redis-cli --cluster reshard 127.0.0.1:6381
>>> Performing Cluster Check (using node 127.0.0.1:6381)
...
... # 省略 节点 id 及槽位信息
# 需要转移多少个槽位
How many slots do you want to move (from 1 to 16384)? 4096
# 需要转移到哪个节点
What is the receiving node ID? c04144606c0b6c12aaa92f8022e4a6dbe2109ffd
# 从哪几个节点进行转移
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.
Source node #1: b1710ed597bbc38e66105b429aced4fbfc04281a
Source node #2: 45cc61a214983f387e1159a9b6a918be6fe36b90
Source node #3: 0a68b1d915956c322119843b1ed848bc95096b0f
Source node #4: done
# 最后会有一个迁移方案,输入yes表示同意,迁移开始。输入no表示不同意,重新设置迁移方案。

通过 redis-cli --cluster rebalance 检测节点间槽的均衡性

vagrant@homestead:/etc/redis$ redis-cli --cluster rebalance 127.0.0.1:6381
>>> Performing Cluster Check (using node 127.0.0.1:6381)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
*** No rebalancing needed! All nodes are within the 2.00% threshold.

可以看出,节点负责的槽数据差异在2%以内,因此槽分配均衡。

节点失效

先杀死 6381,连接 6382 看集群状况

vagrant@homestead:/etc/redis$ redis-cli -c -p 6382
127.0.0.1:6382> cluster nodes
c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 127.0.0.1:6387@16387 master - 0 1569647721351 7 connected 0-1364 5461-6826 10923-12287
0a68b1d915956c322119843b1ed848bc95096b0f 127.0.0.1:6383@16383 master - 0 1569647721000 3 connected 12288-16383
45cc61a214983f387e1159a9b6a918be6fe36b90 127.0.0.1:6382@16382 myself,master - 0 1569647718000 2 connected 6827-10922
10d6657b18b4ae6c01ce1fc87b5735e9725dccba 127.0.0.1:6384@16384 slave 0a68b1d915956c322119843b1ed848bc95096b0f 0 1569647722363 4 connected
e72718e00fb36c63cd7e04a6e266897c698dddea 127.0.0.1:6388@16388 slave c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 0 1569647720000 7 connected
b1710ed597bbc38e66105b429aced4fbfc04281a 127.0.0.1:6381@16381 master - 1569647712751 1569647710000 1 disconnected 1365-5460
09265af88d3d715803c2d018e97fbe7e0b56c847 127.0.0.1:6386@16386 slave 45cc61a214983f387e1159a9b6a918be6fe36b90 0 1569647720000 2 connected
61a48d614c0216765a89b8f7ce2ec999255be333 127.0.0.1:6385@16385 slave b1710ed597bbc38e66105b429aced4fbfc04281a 0 1569647721000 5 connected
127.0.0.1:6382> cluster nodes
c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 127.0.0.1:6387@16387 master - 0 1569647735000 7 connected 0-1364 5461-6826 10923-12287
0a68b1d915956c322119843b1ed848bc95096b0f 127.0.0.1:6383@16383 master - 0 1569647734501 3 connected 12288-16383
45cc61a214983f387e1159a9b6a918be6fe36b90 127.0.0.1:6382@16382 myself,master - 0 1569647732000 2 connected 6827-10922
10d6657b18b4ae6c01ce1fc87b5735e9725dccba 127.0.0.1:6384@16384 slave 0a68b1d915956c322119843b1ed848bc95096b0f 0 1569647733494 4 connected
e72718e00fb36c63cd7e04a6e266897c698dddea 127.0.0.1:6388@16388 slave c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 0 1569647733000 7 connected
b1710ed597bbc38e66105b429aced4fbfc04281a 127.0.0.1:6381@16381 master,fail - 1569647712751 1569647710000 1 disconnected
09265af88d3d715803c2d018e97fbe7e0b56c847 127.0.0.1:6386@16386 slave 45cc61a214983f387e1159a9b6a918be6fe36b90 0 1569647734000 2 connected
61a48d614c0216765a89b8f7ce2ec999255be333 127.0.0.1:6385@16385 master - 0 1569647735513 8 connected 1365-5460

会发现 6381 先是 disconnected 表示节点发现 6381 可能挂了,通知其他节点也去看下,当大部分节点都觉得 6381 挂了之后,6381 变成了 fail ,表明确定下线了。然后启用了 6381 的从节点 6385 作为 master。

当我们再启动 6381。发现,6381 已经变成了 slave。

127.0.0.1:6382> cluster nodes
c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 127.0.0.1:6387@16387 master - 0 1569648018000 7 connected 0-1364 5461-6826 10923-12287
0a68b1d915956c322119843b1ed848bc95096b0f 127.0.0.1:6383@16383 master - 0 1569648018000 3 connected 12288-16383
45cc61a214983f387e1159a9b6a918be6fe36b90 127.0.0.1:6382@16382 myself,master - 0 1569648017000 2 connected 6827-10922
10d6657b18b4ae6c01ce1fc87b5735e9725dccba 127.0.0.1:6384@16384 slave 0a68b1d915956c322119843b1ed848bc95096b0f 0 1569648017000 4 connected
e72718e00fb36c63cd7e04a6e266897c698dddea 127.0.0.1:6388@16388 slave c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 0 1569648018000 7 connected
b1710ed597bbc38e66105b429aced4fbfc04281a 127.0.0.1:6381@16381 slave 61a48d614c0216765a89b8f7ce2ec999255be333 0 1569648019000 8 connected
09265af88d3d715803c2d018e97fbe7e0b56c847 127.0.0.1:6386@16386 slave 45cc61a214983f387e1159a9b6a918be6fe36b90 0 1569648017000 2 connected
61a48d614c0216765a89b8f7ce2ec999255be333 127.0.0.1:6385@16385 master - 0 1569648019862 8 connected 1365-5460

#

删除节点

在 6382 中创建几条数据后,对节点进行删除操作。由于 6382 是 master,会告诉你 6382 不为空,请先转移槽在重试。

vagrant@homestead:/etc/redis$ redis-cli --cluster del-node 127.0.0.1:6382 45cc61a214983f387e1159a9b6a918be6fe36b90
>>> Removing node 45cc61a214983f387e1159a9b6a918be6fe36b90 from cluster 127.0.0.1:6382
[ERR] Node 127.0.0.1:6382 is not empty! Reshard data away and try again.

转移槽,从 6382 转到 6382 从节点 6386 上,发现不能转移,只能转移给 master 节点

vagrant@homestead:/etc/redis$ redis-cli --cluster reshard 127.0.0.1:6382 --cluster-from 45cc61a214983f387e1159a9b6a918be6fe36b90 --cluster-to 09265af88d3d715803c2d018e97fbe7e0b56c847 --cluster-slots 4096 --cluster-yes
>>> Performing Cluster Check (using node 127.0.0.1:6382)
M: 45cc61a214983f387e1159a9b6a918be6fe36b90 127.0.0.1:6382
   slots:[6827-10922] (4096 slots) master
   1 additional replica(s)
M: c04144606c0b6c12aaa92f8022e4a6dbe2109ffd 127.0.0.1:6387
   slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
   1 additional replica(s)
M: 0a68b1d915956c322119843b1ed848bc95096b0f 127.0.0.1:6383
   slots:[12288-16383] (4096 slots) master
   1 additional replica(s)
S: 10d6657b18b4ae6c01ce1fc87b5735e9725dccba 127.0.0.1:6384
   slots: (0 slots) slave
   replicates 0a68b1d915956c322119843b1ed848bc95096b0f
S: e72718e00fb36c63cd7e04a6e266897c698dddea 127.0.0.1:6388
   slots: (0 slots) slave
   replicates c04144606c0b6c12aaa92f8022e4a6dbe2109ffd
S: b1710ed597bbc38e66105b429aced4fbfc04281a 127.0.0.1:6381
   slots: (0 slots) slave
   replicates 61a48d614c0216765a89b8f7ce2ec999255be333
S: 09265af88d3d715803c2d018e97fbe7e0b56c847 127.0.0.1:6386
   slots: (0 slots) slave
   replicates 45cc61a214983f387e1159a9b6a918be6fe36b90
M: 61a48d614c0216765a89b8f7ce2ec999255be333 127.0.0.1:6385
   slots:[1365-5460] (4096 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
*** The specified node (09265af88d3d715803c2d018e97fbe7e0b56c847) is not known or not a master, please retry.

将槽位转换到 6387 后,删除 6382,则成功。

vagrant@homestead:/etc/redis$ redis-cli --cluster del-node 127.0.0.1:6382 45cc61a214983f387e1159a9b6a918be6fe36b90
>>> Removing node 45cc61a214983f387e1159a9b6a918be6fe36b90 from cluster 127.0.0.1:6382
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

然后使用 rebalance 命令平均下槽位。

vagrant@homestead:/etc/redis$ redis-cli --cluster rebalance 127.0.0.1:6383
>>> Performing Cluster Check (using node 127.0.0.1:6383)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Rebalancing across 3 nodes. Total weight = 3.00
...
...
...
vagrant@homestead:/etc/redis$ redis-cli --cluster info 127.0.0.1:6383
127.0.0.1:6383 (0a68b1d9...) -> 3 keys | 5462 slots | 1 slaves.
127.0.0.1:6385 (61a48d61...) -> 2 keys | 5461 slots | 1 slaves.
127.0.0.1:6387 (c0414460...) -> 3 keys | 5461 slots | 2 slaves.
[OK] 8 keys in 3 masters.
0.00 keys per slot on average.
vagrant@homestead:/etc/redis$

可以发现 6387 有两个 slave,可以推断出 之前 6382 的 salve 转移到了 6387 上。

在 laravel 上进行测试

首先修改 database.php 配置文件,改为 cluster 模式。

<?php
return [
.
.
.
 'redis'         => [
        'client'   => 'predis',
        'cluster'  => true,
        'options'  => [
            'cluster' => 'redis'
        ],
        'default'  => [
            'host'         => env('REDIS_HOST_FIRST', '127.0.0.1'),
            'password'     => env('REDIS_PASSWORD', null),
            'port'         => env('REDIS_PORT', 6379),
            'database'     => 1,
            'read_timeout' => env('REDIS_TIMEOUT', 5),
        ],
        'clusters' => [
            'mycluster1' => [
                [
                    'host'     => '127.0.0.1',
                    'password' => null,
                    'port'     => 6381,
                    'database' => 0,
                ],
                [
                    'host'     => '127.0.0.1',
                    'password' => null,
                    'port'     => 6382,
                    'database' => 0,
                ],
                [
                    'host'     => '127.0.0.1',
                    'password' => null,
                    'port'     => 6383,
                    'database' => 0,
                ],
                [
                    'host'     => '127.0.0.1',
                    'password' => null,
                    'port'     => 6384,
                    'database' => 0,
                ],
                [
                    'host'     => '127.0.0.1',
                    'password' => null,
                    'port'     => 6385,
                    'database' => 0,
                ],
                [
                    'host'     => '127.0.0.1',
                    'password' => null,
                    'port'     => 6386,
                    'database' => 0,
                ],
            ],
        ],
    ],
];

使用

<?php 
        $redis = \Redis::connection('mycluster1');
        $redis->set('name','jack');
        $redis->set('sex','女');
        $redis->set('age','18');
        $redis->set('class','一班');
        dump($redis->get('sex'));
        dump($redis->get('age'));
        dump($redis->get('class'));
        dd($redis->get('name'));

参考

redis实战第九篇 集群扩容自动迁移槽(redis-cli

三张图秒懂Redis集群设计原理

全面剖析Redis Cluster原理和应用

Copyright © Kagami丶 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-12-10 21:44:54

results matching ""

    No results matching ""