Redis高可用集群
一、Redis主从复制
info replication
#查看主从复制状态从节点配置
动态配置
REPLICAOF 192.168.1.1 6379
#配置主节点IP和端口
CONFIG SET masterauth PassWord
#配置主节点密码配置文件REPLICATION部分
replicaof 192.168.1.1 6379
masterauth PassWord配置后重启从节点redis服务。
取消从节点
replicaof no one
#取消从节点取消后数据还存在,自身的身份变为主节点。
主从复制故障恢复
当slave节点故障时,将redis client指向另一个slave节点。
master_link_status:up
master_last_io_seconds_ago:2
#从节点状态正常
master_link_status:down
master_last_io_seconds_ago:-1
master_link_down_since_seconds:8
#从节点状态错误。当master节点故障时,需要提升slave为新的master节点。
手动方式
将要提升的从节点断开主从,重新成为主节点;将其他子节点重新指向新提升的主节点。
replicaof no one
#提升从节点
replicaof 192.168.1.1 6379
#从节点重新指向新提升的从节点,密码不变。级联复制
三级从节点指向二级从节点,二级从节点指向主节点。
二级从节点即是一个从节点,同时也有子节点。
主节点只和一个从节点进行交互,可以降低负载。
主从复制的过程
主从复制分为全量复制和增量复制。
主从同步是非阻塞的,有专门用于注册复制的线程。
- 从节点向主节点发送psync指令。
- 主节点发送全量同步指令,发送replid号和offset(偏移量)。
- 从节点保存 masterinfo (runid和offset)。
- 主节点执行bgsave快照并保存。同时如有持续写入数据,将放进buffer中。如果buffer满了就放进RDB文件中。
- 发送RDB给从节点。
- 发送buffer给从节点。
- 从节点清除旧数据。
- 从节点加载RDB文件。
从节点断开
- 主节点写入buffer区。
- 从节点恢复连接,向主节点发送offset和runid。
主节点向从节点发送增量部分数据。
如果断开时间过长,buffer存满后会写入RDB中。再次连通则会触发全量复制。
buffer区的大小设置
环形队列
repl-backlog-size 1mb
#buffer区的大小,默认值为1M。
repl-backlog-ttl 3600
#指定时间内若无从节点连接,则backlog size内存空间会被释放,若永不释放则设置为0。计算公式
repl-backlog-size = 允许从节点断开时长 * 主节点offset每秒写入量
例:master每秒写入量为64MB,最大允许断开60秒,设置buffer空间为3840MB.
避免全量复制
- 小主节点即小内存,则全量复制较快。
- 节点运行ID不匹配,若主节点重启,runid变化则会触发全量复制。runid变化,从节点认为的新主节点,会清理全部数据,重新全量复制。
- 环形队列缓冲区空间不足。
避免复制风暴
单主节点复制风暴
解决方案:级联复制,可减少复制流量。缺点:存在复制延迟。
单机多实例
机器宕机后大量全量复制。
解决方案:主节点分散到多台机器,错开复制。
主从复制优化设置
性能相关配置
repl-diskless-sync no
#是否使用无盘方式同步RDB文件,默认为no。
#RDB文件不保存到磁盘,直接通过网络发送给slave。
repl-diskless-sync-delay 5
#无盘时复制的服务器等待时间
repl-ping-slave-period 10
#slave向master发送ping指令的时间间隔,默认为10秒。
repl-timeout 60
#指定ping连接超时时间,若超过此值,master_link_status变为down,并记录错误日志。
repl-disable-tcp-nodelay no
#是否启用TCP nodelay
#若为yes则redis会将多个小TCP包合并为一个大包再发送,以节约带宽,但会造成延迟。
#若为no则master会立即同步数据。
repl-backlog-size 1mb
#设置环形队列buffer区大小。
repl-backlog-ttl 3600
#超过指定时间无slave连接,则释放buffer内存空间。
slave-priority 100
#slave参选master的优先级,数值越小越高。
#若值为0,则永远不参与选举。
min-reaplicas-to-write 1
#master的可用从节点不能少于此值,否则master将无法执行写入操作。默认为0,生产建议为1。
min-slave-max-log 20
#slave延迟大于此值时,则主节点不能执行写入操作(配合min-reaplicas-to-write配置使用)。常见主从复制故障
主从配置不同
- 主节点内存比从节点大,导致从节点数据溢出。
- rename-command命令不一致。例如主节点命令可用,但从节点命令禁用,导致无法同步。提示:未知命令。
- master错误:密码错误。
- redis版本不一致,4与5差别较大。至少大版本一致。
- 安全模式下。redis在保护模式下:既没有设置密码也没有绑定端口(在配置文件中注释掉),则会无法连接。
二、sentinel-哨兵模式
sentinel解决故障转移,同时监控多组主从复制。
sentinel本身也需要多个节点,大于等于3个且正好为奇数。
可以同时监控多组redis组从节点。
故障转移流程
客户端不再直接连接redis,先连接sentinel,再连接sentinel返回的redis节点。
- 多个sentinel发现并确认master存在问题。
- 选举出一个sentinel作为领导。
- 选出一个slave作为master
- 通知其余slave成为新matser的slave。
- 通知客户端主从变化。
- 等待老的master复活成为新master的slave
实现原理
Sentinel是一个分布式系统,运行在多个节点上。Sentinel进程通过流言协议(Gossip protocols)接收关于Master是否下线的状态信息。并使用投票协议(Agreement Protocols)来决定是否执行自动故障转移,并选择合适的Slave作为新的Master。
每个Sentinel进程定时向其他Sentinel、Master、Slave节点发送消息,确认对方是否存活。若发现某个节点在指定时间内未响应,则会认为此节点已离线,即为主观宕机(Subjective Down),简称SDOWN。
如果哨兵集群中的多数Sentinel节点进程认为Master存在SDOWN,共同利用is-master-down-by-addr命令互相沟通后,则认为客观宕机(Objectively Down),简称ODOWN。
接下来利用投票算法,从所有Slave节点中,选一台合适的Slave将之提升为Master节点,然后自动修改其他Slave相关配置,指向新的Master,最终实现故障转移Fallover。
定时任务
每10秒每个sentinel对master和slave执行info
- 发现slave节点
- 确认主从关系。
每2秒每个sentinel通过master节点的channel交换信息(pub/sub)
- 通过sentinel_:hello频道交互
- 交互对节点的看法和自身信息
- 每1秒每个sentinel对其他sentinel和redis执行ping
部署哨兵架构
sentinel使用redis相同的程序,使用不同的配置文件,默认监听端口26379。
sentinel配置项
bind 0.0.0.0
port 26379
daemonize yes
pidfile /usr/local/redis/run/redis-sentinel.pid
logfile /usr/local/redis/log/redis-sentinel.log
sentinel monitor mymaster 192.168.1.1 6379
sentinel auth-pass mymaster password
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
注册systemctl
[Unit]
Description=Redis Sentinel
After=network.target
[Service]
ExecStart=/usr/local/redis/bin/redis-sentinel /usr/local/redis/etc/sentinel.conf --supervised systemd
ExecStop=/bin/kill -s QUIT
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target验证
redis-cli -p 26379
info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.3.60:6379,slaves=2,sentinels=3手动下线主节点
修改优先级(如果需要)
slave-priority 100再手动下线主节点
sentinel failover mymaster集群名切换当前的集群主节点。
应用程序连接sentinel
程序编写时不是直接连接redis,而是使用专门的库连接sentinel。
客户端先连接到sentinel的集合,查询masterName。
sentinel返回master节点,客户端会再次确认返回的redis节点的role。
确定role是master,进行连接。
客户端会订阅节点频道,获取新的主节点变化。
三、redis cluster 集群
分布式集群
数据分布在多个redis主机,同时对外提供服务,提高性能。
早期的解决方案数据分区
客户端分区:人为分区,客户端将数据分别写入。
代理服务:第三方代理实现。
redis3.0后的版本
无中心架构redis cluster,支持多节点并行写入和故障自动转移功能。
用户写入数据,每个master负责不同的槽位区间。
hash slot
16384个槽位
0-16383之间
节点M1 0-5460
节点M2 5461-10922
节点M3 10923-16383
分布方式 顺序分布 哈希分布
数据分散度 分布倾斜 分布散列
顺序访问 支持 不支持
CRC16(key) --> 获得值 --> 值%16384(取模) --> 数值区间
cluster集群部署
bind 0.0.0.0
masterauth password
requirepass password
cluster-enabled yes
#开启集群,开启后进程会有cluster标识。
cluster-config-file nodes-6379.conf
#集群状态文件,记录主从关系即solt范围信息。由reids cluster集群自动创建和维护。
cluster-require-full-coverage no
#设置为no,若cluster的一组节点宕机,剩余的节点继续提供服务。默认为yes,默认情况下整个cluster将不可用。ps axu|grep redis
redis-server 0.0.0.0:6379 [cluster]
#已启用集群会有cluster标志建立集群
redis-cli -a password --cluster create 192.168.3.60:6379 192.168.3.61:6379 192.168.3.62:6379 192.168.3.63:6379 192.168.3.64:6379 192.168.3.65:6379 --cluster-replicas 1执行命令后查看各节点的角色,确认正确后输入yes继续。(在本例子中是3个M节点,3个S节点)
查看cluster信息
cat redis/data/nodes-6379.conf扩容集群
添加新的主节点
redis-cli -a password --cluster add-node 新节点的ip:端口 现有任一节点ip:端口
redis-cli -a password --cluster add-node 192.168.3.66:6379 192.168.3.60:6379添加从节点进集群,并同时指定主节点。
redis-cli -a password --cluster add-node 新节点的ip:端口 现有任一节点ip:端口 --cluster-slave --cluster-master-id 欲指定的主节点ID
redis-cli -a password --cluster add-node 192.168.3.67:6379 192.168.3.60:6379 --cluster-slave --cluster-master-id dd6acd798baf8cca87c5c664c8a854a0c04d6b91重新组织槽位
redis-cli -a password --cluster reshard 192.168.3.60:6379
提问需要移动多少个槽位
4906
提问接收槽位的节点ID
dd6acd798baf8cca87c5c664c8a854a0c04d6b91
提问槽位来源:
all 平均自动转移槽位
或者>>
输入源节点ID
程序列出槽位转移的计划提问是否执行?
执行yes
缩容集群
缩容前转移槽位,需要手动移动多次,平衡地移动到其他主节点上去。
redis-cli -a password --cluster reshard 192.168.3.60:6379
提问需要移动多少个槽位
4906
提问接收槽位的节点ID
dd6acd798baf8cca87c5c664c8a854a0c04d6b91
提问槽位来源:
输入源节点ID
程序列出槽位转移的计划提问是否执行?
执行yes删除节点
redis-cli -a password --cluster del-node 现有任一节点ip:端口 欲删除节点的ID
redis-cli -a password --cluster del-node 192.168.3.60:6379 dd6acd798baf8cca87c5c664c8a854a0c04d6b91 从cluster中删除一个有从节点的主节点后,从节点会重新匹配主节点,形成多从。
导入数据到新cluster集群中
redis-cluster import
1.关闭redis密码
关闭相关全部redis的密码,包括集群和集群外源主机。
redis-cli -h 192.168.0.60 -p 6379 -a password --no-auth-warning CONFIG SET requirepass ""2.执行导入命令
redis-cli --cluster import <集群服务器IP:PORT> --cluster-from <外部redisIP:PORT> --cluster-copy --cluster-replace执行这个导入命令时,如果节点有密码,因为不是交互式的,所以无法验证。需要事先删除密码。
集群偏移
槽位是均匀的,但是数据不一定均匀,因此存在偏移。
redis-cli cluster countkeysinslot <槽位值>
#获取指定槽位的key数量自动均匀
redis-cli -a password --cluster rebalance 192.168.3.60:6379列出big key
redis-cli -a password --bigkeyscluster局限性
1.从节点不能读写。尝试连接从节点时也会被重定向。
2.读写分离复杂,需要手动维护对应关系。
3.不建议在集群模式下构建读写分离,通过增加节点来解决需求。
4.客户端过多性能会降低,因为可能会重定向。
5.部分命令不支持。mget、keys、scan、flush、sinter等
6.不支持多库
7.复制只支持一层
8.key和Lua支持有限,操作的key必须在一个节点上,Lua和事务无法跨节点使用。