文章目录
目录
前言
主要介绍了Redis的主从复制和SEntinel监视服务器如何实现
一、复制
- SYNC命令
- 从机向主机发送SLAVEOF命令,开始复制主机数据以达到主从数据库一致
- 主机执行BGSAVE命令生成dump.rdb文件,同时将这期间所有的写命令追加到缓冲区内,持久化完成后将RDB文件和期间所有的写命令发送给从机,从机载入RDB文件且执行所有传输来的写命令,达到与主机数据的一致
- 缺点
- 出现断连时,执行SYNC命令会将主机数据库内所有内容都写入RDB文件并传送给从机,消耗太多性能
- 2.8版本后的PSYNC命令
- 包含完整重同步和部分重同步,完整重同步和SYNC命令一样,载入RDB文件和执行缓冲区写命令
- 部分重同步
- 从机向主机发送PSYNC命令,主机回复CONTINUE,主机将断连期间的写命令发送给从机,实现主从数据同步
- 实现细节
- 复制偏移量
- 主机与从机都维持一个复制偏移量,主机每次执行N个写操作就将复制偏移量加N,从机接收到主机发送来的写请求并且成功执行后也将自己的复制偏移量加N
- 复制积压缓冲区
- 是一个默认大小为1MB的FIFO的固定大小队列,进队发现超过固定大小会弹出最先进入的数据,其大小可以根据平均重连秒数second*write-per-second来确定(保险起见可以设置为其2倍)
- 主机每次执行一个写操作,不仅需要将该操作发给从机,还需要将其写入复制积压缓冲区
- 从机重连时向主机发送PSYNC命令并且告知主机其复制偏移量,若该复制偏移量在复制积压缓冲区内,主机执行部分重同步,将复制积压缓冲区中从 从机复制缓冲区开始 到结尾的所有写命令发送给从机(不在复制积压缓冲区内需要执行完整重同步)
- 服务器运行ID
- 初次复制时,从服务器会接受到主服务器发送来的运行ID并保存,从机断开重连时,会向主服务器发送之前存的运行ID,若与重连服务器运行ID相同则可以尝试部分重复制否则需要进行完整重复制
- 复制偏移量
- 实现过程
- 从服务器第一次执行执行SLAVEOF命令,发送PSYNC ? -1命令给主服务器,请求主服务器执行完整复制操作,主服务器执行BGSAVE命令,并且返回给从服务器FULLRESYNC+运行ID+复制偏移量,从服务器保存发送来的运行ID
- 从服务器与主服务器断连后重新尝试连接,发送PSYNC +上次连接的主服务器的运行ID+自身复制偏移量 命令,请求主服务器部分重同步,运行ID相同 & 该复制偏移量在复制积压缓冲区内则执行部分重同步,主服务器返回给从服务器CONTINUE,主服务器将复制积压缓冲区内的写操作发送给从服务器
- 复制的实现过程
- 保存主机信息
- 从机发送SLAVEOF命令,将需要复制的主机的IP地址(masterhost)和端口(masterport)保存到自己的RedisServer数据结构内存储
- 套接字
- 主服务器将从服务器视作一个客户端,建立一个套接字并且为其关联一个用于处理复制的文件事件处理器,用于接收RDB文件并且接收主机传播的写命令
- PING
- 从服务器向主服务器发送PING,正确接收到从服务器的PONG回复代表套接字可以正常使用,未收到或者回复超时需要断开重连
- 身份验证
- 从服务器将自己的AUTH信息发送给主服务器进行身份验证,只有一方设置了身份验证信息或者身份验证信息不匹配都无法进行接下来的复制操作,需要重新建立套接字连接或者放弃复制
- 端口信息
- 从服务器向主服务器发送自己的监听端口(PEPLCONF listening-port xxxxx),主服务器将该监听端口保存到自己的RedisServer数据结构的slave-listening-port中
- 同步
- 从服务器向主服务器发送PSYNC命令,主服务器也成为从服务器的客户端,可以向从服务器发送写命令
- 命令传播
- 主服务器一直将自己的写命令发送给从服务器,以达到主从一致性
- 心跳检测
- 从服务器默认以每秒一次的频率向主服务器发送命令REPLCONF ACK 自己的复制偏移量
- 功能
- 检测主从服务器网络连接状态
- 超过1s没有收到从服务器发来的ACK则表示主从服务器之间的连接出现了问题
- 检测命令丢失
- 主服务器会检查从服务器发来的ACK中的复制偏移量,如果发现其与自己的复制偏移量不同,则可以判断出主从服务器之间出现了命令丢失,主服务器会在复制积压缓冲区中找到这些写命令重发给从机
- 命令丢失的重发是主从机未断连的重发,部分重同步的重发是主从机断连后的重发
- 辅助实现min-slaves选项
- min-slaves-to-write:未达到该选项指定的从服务器数量,主服务器拒绝写命令
- min-slaves-max-lag:指定数量的从服务器的延迟都大于等于该选项指定的值时,主服务器拒绝写命令
- 检测主从服务器网络连接状态
- 保存主机信息
二、sentinel
- redis的一种特殊的服务器,可以监控一些主服务器以及复制该主服务器的从服务器,当主服务器下线时选取从服务器作为新的主服务器,当下线的主服务器重新上线时让他当从服务器,去复制之前选取出来的新的主服务器
- sentinelState结构体储存sentinel相关信息
redisServer结构存服务器基础信息- masters字典
sentinel初始化时根据sentinel配置文件初始化- 存监视的主服务器实例信息,要与sentinel服务器建立命令连接和订阅连接
- key= sentinel配置文件中给出的主服务器名字
- value= sentinelRedisInstance存主服务器实例信息的结构体
- runid
- addr存主机的ip和port
- slaves字典
sentinel通过命令连接向masters字典里的主服务器发送INFO命令,通过命令回复自动找到从服务器,初始化slaves字典- 存要监视从服务器实例信息,要与sentinel服务器建立命令连接和订阅连接
- key=IP:port
- value=存从服务器实例信息的结构体
- sentinels字典
sentinel通过订阅连接接收到的信息中的sentinel相关信息,自动找到监视同一主服务器的sentinel服务器,初始化sentinels字典- 存该sentinel服务器本身信息 + 共同监视某个主服务器的其他sentinel服务器信息,要与sentinel服务器建立命令连接
- key=IP:port
- value=存sentinel服务器实例信息的结构体
- masters字典
- sentinel的启动和初始化--要监视的主服务器信息初始化
根据sentinel配置文件引入要监视的主服务器- 初始化服务器
- 与普通服务器的区别在于,sentinel服务器无需载入RDB或者AOF文件,只能使用部分命令(复制、发布与订阅、文件事件处理器、时间事件处理器)
- 使用sentinel专用代码
- 端口使用REDIS-SENTINEL-PORT 26379
- sentinelcmds作为命令表,只能执行部分命令
- 初始化sentinelState的masters字典
- 根据sentinel配置文件创建sentinelRedisInstance实例,并保存到sentinelState的masters属性中
- 创建与主服务器的异步网络连接:命令连接和订阅连接
- sentinel会成为主服务器的客户端,向主服务器发送命令并从命令回复中获取相关信息(因为会成为多个主服务器的客户端,所以建立异步网络连接)
- 命令连接:用于向主服务器发送命令
- 订阅连接:订阅主服务器的-sentinel-:hello频道,可以实现共同监视某个服务器的多个sentinel服务器的自动发现
- 初始化服务器
- 自动发现要监视的从服务器和sentinel服务器
通过与主服务器建立的命令连接和订阅连接自动发现要监视的从服务器和sentinel服务器- 命令连接
- 获取主服务器信息
自动发现从服务器- sentinel以每10s一次的频率通过命令连接向主服务器发送INFO命令,分析命令回复获取主服务器当前信息:更新masters字典的runid等信息、创建/更新slaves字典:自动发现从服务器
- 发现从服务器后不仅需要创建从服务器实例存在slaves字典里,还会建立命令连接和订阅连接
- 获取从服务器信息
- 和主服务器一样,10s一次通过命令连接发送INFO命令,通过命令回复获取从服务器信息,更新slaves字典
- 当主服务器下线-->sentinel服务器正在对主服务器执行故障转移时,会以每1s发一次的频率向从服务器发送INFO命令
- 向主、从服务器发送信息
自动发现sentinel服务器- 每2s一次的频率通过命令连接向所有监视的服务器的-sentinel-:hello频道发送信息:信息包括sentinel相关的参数、主服务器相关的参数
- 共同监视同一服务器的多个sentinel服务器可以通过订阅连接接收到该消息,实现sentinel服务器的自动发现
- 获取主服务器信息
- 订阅连接
自动发现sentinel服务器- sentinel服务器通过订阅连接向服务器发送SUBSCRIBE -sentinel-:hello命令,以实现从 从服务器的-sentinel-:hello频道接受信息
- 多个sentinel服务器监视着一个主服务器,源sentinel服务器通过命令连接向主服务器的-sentinel-:hello连接发送消息,该消息会被其他subscribe该hello通道的目标sentinel服务器接收到
- 目标sentinel服务器解析该消息可以得到sentinel相关信息和主服务器相关信息
- 根据主服务器相关信息在sentinelState里的masters字典里取出主服务器实例结构
- 根据得到的sentinel相关信息看看自己的sentinelState的sentinels字典里是否有源sentinel服务器实例结构,有则根据sentinel相关信息更新,没有则创建sentinel实例并且存在sentinels字典,监视同个服务器的多个sentinel可以自动发现对方
- 目标sentinel服务器发现源sentinel服务器后不仅会创建sentinel实例存在自己的sentinels字典里,还会与该sentinel服务器建立命令连接,不需要建立订阅连接
- 命令连接
- 服务器下线管理
- 检测主观下线状态
主、从、sentinel服务器都可以主观下线- sentinel以每秒1次的频率向所有与之建立了命令连接的服务器(主+从+sentinel)发送PING命令,并且通过PING回复判断服务器是否在线
- 若超过sentinelState中的down-after-milliseconds规定的数值还未收到有效的PING回复,则sentinel服务器会修改自己sentinelState中存的服务器对应的实例信息,将该服务器标识为主观下线状态
- 检测客观下线
主服务器才会客观下线- 主服务器已经主观下线,则监视该主服务器的sentinel服务器可互相发送SENTINEL is-master-down-by-addr命令,询问该主服务器是否在其他sentinel服务器中标识为主观下线
- 根据sentinel服务器的命令回复,确定该主服务器是否已主观下线,统计服务器的主观下线数量
- 若主观下线数量已经达到了sentinelState中的配置指定的客观下线数量时,则确认该主服务器已经客观下线,修改sentinelState中的master字典中的主服务器实例信息标识为客观下线
- 选举领头Sentinel
- 某个主服务器客观下线,监视该主服务器的多个sentinel会选举出一个领头sentinel服务器,对该主服务器执行故障转移操作
- 主服务器已经被标识为客观下线,监视该主服务器的各个sentinel再次互相发送SENTINEL is-master-down-by-addr命令,这次这个命令需要带上sentinel服务器自己的runid,如果接受到这个命令的sentinel服务器还没有设置领头羊sentinel的话,就将该runid设置为领头羊sentinel,当某个runid被超过半数的sentinel服务器设置为领头羊sentinel,则该runid对应的sentinel服务器成为领头羊sentinel,开始对主服务器实现故障转移
- 故障转移
- 领头羊sentinel对客观下线的主服务器的处理
- 从该主服务器下的所有从服务器中选取出一个作为新的主服务器
- 领头sentinel服务器会先向该从服务器发送SLAVEOF no one命令,然后以每1s发一次的频率向它发送INFO命令,当命令回复的role变成masters代表它已经成功成为新的主服务器
- 让其他从服务器改为复制该新的主服务器
- 领头羊sentinel服务器向其他从服务器发送SLAVEOF命令,让他们复制新主服务器
- 让下线主服务器成为新主服务器的从服务器,重新上线后复制该新主服务器
- 当该主服务器重新上线时,领头羊sentinel服务器向其发送SLAVEOF命令,让他复制新的主服务器
- 检测主观下线状态