Redis slots迁移丢key问题排查

最近在公司wiki写了几篇还不错的wiki,感觉有分享的必要,所以贴出来和大家分享。
这个是redis的一个critical级别的bug,在目前的3.2.6的小版本都没有修复,只有在4.0rc2里面修了。就是说即使你们用12月发布的3.2.6都是有问题的。

1.问题

redis slots迁移的时候,在迁移之后key数量会变少.

2.排查

2.1思考

  • redis 3.x也是比较成熟的产品了,为什么会丢key?别人有没有遇到同样的问题?
  • 假设丢key了,如果key是因为expire丢失,那应该是正常,如果没有expire丢失,就是问题了,首先复现问题。

2.2复现问题

0.准备集群

造了两个节点的集群:10.0.0.10:20003和10.0.0.10:20004,最大可使用内存200M,并保证在测试过程中不会导致内存满等其他问题

10.0.0.10:20004> cluster nodes
2aed426536067077179a3d23875b93b223802dea 10.0.0.10:20003 master - 0 1482132098352 6 connected
03a53320815d8b5f774810f2d41329007d60ebf4 10.0.0.10:20004 myself,master - 0 0 7 connected 0-16383

key格式:{test}_i, 保证所有的key使用同一个slot。{test}_i的slot为6918,并且测试前slot里面没有key.

10.0.0.10:20004> cluster keyslot {test}_i
(integer) 6918
10.0.0.10:20004> cluster countkeysinslot 6918
(integer) 0
10.0.0.10:20003> cluster countkeysinslot 6918
(integer) 0

# 迁移函数,配合redis-trib fix迁移
def migrate_from_4_to_3(slot):
    cmd="cluster setslot %s migrating 2aed426536067077179a3d23875b93b223802dea" % (slot,)
    cli4.execute_command(cmd)
    cmd="cluster setslot %s importing 03a53320815d8b5f774810f2d41329007d60ebf4" % (slot,)
    cli3.execute_command(cmd)

def migrate_from_3_to_4(slot):
    cmd="cluster setslot %s migrating 03a53320815d8b5f774810f2d41329007d60ebf4" % (slot,)
    cli3.execute_command(cmd)
    cmd="cluster setslot %s importing 2aed426536067077179a3d23875b93b223802dea" % (slot,)
    cli4.execute_command(cmd)
1.非过期key测试
10.0.0.10:20003> cluster countkeysinslot 6918
(integer) 0
10.0.0.10:20004> cluster countkeysinslot 6918
(integer) 0

# 向10.0.0.10:20004写入20000个不带过期时间的key
for i in range(20000):
    cmd="set {test}_%s %s" % (i, i)
    print cmd, cli4.execute_command(cmd)

10.0.0.10:20004> cluster countkeysinslot 6918
(integer) 20000

# 迁移slot 6918
migrate_from_4_to_3(6918)
redis-trib fix 10.0.0.10:20004

#check
10.0.0.10:20003> cluster countkeysinslot 6918
(integer) 20000
10.0.0.10:20004> cluster countkeysinslot 6918
(integer) 0

结论: 20000个key全部迁移,没有问题。

2.部分带过期时间的key测试

使用和上面相同的方法,测试{20000个不过期的key,20000个带过期时间的key}的情况。使用了{test}_i的slot=6918和{bug}_i的slot=7910这两个slot进行了测试。

如果迁移的过程中没有key正在过期,发现迁移后key的数量也会减少

如果有迁移的过程中有key正在过期,那么迁移完成后key的数量少于20000,并且多次实验测试少的key的数量不同,有的时候少几百个,有的时候少2000多个。

说明,如果在迁移slot的过程中,如果有key过期,那么会对那么没有过期时间的key造成影响,导致丢失一些不过期的key.

3.是不是redis-trib的问题?

redis-trib在判断是不是迁移完成时,只判断了getkeysinslot,当getkeysinslot返回空时就直接认为迁移完成了,直接退出。
所以在代码里面添加了countkeysinslot,当两者同时为0时,在尝试判断10次在退出试一下。

# 修改后的redis-trib.rb
...
# Migrate all the keys from source to target using the MIGRATE command
zerocounttime = 0
while true
    keys = source.r.cluster("getkeysinslot",slot,o[:pipeline])
    cntkeysinslot = source.r.cluster("countkeysinslot",slot)
    
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值