在redis实例宕机后,通过AOF和RDB可以恢复数据,这是高可用的一部分。但是在宕机期间,如何持续提供服务呢?这是高可用的另一部分。redis的方案是主从库模式,在主库宕机后,由从库提供服务。
主从架构
遵从单线程处理原则,从库只接受读请求,写请求都在主库执行,主库执行后再同步到从库中去。在这种模式下,从库实际上是主库的一个数据备份,用于分担主库读请求和提供高可用服务。
启动从库
与主库不同,从库需要进行额外的配置,以确保可以与主库进行连接。每个redis实例都有一个runId,主库通过该runId管理不同从库的同步进度。
vi redis.conf
# 要连接的主库信息
replicaof <masterip> <masterport>
# 主库密码
masterauth <master-password>
# 从库优先级,用于主从切换时的计算
replica-priority 100
编辑好配置后,启动从库
redis-server redis.conf
主从库数据同步
在主从库启动后,从库根据replicaof配置(redis5.0之前为slaveof),与主库建立连接。
建立连接后,执行数据同步操作
- 如果是第一次同步(根据偏移量),则进行全量同步,在主库中,主线程fork一个子线程,然后由子线程执行RDB生成快照文件,然后将快照文件发送给从库。
- 如果不是第一次同步,将repl_backlog_buffer中的命令同步给从库。repl_backlog_buffer是内存中的一个区域,用于缓存执行RDB之后的写入命令,可以通过配置调整该buffer的大小,默认为{repl-backlog-size 1mb}。
日志同步过程是异步完成的,不会阻塞主库中的主线程。只在主线程fork子线程时是同步的,需要消耗主线程时间。
主从库断联后如何处理?
主从库断联后再次连接,不再进行全量同步,而是进行增量同步。主库中主线程将更改命令写入到repl_backlog_buffer中,重新连接后,由异步线程将断联期间的命令同步至从库。需要注意的是,repl_backlog_buffer是一个环形结构,长时间断联后,一些命令可能会被覆盖。命令被覆盖后,可能导致主从库数据不一致,需要合理配置repl-backlog-size大小。
主从同步能确保数据一致性吗?
不能,在主库向从库发送同步命令后,因为网络错误或者从库宕机,都会导致该命令在从库端未执行,而redis没有重试机制。
内存回收能同步吗?
不能,redis主库中进行内存回收时删除的Key,不会同步至从库。这导致的数据不一致问题如何解决?
使用相同的清除算法,如allkeys-lru。
哨兵
在主从架构中,如果主库出问题了,如何应该完成主从切换呢?
传统方案
利用主从库节点来完成选主,每个从库都与主库保持着连接,在超过半数的从库都无法与主库连接后,从库重新选举主节点。想象中是可以的,但这种方法需要至少三个节点,少于三个节点可能导致脑裂。而我们部署主从时,往往只有一个从库,这种方式对灵活部署限制较大。
redis方案
redis中的方案是引入哨兵集群,负责完成主从切换任务,具体职责为:
- 监控主从库状态,判断其是否在线
- 如果主库下线,执行主从库切换,选择一个从库作为新的主库
- 通知从库、哨兵、客户端主从库切换信息
哨兵其实是一个特殊的redis实例,只是不负责处理客户端请求,也不存储键值对数据,仅仅用于维护主从库状态,在必要时完成主从库切换。
搭建哨兵集群
启动哨兵实例
在sentinel.conf中进行配置,配置主库信息和主从切换相关配置
# 配置主库master_6379连接信息,并设置主从切换时需获得的最少投票数(这里设置为2,计算公式为(节点数/2)+ 1)
sentinel monitor master_6379 127.0.0.1 6379 2
# 配置主库master_6379的连接密码
sentinel auth-pass master_6379 passwd@12p
# 判断主master的挂机时间(毫秒),超时未返回正确信息后标记为sdown状态(主观下线)
sentinel down-after-milliseconds master_6379 5000
# 若sentinel在该时间值内(毫秒)未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
sentinel failover-timeout master_6379 18000
然后以哨兵模式启动redis
redis-server sentinel.conf --sentinel
组成集群
在上述哨兵配置中,可以发现,我们既没有配置从库信息,也没有配置其它的哨兵信息。那怎么组成哨兵集群,又怎么完成主从切换呢?这就得说到redis提供pub/sub(发布订阅)机制了,哨兵与主库建立连接后,可以相互进行消息得发布和订阅。
哨兵之间的发现
主库上有一个叫做"sentinel:hello"的频道,哨兵与主库连接后,将自身的连接信息发布到该频道。同时也订阅该频道,在其它哨兵信息发布后,通过连接信息与其它哨兵进行连接。
从库节点的发现
哨兵与主库连接后,通过发送INFO命令获取到所有从库的连接信息,然后与从库进行连接。
如何判断主库下线?
当一个哨兵与主库断联后,可以判断主库挂了吗?
很明显不能,不然还要哨兵集群干嘛。在集群中,至少得有((节点数量/2)+ 1)个哨兵投票认为主库挂了,才能判定主库是真的挂了。
如何选择新主库?
在确定要完成主从切换时,如果只有一个从库,那直接将其作为主库就行了;但在有多个从库的情况下,选择那个作为主库呢?
redis中定制了多种规则,优先级最高的是从库优先级,选择优先级最高的作为主库。优先级相同时,根据主从库的同步程度进行判断,同步程度最高的作为主库。优先级与同步程度均一致时,选择Id最小的作为从库作为主库。
- 从库优先级:在启动从库实例时,在redis.conf中进行配置,默认为100
replica-priority 100
标签:主库,同步,架构,redis,Redis,哨兵,从库,主从
From: https://www.cnblogs.com/cd-along/p/18168875