上一篇:Redis 系列11--Redis 持久化_fengxianaa的博客-优快云博客
单节点的redis,并发能力是有上限的,要进一步提高,就需要搭建集群,读写分离
1. 准备
切换到 /root/soft/redis 目录,删除不需要的文件,保留下下面几个文件即可
在 /root/soft/redis 目录 创建3个文件夹:7001、7002、7003
复制 redis.conf 文件到 7001、7002、7003 文件夹,执行下面的命令
echo 7001 7002 7003 | xargs -t -n 1 cp redis.conf
在 7001、7002、7003 下,分别建立 db 和 logs 目录
修改配置文件,以 7001 为示例
# 端口 port 7001 # 进程文件 pidfile /var/run/redis_7001.pid # 日志文件,需要提前建好logs文件夹 logfile /root/soft/redis/7001/logs/redis.log # 持久化文件目录,需要提前建好logs文件夹 dir /root/soft/redis/7001/db # aof暂时关掉 appendonly no # rdb也暂时恢复到默认配置 # 虚拟机有多个ip,为了避免混乱,为主从通信,绑定一个ip replica-announce-ip 192.168.56.103
7002 、7003 类似
2. 主从
让 7002、7003 作为 7001 的从节点
修改 7002 、7003 的配置文件
replicaof 192.168.56.103 7001
注意,redis 5.0之前的版本叫 slaveof
然后分别启动
可以看到启动成功3个 redis 实例
查看集群状态
测试数据同步
在 7001 实例 设置一个key
在 7002 实例可以获取到这个key
而且,默认情况下,从节点不能写
对应的 配置
3. 数据同步机制
1. 第一次同步,全量同步
第一阶段
- slave 启动时,与 master 建立连接,并请求数据同步
- slav建立连接时候会发送 runId 和 offset
- offset:数据偏移量,第一次连接是-1,表示全量同步
- runId :master的唯一标示,redis 在启动的时候,都会为自己生成一个ID,第一次salve传一个“?”
- slav建立连接时候会发送 runId 和 offset
- master 会判断这个 slave 是不是第一次连接
- 是:会把offset 和 runId 发给 slave ,slave会保存这个信息
第二阶段
- 然后 master 生成一个rdb,发送给 slave,slave拿到后清空本地数据,加载rdb文件
- master 生成rdb的时候,正常接收客户端请求,会把命令记录到 replication_buffer 中(也叫复制缓冲区)
第三阶段
- master 发送 replication_buffer 中的命令 , slave接到后执行,全量同步完毕
2. 增量同步
一般情况下,当 slave 故障,重启后,会做增量同步
主从正常同步的时候,master会把命令写到 replication_buffer 中,
同时也会写在 replication_backlog_buffer 中(也叫:复制积压缓冲区,默认1M大小)
当 slave 断开,又重新连接的时候,master 会根据 offset ,从 repl_backlog 中获取增量数据给 slave
但是repl_backlog的大小有上限,写满后,新来的数据会覆盖最早的数据,如果 slave 断开时间太久,导致一部分数据还没有同步就被覆盖了,就只能最全量同步
3. replication_buffer 和 replication_backlog_buffer
- replication_buffer:复制缓冲区
- Master 会为每一个 Slave 生成一个这样的缓冲区,因为每个 Slave 同步的进度是不一样的,所以要分别设置(传说 redis 7.0 在解决这个问题)
- 只要一个Slave和Master 建立好连接,这个缓冲区就会建立,如果断开连接,那么这个缓冲区就会释放
- 主从库之间复制命令的传输,都会经过这个buffer
- buffer 配置:client-output-buffer-limit replica 256mb 64mb 60
- 含义:当60s内缓冲区持续大于64MB或者直接超过256MB时,master直接关闭复制客户端连接
- 实验:redis.conf 中 client-output-buffer-limit replica 1mb 1mb 60,然后客户端一次存储超过1MB的数据,比如:
byte[] arr = new byte[1024 * 1024];//大概3M多 stringRedisTemplate.opsForValue().set("fengxiansheng", Arrays.toString(arr));
- 结果:buffer 溢出,slave 断开,然后重新申请同步
-
- 请注意,上图中有:Unable to partial resync with replica 192.168.56.103:7002 for lack of backlog
- 解释:由于缺少积压工作,无法与副本192.168.56.103:7002部分同步,
- 这是因为我repl-backlog-size 配置的是 1mb,而放入了3M多的数据,所以replication_backlog_buffer产生覆盖
- 这是因为我repl-backlog-size 配置的是 1mb,而放入了3M多的数据,所以replication_backlog_buffer产生覆盖
- replication_backlog_buffer:复制积压缓冲区
- Master 只要有 Slave 就会建立这个buffer,所有 slave 共享
- slave 断开,又重新连的时候,master 会根据 slave 提交的offset ,从 buffer 中获取增量数据
- 如果 slave 提交的offset,在 buffer 找不到,就全量同步
- buffer 配置:repl-backlog-size 1mb
- 实验:修改配置,repl-backlog-size 100mb,然后再次运行代码
-
- 可以看到 slave 一直在断开重连,每次重连都从 offset 127的地方同步数据
- 解释:client-output-buffer-limit 配置的是 1mb,而增量同步需要同步 3145796 bytes,所以会导致一直断开重连,但是这也证明了 slave 断开重连后 提交 offset ,增量同步
-
- 注意:这时候要杀掉redis进程,否则日志会一直疯狂增长
测试增量同步:修改 client-output-buffer-limit 为 10mb , 然后重启 7001 7002
仿照下图,随便设置几个值,目的是为了让 7002 实例 记录一下offset
然后把 7002 kill 掉
然后执行代码,再重启7002,查看日志,如下
3. 同步优化
- 在 master 中配置 repl-diskless-sync yes,无磁盘化复制
- master 会直接在内存中创建 rdb ,然后发送给 slave,不会落在本地磁盘上
- Redis 单节点的内存在用不要太大,减少RDB产生的磁盘IO
- 提高 replication_backlog_buffer 的大小,slave 宕机时尽快恢复,避免全量同步
- 提高 replication_buffer 大小,正常同步阻塞时候,避免溢出
- 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力,如下图