Redis主从同步与故障切换,有哪些坑

146 阅读3分钟

主从数据不一致

为啥会出现这个坑呢?其实这是因为主从库间的命令复制是异步进行的。

具体来说,在主从库命令传播阶段,主库收到新的写命令后,会发送给从库。但是,主库并不会等到从库实际执行完命令后,再把结果返回给客户端,而是主库自己在本地执行完命令后,就会向客户端返回结果了。如果从库还没有执行主库同步过来的命令,主从库间的数据就不一致了。

为什么从库会滞后执行同步命令呢?其实,这里主要有两个原因。一方面,主从库间的网络可能会有传输延迟,所以从库不能及时地收到主库发送的命令,从库上执行同步命令的时间就会被延后。

另一方面,即使从库及时收到了主库的命令,但是,也可能会因为正在处理其它复杂度高的命令(例如集合操作命令)而阻塞。

应对:

  1. 在硬件环境配置方面,我们要尽量保证主从库间的网络连接状况良好。
  2. 我们还可以开发一个外部程序来监控主从库间的复制进度。

我们可以开发一个监控程序,先用 INFO replication 命令查到主、从库的进度,然后,我们用 master_repl_offset 减去 slave_repl_offset,这样就能得到从库和主库间的复制进度差值了。如果某个从库的进度差值大于我们预设的阈值,我们可以让客户端不再和这个从库连接进行数据读取,这样就可以减少读到不一致数据的情况。不过,为了避免出现客户端和所有从库都不能连接的情况,我们需要把复制进度差值的阈值设置得大一些。

image.png

读取过期数据

从库本身不会执行删除操作,如果客户端在从库中访问留存的过期数据,从库并不会触发数据删除。

在 3.2 版本后,Redis 做了改进,如果读取的数据已经过期了,从库虽然不会删除,但是会返回空值,这就避免了客户端读到过期数据。所以,在应用主从集群时,尽量使用 Redis 3.2 及以上版本。

image.png

在业务应用中使用 EXPIREAT/PEXPIREAT 命令,把数据的过期时间设置为具体的时间点,避免读到过期数据。

不合理配置项导致的服务挂掉

protected-mode 配置项

这个配置项的作用是限定哨兵实例能否被其他服务器访问。当这个配置项设置为 yes 时,哨兵实例只能在部署的服务器本地进行访问。当设置为 no 时,其他服务器也可以访问这个哨兵实例。

正因为这样,如果 protected-mode 被设置为 yes,而其余哨兵实例部署在其它服务器,那么,这些哨兵实例间就无法通信。当主库故障时,哨兵无法判断主库下线,也无法进行主从切换,最终 Redis 服务不可用。

cluster-node-timeout 配置项

这个配置项设置了 Redis Cluster 中实例响应心跳消息的超时时间。

建议你将 cluster-node-timeout 调大些(例如 10 到 20 秒)。

总结

image.png

Redis 中的 slave-serve-stale-data 配置项设置了从库能否处理数据读写命令,你可以把它设置为 no。这样一来,从库只能服务 INFO、SLAVEOF 命令,这就可以避免在从库中读到不一致的数据了。


此文章为8月Day26学习笔记,内容来源于极客时间《redis核心技术与实战》