哈希槽(hash slot)
在 Redis 集群中,哈希槽(hash slot)是数据分片的核心机制。Redis 集群使用哈希槽来将数据分布到多个节点上。在 Redis 集群中,哈希槽(hash slot)是数据分片的核心机制。Redis 集群使用哈希槽来将数据分布到多个节点上。
Redis 使用 CRC16 哈希算法来将键映射到哈希槽中。首先根据CRC16(key)计算出一个hash值,然后对16384取模计算出对应的槽位:
slot = CRC16(key) % 16384
这样,每个键就会被分配到 0 到 16383 之间的一个槽中。每个哈希槽会被分配到集群中的一个节点(master),每个键会根据其哈希槽分配到相应的节点。当 Redis 集群的拓扑结构发生变化(例如,添加或移除节点),哈希槽需要进行重新分配和迁移。Redis 提供了命令来支持这种迁移操作。
下面具体一步步来搭建一个集群。
准备节点
准备三个集群节点,还是单机不同端口形式演示。准备7001,7002,7003三个目录、端口及配置文件
mkdir cluster
mkdir 7001 7002 7003
cp ../redis.conf 7001/
cp ../redis.conf 7002/
cp ../redis.conf 7003/
修改配置文件
依次修改配置文件:vim 7001/redis.conf
port 7001
#开启集群模式
cluster-enabled yes
#指定集群节点信息存储文件
cluster-config-file nodes.conf
#判断节点不可用最大时间,毫秒
cluster-node-timeout 15000
#开启AOF持久化,默认是yes
appendonly yes
cluster-config-file指定的nodes.conf配置文件会存储集群中每个节点的槽位范围,这样当客户端发送一个key操作指令时当前节点能判断具体应该在哪个节点上,如果是当前节点,则直接执行对应的key操作。如果是其它节点则MOVE到对应的节点。
cluster-node-timeout
参数指定了一个节点在认为另一个节点宕机之前,应该等待的时间长度。换句话说,它定义了节点在等待来自其他节点的响应时的超时时间。如果一个节点在这个时间段内没有收到来自其他节点的响应,它会将该节点标记为“不可用”并启动相应的恢复机制。
另外还需要修改对应pid进程文件和data目录,参加前面的主从搭建文章。
依次进入各节点目录,启动各节点
/path/redis/src/redis-server redis.conf
到这里三个节点就准备好了,下面使用命令来进行集群节点间关联
redis-cli --cluster子命令
redis-cli --cluster
命令是 Redis 提供的工具,用于管理和维护 Redis 集群。使用这个命令可以进行集群的各种操作,如重新分片、查看集群状态、添加或删除节点等。接下来集群的管理都将使用redis-cli --cluster子命令来完成。
1、创建集群
create host1:port1 ... hostN:portN --cluster-replicas <arg>
2、添加节点
redis-cli --cluster add-node <new-node-ip:port> <existing-node-ip:port>
将新的 Redis 节点添加到现有的 Redis 集群中。
3、删除节点
redis-cli --cluster del-node <node-ip:port> <node-id>
这个命令用于从 Redis 集群中删除指定的节点。node-id
是要删除的节点的 ID,可以通过 redis-cli --cluster nodes <node-ip:port>
命令获取,也可以使用redis-cli cluster info 来获取节点ID。
4、检查集群状态
redis-cli --cluster check <node-ip:port>
检查 Redis 集群的健康状况,帮助诊断集群中的潜在问题。
# /data/src/redis-5.0.14/src/redis-cli --cluster check 127.0.0.1:7001
127.0.0.1:7001 (215e7256...) -> 1 keys | 5461 slots | 0 slaves.
127.0.0.1:7003 (7996b42d...) -> 0 keys | 5461 slots | 0 slaves.
127.0.0.1:7002 (88ed05be...) -> 0 keys | 5462 slots | 0 slaves.
[OK] 1 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: 215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
M: 7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
M: 88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
5、重新分片
redis-cli --cluster reshard <node-ip:port>
重新分片集群中的哈希槽。在执行过程中,redis-cli
会提示你输入需要迁移的槽范围、目标节点等信息。一般在新增或删除节点后执行。
创建cluster
将7001,7002,7003三个节点组成一个集群
# ./redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003
>>> Performing hash slots allocation on 3 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
M: 215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
M: 88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
M: 7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
#自动计算好每个节点分片的hash slots,这里确认执行即可
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:7001)
M: 215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
M: 7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
M: 88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
查看cluster,使用redis-cli随便连接集群中一个节点
[root@iZbp173usy5pvd19i081dgZ src]# ./redis-cli -p 7001
127.0.0.1:7001> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:3
cluster_current_epoch:3
cluster_my_epoch:1
cluster_stats_messages_ping_sent:120
cluster_stats_messages_pong_sent:121
cluster_stats_messages_sent:241
cluster_stats_messages_ping_received:119
cluster_stats_messages_pong_received:120
cluster_stats_messages_meet_received:2
cluster_stats_messages_received:241
127.0.0.1:7001> cluster nodes
7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003@17003 master - 0 1725329916592 3 connected 10923-16383
88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002@17002 master - 0 1725329915590 2 connected 5461-10922
215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001@17001 myself,master - 0 1725329915000 1 connected 0-5460
16384个hash slots平均分配到了三个节点上。
数据测试
127.0.0.1:7001> set name hello
(error) MOVED 5798 127.0.0.1:7002
127.0.0.1:7001> get name
(error) MOVED 5798 127.0.0.1:7002
127.0.0.1:7001> set age 18
OK
127.0.0.1:7001> get age
"18"
这里在设置key为name的值时候,其key计算slots值位5798不在当前7001节点(0~5460)范围内,执行了MOVE操作。
水平扩容
上面集群中有3个节点,下面往现有集群中增加一个节点来扩展系统的处理能力和存储能力。
同样修改对应配置新启动一个7004的节点服务
使用redis-cli --cluster add-node命令将7004加入上面的集群
# /path/redis/src/redis-cli --cluster add-node 127.0.0.1:7004 127.0.0.1:7002
>>> Adding node 127.0.0.1:7004 to cluster 127.0.0.1:7002
>>> Performing Cluster Check (using node 127.0.0.1:7002)
M: 88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
M: 7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
M: 215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
[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:7004 to make it join the cluster.
[OK] New node added correctly.
再次查看集群信息
[root@iZbp173usy5pvd19i081dgZ 7004]# /data/redis/src/redis-cli -p 7001
127.0.0.1:7001> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:4
cluster_size:3
cluster_current_epoch:3
cluster_my_epoch:1
cluster_stats_messages_ping_sent:4211
cluster_stats_messages_pong_sent:4287
cluster_stats_messages_sent:8498
cluster_stats_messages_ping_received:4285
cluster_stats_messages_pong_received:4211
cluster_stats_messages_meet_received:2
cluster_stats_messages_received:8498
127.0.0.1:7001> cluster nodes
6682d39e8176396a7e3aa7cf5f22ececf0b9097a 127.0.0.1:7004@17004 master - 0 1725333672692 0 connected
7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003@17003 master - 0 1725333672190 3 connected 10923-16383
88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002@17002 master - 0 1725333671187 2 connected 5461-10922
215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001@17001 myself,master - 0 1725333672000 1 connected 0-5460
这时候集群中节点已经是4个,但是新加入的7004对用分片的槽位是0,不会承载数据的读写,这个时候还需要执行reshard进行槽位迁移,从其它节点将一部分槽位迁移到当前节点。
#1、连接到集群任意一个master节点
[root@iZbp173usy5pvd19i081dgZ 7004]# /data/redis/src/redis-cli --cluster reshard 127.0.0.1:7001
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: 215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
M: 6682d39e8176396a7e3aa7cf5f22ececf0b9097a 127.0.0.1:7004
slots: (0 slots) master
M: 7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
M: 88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
#2、确认迁移的槽位数量
How many slots do you want to move (from 1 to 16384)? 1000
What is the receiving node ID? 6682d39e8176396a7e3aa7cf5f22ececf0b9097a
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.
#3、确认迁移槽位来源:all从集群所有的主节点中抽取一定的槽位迁移到当前节点,总数位上面指定的槽位树
Source node #1: all
Ready to move 1000 slots.
Source nodes:
M: 215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
M: 7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
M: 88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
Destination node:
M: 6682d39e8176396a7e3aa7cf5f22ececf0b9097a 127.0.0.1:7004
slots: (0 slots) master
Resharding plan:
Moving slot 5461 from 88ed05be0d17373426edd775d0689eb7bb046def
Moving slot 5462 from 88ed05be0d17373426edd775d0689eb7bb046def
...
#4、确认执行
Do you want to proceed with the proposed reshard plan (yes/no)? yes
Moving slot 5461 from 127.0.0.1:7002 to 127.0.0.1:7004:
Moving slot 5462 from 127.0.0.1:7002 to 127.0.0.1:7004:
...
迁移后,查看集群节点信息
127.0.0.1:7001> cluster nodes
6682d39e8176396a7e3aa7cf5f22ececf0b9097a 127.0.0.1:7004@17004 master - 0 1725345390240 4 connected 0-332 5461-5794 10923-11255
7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003@17003 master - 0 1725345389000 3 connected 11256-16383
88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002@17002 master - 0 1725345389238 2 connected 5795-10922
215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001@17001 myself,master - 0 1725345389000 1 connected 333-5460
从原来(7001,7002,7003)每个抽取333个迁移到了7004。
会过头来看下前面使用cluster-config-file nodes.conf 配置的nodes.conf文件中内容
6682d39e8176396a7e3aa7cf5f22ececf0b9097a 127.0.0.1:7004@17004 master - 0 1725333938687 4 connected 0-332 5461-5794 10923-11255
7996b42df53132a7cc665f857c9536633e8cd6ef 127.0.0.1:7003@17003 myself,master - 0 1725333938000 3 connected 11256-16383
88ed05be0d17373426edd775d0689eb7bb046def 127.0.0.1:7002@17002 master - 0 1725333938587 2 connected 5795-10922
215e725629e4075ab05a5b9797464bd708fce41d 127.0.0.1:7001@17001 master - 0 1725333939691 1 connected 333-5460
vars currentEpoch 4 lastVoteEpoch 0
里面记录了集群中每个节点的slots范围信息。
节点删除
在删除节点之前,确保所有与该节点相关的数据已经被迁移到其他节点,使用前面的resharding 迁移槽位。如果删除的节点是主节点,还需要确保其复制的从节点能够重新配置以接管主节点的工作。
删除节点后,使用 redis-cli --cluster check <node-ip:port>
命令检查集群状态,确保集群正常运行,并且其他节点已经正确接管了被删除节点的哈希槽。