Redis集群【主从切换如何减少数据丢失】

358 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

主从切换时有两种可能导致数据丢失。

  • 异步复制同步丢失
  • 集群产生脑裂数据丢失

异步复制同步丢失

对于 redis 主节点与从节点之间的数据复制,时异步复制的,当客户端发送写请求给主节点的时候,客户端会返回 ok,接着主节点将写请求异步同步给各个从节点,但是如果此时主节点还没来得及同步给从节点时发生了断电,那么主节点内存中的数据会丢失。

解决方案

  • 第一种:客户端将数据暂时写入本地缓存和磁盘中,在一段时间后将本地缓存或者磁盘的数据发送给主节点,来保证数据不丢失;
  • 第二种:客户端将数据写入到消息队列中,发送一个延时消费消息,比如10分钟后再消费消息队列中的数据,然后再写到主节点。

集群产生脑裂数据丢失

脑裂有以下场景,当主节点的网络发生问题,主节点与其他节点断连,但是与客户端连接正常。

这时,客户端的写命令产生在主节点但是无法同步到从节点,而哨兵将会选举出来新主节点。当主节点再次上线时,主节点就会成为从节点,清空所有数据,包括之前未同步的写命令,然后做第一次同步,全量同步新主节点的数据。此时就是由脑裂导致的数据丢失问题。

解决方案:

当主节点发现从节点下线或者通信超时的总数量小于阈值时,那么禁止主节点进行写数据,直接把错误返回给客户端。

在 redis 的配置文件中有两个参数我们可以设置:

  • min-slaves-to-write x,主节点必须要有至少 x 个从节点连接,如果小于这个数,主节点会禁止写数据。
  • min-slaves-max-lag x,主从数据复制和同步的延迟不能超过 x 秒,如果超过,主节点会禁止写数据。

我们可以把 min-slaves-to-write 和 min-slaves-max-lag 这两个配置项搭配起来使用,分别给它们设置一定的阈值,假设为 N 和 T。

这两个配置项组合后的要求是,主库连接的从库中至少有 N 个从库,和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主库就不会再接收客户端的写请求了。

即使原主库是假故障,它在假故障期间也无法响应哨兵心跳,也不能和从库进行同步,自然也就无法和从库进行 ACK 确认了。这样一来,min-slaves-to-write 和 min-slaves-max-lag 的组合要求就无法得到满足,原主库就会被限制接收客户端写请求,客户端也就不能在原主库中写入新数据了

等到新主库上线时,就只有新主库能接收和处理客户端请求,此时,新写的数据会被直接写到新主库中。而原主库会被哨兵降为从库,即使它的数据被清空了,也不会有新数据丢失。我再来给你举个例子。

假设我们将 min-slaves-to-write 设置为 1,把 min-slaves-max-lag 设置为 12s,把哨兵的 down-after-milliseconds 设置为 10s,主库因为某些原因卡住了 15s,导致哨兵判断主库客观下线,开始进行主从切换。同时,因为原主库卡住了 15s,没有一个从库能和原主库在 12s 内进行数据复制,原主库也无法接收客户端请求了。这样一来,主从切换完成后,也只有新主库能接收请求,不会发生脑裂,也就不会发生数据丢失的问题了。