一个 randomkey 命令致使的 Redis 事故

最近在公司对redis作一些二次开发时,发现一个randomkey命令可能致使整个redis实例长时间阻塞的问题,redis版本为3.2.9,以此记录。redis

问题

因为咱们公司使用的是redis集群版Codis,Codis内置的redis版本比较低,为3.2.9版本。dom

咱们近期在作Codis双机房时,须要对redis增长一些功能以此支持双机房,在开发和测试中发现,执行randomkey命令有可能致使整个redis长时间阻塞的问题。测试

randomkey主要功能是在redis中随机返回一个key出来,它随机选取key的代码以下。spa

一个 randomkey 命令致使的 Redis 事故

从上面代码能够看出来,若是当前是个slave,而且整个实例中存在大量已通过期的key(key已过时,但redis还将来得及删除key),执行randomkey命令时,因为找不到不过时的key,那么这个逻辑就会陷入死循环,阻塞住整个实例,整个实例不可用。blog

若是当前是master,执行randomkey命令时,redis会一直随机选择key,直到找到一个不过时的key,同时会把已通过期的key从整个实例中删除。开发

也就是说,在这种场景下,虽然不会长时间阻塞整个实例,但也会比执行一个普通的命令耗时要久。若是你在一个大量已过时的实例上执行randomkey命令,那可能会致使业务访问redis变慢。rem

解决

咱们对比了官方最新版的redis,已经针对此问题进行了修复。it

一个 randomkey 命令致使的 Redis 事故

解决方案就是增长一个最大重试次数,若是整个实例都是过时key,那么最多寻找maxtries次就返回,避免阻塞整个实例。ast

注意点

但要注意的是,若是达到了maxtries,那么返回的key是已通过期的key,你虽然在randomkey中看到了这个key,但对这个key执行其余命令时,仍是拿不到这个key的。class

这个方案只针对slave上执行这个命令进行了修复,也就是不会再让redis陷入死循环。

但在master上执行这个命令仍是会发生上述的变慢问题,若是你在使用redis时,常常使用这个命令,同时实例中存在大量已通过期的key,那么redis变慢颇有多是这个问题致使的。