redis-cli keys * | args redis-cli del
(error) ERR network error
(30.00s)
#执行了一条 keys xxxxx* 命令,令数据库宕机了,怪不得技术总监发狠话:谁要是敢用 keys 命令,直接收拾包袱走人。接下来我们看看是什么回事:
最近有好多个项目要迁移了,一般迁移前都会做评估,对现有的业务,资源,关系等等做整理,其中有个项目,在做旧云 与 新云之间的数据源(redis)同步时,同步工具卡死了,新云的数据源竟然报警,内存不足!纳尼!!!!用的可是 8G容量的redis实例阿!why!!!! 赶紧查下redis内存信息
info memory
used_memory:16638616792
used_memory_human:16.88G
dbsize
(integer) 98923051
旧云的redis实例的key竟然高达 16G+,接近1亿个key,我的天,操着为公司节省资源的心,我发誓一定要把一切的垃圾通通清掉,于是就走向了深渊
开始我使用 big key命令
[0.43%] Sampled 1000000 keys so far
[0.87%] Sampled 2000000 keys so far
但是一个下午过去了,才0.87%,果断放弃了,选择直接看业务代码,后来发现是因为某个key没有设过期时间造成的,于是就想看看它的量有多大,于是就有了下面的操作
redis-cli keys * | args redis-cli del
(error) ERR network error
(30.00s)
直接30秒超时,并且直接锁住了整个redis,执行 keys 模糊的匹配命令是为了清理没用的键,但是没有考虑到keys *进行模糊匹配引发 Redis 锁,造成 Redis 锁住,CPU 飙升,引起了所有调用链路的超时并且卡住,等 Redis 锁的那几秒结束,所有的请求流量全部请求到 RDS 数据库中,使数据库产生了雪崩,使数据库宕机
Redis从2.8版本开始支持scan命令,SCAN命令的基本用法如下:
因为KEYS命令的时间复杂度为O(n),而SCAN命令会将遍历操作分解成m次,然后每次去执行,从而时间复杂度为O(1)。也解决使用keys命令遍历大量数据而导致Redis服务器阻塞的情况。所以建议使用下边的指令进行批量的删除操作:
redis-cli --scan --pattern "key的前缀*" | xargs -L 1000 redis-cli del
最后,经过删除命令,redis实例的内存占用,之下下降到 不到100M,直接换要给1g的实例,刚刚,经过1天的折腾,为公司剩下了资源,也算是很有意义产出了,日报周报赶紧安排!!!
总结 因为Redis的KEYS在某种情况下会阻塞。在生产环境中一定要慎用慎用,有个真实真案件小哥哥生产用KEYS,最终导致服务宕机。后果很严重,产生的经济损失就不说了。
切记严重会导致程序的雪崩,删除的时候用SCAN命令,看完这篇文章应该都记住了。