Redis EXISTS DEL命令耗时过长问题排查

时间:2024-03-28 09:26:59

Redis EXISTS DEL命令耗时过长问题排查

问题发现:

44) 1) (integer) 993502

    2) (integer) 1482239898

    3) (integer) 114521

    4) 1) "EXISTS"

       2) "data_**Facade_load**k**Stack_sale_day_null_null_null_null"

33) 1) (integer) 993513

    2) (integer) 1482253748

    3) (integer) 133532

    4) 1) "DEL"

       2) "comment_loadCommentsBy**Id_459902_11"

 

参考:Redis EXISTS命令耗时过长case排查http://blog.csdn.net/chosen0ne/article/details/50543335

一、背景

redis慢日志分析平台上线后,随便看了一下,发现onestore使用的缓存集群,存在大量的EXISTS命令慢查询的情况:

Redis EXISTS DEL命令耗时过长问题排查

 

平均每个EXISTS命令需要13ms,最大耗时近20ms。这个结果很不科学啊,EXISTS命令只是执行一次hash查找操作,应该是us级别。

和相关同学了解业务背景如下:

- 业务是userfeed,存放用户发表的动态

- 使用zset存储一个用户发表的所有动态,key是用户id,集合中对应的是feedid。如果用户发表的动态很多,zset也很大

- redis集群作为onestore的缓存,过期时间是10分钟

- 在访问cache前会调用EXISTS查看是否命中,如果不命中就用onestore回填cache

由于一些用户发表的动态很多(2W+),所以存在很多的ZADD慢查询。

二、排查

 

1. redis的清除过期key的策略

- 被动方式:在事件循环中,每秒执行约10次,尽力删除过期的key,会有漏掉的情况

- 从expire set中随机检查20个key

- 删除到过期的key

- 如果超过25%的key都是过期了,就重复第一步(超过25%说明过期的key占比很多)

- 主动方式:

- 如果该key在被动方式中漏过,在其再次被访问时检查并清除

2. 查看代码

 

[cpp] view plain copy
 
 print?Redis EXISTS DEL命令耗时过长问题排查Redis EXISTS DEL命令耗时过长问题排查
  1. void existsCommand(redisClient *c) {  
  2.     expireIfNeeded(c->db,c->argv[1]);  // 检查该key是否过期,如果过期就delete掉  
  3.     if (dbExists(c->db,c->argv[1])) {  
  4.         addReply(c, shared.cone);  
  5.     } else {  
  6.         addReply(c, shared.czero);  
  7.     }  
  8. }  

在EXISTS命令处理函数中实现了清除过期key的主动策略,会先调用expireIfNeeded函数检查要访问的key是否过期,如果过期就delete掉这个key。del命令在删除元素很多的复合数据类型(list、hash、zset、set)时是一个很耗时的操作。由于存在元素很多的zset,和ZADD一样,在删除zset时需要一个一个遍历所有元素,时间复杂度是大O(n)。由于这个删除操作在EXISTS命令的处理函数中执行,所以导致EXISTS耗时过长。

 

3. redis慢日志验证

通过慢日志可以验证上述结论

Redis EXISTS DEL命令耗时过长问题排查

 

- EXISTS先检查‘user:94479529:feed’是否存在,该key已经过期,触发主动过期机制,将该key删除

- 从onestore获取该key的数据,然后通过ZADD回填

三、风险

该集群单个实例qps达到8k+,同时每天有10W+的慢查询。在redis存在大量慢查询时,会存在个别客户端超时的情况,导致请求失败。

四、后续处理

1. 增加过期时间,由10分钟到20分钟

2. 对redis集群扩容(试增加过期时间的效果而定)

对于redis删除大key耗时的问题,redis作者提供了解决方案,具体就是使用异步线程对大key进行删除操作,避免阻塞主线程。(中文翻译:)

 

from:http://blog.csdn.net/wsliangjian/article/details/52329320

 

-

-

-

=

=

=