1.1.1. 20.懒惰删除

Redis 是单线程,单线程为 Redis 带来了代码的简洁性和丰富多样的数据结构。不过 Redis 的内部实际上不止一个主线程,还有几个异步线程来专门处理一些耗时的操作。

为什么要懒惰删除(lazy free)

删除指令 del,是非常快的操作,没有延迟。但是当如果一个 key 非常的大,如包含了千万元素的 hash 那么删除就会造成单线程卡顿。

为了解决这个问题,Redis 4.0 引入了 「unlink」指令,它能对删除操作进行懒处理,也就是丢给后台异步回收内存。

127.0.0.1:6379> set name jk4905
OK
127.0.0.1:6379> unlink name
(integer) 1

可能有人会担心,如果多个线程同时修改数据结果该怎么办。关于这个,可以这样理解, Redis 的内存所有有效数据当做一个大树,当执行了 unlink 之后,它只是把这个大树的一个树枝折断了,扔到火堆里焚烧(异步线程池),树枝离开大树的一瞬间,它就不能再被主线程的其他指令访问到了,因为主线程只会沿着这个大树访问。

flush

Redis 提供了 「flushdb」 「flushall」 指令,用来清空数据库,但这个也是非常缓慢的操作。 Redis4.0 之后,也将这两个指令异步化,在指令后加入 「async」参数就可以将整颗大树连根拔起。

127.0.0.1:6379> flushall async
OK

异步队列

主线程将对象的引用从「大树」中摘除后,会将这个 key 的内存回收操作包装成一个任务,塞进异步任务队列,后台线程会读取这个异步任务队列中的任务。

异步队列

不是所有的 「unlink」操作都会延后处理,如果对应的 key 占用非常的小,还是会想 del 指令一样,立刻执行回收。

AOF Sync 也很慢

Redis 需要每秒一次(可配置)的同步 AOF 日志到磁盘,确保消息不丢失,需要调用 sync 函数,但是这个操作会比较耗时,会导致主线程的效率下降,所以 Redis 也将这个操作异步化。执行 AOF Sync 操作是一个独立线程(区别于前面的懒惰删除),同样也有属于自己的任务队列,队列中只用来存放 AOF Sync 任务。

更多异步删除点

Redis 回收内存除了 del 和 flush 之外,还会对过期的 key,LRU 淘汰、rename 指令以及从库全量同步接收完后立即执行的 flush 操作。

Redis3.0 还带来异步删除机制,打开这些需要额外的配置选项:

  1. slave-lazy-flush 从库接受完 rdb 文件后的 flush 操作
  2. lazyfree-lazy-eviction 内存达到 maxmemory 时进行淘汰
  3. lazyfree-lazy-expire key 过期删除
  4. lazyfree-lazy-server-del rename 指令删除 destKey
Copyright © Kagami丶 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-12-10 20:25:25

results matching ""

    No results matching ""