引言
Redis是一款基于内存、键值对的非关系型数据库,它的性能十分的优秀,但单机节点的Redis还是存在许多不足的功能
单机无法保证高可用性,当单机Redis宕机时,无法继续提供服务,在主从架构 + 哨兵模式下能够解决无法保证高可用的问题
主从架构的前提就是主从节点间的数据同步(主从复制),主从复制是高可用的基础,本篇文章将深入浅出的解析主从之间数据的复制
注意:观看本篇文章需要了解RDB的持久化方式深入浅出Redis(四):Redis基于RDB、AOF的持久化
主从架构
主从架构指的是主节点负责处理写命令,从节点负责处理读命令
主从复制指的是主节点向从节点同步数据
- 主从架构的特点
- 读写分离:写命令主节点处理、读命令从节点处理,每个节点有不同的职责,减轻主节点压力
- 负载均衡:当从节点有多台时,可以负载均衡的处理读命令,减取各个节点的压力
- 故障恢复:当主节点发生宕机时,从节点可以取代主节点成为新的主节点,提供服务(高可用基石,哨兵和集群都使用)
- 数据冗余:从节点中的数据都是主节点的冗余数据
注意本篇文章主要介绍主从架构与主从复制原理,故障恢复功能将在后续哨兵、集群中的文章中介绍
主从复制
主从复制的使用
连接
- 从节点客户端发送命令
slaveof 主节点IP 主节点端口
- 启动从节点时携带参数
redis-server -slaveof 主节点IP 主节点端口
- 从节点配置文件(常用)
slaveof 主节点IP 主节点端口号
masterauth 主节点密码
断开
在从节点上使用slaveof on one
命令断开
断开连接后,从节点没同步主节点新增加的数据
主从复制原理
主从复制的大体流程可以分为两个步骤
- 建立连接:从节点需要发起请求与主节点建立连接
- 数据复制:数据复制有两种模式,可能通过RDB文件进行数据复制也可能通过传输写命令进行
- 命令传播:通过持续通信(携带命令)的方式进行实现数据一致性
接下来将会展开详细说明三个重要步骤
建立连接
从节点发起建立连接命令,主节点接收建立连接并验证身份,双方保存信息的过程
建立连接流程
- 从节点发送命令
slaveof 主节点IP 主节点端口号
,主节点收到响应后,从节点保存主节点IP、端口信息 - 从节点根据保存主节点的IP、端口信息建立socket连接
- 周期性的ping、pong测试网络通畅
- 从节点根据配置文件中配置的
auth password
向主节点进行身份验证,主节点根据自己配置文件的auth password
进行验证授权 - 从节点验证通过后发送命令
replconf listening-port 从节点端口号
,主节点接收并保存从节点IP、端口等信息
建立连接阶段主要是从节点向主节点请求建立连接,从节点保存主节点的IP,端口号等信息,主节点验证从节点身份,保存从节点IP,端口号等信息
数据复制
在重点介绍数据的复制原理前,先说明几个重要的信息
runid: 节点唯一标识,用于判断主节点是否改变的字符串,重启会改变
复制缓冲区: 主节点会使用复制缓冲区记录序列化后写命令操作(复制缓冲区是有一定范围的,超过范围则会覆盖之前的偏移量)
offset: 代表复制缓冲区上的偏移量(如果主节点收到从节点带来的offset不在复制缓冲区中说明需要使用RDB文件来进行数据恢复)
数据复制流程
- 数据同步时,从节点使用
psync runid offset
命令进行同步,向主节点发送psync ? -1
- 主节点接收到命令,判断到offset不在当前复制缓冲区中,执行
bgsave
生成RDB文件后,将RDB文件、runid、offset等信息通过套接字发送给从节点 - 从节点收到后,保存主节点runid、offset等信息,清空数据库数据,使用RDB文件进行数据恢复
- 从节点恢复完数据(在此期间主节点还可能处理写命令,为了保持数据一致性)向主节点发送
psync runid offset
runid、offset是上次保存的信息 - 主节点收到命令后,根据情况发送RDB文件的方式或发送写命令的方式进行数据恢复
- 先判断runid是不是自己的runid,如果不是说明在此期间主节点已经更换,使用RDB文件方式(步骤2)进行数据恢复
- 如果runid相同则继续判断offset是否存在当前复制缓冲区,如果不存在说明在此期间接收到太多的写命令,也要使用RDB方式(步骤2)进行数据恢复
- 如果在复制缓冲区,将offset与最新的偏移量之间的写命令通过套接字发送给从节点
- 主节点无论使用哪种策略,都会顺便发送最新offset的信息,以便告知从节点数据同步具体位置
复制缓冲区与offset的这种方式使得数据复制时分为两种策略,一种使用RDB方式同步数据,另一种则是通过序列化的写命令进行同步数据
在早期版本中不存在offset,当网络故障从节点重新连接时,直接触发使用RDB的方式进行数据复制,可能在此期间主节点只接收了一条写命令,使用RDB方式开销非常大,主节点需要执行bgsave,从节点要清空数据再恢复,复制缓冲区与offset策略的出现,提升了复制的效率
在这种策略下可能出现频繁RDB方式复制的情况,比如重启主节点时runid会更换,这会导致所有从节点触发RDB方式的数据复制,这种情况可以设置重启runid不改变
当复制缓冲区太小,由于RDB恢复数据、网络延迟等问题让从节点延时很长时间,导致offset总不在缓冲区也会造成频繁RDB方式复制数据,可以通过改变复制缓冲区大小repl-backlog-size
来解决
计算公式:最优空间 = 主节点到从节点重连多少秒 * 2 * 主节点每秒最高产生写命令数量
命令传播
当执行完数据复制,接下来只需要主节点将处理完的写命令持续同步给从节点就维护数据一致性了
命令传输过程中要维持心跳检测机制,默认从节点每秒发送命令replconf ack offset
维持心跳时会传输从节点维护的offset,告诉主节点从节点当前同步数据的位置,以防命令出现丢失
网络延迟/中断引起的问题
从节点因为网络中断或者从节点CPU占用过高,导致没与主节点维持心跳导致主节点各种资源被从节点占用,可以通过设置心跳超时时间来解决 (repl-timeout
默认60s,超时释放从节点)
主节点发送的ping命令可能在网络中丢包,所以超时时间设置太短repl-timeout
和发送ping命令频率设置太低repl-ping-slave-period
都会导致断开连接 (超时时间一般为频率的5到10倍)
因为网络延迟,多个从节点获取相同数据可能是不同步的,如果对数据一致性要求很高,并且从节点因为网络延迟数据不一致,可以屏蔽对从节点的访问slave-serve-stale-data yes/no
总结
主从架构是哨兵、集群模式的前提,是保证高可用条件的基石,本篇文章围绕主从架构深入浅出的介绍了主从架构、主从复制原理以及因为网络可能引起的问题
主从架构有着读写分离、负载均衡、数据冗余、故障转移等特点,是高可用的基础
主从复制主要分为建立连接、数据复制、命令传播三个阶段
在建立连接中,从节点需要记录主节点IP、端口等信息,主节点需要对从节点进行验证授权并记录IP、端口等信息
在数据复制时,利用runid、offset来判断数据复制时主节点发送的是RDB文件还是序列化写命令,这种方式的提出大大优化网络中断情况下数据复制的效率
主节点重启更换runid、复制缓冲区设置太小都会导致数据复制频繁使用RDB的方式,这种情况需要修改配置
完成数据复制后,只需要在命令传播阶段持续保持主从数据一致性即可,顺便维持心跳和offset,判断网络状态以及数据同步是否丢失命令等
因为网络中断等问题,引起的维持心跳失败、数据不同步等问题都可以通过参数进行设置
最后
- 参考资料
- 《Redis深度历险》
- 《Redis设计与实现》