Redis主从同步数据死循环

根据业务需求搭建了Redis Cluster集群,使用了4台服务器配置是8核32G内存。Redis集群的配置是2主2从。经过艰难困苦的各种操作,终于把2个主节点组建完毕。具体步骤和困难可以参考《从零搭建Redis Cluster分片集群》和《Redis Cluster分片数据迁移过程中的挑战》两篇文章。本篇文章将讨论另外一个问题,就是主从之前数据初始化过程中从服务器不断出现请求全量同步数据问题。以下是问题的具体细节和相关方案。

问题描述

主节点内存数据比较大,压缩后的RDB文件大约15GB。在百兆网络的环境下,大约耗时18分钟。随后Redis从服务器要把15GB的RDB文件解压并加载到内存中,大约耗时20分钟。因此在从节点第一从主节点同步数据大约耗时40分钟。完成整个流程以后,从节点早就失联了。重新连接主服务器后,由于lack of backlog原因(在主节点的日志中可以发现)需要重新全量同步数据。因此,这个数据同步进入了死循环。以下是从节点的日志。

从节点日志
以下是从节点的一个日志片段,为了能够说清楚问题,我已经在重点时间节点位置写了注释。在分析从节点日志的过程中,可以同时参考主节点在相同时间点的日志,能够对主从同步的问题有更清晰的了解。

# 向主节点发起全量数据同步请求
6904:S 27 Jun 2021 21:58:03.726 * Full resync from master: c7155b634d6e303d3fc5fab5c56f5ba73e4c77d9:36608053
6904:S 27 Jun 2021 21:58:03.726 * Discarding previously cached master state.
# 主节点花了9分钟成功将内存数据持久化到RDB文件中,开始传输15GB的RDB文件
6904:S 27 Jun 2021 22:07:06.987 * MASTER <-> REPLICA sync: receiving 15102201373 bytes from master to disk
# 主节点RDB文件传输完成,从节点清除所有数据
6904:S 27 Jun 2021 22:25:22.631 * MASTER <-> REPLICA sync: Flushing old data
# 从节点读取RDB文件
6904:S 27 Jun 2021 22:28:17.128 * MASTER <-> REPLICA sync: Loading DB in memory
6904:S 27 Jun 2021 22:28:17.128 * MASTER <-> REPLICA sync: Loading DB in memory
6904:S 27 Jun 2021 22:28:17.136 * Loading RDB produced by version 5.0.0
6904:S 27 Jun 2021 22:28:17.136 * RDB age 1814 seconds
6904:S 27 Jun 2021 22:28:17.136 * RDB memory usage when created 29745.77 Mb
# 从节点读取完毕,此时发现已经和主节点失去连接,开始发起重连
6904:S 27 Jun 2021 22:48:37.784 * MASTER <-> REPLICA sync: Finished with success
6904:S 27 Jun 2021 22:48:38.767 # Connection with master lost.
6904:S 27 Jun 2021 22:48:38.767 * Caching the disconnected master state.
6904:S 27 Jun 2021 22:48:38.767 * Reconnecting to MASTER 101.89.92.176:6379
# 从节点重连上主节点,发起部分数据同步
6904:S 27 Jun 2021 22:48:38.767 * MASTER <-> REPLICA sync started
6904:S 27 Jun 2021 22:48:38.770 * Non blocking connect for SYNC fired the event.
6904:S 27 Jun 2021 22:48:38.770 * Master replied to PING, replication can continue…
6904:S 27 Jun 2021 22:48:38.771 * Trying a partial resynchronization (request c7155b634d6e303d3fc5fab5c56f5ba73e4c77d9:40851390).
# 从节点向主节点发起全量数据同步请求
6904:S 27 Jun 2021 22:48:39.224 * Full resync from master: c7155b634d6e303d3fc5fab5c56f5ba73e4c77d9:54634433
6904:S 27 Jun 2021 22:48:39.224 * Discarding previously cached master state.

主节点日志
以下是主节点的日志,由于数据同步是从节点发起的,因此该日志结合从节点的日志一起看会比较清晰。

# 主节点收到全量数据同步请求后开始把内存数据持久化到磁盘上,生成RDB文件
5771:M 27 Jun 2021 21:58:03.220 * Starting BGSAVE for SYNC with target: disk
5771:M 27 Jun 2021 21:58:03.723 * Background saving started by pid 3446
# RDB文件持久化成功
5771:M 27 Jun 2021 22:07:05.781 * Background saving terminated with success
# RDB文件传输成功
5771:M 27 Jun 2021 22:25:22.198 * Synchronization with replica 10.16.99.155:6379 succeeded
# 失去和从节点的连接,主要是因为从节点再倒入主节点发给他的RDB文件
5771:M 27 Jun 2021 22:27:52.670 # Disconnecting timedout replica: 10.16.99.155:6379
5771:M 27 Jun 2021 22:27:52.670 # Connection with replica 10.16.99.155:6379 lost.
# 从节点完成数据初始化后重连主节点并发起部分数据同步
5771:M 27 Jun 2021 22:48:38.768 * Replica 10.16.99.155:6379 asks for synchronization
# 主节点报告由于lack of backlog,无法部分同步
5771:M 27 Jun 2021 22:48:38.768 * Unable to partial resync with replica 10.16.99.155:6379 for lack of backlog (Replica request was: 40851390).
# 主节点收到全量数据同步请求后开始把内存数据持久化到磁盘上,生成RDB文件
5771:M 27 Jun 2021 22:48:38.768 * Starting BGSAVE for SYNC with target: disk
5771:M 27 Jun 2021 22:48:39.221 * Background saving started by pid 26707

问题分析

从日志文件中大概能够总结出由于主节点的数据量比较大,从节点第一次全量同步数据需要很长时间,同步完毕后,由于lack of backlog无法做部分数据同步,只能再次发起全量数据同步。网上有很多关于lack of backlog问题的分析,这里就不再搬砖。这篇文章可以参考:Unable to partial resync with the slave for lack of backlog

解决方案

修改以下3个参数,能够解决无法部分同步的问题。

  • repl-timeout
  • repl-backlog-size
  • client-output-buffer-limit

如果不想重启主节点的话,可以直接在redis-cli中修改配置:

  • config set repl-timeout 3600
  • config set repl-backlog-size 536870912000(500GB)
  • config set client-output-buffer-limit “normal 0 0 0 slave 0 0 0 pubsub 33554432 8388608 60”

如果要查看当前Redis节点的配置情况,可以在redis-cli中查看:

  • config get repl-timeout
  • config get repl-backlog-size
  • config get client-output-buffer-limit
Captain QR Code

扫码联系船长

发表回复

您的电子邮箱地址不会被公开。