Redis Cluster分片数据迁移过程中的挑战

前两天写了一篇文章《从零搭建Redis Cluster分片集群》,但是在实际部署的过程中,还是发现了很多问题。主要集中在Redis Cluster分片迁移Slot和Redis主从同步数据两个方面。

Redis Cluster集群数据迁移

Redis Cluster搭建好以后涉及到划分Slot槽位和迁移数据。一般情况下如果是新建的一套Redis Cluster集群就不会涉及到该问题。但是如果项目之前已经在运行Redis,需要把原redis的数据导入新的Redis Cluster集群中。

Redis Cluster数据导入

默认情况下使用以下命令:

./redis-cli -a Mypassword --cluster import 10.16.99.157:6379 --cluster-from 10.16.99.133:6379 --cluster-from-pass Mypassword --cluster-replace

其中10.16.99.157是集群中的一个主节点,10.16.99.133是原Redis服务器。然而在实际数据迁移过程中,由于原redis服务器内存不足,迁移到一半,服务器就崩了。使用以下命令在原服务器上可以看出由于内存耗尽,Redis服务被强制退出:

dmesg -T | egrep -i -B100 “killed process”
out of memory, Killed process

Redis Cluster主节点数据导入

如果无法直接从原Redis服务器把数据导入至Redis Cluster集群。那么我们可以使用另外一种方案。首先需要先将所有的slot移动到一台主节点上,随后把旧数据通过rdb文件导入到该主节点。然而,如果原有的Redis服务器没有开启RDB,只能尝试连入Redis以后,使用bgsave在后台做Redis备份,正常情况下,20分钟以内可以完成。
background saving succss

BGSAVE持久化失败
但是在生产环境中却不是那么回事。在Redis中执行RDB,结果显示失败,应该还是内存不足导致子进程被强制关闭。

因此,我尝试开启AOF模式。在Redis Cli中执行:

config set appendonly yes

正常情况下,大约也需要20分钟才能完成。
AOF success

心得
在Redis服务器内存不足的情况下,是否能够持久化成功,完全就看运气。因为不能停机,所以无法升级服务器的内存,只能想办法删除占用内存大的主键,具体方法后文中会提到。

对现有数据进行分片和移动槽位
接下来,我把RDB数据拷贝到新Redis集群的主节点上后,重启Redis主节点读取持久化的数据,并通过以下命令重新分片:

./redis-cli -a Mypassword --cluster reshard 10.16.99.157:6379

上述命令会询问要移动多少个slot(范围是1到16383),来源主节点和目标主节点等信息。随后会自动迁移Slot到目标节点中。然而在自动分片迁移的过程中,分片的主节点又崩了。目前最大的问题是,当前服务器是8核32G的云主机,Redis启动以后使用了31G内存,以下是当前内存状态:
redis memory free

因此在目前情况下,只有想办法提升主机的内存或者减少Redis的内存使用才能顺利分片。如果条件允许,可以购买同区域的64G内存的服务器,并加入到Redis集群中。在实际操作中,我通过扫描Redis中的所有主键并检查每个主键的内存使用情况,最后决定删除无效主键从而降低Redis的内存使用。

rc_end = []
try:
    rc_end = rc.scan_iter("*")
except Exception as e:
    print(e)
    
for key in rc_end:
    size = 0
    memory = rc.memory_usage(key)
    keyType = rc.type(key)
    if keyType == b'set':
        size = rc.scard(key)
    elif keyType == b'zset':
        size = rc.zcard(key)
    print(f"info:{key.decode('utf-8')}\t{size}\t{memory}")

随后使用bash命令行把数据格式化成csv文件,并分析哪个主键占用了较大的内存空间,删除掉无用的主键即可。

grep 'info:' a.log | sed 's/.*info://' > slots1.txt

Slot过大导致迁移超时

在迁移的过程中又遇到新的问题。有一个槽位迁移过程中卡住了,最终导致迁移超时分片失败。在我遇到的情况中,其中一个set类型的key中有79,492,879个值,使用约6G内存。目前决定暂不迁移这个槽位,以下是检查该槽位的一个方法步骤:

  • 查看槽位4000中有多少个主键:
  • CLUSTER COUNTKEYSINSLOT 4000
    
  • 通过查看槽位中的key数量,列出所有的主键。如果槽位4000中有3个主键:
  • CLUSTER GETKEYSINSLOT 4000 3
    
  • 使用type查看每个主键的类型,对于set类型和zset类型要额外关注
  • 查看重要主键占用内存情况:
  • MEMORY USAGE key
    

总结

Redis集群分片和槽位移动直接影响到每一个主节点的内存占用情况。如果槽位划分不均匀,或者某一个槽位中的主键规模非常大,就很可能导致该节点内存使用量过大。因此,在实际项目中,要时长关注Redis的内存使用情况,对于内存使用量飙升的Redis主节点,要检查槽位情况和主键情况。

相关文档
Redis Reshard机制:http://redisdoc.com/topic/cluster-spec.html#live-reconfiguration
Redis槽位操作文档:https://redis.io/commands/cluster-setslot
Redis主键迁移文档:https://redis.io/commands/migrate

Captain QR Code

扫码联系船长

发表回复

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