【redis】主从的高可用

Redis副本是如何保证高可用的

在redis副本的基础上,redis提供了简单易用的主从模式。从节点会精确的从主节点复制数据,并且在连接中断的时候自动重连,无论主节点发生什么都会尝试复制数据。

实现机制主要如下3种:

  1. 当主从节点连接良好时,如果主节点数据集发生改变(包括客户端写入,key过期或删除,或其他影响数据集的操作),主节点会向从节点发送一系列命令来保证从节点更新数据。
  2. 当主从之间的连接断开时,不论是网络问题还是主或从发生超时,从节点都会试图重连主节点并进行部分数据的重新同步,也就是在断开期间丢失的数据。
  3. 当无法部分重新同步时,从节点会申请全部数据的重新同步。这会牵扯到更复杂的程:主节点需要创建全部数据的快照发送给从节点,然后继续发送数据集变更的指令流。

Redis默认使用异步的副本,这样延迟低性能高,是绝大多数redis实例的自然复制模式。然而从节点会异步的定期和主节点确认接收到的数据量,所以主节点不会每次等待数据同步给从节点,但是有需要的话,主节点也直到哪个从节点接收了哪些数据,所以也允许使用同步的副本。

客户端可以使用WAIT命令请求某些数据的同步复制。然而,wait命令只能确保其他Redis实例中存在指定数量的已确认copies,它不会将一组Redis实例转换为具有强一致性的CP系统:根据Redis持久化的配置,在故障切换期间仍可能丢失已确认的写入。然而,使用wait命令,写入丢失的情况会大大减小,只局限于某些难以出发的故障中。

Redis副本的一些重要知识

  • redis使用异步的副本,在主从之间异步确认变更的数据数量
  • 一个master可能有多个从节点
  • 副本之间也可以建立连接,除了多个副本和master之间连接外,副本直接也可以使用级联结构连接。从redis4.0开始,所有的子副本都会从master接收相同的复制流。
  • 对于master来说副本是非阻塞的,也就是说当一个或多个副本正在进行部分重新同步或者初始化同步时,master会持续处理客户端请求。
  • 副本之间大体上也是非阻塞的,当一个副本正在初始化同步时,它也可以使用旧版本的数据来处理请求(如果你在配置文件中这么配置了)。否则你也可以这样设置,当数据流关闭时,副本会给客户端返回错误。然而,在初始化同步完成后,旧版本数据一定会被删除,新的数据一定会被加载。在这期间replica会拒绝连接(数据集大的话可能会持续很多秒)。从redis4.0开始你可以配置旧数据的删除操作在其他线程执行,但是新数据的加载还是会在主线程执行,会造成从节点阻塞。
  • replica既可以用于可扩展性,也可以用于只读查询的多个副本(例如,可以将缓慢的O(N)操作卸载到副本),也可以简单地用于提高数据安全性和高可用性。
  • 您可以使用replica来避免主机将完整数据集写入磁盘的成本:一种典型的技术是配置主节点redis.conf关闭持久化,然后连接时刻持久化的replica,或者启用AOF的。但是,这种模式必须要小心使用,因为一旦master重启,那么他的数据集会变成空的,如果replica与主节点同步,replica也变成空了。

当主节点不持久化时副本的安全性

当使用redis主从时,强烈建议主节点和从节点都开启持久化。如果没办法的话(比如磁盘很慢会造成高延迟),一定要避免redis程序自动重启。因为如果主节点所在机器崩溃了,在重启后redis服务也自动重启了,那么所有从节点会自动从主节点复制数据。这会导致所有从节点中的数据也丢失了。

当使用哨兵做高可用时,关闭master的持久化和开启自动重启是很危险的。因为重启过程可能很快,哨兵检测不到主节点故障。

redis副本的工作原理

每个master都有一个replication id:一个长的伪随机字符串,用来表示数据集。同时master还使用随复制流字节递增的offset,来完成从节点的数据更新。就算实际上没有可连接的从节点,offset还是会递增,所以下面的信息可以master数据集的精确版本:

Replication ID, offset

当有从节点连接master时,master使用psync命令来发送旧的replication id和目前位置的offset。这样可以只发送所需的增量部分。然而如果master缓冲区没有足够的数据,或者从节点正在引用一个不再使用的replication id,此时就会执行全量复制,从节点会受到从头开始的数据集的完整副本。

全量同步的工作细节:
master后台启动一个保存程序来生成rdb文件。同时将从客户端接收到的指令放入缓冲区。当rdb生成完成,master将这个文件同步给从节点,从节点将文件落盘,然后加载到内存中。然后master将缓冲区的数据发送给从节点,这个流程使用和redis协议一致格式的指令流来完成。

你可以使用telnet自己尝试一下。连接到redis端口然后使用sync命令,你会看到批量的传输,且master将接收到的每个指令都显示在telnet session上。实际上sycn是一个新版本不再使用的旧协议,但是依然兼容。因为sync不允许部分重新同步,所以现在使用psync。

上面提到,当master的连接断了,replica会自动重连。如果master同时收到多个replica的同步请求,它只生成一个后台程序来完成所有replica的同步。

什么是Replication ID

如果两个redis实例的Replication ID和offset一样,那么数据集也是一模一样的。但是也需要理解一下什么是Replication ID ,为什么一个实例有两个Replication ID :main id和secondary ID。

一个Replication ID大体上就是用来表示数据集的一个历史版本。每次一个实例从零开始作为master启动,或者replica升级为master,这个实例就会生成一个新的Replication ID。当一个replica连接一个master握手完成后,他就会继承master的Replication ID。所以两个Replication ID一样的实例实际上也拥有同一个数据集,但可能在不同的时间。对于一个历史Replication ID来说,offset可以视为逻辑上的时间来查看哪个实例保存了最新的数据。

例如,两个实例A和B的Replication ID一样,但是其中一个offste是1000,另一个是1023,这就意味着A的数据集中缺了某些命令,补上这些命令后就与B一致了。

至于为什么有两个Replication ID,是因为replica可能升级为master。在发生一次故障转移后,新的master依然会保存旧的Replication ID,因为旧的Replication ID代表了上一个master。当其他replica尝试与新master同步时会使用旧的Replication ID。replica成为master时,会将secondary id和main id交换,并记录id切换时的offset。当replica与这个新的master连接时,他会用新的id和secondary id来匹配replica给出的id和offset。简而言之就是故障切换之后,replica不必执行全部重新同步。

你可能疑惑为什么升级为master要使用新的id,因为旧的master可能因为网络分隔的原因仍在运行,这样就违背了一样的id和offset代表一样的数据的原则。

无盘复制

通常全量的重新同步需要将rdb文件落盘并加载到内存中,但是在磁盘很慢的时候,这个操作的开销比较大。Redis2.8.18开始提供了无盘复制,master的子进程会直接将rdb通过线缆直接传给replica,而不需要磁盘这样的中间存储。

配置

要使用replica很简单,只需要在replica的配置文件中添加一行:

replicaof 192.168.1.1 6379

ip和端口替换成你的master的ip和端口即可。或者你可以调用replicaof命令。

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值