简介Redis中的showlog功能
Redis有一个实用的slowlog功能,正如你可以猜到的,可以让你检查运行缓慢的查询.Slowlog将会记录运行时间超过Y微秒的最后X条查询.X和Y可以在redis.conf或者在运行时通过CONFIG命令:
CONFIGSETslowlog-log-slower-than5000 CONFIGSETslowlog-max-len25
进行设置。
slowlog-log-slower-than是用来设置微秒数的,因此上面的设置将记录执行时间超过5秒的查询.要获取记录的日志,你可以使用SLOWLOGGETX命令,这里X是你想要获取的记录条数:
SLOWLOGGET10
它将会展示一个唯一的id,时间戳和发生的查询,查询执行所花掉的时间和实际被执行的命令+参数.你可以通过SLOWLOGRESET擦出日志.
最后一次查看slowlog,我很不淡定的看到DEL命令的执行竟然花了超过20毫秒的时间.还记得吗,Redis是单线程的,因此这样会阻塞(并且严重的有碍)我们系统的并发.还有,因为这是一个写操作,它将会在向所有从属Redis服务复制的时候阻塞这一复制过程.额,到底这是咋回事呢?
也许除了我之外所有人都知道这个问题了,但是这证明了Redis的DEL命令的时间复杂度对于字符串和哈希值而言是O(1),而对于list、set和sortedset而言则是O(N)(这里的N是集合中数据项的数目).你会删除一个包含数百万条数据的set吗?那就等着阻塞吧.
我们的解决方案很简单:不去删除这些数据项,而是将它们重命名,并且在后台作业中用小而可间断的块去执行对它们的删除操作.首先,是我们的delayed_delete函数:
localkey=KEYS[1] localdata_type=redis.call('type',key).ok ifdata_type=='set'ordata_type=='zset'then localtemp='gc:tmp:'..redis.call('incr','gc:ids')..':'..key redis.call('rename',key,temp) returnredis.call('sadd','gc:'..data_type,temp) end returnredis.call('del',key)
这将会将集合重命名,并且将新的名称添加到gc:set或者gc:zsetset中(我们没有使用list,但如果你使用了的话,你也应该向其加入这方面的支持).
下一步我们安排了一个Ruby脚本每分钟运行一次:
require'redis' r=Redis.new(driver::hiredis) r.srandmember('gc:set',10000).eachdo|set| items=r.srandmember(set,5000) ifitems.nil?||items.length==0 r.srem('gc:set',set) next end r.srem(set,items) end r.srandmember('gc:zset',10000).eachdo|zset| ifr.zremrangebyrank(zset,0,5000)<5000 r.srem('gc:zset',zset) end end
你可以基于自己的需要将修改数字.你的集合有多大,以及它们被删除有多频繁?因为我们不去太过频繁的做这些类型的产出操作,我们可以一次只进行一小块的删除操作.
不过这种方法比直接删除更加的慢,但它在并发的环境下却可以表现得很好.