Redis6 集群
2543字约8分钟
2024-08-10
容量不够,redis 如何进行扩容?
并发写操作,redis 如何分摊?
主从模式、薪火相传模式,主机宕机导致 ip 地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息
之前通过代理主机来解决;redis3.0 中提供了解决方案,就是配置
栗子
商品、用户、订单等 redis 数据分别存在不同机器上
介绍
Redis 集群实现了对 Redis 的水平扩容,即启动 N 个 redis 节点,将整个数据库分布存储在这 N 个节点中,每个节点存储总数据的 1/N
Redis 集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
好处
实现扩容
分摊压力
无中心配置相对简单
不足
多键操作是不被支持的
多键的 Redis 事务是不被支持的。lua 脚本不被支持
集群方案出现较晚,很多公司采用了其他集群方案,而代理或者客户端分片的方案想要迁移至 redis cluster,需要整体迁移而不是逐步过渡,复杂度较大
模拟集群搭建
制作 6 个实例(6379、6380、6381 三台为主机,6389、6390、6391 分别是对应的从机)
配置基本信息(比如:
daemonize yes
、pid 文件名称、指定端口、Dump.rdb 名字)redis cluster 配置修改
# 引入 redis.conf 配置文件
include /myredis/redis.conf
# 设置 redis-server 进程的 pid,即 Process ID(进程 ID)
pidfile /var/run/redis_6379.pid
# 设置端口号
port 6379
# 设置 rdb 持久化文件的名称
dbfilename dump6379.rdb
# 打开集群模式
cluster-enabled yes
# 设置节点配置文件名
cluster-config-file nodes-6379.conf
# 设置节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000
# 复制 5 份
cp redis6379.conf redis6380.conf
cp redis6379.conf redis6381.conf
cp redis6379.conf redis6389.conf
cp redis6379.conf redis6390.conf
cp redis6379.conf redis6391.conf
# 将对应端口和名称的数字修改一致,只需要修改下面几行即可
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb
cluster-config-file nodes-6380.conf
使用查找替换修改另外 5 个文件
- 启动 6 个 redis 服务
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf
redis-server redis6389.conf
redis-server redis6390.conf
redis-server redis6391.conf
# 查看一下是否启动成功
[root@iZ2zeciiosuxr5a7loycmeZ myredis]# ps -ef | grep redis
root 27876 1 0 17:29 ? 00:00:00 redis-server *:6379 [cluster]
root 27882 1 0 17:29 ? 00:00:00 redis-server *:6380 [cluster]
root 27888 1 0 17:29 ? 00:00:00 redis-server *:6381 [cluster]
root 27894 1 0 17:29 ? 00:00:00 redis-server *:6389 [cluster]
root 27900 1 0 17:29 ? 00:00:00 redis-server *:6390 [cluster]
root 27906 1 0 17:29 ? 00:00:00 redis-server *:6391 [cluster]
root 27912 27789 0 17:29 pts/0 00:00:00 grep --color=auto redis
- 将 6 个节点合成一个集群
组合之前,请确保所有 redis 实例启动后,nodes-xxxx.conf 文件都生成正常
旧版本 redis 搭建集群需要脚本工具(yum install ruby
),新版本已经预装了,无需再装 ruby 脚本工具
# 首先进入到 redis 的安装目录的 src 目录下(里面有这个 ruby 环境,redis-trib.rb)
cd /usr/local/redis/redis-6.2.4/src
# 此处不要采用 127.0.0.1,请使用真实地址(如果是云服务器,用公网ip需要在安全组配置所有端口开放,可以采用内网ip)
# --cluster-replicas 1 采用最简单的方式配置集群,一台主机,一台从机,正好三组
# 注意,如果 redis 有配置密码,需要加上 -a 密码;从机 redis.conf 文件也要配置主机密码:masterauth 密码
redis-cli --cluster create --cluster-replicas 1 [-a password] 172.17.65.134:6379 172.17.65.134:6380 172.17.65.134:6381 172.17.65.134:6389 172.17.65.134:6390 172.17.65.134:6391
# 这里我没有进入 redis 安装目录 src 下,直接在 myredis 目录下执行的命令,也正常启动了
[root@iZ2zeciiosuxr5a7loycmeZ myredis]# redis-cli --cluster create --cluster-replicas 1 -a 123456 172.17.65.134:6379 172.17.65.134:6380 172.17.65.134:6381 172.17.65.134:6389 172.17.65.134:6390 172.17.65.134:6391Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.17.65.134:6390 to 172.17.65.134:6379
Adding replica 172.17.65.134:6391 to 172.17.65.134:6380
Adding replica 172.17.65.134:6389 to 172.17.65.134:6381
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: b5118c72c0176ade97db85247c129199e7753f26 172.17.65.134:6379
slots:[0-5460] (5461 slots) master
M: 65fd8972bdb7a44d841e044e3e10973cdd519ac9 172.17.65.134:6380
slots:[5461-10922] (5462 slots) master
M: 3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 172.17.65.134:6381
slots:[10923-16383] (5461 slots) master
S: 38f7d17438b7e3a8b62a8fb7906a4703b1bc4f7d 172.17.65.134:6389
replicates 65fd8972bdb7a44d841e044e3e10973cdd519ac9
S: d043d45ad25ef6ae23855a6f4af04661e24ba387 172.17.65.134:6390
replicates 3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6
S: acba3f0589798fc72180148febfe4b722194d4be 172.17.65.134:6391
replicates b5118c72c0176ade97db85247c129199e7753f26
# 是否接受上面主从机器的分配
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 172.17.65.134:6379)
M: b5118c72c0176ade97db85247c129199e7753f26 172.17.65.134:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 172.17.65.134:6381
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 38f7d17438b7e3a8b62a8fb7906a4703b1bc4f7d 172.17.65.134:6389
slots: (0 slots) slave
replicates 65fd8972bdb7a44d841e044e3e10973cdd519ac9
S: d043d45ad25ef6ae23855a6f4af04661e24ba387 172.17.65.134:6390
slots: (0 slots) slave
replicates 3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6
M: 65fd8972bdb7a44d841e044e3e10973cdd519ac9 172.17.65.134:6380
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: acba3f0589798fc72180148febfe4b722194d4be 172.17.65.134:6391
slots: (0 slots) slave
replicates b5118c72c0176ade97db85247c129199e7753f26
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
- 采用集群策略连接,设置数据会自动切换到相应的写主机
redis-cli -c -p 6379
# 如果设置了密码,那么命令需要机上密码 redis-cli -c -p 6379 -a 123456,否则集群 set 切换不同插槽时候失败,需要密码
[root@iZ2zeciiosuxr5a7loycmeZ myredis]# redis-cli -c -p 6379
# 查看集群节点信息
127.0.0.1:6379> cluster nodes
3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 172.17.65.134:6381@16381 master - 0 1623545708000 3 connected 10923-16383
38f7d17438b7e3a8b62a8fb7906a4703b1bc4f7d 172.17.65.134:6389@16389 slave 65fd8972bdb7a44d841e044e3e10973cdd519ac9 0 1623545708254 2 connected
d043d45ad25ef6ae23855a6f4af04661e24ba387 172.17.65.134:6390@16390 slave 3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 0 1623545709257 3 connected
# 通过这个值可以找到对应主机的从机 myself 当前机器,master 主机
b5118c72c0176ade97db85247c129199e7753f26 172.17.65.134:6379@16379 myself,master - 0 1623545709000 1 connected 0-5460
65fd8972bdb7a44d841e044e3e10973cdd519ac9 172.17.65.134:6380@16380 master - 0 1623545708000 2 connected 5461-10922
# b511 当前主机的从机 f26
acba3f0589798fc72180148febfe4b722194d4be 172.17.65.134:6391@16391 slave b5118c72c0176ade97db85247c129199e7753f26 0 1623545710260 1 connected
127.0.0.1:6379>
操作
redis cluster 如何分配这六个节点?
一个集群至少要有三个主节点
选项--cluster-replicas 1
表示我们希望为集群中的每个主节点创建一个从节点
分配原则上尽量保证每个主数据库运行在不同的 IP 地址,每个从库和主库不在一个 IP 地址上
slots
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
slots 是插槽的意思,搭建集群完毕,[OK] All 16384 slots covered.
,总共有 16384 个插槽,数据库中的每个键都属于这 16384 个插槽中的一个
集群使用 CRC16(key) % 16384 来计算键 key 属于那个槽,其中 CRC16(key) 语句用于计算 key 的 CRC16 校验和计算
集群中的每个节点负责处理一部分插槽,通过cluster nodes
可以看到
在集群中录入值
在 redis-cli 每次录入、查询键值都会计算出该 key 应该送往的卡槽,如果不是该客户端对应服务器的插槽,redis 会报错,并告知应该前往的 redis 实例地址和端口。
redis-cli 客户端提供了 -c 参数实现自动重定向
# 如何 redis 设置了密码,连接的时候加上密码,redis-cli -c -p 6379 -a 123456
[root@iZ2zeciiosuxr5a7loycmeZ myredis]# redis-cli -c -p 6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set k1 v1
-> Redirected to slot [12706] located at 172.17.65.134:6381
OK
172.17.65.134:6381> set k2 v2
-> Redirected to slot [449] located at 172.17.65.134:6379
OK
# 这里添加多个值会有问题,需要分组插入 {user},计算分配插槽根据 user 来
172.17.65.134:6379> mset name lucy age 20 address china
# CROSSSLOT 交叉点
(error) CROSSSLOT Keys in request don't hash to the same slot
172.17.65.134:6379> mset name{user} lucy age{user} 20 address{user} china
-> Redirected to slot [5474] located at 172.17.65.134:6380
OK
查询集群中的值
cluster getkeysinslot <slot> <count>
返回 count 个 slot 槽中的键
172.17.65.134:6380> cluster keyslot k1
(integer) 12706
172.17.65.134:6380> cluster countkeysinslot 12706
# k1 这个 key 是存在的,这里返回 0 不存在是因为,k1 在 6381 端口的插槽里
(integer) 0
172.17.65.134:6380> set k3 v3
-> Redirected to slot [4576] located at 172.17.65.134:6379
OK
# 重新 set 一个 k3 ,然后查询就返回 1 了。也就是说只能查看自己插槽的值
172.17.65.134:6379> cluster keyslot k3
(integer) 4576
172.17.65.134:6379> cluster countkeysinslot 4576
(integer) 1
172.17.65.134:6379> cluster getkeysinslot 4576 1
1) "k3"
故障恢复
主节点下线,从节点自动升为主节点,注意配置的 15 秒超时
主节点恢复后,主节点变为原来从机的从机
某一段插槽的主从节点都宕掉,redis 服务是否能继续?
redis.conf
文件中配置cluster-require-full-coverage
为 yes,那么整个集群都挂掉redis.conf
文件中配置cluster-require-full-coverage
为 no,那么该插槽数据全部不能使用,也无法存储
# 停掉 6379 这个 redis 主机
172.17.65.134:6379> SHUTDOWN
not connected> exit
# redis 设置了密码记得带上密码 -a 123456
[root@iZ2zeciiosuxr5a7loycmeZ myredis]# redis-cli -c -p 6380
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# 可以看到 6379 fail,然后 6391 成为主机
127.0.0.1:6380> cluster nodes
b5118c72c0176ade97db85247c129199e7753f26 172.17.65.134:6379@16379 master,fail - 1623590047934 1623590043920 1 disconnected
acba3f0589798fc72180148febfe4b722194d4be 172.17.65.134:6391@16391 master - 0 1623590064000 7 connected 0-5460
3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 172.17.65.134:6381@16381 master - 0 1623590065004 3 connected 10923-16383
38f7d17438b7e3a8b62a8fb7906a4703b1bc4f7d 172.17.65.134:6389@16389 slave 65fd8972bdb7a44d841e044e3e10973cdd519ac9 0 1623590065000 2 connected
d043d45ad25ef6ae23855a6f4af04661e24ba387 172.17.65.134:6390@16390 slave 3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 0 1623590066012 3 connected
65fd8972bdb7a44d841e044e3e10973cdd519ac9 172.17.65.134:6380@16380 myself,master - 0 1623590064000 2 connected 5461-10922
# 开另外一个连接,启动 6379
[root@iZ2zeciiosuxr5a7loycmeZ myredis]# redis-server redis6379.conf
# 可以看到 6379 成为了 6391 的从机
127.0.0.1:6380> cluster nodes
b5118c72c0176ade97db85247c129199e7753f26 172.17.65.134:6379@16379 slave acba3f0589798fc72180148febfe4b722194d4be 0 1623590163420 7 connected
acba3f0589798fc72180148febfe4b722194d4be 172.17.65.134:6391@16391 master - 0 1623590162416 7 connected 0-5460
3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 172.17.65.134:6381@16381 master - 0 1623590162000 3 connected 10923-16383
38f7d17438b7e3a8b62a8fb7906a4703b1bc4f7d 172.17.65.134:6389@16389 slave 65fd8972bdb7a44d841e044e3e10973cdd519ac9 0 1623590162000 2 connected
d043d45ad25ef6ae23855a6f4af04661e24ba387 172.17.65.134:6390@16390 slave 3f38e8754dcfb6dbb2fce0a274c6ff7db0a0c1e6 0 1623590162000 3 connected
65fd8972bdb7a44d841e044e3e10973cdd519ac9 172.17.65.134:6380@16380 myself,master - 0 1623590160000 2 connected 5461-10922
127.0.0.1:6380>
集群的 Jedis 开发
即使链接的不是主机,集群会自动切换主机存储。主机写,从机读
无中心化主从集群,无论从哪台主机写的数据,其他主机上都能读到数据
public static void main(String[] args) {
// 创建对象
HostAndPort hostAndPort = new HostAndPort("39.105.172.126", 6379);
JedisCluster jedisCluster = new JedisCluster(hostAndPort);
// 操作
jedisCluster.set("b1", "value1");
String value = jedisCluster.get("b1");
System.out.println(value);
}