研发工作中我们总是会用到缓存,redis作为目前互联网企业最流行的缓存中间件,我们这篇文章想跟大家一起讨论下它的集群解决方案。
后续笔者会从redis的主从同步机制、哨兵模式(Sentinel)、Codis、Cluster几个方向来逐一阐述自己的观点。
这篇文章主要讨论redis的主从同步机制。很多公司未必会有redis集群,但是使用redis的时候至少都做了主从来保证服务的可用性。
什么是主从?顾名思义,一个节点作为Master,一个节点作为Slave,当Master作为挂掉的时候,Slave过来接管,服务就可以继续,否则Master的重启、数据恢复过程可能会拖延很长时间,从而影响到业务系统的持续服务。
说道集群,我们就会想到著名的CAP原理。
C:Consistent,一致性
A:Availability,可用性
P:Partition tolerance,分区一致性
这里有个术语需要解释:网络分区。分布式系统的节点通常都是分布在不同的机器上,机器之间的网络有可能会断开,当网络断开时,这样的场景就叫做网络分区。
网络分区发生时,由于节点间无法通信,如果持续写入或者修改数据,会导致节点之间数据一致性无法保证。除非当分区发生时,我们不在提供服务,直到网络恢复,这样就牺牲了可用性。所以CAP的原理是:当网络分区发生时,C与A难以两全。
redis的主从数据是异步同步的,所以分布式的redis只能满足AP。当客户端在redis的主节点修改了数据后,立即返回。所以主从的网络分区发生时,主节点会继续提供服务,从节点的数据版本会在网络恢复后,通过多种策略进行恢复,尽力保持与主节点一致。达成最终一致性。
redis支持主从同步与从从同步。如下图:
下面我们再谈一下主从同步的几种策略:
1.增量同步
redis同步的是指令流,主节点会将对自己的状态产生修改性影响的指令记录在本地的内存buffer中,然后异步将buffer中的指令同步到从节点,从节点一边执行同步的指令流,一边向主节点反馈同步偏移量。
由于buffer的大小有限,所以是循环使用的。如果因为网络故障,导致master与slave之间的数据不一致,同时buffer里面的数据版本已经被覆盖了,那么redis会触发快照同步。
2.快照同步
快照同步因为涉及到磁盘IO,所以是一种非常耗费资源的操作。
master通过bgsave操作将内存快照存储到磁盘文件,然后将快照文件发送到从节点,从节点接收完毕后,立即执行一次全量加载。全量加载操作前需要清空内存,加载完毕后通知master继续进行增量同步。
问题:加载快照时间过长或者复制buffer太小都会导致同步期间的增量指令在复制buffer中被覆盖,导致快照同步完成后无法增量复制,再次发起快照同步,陷入死循环。
解决办法:配置合适的buffer大小参数,避免快照复制死循环。
增加从节点
当slave刚刚加入到集群,它必须进行一次快照同步,完成后再增量同步
无盘复制
master在进行快照同步时,io操作会很耗时。当磁盘不是ssd的时候,影响尤其严重。系统如果正在进行AOF的fsync操作时,如果发生快照同步,fsync将会被推迟执行。
redis2.8.18版本后,redis的master会通过套接字将快照内容发送到从节点,生成快照是一个遍历的过程,master会一边遍历内存,一边讲内容发送到slave。这个过程叫做无盘复制。
wait指令
redis的复制是异步操作,wait指令可以让异步操作变成同步复制,确保强一致性。
wait是在redis3.0之后才出现的。wait命令包含2个参数:从节点数量n与时间t(毫秒)
wait 1 0 代表无限期等待1个slave复制完成。
时间为0代表无限期等待,当此时发生网络分区,那么redis会丧失可用性。
主从同步是redis分布式集群的基础,也是高可用的保证。
后续文章我们会继续探讨主节点宕机后的恢复机制:哨兵模式。