本文大部分内容引自《Redis深度历险:核心原理和应用实践》,感谢作者!!!
Redis是不是单线程的
Redis内部实际上不只有一个主线程,还有几个异步线程专门用来处理耗时操作
Redis懒惰删除key的原因
1、普通的del指令会直接释放对象内存且非常迅速,但是如果删除的是一个非常大的对象,就会导致单线程卡顿
2、Redis4.0之后引入了unlink指令,能对删除操作进行懒处理,丢给后台线程来异步回收内存;当unlink指令发出时,相当于把大树中的一个树枝别断了,然后扔到旁边的火堆里焚烧(异步线程池);树枝离开大树的一瞬间就再也无法被主线程中的指令访问到了,因为主线程只会沿着这颗大树来访问
> unlink key
OK
flush
Redis提供了flush和flushall指令用来清空数据库,这也是极其缓慢的操作。Redis4.0同样给这两个指令带来了异步化,在指令后增加async参数就可以将整棵大树连根拔起,扔给后台线程慢慢焚烧
> flushall async
OK
异步指令实现的原理-异步队列
1、主线程将对象的引用从“大树”中摘除后会将这个key的内存回收操作包装成一个任务塞进异步任务队列,后台线程会从这个异步队列中取任务;异步任务被主线程和异步线程同时操作,所以必须是一个线程安全的队列
2、不是所有的unlink都会延后处理,如果对应key所占用的内存很小,Redis会将对应的key内存立即回收,不会进行延后处理
AOF Sync很慢
Redis需要每秒同步一次AOF日志到磁盘来确保信息尽量不丢失,调用fsync函数将指定文件内容强制从内核缓存写入到磁盘中去;这个操作很耗时,所以Redis也将这个操作移到异步线程来完成;执行AOF Sync操作的线程是一个独立的异步线程,和前面的懒惰删除线程不是一个线程,同样它也有一个属于自己的任务队列,队列中只用来存放AOF Sync任务
更多异步删除点
Redis回收内存除了del和flush指令,还会存在于key的过期、LRU淘汰、rename指令以及从库全量同步时接收完rdb文件后悔立即进行的flush操作
Redis4.0为以下操作带来了异步删除机制,需要进行额外配置使以下操作异步处理
1、slave-lazy-flush 从库接受完 rdb 文件后的 flush 操作
2、lazyfree-lazy-eviction 内存达到 maxmemory 时进行淘汰
3、lazyfree-lazy-expire key 过期删除
4、lazyfree-lazy-server-del rename 指令删除 destKey