最近生产环境的redis服务器由于key过期不及时,现在发现时key的个数已经暴增到5000多万了。然后运维同学那边就报警了,最大内存12G,已经用了9G多了,正好下面快要双11了,让我们快些解决。
redis服务器里面堆积大量的队列状态相关的key,其实这些key可以设置有效期,或者任务完成以后删除或者过期,但是由于我们使用类库的问题,这些key既没有删除也没有过期,堆积到redis里面去了,现在我们要做的就是删除这些无用key。在删除这些keys的过程中,走了不少弯路,这里说一下我最终采用的方案。
redis的del函数可以删除单个key,也可以删除多个key,del函数官方文档可以看这里。在google之后看到目前网络上很多文章的思路是使用keys匹配返回要删除的key,然后调用del函数去删除。这种方案在数据量较小时无可厚非,但如果像我这样面临的处理的数据有5千W时,keys的阻塞问题可能会给线上生产环境带来致命的问题。所以我们需要对这种方案作出一些修改。
可喜的是自从2.8.0以后redis提供scan来遍历key,而且这个过程是非阻塞,不会影响线上生产环境。最终经过修改的方案是用scan遍历要删除的key,然后调用del删除。
下面是我用python写的用来删除key的脚本。
import sys,redis
r = redis.Redis(host="127.0.0.1", port=6379,db=0)
if len(sys.argv) <= 1:
print("必须指明匹配key字符串")
exit(1)
pattern = sys.argv[1]
cursor = 0
num = 1
while 1 :
resut = r.scan(cursor, pattern, 10000)
del_keys = []
for i in resut[1]:
key = i.decode()
del_keys.append(key)
#print("del keys len :%d" % len(result))
if len(del_keys) == 0:
break
r.delete(*del_keys)
cursor = resut[0]
print("delete keys num : %dw" % (num))
num +=1
print("donen")
如何利用我这个脚本删除符合某个规则的key哪,如以king开头的key?
下面的命令即可完成上面的问题。
python3 main.py "king*"
期间我看到网上利用keys+del的lua脚本的方案,花了一段时间把scan+del改成lua脚本来删除。但是可惜的是目前redis并不支持这么做,由于scan返回的结果是不确定的,所以禁止在其后直接调用del操作。