再谈分布式锁
在集群中,如果一个客户端申请了一把锁,然后主节点挂了,从节点还未来得及同步的时候,另一个客户端取得了锁,这就相当于两个客户端拿到了一把锁,这样不安全。
redlock算法
加锁时会向过半节点发送set指令,只要过半节点成功,就加锁成功,释放锁时向所有节点发送del指令。
redlock会导致性能下降。
过期策略
redis将设置了过期时间的key单独放在一个集合里,定时遍历删除,除此之外,还会使用惰性策略删除,即当访问的时候检查一下这个key。
定时扫描策略
redis默认每秒进行十次扫描,扫描策略是一种简单的贪心策略。
-
从过期字典中随机获取20条数据,然后删除,如果过期的key占比超过四分之一的话,就继续取20条。
-
为了保证过期扫描不会出现循环过度,导致线程卡死,上限不会超过25ms
-
redis会持续扫描过期字典,直至过期的key变得稀疏,,这就是导致线程卡顿的一个原因,另一个原因就是内存管理器需要频繁的回收内存页。
-
当客户端请求到来的时候,服务器如果刚好进入了过期扫描状态,那么就会至少等待25ms后再处理。
-
不要将key的过期时间都设置在同一个时间,会导致线程卡顿。
从节点的过期策略
从节点不会过期扫描,从主节点同步,有延迟。
LRU
当redis的内存超出物理内存限制的时候,内存数据会与磁盘频繁的交换,会让redis的性能急剧下降。
几种清楚空间的策略:
- noeviction:不会继续写请求,只允许读,默认的淘汰策略
- volatile-lru:尝试淘汰设置了过期时间的key,最少使用的优先淘汰。
- volatile-ttl:比较key的剩余寿命,寿命小的优先淘汰
- volatilr-random:设置了过期时间的key随机淘汰
- allkeys-lru:与第二个相同,不过是针对所有key
- allkeys-random:所有key随机淘汰
LRU算法
除了需要的key/value字典外,还要一个链表,按一定的顺序记录元素,当空间满时,会踢掉链表尾部的元素,当元素被使用时会移动到表头。
近似LRU算法
redis采用的是近似lru算法,为每个key设置了一个小字段,24bit,是最后一次被访问的时间戳。使用懒惰删除,当执行写操作时发现了maxmemory,就会随机采样出5个key,淘汰掉最老的key,直至不出现maxmemory为止。
懒惰删除
redis进行懒惰删除的原因是当删除的一个key是非常大的对象时,会导致单线程的卡顿。
unlink指令,丢给后台自己慢慢跑。
flush
清空数据库flushdb与flushall,很慢,加上async,后台跑。
异步队列
将redis key的内存回收包装成一个任务,,塞进异步队列,后台从这个异步队列中读取任务进行执行。
aof也很慢,所以也会使用的异步队列。