主从复制:将数据从一台机复制到另一台机。前者为主节点(master),后者为从节点(slave);数据的复制是单向的,只能从主节点到从节点。
默认情况下,每台Redis服务器都是主节点,一个主节点可以有多台从节点,一个从节点只能有一个主节点。
一、Redis主从复制作用
复制是单向的,复制就会带来数据一致性问题,无可避免,尽量缩短。
- 数据冗余:实现了数据的热备,是持久化之外的一种数据冗余方式。
- 故障恢复:当主节点出现问题时,可以切换到从节点提供服务,实现故障恢复;实际上是一种服务的冗余。
- 负载均衡:读写分离,主写从读,分担服务器负载;在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。但读写分离是对于有磁盘IO阻塞,redis作为缓存可以不用考虑。Redis集群的redis-proxy按权重将读写请求转发到master或者某个read-only replica上。
- 高可用基石:主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
二、Redis复制连接建立/断开
1、建立复制连接
主从复制需要在从节点发起,不需要在主节点做任何事情,有三种方式:
- 配置文件:在从服务器的配置文件中加入slaveof masterip masterport
- 启动命令:redis-server启动命令(redis-server ./redis.conf)后加入 --slaveof
- 客户端命令:redis-cli客户端执行命令slaveof masterip masterport,则该Redis实例成为从节点;slaveof是异步命令,所以保存主节点ip和port后直接返回OK,然后再执行复制操作。
2、断开复制连接
通过slaveof no one断开,从节点断开链接,不会删除已有的数据,只是不再接受主节点新的数据变化。清除保存的主库的runid,当下一次执行slaveof [IP] [PORT]时就是“是第一次执行复制”。Redis从节点默认是readonly(只读)模式,当断开连接salveof no one就会解除节点只读模式,从节点变回为主节点。
3、服务器运行ID(runid)
每个Redis节点(无论主从),启动时都会自动生成一个随机ID(每次启动都不一样),由40个随机的十六进制字符组成;runid用来唯一识别一个Redis节点。通过info Server命令,可以查看节点的runid。
- 主从节点初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来;当断线重连时,从节点会将这个runid发送给主节点;主节点根据runid判断能否进行部分复制:
- 如果从节点保存的runid与主节点的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);
- 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制。
主从复制的三个阶段
连接建立阶段(即准备阶段)、数据同步阶段、命令传播阶段;
三、连接建立阶段
主从节点之间建立连接。
1、保存主节点信息
从节点执行slaveof 异步命令,存储主节点的ip和port信息,由于slaveof命令是异步命令,客户端直接返回OK。
2、建立socket连接
从节点的复制定时函数replicationCron()每秒调用1次,发现主节点可以连接,便会根据主节点的ip和port,创建socket连接,连接成功后:
从节点:为该socket建立一个专门处理复制工作的文件事件处理器,负责后续的复制工作,如接收RDB文件、接收命令传播等。
主节点:接收到从节点的socket连接后(即accept之后),为该socket创建相应的客户端状态,并将从节点看做是连接到主节点的一个客户端,后面的步骤会以从节点向主节点发送命令请求的形式来进行。
3、发送ping命令
从节点成为主节点的客户端之后,发送ping命令进行首次请求:检查socket连接是否可用,以及主节点当前是否能够处理请求,返回结果说明:
- 返回pong:socket连接正常,主节点可以处理请求,复制过程继续。
- 超时:一定时间后从节点仍未收到主节点的回复,说明socket连接不可用,则从节点断开socket连接,并重连。
- 返回pong以外的结果:如果主节点返回其他结果,如正在处理超时运行的脚本,说明主节点当前无法处理命令,则从节点断开socket连接,并重连。
4、身份验证
requirepass:对登录权限做限制,redis每个节点的requirepass可以是独立、不同的。使用密码来保护 R