一、概述
Redis3.0版本之后支持Cluster.
1.1、redis cluster的现状
目前redis支持的cluster特性:
- 1):节点自动发现
- 2):slave->master 选举,集群容错
- 3):Hot resharding:在线分片
- 4):集群管理:cluster xxx
- 5):基于配置(nodes-port.conf)的集群管理
- 6):ASK 转向/MOVED 转向机制.
1.2、redis cluster 架构
1、redis-cluster架构图
架构细节:
- (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
- (2)节点的fail是通过集群中超过半数的节点检测失效时才生效.
- (3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- (4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
2、redis-cluster选举:容错
- 领着选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.
- 什么时候整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
- a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.
- b:如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态.
1.3、Redis-Cluster集群缺点
- 数据通过异步复制,不保证数据的强一致性。
- Redis Cluster 不支持像 Redis 的独立版本那样支持多个数据库。只有数据库 0 并且不允许使用SELECT命令。
- Key 批量操作限制,如使用 mset、mget 目前只支持具有相同 slot 值的 Key 执行批量操作。对于映射为不同 slot 值的 Key 由于 Keys 不支持跨 slot 查询,所以执行 mset、mget、sunion 等操作支持不友好。
- Key 事务操作支持有限,只支持多 key 在同一节点上的事务操作,当多个 Key 分布于不同的节点上时无法使用事务功能。
二、redis安装
Redis 集群至少需要 3 个主节点。本文档配置6节点,3主3从
安装文档请参考:点击这里
主机名 | 节点IP | 端口号 |
---|---|---|
redis01-server | 172.28.254.221 | 7001 |
redis01-server | 172.28.254.221 | 7002 |
redis01-server | 172.28.254.221 | 7003 |
redis02-server | 172.28.254.27 | 7004 |
redis02-server | 1172.28.254.27 | 7005 |
redis02-server | 1172.28.254.27 | 7006 |
三、redis cluster配置
1、编辑各节点的 Redis 配置文件:
###以下内容在所有节点上配置!!!
################################ REDIS CLUSTER ###############################
cluster-enabled yes
cluster-config-file ./nodes_6379.conf
cluster-node-timeout 5000
# appendonly yes
# cluster-slave-validity-factor 10
# cluster-migration-barrier 1
# cluster-require-full-coverage yes
2、修改配置文件
sed -i 's/6379/7001/g' /etc/redis/7001.conf
sed -i 's/6379/7002/g' /etc/redis/7002.conf
sed -i 's/6379/7003/g' /etc/redis/7003.conf
sed -i 's/6379/7004/g' /etc/redis/7004.conf
sed -i 's/6379/7005/g' /etc/redis/7005.conf
sed -i 's/6379/7006/g' /etc/redis/7006.conf
- 如果设置密码,需修改启动脚本
sed -i 's#^CLIEXEC=.*$#CLIEXEC="/usr/local/redis/bin/redis-cli -a abc123"#g' /etc/rc.d/init.d/redis_7001
sed -i 's#^CLIEXEC=.*$#CLIEXEC="/usr/local/redis/bin/redis-cli -a abc123"#g' /etc/rc.d/init.d/redis_7002
sed -i 's#^CLIEXEC=.*$#CLIEXEC="/usr/local/redis/bin/redis-cli -a abc123"#g' /etc/rc.d/init.d/redis_7003
sed -i 's#^CLIEXEC=.*$#CLIEXEC="/usr/local/redis/bin/redis-cli -a abc123"#g' /etc/rc.d/init.d/redis_7004
sed -i 's#^CLIEXEC=.*$#CLIEXEC="/usr/local/redis/bin/redis-cli -a abc123"#g' /etc/rc.d/init.d/redis_7005
sed -i 's#^CLIEXEC=.*$#CLIEXEC="/usr/local/redis/bin/redis-cli -a abc123"#g' /etc/rc.d/init.d/redis_7006
从节点增加以下 Redis 配置(redis cluster跳过此步骤!):
###以下内容只在从节点上配置!!!
################################# REPLICATION #################################
masterauth abc123 #配置 masterauth(如果有 requirepass)
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
# repl-ping-slave-period 10
# repl-timeout 60
repl-disable-tcp-nodelay no
# repl-backlog-size 1mb
# repl-backlog-ttl 3600
slave-priority 100
# min-slaves-max-lag 10
# min-slaves-max-lag is set to 10.
# slave-announce-ip 5.5.5.5
# slave-announce-port 1234
配置信息:
- masterauth #主数据库连接需要的密码验证
- cluster-enabled #开启集群
- cluster-config-file #指定集群配置文件
- slave-serve-stale-data #在Redis主从同步中,当Redis从服务器发现Redis主服务器不可用时,无法判断自己的数据是否已经过期,如果此时Redis从服务器收到读的请求,则可以会响应过期的数据。如果此参数为yes,则表示Redis从服务器仍然会以可能过期的数据进行响应,但是如果此参数为no,从服务器将阻塞所有请求,有客户端请求时返回“SYNC with master in progress”;。
- slave-read-only #当此参数为yes时,则此Redis服务器将只会响应读请求,该参数默认关闭,在Redis从库上回默认开启。
- repl-diskless-sync #该参数表示是否开启无磁盘交互模式,默认为no,即不开启,也可以手动更改为yes,表示开启。所谓无磁盘交互模式,就是指Redis主和Redis从在进行主从同步时,Redis主同步给Redis从的数据文件不会被写入磁盘中,Redis从服务器会直接将该数据文件读取处理后放入内存,而如果该参数不开启,则Redis从库会将数据文件放入磁盘中,然后再读入内存。
- repl-diskless-sync-delay #该参数表示在进行无磁盘交互模式下Redis从库的延迟时间,该参数默认单位为秒,默认为5.
- slave-priority #该参数指定Redis从库的优先级,通常用于主从同步结合Redis sentinel进行高可用配置时使用,该优先级数值越小,表示优先级越高,在默认情况下,该参数值为100.
- min-slaves-to-write #该参数表示在Redis主从同步过程中,一个Redis主库所对应的最少的从库数量,当少于该参数指定的数量时,Redis主库将拒绝从库读取数据的请求。该参数在默认情况下处于关闭状态。
- min-slaves-max-lag #表示Redis主库与Redis从库之间的最大时差,当时差超过该值时,就无法进行主从同步。该参数在默认情况下处于关闭状态。
3、各节点启动Redis:
#关闭默认端口
killall redis-server
#172.28.254.221
/etc/init.d/redis_7001 restart
/etc/init.d/redis_7002 restart
/etc/init.d/redis_7003 restart
#172.28.254.27
/etc/init.d/redis_7004 restart
/etc/init.d/redis_7005 restart
/etc/init.d/redis_7006 restart
问题:
- 如果修改过监听地址,则修改redis启动脚本
# sed -i 's/$CLIEXEC -p/$CLIEXEC -h 172.28.254.221 -p/g' /etc/init.d/redis_7001
四、配置redis-trib (Redis 5以上版本跳过此步骤,可以直接使用 redis-cli 创建)
前面已经准备好了搭建集群的redis节点,接下来我们要把这些节点都串连起来搭建集群。官方提供了一个工具:redis-trib.rb( /usr/local/redis-3.2.8/src/redis-trib.rb) 看后缀就知道这鸟东西不能直接执行,它是用ruby写的一个程序,所以我们还得安装ruby.
1、安装ruby
yum -y install ruby ruby-devel rubygems rpm-build
2、gem 安装 redis接口
gem是ruby的一个工具包.
gem install redis #等一会儿就好了
如果无法在线安装 Ruby 的 Redis 模块,可以先下载 Redis 模块(https://rubygems.org/gems/redis),再离线安装:
#gem install -l redis-3.3.0.gem
- 创建 redis-trib.rb 软链接:
# ln -sv /data/apps/redis-6.2.6/src/redis-trib.rb /usr/bin/redis-trib
"/usr/bin/redis-trib" -> "/data/apps/redis-6.2.6/src/redis-trib.rb"
注意:在执行gem install redis时,报ERROR:Error installing redis: redis requires Ruby version >= 2.2.2异常。
解决: 点击此处查看解决方案
3、运行redis-trib.rb
查看 redis-trib.rb 使用帮助:
[root@redis01-server ~]# redis-trib
Usage: redis-trib <command> <options> <arguments ...>
create host1:port1 ... hostN:portN # 创建集群,指定集群中的节点;
--replicas <arg> # 指定每个Master的副本数量(即一个Master有几个Slave);
check host:port # 检查集群状态
info host:port # 查看集群信息
fix host:port # 修复集群
--timeout <arg>
reshard host:port # 重新分片(热迁移slots);
--from <arg>
--to <arg>
--slots <arg>
--yes
--timeout <arg>
--pipeline <arg>
rebalance host:port # 平衡集群中各节点的slot数量;
--weight <arg>
--auto-weights
--use-empty-masters
--timeout <arg>
--simulate
--pipeline <arg>
--threshold <arg>
add-node new_host:new_port existing_host:existing_port
# 向集群中添加节点;
--slave
--master-id <arg>
del-node host:port node_id # 从集群中删除节点;
set-timeout host:port milliseconds # 设置节点的超时时间(单位毫秒);
call host:port command arg arg .. arg
# 在集群的所有节点上执行命令;
import host:port # 导入外部redis服务器的数据到当前集群;
--from <arg>
--copy
--replace
help (show this help)
For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
4、为 Ruby Redis 模块配置 Redis 连接密码
[root@redis01-server ~]# find / -name 'client.rb'
/usr/share/ruby/xmlrpc/client.rb
/usr/local/rvm/src/ruby-2.4.10/gems/xmlrpc-0.2.1/lib/xmlrpc/client.rb
/usr/local/rvm/gems/ruby-2.4.10/gems/redis-4.6.0/lib/redis/client.rb
/usr/local/rvm/rubies/ruby-2.4.10/lib/ruby/gems/2.4.0/gems/xmlrpc-0.2.1/lib/xmlrpc/client.rb
[root@redis01-server ~]# vim /usr/local/rvm/gems/ruby-2.4.10/gems/redis-4.6.0/lib/redis/client.rb
class Redis
class Client
# Defaults are also used for converting string keys to symbols.
DEFAULTS = {
... ... ...
password: abc123, #修改此行
五、创建集群
Redis 集群至少需要 3 个主节点。 确认所有的节点都启动
1、使用参数 create 创建集群
前面已经提醒过的 防火墙一定要开放监听的端口,否则会创建失败。
- Redis 5 版本以下,使用redis-trib 创建
[root@redis01-server ~]# redis-trib create --replicas 172.28.254.221:7001 172.28.254.221:7002 172.28.254.221:7003 172.28.254.27:7004 172.28.254.27:7005 172.28.254.27:7006
解释下,--replicas 1 表示 自动为每一个master节点分配一个slave节点 上面有6个节点,程序会按照一定规则生成 3个master(主)3个slave(从)。其他参数是实例的地址集合。
- Redis 5 版本可以直接使用 redis-cli 创建
[root@redis01-server ~]# redis-cli -a abc123 --cluster-replicas 1 --cluster create 172.28.254.221:7001 172.28.254.221:7002 172.28.254.221:7003 172.28.254.27:7004 172.28.254.27:7005 172.28.254.27:7006
005 172.28.254.27:7006
Warning: 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.28.254.27:7006 to 172.28.254.221:7001
Adding replica 172.28.254.221:7003 to 172.28.254.27:7004
Adding replica 172.28.254.27:7005 to 172.28.254.221:7002
M: bb73c60e00c4ebd4ac33db0542ec684a8d201d8e 172.28.254.221:7001
slots:[0-5460] (5461 slots) master
M: c261ce0177a72e0007f4903f8ce5f6e3bee0294f 172.28.254.221:7002
slots:[10923-16383] (5461 slots) master
S: d2d369de207775a5f2e13f3580037b8acb53eeff 172.28.254.221:7003
replicates 27581beea51e7b6e1052ef3675dac6647fdb8355
M: 27581beea51e7b6e1052ef3675dac6647fdb8355 172.28.254.27:7004
slots:[5461-10922] (5462 slots) master
S: d277d6288442806f4893a9ae51ff792b6326a656 172.28.254.27:7005
replicates c261ce0177a72e0007f4903f8ce5f6e3bee0294f
S: 66d4816fcd50da1872d4dbca8312551159e72e3d 172.28.254.27:7006
replicates bb73c60e00c4ebd4ac33db0542ec684a8d201d8e
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.28.254.221:7001)
M: bb73c60e00c4ebd4ac33db0542ec684a8d201d8e 172.28.254.221:7001
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: c261ce0177a72e0007f4903f8ce5f6e3bee0294f 172.28.254.221:7002
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: d2d369de207775a5f2e13f3580037b8acb53eeff 172.28.254.221:7003
slots: (0 slots) slave
replicates 27581beea51e7b6e1052ef3675dac6647fdb8355
M: 27581beea51e7b6e1052ef3675dac6647fdb8355 172.28.254.27:7004
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 66d4816fcd50da1872d4dbca8312551159e72e3d 172.28.254.27:7006
slots: (0 slots) slave
replicates bb73c60e00c4ebd4ac33db0542ec684a8d201d8e
S: d277d6288442806f4893a9ae51ff792b6326a656 172.28.254.27:7005
slots: (0 slots) slave
replicates c261ce0177a72e0007f4903f8ce5f6e3bee0294f
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
六、验证集群创建
集群中任一节点均可查看集群状态和信息;
- redis-cli(Redis-5)
#查看集群状态:
[root@redis01-server ~]# redis-cli -a abc123 -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:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:725
cluster_stats_messages_pong_sent:738
cluster_stats_messages_sent:1463
cluster_stats_messages_ping_received:733
cluster_stats_messages_pong_received:725
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1463
#查看 Node 对应关系:
127.0.0.1:7001> CLUSTER NODES
bb73c60e00c4ebd4ac33db0542ec684a8d201d8e 172.28.254.221:7001@17001 myself,master - 0 1650545949000 1 connected 0-5460
c261ce0177a72e0007f4903f8ce5f6e3bee0294f 172.28.254.221:7002@17002 master - 0 1650545950551 2 connected 10923-16383
d2d369de207775a5f2e13f3580037b8acb53eeff 172.28.254.221:7003@17003 slave 27581beea51e7b6e1052ef3675dac6647fdb8355 0 1650545949344 4 connected
27581beea51e7b6e1052ef3675dac6647fdb8355 172.28.254.27:7004@17004 master - 0 1650545948840 4 connected 5461-10922
66d4816fcd50da1872d4dbca8312551159e72e3d 172.28.254.27:7006@17006 slave bb73c60e00c4ebd4ac33db0542ec684a8d201d8e 0 1650545950555 1 connected
d277d6288442806f4893a9ae51ff792b6326a656 172.28.254.27:7005@17005 slave c261ce0177a72e0007f4903f8ce5f6e3bee0294f 0 1650545949854 2 connected
127.0.0.1:7001> exit
#检查检点
[root@redis-server ~]# redis-cli -a abc123 --cluster check 172.28.254.221:7001
172.28.254.221:7001 (bb73c60e...) -> 0 keys | 5461 slots | 1 slaves.
172.28.254.221:7002 (c261ce01...) -> 0 keys | 5461 slots | 1 slaves.
172.28.254.27:7004 (27581bee...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
... ... ...
- redis-trib.rb 指定集群中的任一节点均可查看集群的状态信息;
#查看集群信息:
[root@redis01-server ~]# redis-trib info 172.28.254.221:7001
#检查集群状态:
[root@redis01-server ~]# redis-trib check 172.28.254.221:7001
- 查看集群配置文件
[root@redis01-server ~]# ]# cat /data/redis/7001/nodes_7001.conf
bb73c60e00c4ebd4ac33db0542ec684a8d201d8e 172.28.254.221:7001@17001 myself,master - 0 1650545543000 1 connected 0-5460
c261ce0177a72e0007f4903f8ce5f6e3bee0294f 172.28.254.221:7002@17002 master - 0 1650545541561 2 connected 10923-16383
d2d369de207775a5f2e13f3580037b8acb53eeff 172.28.254.221:7003@17003 slave 27581beea51e7b6e1052ef3675dac6647fdb8355 0 1650545543569 4 connected
27581beea51e7b6e1052ef3675dac6647fdb8355 172.28.254.27:7004@17004 master - 0 1650545543000 4 connected 5461-10922
66d4816fcd50da1872d4dbca8312551159e72e3d 172.28.254.27:7006@17006 slave bb73c60e00c4ebd4ac33db0542ec684a8d201d8e 0 1650545543569 1 connected
d277d6288442806f4893a9ae51ff792b6326a656 172.28.254.27:7005@17005 slave c261ce0177a72e0007f4903f8ce5f6e3bee0294f 0 1650545543000 2 connected
vars currentEpoch 6 lastVoteEpoch 0
七、测试集群读写
- 集群数据写入 172.28.254.221:7001节点上尝试写入:
提示 foo1 这个 key 的 CRC 结果被调度到了 13431 槽位,该槽位在 172.28.254.221:7002 节点上;
[root@redis01-server ~]# redis-cli -a abc123 -p 7001
127.0.0.1:7001> SET foo1 bar1
(error) MOVED 13431 172.28.254.221:7002
172.28.254.221:7002节点 写入 foo1:
[root@redis01-server ~]# redis-cli -a abc123 -p 7002
127.0.0.1:7002> SET foo1 bar1
OK
127.0.0.1:7002> KEYS foo1
1) "foo1"
各节点只保存各自槽位的数据,所以 7001 和 7003 都没有刚刚写入的 foo1:
[root@redis01-server ~]# redis-cli -a abc123 -p 7003
127.0.0.1:7003> KEYS foo1
(empty array)
- 集群数据读取 因为各节点只保存各自槽位的数据,所以数据的读取也只能到相应的节点上进行; 而且集群中的 Slave 节点,读写服务均不提供;
查看 172.28.254.221:7002 的 Slave 节点:
172.28.254.221:7002 的 ID 为:c261ce0177a72e0007f4903f8ce5f6e3bee0294f; 可以查到对应的 Slave 为 172.28.254.27:7005;
[root@redis01-server ~]# cat /data/redis/7002/nodes_7002.conf |grep 'c261ce0177a72e0007f4903f8ce5f6e3bee0294f'
c261ce0177a72e0007f4903f8ce5f6e3bee0294f 172.28.254.221:7002@17002 myself,master - 0 1650545541000 2 connected 10923-16383
d277d6288442806f4893a9ae51ff792b6326a656 172.28.254.27:7005@17005 slave c261ce0177a72e0007f4903f8ce5f6e3bee0294f 0 1650545541000 2 connected
到 172.28.254.27:7005 读取刚刚写入到 172.28.254.221:7002 的 foo1: 可以查到有 foo1 的数据,但是读取还是得到 172.28.254.221:7002 上;
[root@redis02-server ~]# redis-cli -a abc123 -p 7005
127.0.0.1:7005> KEYS foo1
1) "foo1"
127.0.0.1:7005> GET foo1
(error) MOVED 13431 172.28.254.221:7002
八、集群扩容
[详情参考博客] https://www.cnblogs.com/PatrickLiu/p/8473135.html
#新增Master主节点
redis-cli --cluster add-node 120.78.204.98:9007 120.78.204.98:9001
#为新节点分配槽位
redis-cli --cluster reshard 120.78.204.98:9007
#新增Slave从节点
##将9008端口redis实例添加为cluster集群中9007端口redis实例的从节点
redis-cli --cluster add-node 120.78.204.98:9008 120.78.204.98:9007 --cluster-slave
九、Cluster集群删除操作
#删除的顺序是先删除Slave从节点,然后在删除Master主节点
##1、动态删除Slave从服务器节点
redis-cli --cluster del-node 192.168.127.130:7007 991ed242102aaa08873eb9404a18e0618a4e37bd
#2、动态删除Master主服务器节点
#要想删除Master主节点,可能要繁琐一些。因为在Master主节点上有数据槽(slots),为了保证数据的不丢失,必须把这些数据槽迁移到其他Master主节点上,然后在删除主节点。
##2.1、重新分片
##把要删除的Master主节点的数据槽移动到其他Master主节点上,以免数据丢失。
redis-cli --cluster reshard 192.168.127.130:7006
##将此节点的槽重新分配给其他节点后再删除
redis-cli --cluster del-node 192.168.127.130:7006 71ecd970838e9b400a2a6a15cd30a94ab96203bf
十、SpringBoot整合Redis-Cluster
1、Pom文件新增依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2、新增配置
#集群节点
spring.redis.cluster.nodes=120.78.204.98:9001,120.78.204.98:9002,120.78.204.98:9003,120.78.204.98:9004,120.78.204.98:9005,120.78.204.98:9006
#最大重定向数
spring.redis.cluster.max-redirects=6
# 连接池最大连接数(使用负值表示没有限制) 默认为8
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1
spring.redis.jedis.pool.max-wait=-1ms
# 连接池中的最大空闲连接 默认为8
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接 默认为 0
spring.redis.jedis.pool.min-idle=0