单线程Redis内部的过期key是怎么处理的?会不会同一时刻过期key太多,导致来不及删除?
【过期key集合】
Redis会将每个设置了过期时间的key放入一个独立的字典里,以后会定时遍历这个字典来删除到期的key。
除了定时遍历,还会使用惰性策略,即客户端访问这个key时,Redis发现这个key过期了,那就立即删除。
【定时扫描】
Redis默认每秒进行10次过期扫描,过期扫描不会遍历过期字典中所有的key,而是采取了一种策略:
1.从过期字典中随机选择20个key;
2.删除这20个key中已经过期的key;
3.如果过期的key的比例超过1/4,那就重复步骤(1)。
同时为了保证过期扫描不会出现循环过渡,导致线程卡死,算法还增加了扫描时间的上限,默认不会超过25ms。
如果在同一时期,有大量的key过期,那么Redis会持续扫描过期字典,直到过期字典中过期的key变得稀疏,才会停止,这就会导致线上读写请求出现明显的卡顿。另外,这种时候内存管理器也会频繁回收内存页,这也会产生一定的CPU消耗。
当客户端请求到来,服务器如果正好进入过期扫描状态,客户端的请求将会等待至少25ms才能进行处理,如果客户端将超时时间设置的比较短,那么就会出现大量的链接因为超时而关闭。
而且,此时还无法从Redis的slowlog中看到慢查询的记录,因为慢查询指的是逻辑处理过程慢,不包含等待时间。
对于一些定时结束的任务或者逻辑,且参加的人很多,如果业务上允许,最好是能够在过期时间上加一个随机时间戳,比如在目标过期时间上增加1天的随机时间。这样能够有效避免上述情形。
【从节点的过期策略】
从节点不会进行过期扫描,从节点对过期的处理是被动的。主节点在key到期时,会在AOF文件中增加一条del指令,同步到从节点从而让从节点删除过期key。
指令同步是异步进行的,所以如果主节点过期的key的del指令没有及时同步到从节点的话,就会出现主从数据不一致,主节点没有的数据在从节点还在。