Redis migrate slots丢key排查

1.问题

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

2.排查

2.1思考

  • redis 3.x也是比较成熟的产品了,为什么会丢key?别人有没有遇到同样的问题?

  • 假设丢key了,如果key是因为expire丢失,那应该是正常,如果没有expire丢失,就是问题了,首先复现问题。

2.2复现问题

0.准备集群

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

image

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

image

1.非过期key测试

image

结论: 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次在退出试一下。

image

结论:问题同样复现,不是这里的问题。

4.redis新版本如何?

我们用的redis版本为3.2.1,新版本是不是也存在这个问题?

在github上clone了最新的代码

3.x的最新版本3.2.6, 问题可以复现。

4.0, 问题没有复现。并且在测试中发现,4.0的redis-server和当前3.2的无法兼容。

并且在测试中发现,4.0的redis-server和当前3.2的无法兼容。

例如10.1.100.100:20003是3.2.1,10.1.100.100:20004是4.0,cluster nodes如下:

image

全部是4.0时,cluster nodes如下:

image

所以继续使用3.2.6的排查。

5.问题在哪?

修改redis-trib代码添加迁移的key 的log,修改redis 3.2.6的代码,在源节点的log里面打印处理的key

image

redis 3.2.6

image

问题复现,这次丢失的key为:

image

在redis-trib和source节点都能看到缺少的key的日志,很明显的看到key被迁移了。

在target的节点看到日志是这样的:

image

所有丢失的key的ttl都不对!

去源节点看一下ttl是啥?

image

说明所有丢失key的ttl因为没有处理而使用了前一个key的ttl!

问题出在下面代码的for循环,对于不过期的key,ttl应该是0,但是如果前面有过期的key,ttl>0.那么在下一个处理不过期key时,expireat=-1,不会进入if,ttl还是使用前一个ttl,导致一个永不过期的key因为ttl>0而过期。

image

6.提PR?

去github看一眼最新的代码,发现已经被@badboy发现并fix了,好悲伤~

https://github.com/antirez/redis/pull/3673/files

更新日期:
本文总阅读量