开发项目中经常会用到redis做临时存储,比如一些上报较为频繁的浏览、点击等记录信息,都会事先丢到redis中,再由定时脚本将redis中的数据读取出来,处理完成过后入库、删除redis信息,一套下来行云流水,看起来并没有任何问题...
自嘲一波
问题出现在使用了KEYS
上...虽然知道这个东西会导致全表查询,并且官方并不推荐使用,但还是犯傻逼了,没当一回事儿...因为平时存放在数据库的量并不大,百万级,并没有发现有什么性能问题(可能已经有了, 但是很不明显)
直到公司的项目上线,并且数据增长出乎预料,内部逐渐发现接口好像时不时的会有一些卡顿,而且愈发严重..
开始以为是数据库内容增长,可能某个查询条件没有做索引导致的慢查询,结果发现并没有任何慢查询记录...
最后在redis
服务器上发现redis-server
会在每分钟开始的时候cpu瞬间100%,并且持续大几秒,同时在这个时间段内接口也会无响应,直到redis-server
的cpu负载降低过后,所有接口请求会一起返回。
由于问题是周期性的复现,第一时间就锁定到了cron.d
定时任务上, 在查看几个* * * * *
的任务代码过后猛地发现用到了keys('analysis_xxxx_xxx_*')
, 瞬间想起来keys可能导致的效率问题,再使用redis-cli INFO
发现表中已经有上千万的数据, 这时候keys
带来的效率问题就显而易见了, 而且是灾难级的问题...
解决方案
使用SCAN
代替
1 2 3 4 5 6 7 8 9 10 11 12 |
cursor = 0 count = 100 while True: start_time = time.time() cursor, keys = r.scan(cursor=cursor, match='analysis_xxx_*', count=count) end_time = time.time() print(f'获取到{len(keys)}条数据, 耗时{end_time-start_time}秒') // 逻辑代码 if cursor == 0: break |