Akemi

Redis-Cluster集群模式

2024/09/24

sentinel哨兵模式的缺点

1.在sentinel选举出来新master时,选举期间会存在访问瞬断的情况
2.哨兵模式对外只有master节点可以写,slave节点只能用于读,写的压力相对较大,高并发场景下不合适
3.Redis的单节点内存不能设置过大,若数据过大在主从同步将会很慢;在节点启动的时候由于需要全量同步很慢

Redis集群的优点

  • Redis集群有多个master,不需要切换,可以减小访问瞬断问题的影响
  • Redis集群有多个master,可以提供更高的并发量
  • Redis集群可以分片存储,这样就可以存储更多的数据

Redis集群是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。

适合在数据量特别大的时候使用

Redis-Cluster工作原理

slots(槽位)机制

Redis Cluster将所有数据划分为16384个slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。只有master节点会被分配槽位,slave节点不会分配槽位。

第一步:
客户端连接到集群时,会给客户端返回一个槽位对应表,并且将其缓存到客户端本地

第二步:
Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。
(根据k1计算出的槽值进行切换节点,并存入数据。不在一个slot下的键值,是不能使用mget、mset等多建操作)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
redis-cluster的安装详见下面部分

192.168.10.116:8001> set k1 v1
-> Redirected to slot [12706] located at 192.168.10.118:8001
OK
192.168.10.118:8001>
在这里我set了一个key之后
redis自动将key进行了hash运算,并且计算出这个槽位是分配给192.168.10.118的
就自动给我切换过去了

同时也只能在192.168.10.118进行get k1的操作
在另外节点就无法get到
192.168.10.116:8001> get k1
-> Redirected to slot [12706] located at 192.168.10.118:8001
"v1"

通过{}来定义组,相同组中的键值对放到同个slot中
192.168.10.117:8001> mset k1{wang} 10 k2{wang} 20 k3{wang} 30
-> Redirected to slot [2919] located at 192.168.10.116:8001
OK
#在不同节点上,通过{}获取可以获取
192.168.10.117:8001> get k2{wang}
-> Redirected to slot [2919] located at 192.168.10.116:8001
"20"
#在不同节点上,直接获取无法获取
192.168.10.117:8001> get k2
-> Redirected to slot [449] located at 192.168.10.116:8001
(nil)

Redis-Cluster通讯

在分布式存储中提供维护节点元数据信息的机制,使用gossip协议。

每个节点都会单独开辟一个tcp通道用于特殊通信,通信端口的在基础上加10000,如8001端口,开辟的就是18001端口。(发送ping消息,用pong消息作为相应)

在生产环境中,安全配置需要考虑到这个特殊端口

meeting消息

消息发送者发送给meeting,消息通信正常完成后,接受节点开始收发ping和pong消息

Redis-Cluster搭建

环境与配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
环境:
centos7.9
redis版本5.0.5
192.168.10.116 redis1
192.168.10.117 redis2
192.168.10.118 redis3
使用8001端口作为master端口
使用8002端口作为slave端口

部署redis的过程略过

mkdir -p /usr/local/redis-cluster/8001
mkdir -p /usr/local/redis-cluster/8002
cd /usr/local/redis-cluster

#清一下环境
pkill redis
rm -rf /usr/local/redis-cluster/8001/*
rm -rf /usr/local/redis-cluster/8002/*

# 写一个redis-cluster的配置文件,使用8001端口
cat >redis-cluster.conf<<EOF
port 8001
daemonize yes
pidfile "/var/run/redis_8001.pid"
dir /usr/local/redis-cluster/8001
cluster-enabled yes #设置以集群模式启动
cluster-config-file nodes-8001.conf #集群节点信息文件
cluster-node-timeout 5000 #离线超时时间
bind 0.0.0.0
protected-mode no
appendonly yes #使用aof
EOF

#写8002从节点的配置文件redis-slave.conf
cat >redis-slave.conf<<EOF
port 8002
daemonize yes
pidfile "/var/run/redis_8002.pid"
dir /usr/local/redis-cluster/8002
cluster-enabled yes
cluster-config-file nodes-8002.conf
cluster-node-timeout 5000
bind 0.0.0.0
protected-mode no
appendonly yes
EOF

#将本机这个目录复制到另外两台redis主机上
scp -r /usr/local/redis-cluster redis2:/usr/local/redis-cluster
scp -r /usr/local/redis-cluster redis3:/usr/local/redis-cluster

redis启动与初始化(手动)

手动发现节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#每台节点上都启动redis
redis-server /usr/local/redis-cluster/redis-cluster.conf
redis-server /usr/local/redis-cluster/redis-slave.conf

redis-cli -h 192.168.10.116 -p 8001
cluster nodes
#9a81edf239c532b6736a8910b2caddfae77ee93c 192.168.10.116:8002@18002 master - 0 1727091025966 0 connected
# 手动发现
CLUSTER MEET 192.168.10.116 8002
#OK
cluster nodes
9a81edf239c532b6736a8910b2caddfae77ee93c 192.168.10.116:8002@18002 master - 0 1727091025966 0 connected
38a18490e78a35ef22f35ef80cd00c07389a2baa 192.168.10.116:8001@18001 myself,master - 0 0 1 connected

cat 8001/nodes-8001.conf
9a81edf239c532b6736a8910b2caddfae77ee93c 192.168.10.116:8002@18002 master - 0 1727091005009 0 connected
38a18490e78a35ef22f35ef80cd00c07389a2baa 192.168.10.116:8001@18001 myself,master - 0 0 1 connected
vars currentEpoch 1 lastVoteEpoch 0

cluster info
cluster_state:fail #集群状态失败
...
cluster_known_nodes:2 #发现两个节点
...

#继续添加节点
CLUSTER MEET 192.168.10.117 8001
CLUSTER MEET 192.168.10.117 8002
CLUSTER MEET 192.168.10.118 8001
CLUSTER MEET 192.168.10.118 8002

cluster nodes
9a81edf239c532b6736a8910b2caddfae77ee93c 192.168.10.116:8002@18002 master - 0 1727092265579 0 connected
f5b3f524b1b024df2e74f749e8023dec2f6c2da6 192.168.10.118:8002@18002 slave 1b93b48276aece5b94de1ed9e060b65aa6c376a0 0 1727092265000 3 connected
06aada2ea17a85743fb7e02ae1cfcfb12c3acef1 192.168.10.118:8001@18001 master - 0 1727092266000 5 connected 10923-16383
1b93b48276aece5b94de1ed9e060b65aa6c376a0 192.168.10.117:8001@18001 master - 0 1727092266582 3 connected 5461-10922
38a18490e78a35ef22f35ef80cd00c07389a2baa 192.168.10.116:8001@18001 myself,master - 0 1727092265000 1 connected
736d0f4ccd33b00c0c128db6f9fd37da9e10d484 192.168.10.117:8002@18002 slave - 0 1727092267083 1 connected

cluster info
cluster_state:fail
集群状态依然失败,因为没有分配slots

手动分配槽位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cluster addslots {0..槽位数}

给上面三个的主节点添加:
redis-cli -c -h 192.168.10.116 -p 8001 CLUSTER ADDSLOTS {0..5460}
redis-cli -c -h 192.168.10.117 -p 8001 CLUSTER ADDSLOTS {5461..10922}
redis-cli -c -h 192.168.10.118 -p 8001 CLUSTER ADDSLOTS {10923..16383}

#此时cluster已经ok状态,规模也已经正常
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

redis启动与初始化(使用工具、自动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#每台节点上都启动redis
redis-server /usr/local/redis-cluster/redis-cluster.conf
redis-server /usr/local/redis-cluster/redis-slave.conf

ps -ef | grep redis
root 10389 1 0 22:46 ? 00:00:00 redis-server 0.0.0.0:8001 [cluster]
root 10395 1 0 22:46 ? 00:00:00 redis-server 0.0.0.0:8002 [cluster]
root 10414 8863 0 22:46 pts/1 00:00:00 grep --color=auto redis

ss -tunlp | grep 800
tcp LISTEN 0 128 *:8001 *:* users:(("redis-server",pid=2
tcp LISTEN 0 128 *:8002 *:* users:(("redis-server",pid=2
tcp LISTEN 0 128 *:18001 *:* users:(("redis-server",pid=2
tcp LISTEN 0 128 *:18002 *:* users:(("redis-server",pid=2
↑元数据通信端口

在初始化之前需要先清空数据库中的数据
redis-cli -h redis1 -p 8001 flushdb
redis-cli -h red is2 -p 8001 flushdb
redis-cli -h redis3 -p 8001 flushdb

# 每个redis进程都会有一个对应的节点id
cat 8001/nodes-8001.conf
d7866353d9e708a59525c9783ff312459cd8f14d :0@0 myself,master - 0 0 0 connected
或者
127.0.0.1:8001> CLUSTER NODES
d7866353d9e708a59525c9783ff312459cd8f14d :8001@18001 myself,master - 0 0 0 connected
查看

# 初始化集群
redis-cli --cluster create --cluster-replicas 1 \
192.168.10.116:8001 192.168.10.116:8002 192.168.10.117:8001 \
192.168.10.117:8002 192.168.10.118:8001 192.168.10.118:8002

参数说明:
-a 密码
--cluster create 表示新创建状态
--cluster-replicas 1 表示每个主节点的从节点数为1

Redis-Cluster信息

再次查看集群节点

这些节点都是各个节点中查看到的node-id信息

1
2
3
4
5
6
7
redis-cli -h redis1 -p 8001 cluster nodes
f5b3f524b1b024df2e74f749e8023dec2f6c2da6 192.168.10.118:8002@18002 slave 1b93b48276aece5b94de1ed9e060b65aa6c376a0 0 1727089606773 6 connected
d7866353d9e708a59525c9783ff312459cd8f14d 192.168.10.116:8001@18001 myself,master - 0 1727089607000 1 connected 0-5460
736d0f4ccd33b00c0c128db6f9fd37da9e10d484 192.168.10.117:8002@18002 slave d7866353d9e708a59525c9783ff312459cd8f14d 0 1727089608276 4 connected
1b93b48276aece5b94de1ed9e060b65aa6c376a0 192.168.10.117:8001@18001 master - 0 1727089606272 3 connected 5461-10922
06aada2ea17a85743fb7e02ae1cfcfb12c3acef1 192.168.10.118:8001@18001 master - 0 1727089607074 5 connected 10923-16383
c93652ccdcb6a640b66ffbfff913ba923d3995d7 192.168.10.116:8002@18002 slave 06aada2ea17a85743fb7e02ae1cfcfb12c3acef1 0 1727089607273 5 connected

查看集群状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Redis 集群信息  
# 集群状态:正常
cluster_state:ok
# 已分配的槽位数量:16384(Redis 集群总共 16384 个槽位)
cluster_slots_assigned:16384
# 槽位状态良好的数量:16384
cluster_slots_ok:16384
# 槽位处于可能失败状态的节点数量:0
cluster_slots_pfail:0
# 槽位处于失败状态的节点数量:0
cluster_slots_fail:0
# 集群中已知节点的数量:6(表示集群中有6个节点)
cluster_known_nodes:6
# 集群的实际大小(即主节点的数量):3
cluster_size:3
# 集群的当前纪元:6(纪元是集群状态版本号,用于节点间的配置同步)
cluster_current_epoch:6
# 当前节点的纪元:1(表示这是节点自己的纪元版本)
cluster_my_epoch:1
# 发送的 PING 消息数量:809
cluster_stats_messages_ping_sent:809
# 发送的 PONG 消息数量:847
cluster_stats_messages_pong_sent:847
# 发送的总消息数量(PING + PONG):1656
cluster_stats_messages_sent:1656
# 接收的 PING 消息数量:842
cluster_stats_messages_ping_received:842
# 接收的 PONG 消息数量:809
cluster_stats_messages_pong_received:809
# 接收的 MEET 消息数量(用于节点发现):5
cluster_stats_messages_meet_received:5
# 接收的总消息数量(PING + PONG + MEET):1656
cluster_stats_messages_received:1656

Redis-Cluster简单故障恢复测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
CLUSTER NODES
1da6c02ff0dbbfbb13a36e2763b9ec9cec5e712c 192.168.10.118:8001@18001 master - 0 1721143350546 5 connected 10923-16383
d5a3fe999c0375bf625d7e7038b22f27616d5d71 192.168.10.117:8001@18001 master - 0 1721143351548 3 connected 5461-10922
2c767536a9cbe2a0afafe154fd2a7c925cff5afc 192.168.10.116:8002@18002 slave 1da6c02ff0dbbfbb13a36e2763b9ec9cec5e712c 0 1721143351548 5 connected
bd04e3bd7b58e60732fd243d002497633790c85e 192.168.10.118:8002@18002 slave d5a3fe999c0375bf625d7e7038b22f27616d5d71 0 1721143350000 6 connected
2bf33697731457bcfcbe11cffbec0ed70dde9330 192.168.10.117:8002@18002 slave 2031e58e9a74a6fb3e4a71d29e1f0aea3758902f 0 1721143350546 4 connected
2031e58e9a74a6fb3e4a71d29e1f0aea3758902f 192.168.10.116:8001@18001 myself,master - 0 1721143350000 1 connected 0-5460

# 在192.168.10.118的redis进程关闭
ps -ef | grep redis
root 10389 1 0 22:46 ? 00:00:02 redis-server 0.0.0.0:8001 [cluster]
root 10395 1 0 22:46 ? 00:00:02 redis-server 0.0.0.0:8002 [cluster]

kill 10389

#通过另外一台机器打开redis-cli进行查看
CLUSTER NODES
2c767536a9cbe2a0afafe154fd2a7c925cff5afc 192.168.10.116:8002@18002 slave 1da6c02ff0dbbfbb13a36e2763b9ec9cec5e712c 0 1721143556539 5 connected
1da6c02ff0dbbfbb13a36e2763b9ec9cec5e712c 192.168.10.118:8001@18001 master - 0 1721143556038 5 connected 10923-16383
bd04e3bd7b58e60732fd243d002497633790c85e 192.168.10.118:8002@18002 slave d5a3fe999c0375bf625d7e7038b22f27616d5d71 0 1721143557000 6 connected
2bf33697731457bcfcbe11cffbec0ed70dde9330 192.168.10.117:8002@18002 master - 0 1721143555035 8 connected 0-5460
d5a3fe999c0375bf625d7e7038b22f27616d5d71 192.168.10.117:8001@18001 myself,master - 0 1721143555000 3 connected 5461-10922
2031e58e9a74a6fb3e4a71d29e1f0aea3758902f 192.168.10.116:8001@18001 master,fail - 1721143509189 1721143508000 1 disconnected

可以看到刚刚那台192.168.10.116:8001现在是fail状态
原本的备机192.168.10.117:8002变成了master
CATALOG
  1. 1. sentinel哨兵模式的缺点
  2. 2. Redis集群的优点
  3. 3. Redis-Cluster工作原理
    1. 3.1. slots(槽位)机制
    2. 3.2. Redis-Cluster通讯
  4. 4. Redis-Cluster搭建
    1. 4.1. 环境与配置文件
    2. 4.2. redis启动与初始化(手动)
    3. 4.3. redis启动与初始化(使用工具、自动)
    4. 4.4. Redis-Cluster信息
  5. 5. Redis-Cluster简单故障恢复测试