版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/njys1/article/details/82795884
- 复制
- 复制优化
- sentinel
- cluster
复制
info replication 检测复制关系
master_replied 标记主实例
master_repl_offset 是复制流中的一个偏移量标记、会随着主实例上的数据事件的发生而增长
完全同步:
将所有数据复制到rdb文件、然后发送给从实例、
从实例接收到rdb文件后、会先将内存的数据清空、然后回访rdb数据
从实例的复制过程是异步的、不会阻塞服务器处理客户端的请求
部分重新同步:
redis4.0之后的版本、master_replid和offset会存储在rdb文件中、
从实例被优雅的关闭和重启后、redis可以从rdb文件中重新加载它们的值、进行部分重同步
从实例被提升为新主后、新主会记录旧主的这两个值、实现部分重同步
复制优化
1. 在redis主实例与从实例不能同步的时候、主实例上的一段内存(一个环形缓冲区)会跟踪最近写入的所有命令、实际上是一个固定长度的列表(也即:replication backlog、默认1MB)
2. 在发出slaveof命令后、从实例使用最新的一个offset和最近一个master的id向新主实例发送
部分重新同步请求、新主会检测请求中的master_replid是否与自己的master_replid一致、
然后会检测请求中的offset是否可以从backlog缓冲中获取、可以的话、意味着backlog中包含连接
断开期间的所有命令、可以进行部分同步
3. 否则、说明在连接断开期间收到的写入命令数量超过了backlog的容量、部分同步请求会被拒绝、同时启动完全同步
4. repl-backlog-ttl 默认3600
若所有的从实例与主实例断开连接、过多久释放backlog的内存
5. 从网络传输的角度看、还可以使用 repl-disable-tcp-nodelay 来减少带宽使用
设为yes、redis会尝试将小数据包合并、但是也会造成数据延迟、约40ms
6. repl-diskless-sync yes可以不使用rdb文件存储、直接将rdb的内容发送给从实例
这个参数目前是实验阶段、不稳定、需要小心使用~~
7. redis的键过期是由主实例来驱动的、当主实例中的键过期时、会向所有的从实例发送del命令、
在同步期间、del命令也会被放到复制客户端缓冲区中
sentinel
故障迁移过程:
1. 一个哨兵发现主实例不可用、
每个哨兵会定期向主实例、从实例及其他哨兵发送ping命令、若超时、认为服务不可用(主观下线)
标记主实例下线的哨兵会向其它哨兵发送请求、要求他们检查主实例的状态、只有超过一定值的哨兵(哨兵数/2+1)认为
主实例下线、才会发生故障转移、
执行故障转移是由leader哨兵来进行的
2. 如何进行leader选举呢 ?
一个哨兵标记主实例主观下线后、投票开始、哨兵会开始从其它哨兵那里征集选票、另一个哨兵接到拉票请求时、若还未投票、则响应请求、 若哨兵从其它哨兵处得到足够数量的选票、则会成为leader
3. sentinel管理
sentinel get-master-addr-by-name <master-name> 获取当前主实例的信息
sentinel masters 获取所有被监控实例的状态
sentinel slaves <master-name> 获取一个主实例的所有从实例
sentinel set 更新哨兵配置
eg. sentinel set mymaster notification-script mymaster /redis/script/sentinel_events_notify.sh
然后再 bash 脚本里边实现想要的功能、当然可以是其它任意类型的脚本
另外还可以配置redis sentinel在故障迁移发生时自动执行的脚本、
eg. 我们可能希望在故障迁移时禁用主实例上的 RDB 持久化选项、在从实例上启用、
当主实例发生故障时被降为从实例、这个从实例的配置不能被哨兵更新、因此、除非我们手动更新该从实例上的rdb功能、否则它一直会是启用状态
eg. sentinel set mymaster notification-script mymaster /redis/script/rdb_control.sh
在脚本里实现配置修改的功能
脚本执行成功返回0、若返回值为1、则脚本会被重试10次、
若一个脚本60s内未执行完、会被sigkill信号结束掉、并重试10次
若脚本的返回值为1 、则不会重试
切换新主、是通过向选定的新主发送slave of none命令来实现的
如何选定?日志最新的slave、也就是尽量的保障数据的完整性
cluster
1. redis集群运行时、每个节点会打开两个TCP套接字、
第一个套接字是用于客户端连接的标准redis通信协议、
第二个是 第一个 + 10000(硬编码)
#define CLUSTER_PORT_INCR 10000 /*Cluster port = baseport + PORT_INCR */
被用作实例间信息交换的通信总线、所以、监听端口大于 55535 的redis集群节点是不能启动的
2. cluster meet命令可以让redis示例发现彼此
3. 总的可以分配的数据槽的数量为 16384
#define CLUSTER_SLOTS 16384
分配时不可超过该值、否则会报错:
ERR Invalid or out of range slot
cluster.c:4022: addReplyError(c,"Invalid or out of range slot");
若遇到已分配过的槽、也会报错: ERR Slot {{id}} is already busy
cluster.c:4180 - 4183
if (!del && server.cluster->slots[slot]) {
addReplyErrorFormat(c,"Slot %d is already busy", slot);
zfree(slots);
return;
}
4. cluster nodes可以查看主从复制的状态、或者直接使用cluster info
集群管理:
获取集群状态:cluster info
eg. redis-cli -h 127.0.0.1 -p 63790 -c cluster info
获取集群中节点状态:cluster nodes
eg. redis-cli -h 127.0.0.1 -p 63790 -c cluster nodes
添加主从实例:cluster meet
eg. redis-cli -h 127.0.0.1 -p 63790 -c cluster meet
若添加一个节点的时候、提示该节点已有一些数据存在火灾节点配置文件已存在、
[ERR] Node .. is not empty. Either the node is already knows ...