Redis lazyFree机制

背景

在使用DEL命令删除体积较大的键,又或者在使用FLUSHDB和FLUSHALL删除包含大量键的数据库时,造成redis阻塞的情况;另外redis在清理过期数据和淘汰内存超限的数据时,如果碰巧撞到了大体积的键也会造成服务器阻塞。

为了解决以上问题, redis 4.0 引入了lazyfree的机制,它可以将删除键或数据库的操作放在后台线程里执行, 从而尽可能地避免服务器阻塞。

lazyfree机制

lazyfree的原理就是在删除对象时只是进行逻辑删除,然后把对象丢给后台,让后台线程去执行真正的destruct,避免由于对象体积过大而造成阻塞。

Redis给新加入的lazyfree线程起了个名字叫BIO_LAZY_FREE,后台线程根据type判断出自己是lazyfree线程,然后再根据bio_job里的参数情况去执行相对应的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void *bioProcessBackgroundJobs(void *arg) {
...
if (type == BIO_LAZY_FREE) {
/* What we free changes depending on what arguments are set:
* arg1 -> free the object at pointer.
* arg2 & arg3 -> free two dictionaries (a Redis DB).
* only arg3 -> free the skiplist. */
if (job->arg1)
lazyfreeFreeObjectFromBioThread(job->arg1);
else if (job->arg2 && job->arg3)
lazyfreeFreeDatabaseFromBioThread(job->arg2, job->arg3);
else if (job->arg3)
lazyfreeFreeSlotsMapFromBioThread(job->arg3);
}
...
}
  • 后台删除对象,调用decrRefCount来减少对象的引用计数,引用计数为0时会真正的释放资源。
    1
    2
    3
    4
    void lazyfreeFreeObjectFromBioThread(robj *o) {
    decrRefCount(o);
    atomicDecr(lazyfree_objects,1);
    }
  • 后台清空数据库字典,调用dictRelease循环遍历数据库字典删除所有对象。
    1
    2
    3
    4
    5
    6
    void lazyfreeFreeDatabaseFromBioThread(dict *ht1, dict *ht2) {
    size_t numkeys = dictSize(ht1);
    dictRelease(ht1);
    dictRelease(ht2);
    atomicDecr(lazyfree_objects,numkeys);
    }
  • 后台删除key-slots映射表,原生redis如果运行在集群模式下会用,云redis使用的自研集群模式这一函数目前并不会调用。
    1
    2
    3
    4
    5
    void lazyfreeFreeSlotsMapFromBioThread(rax *rt) {
    size_t len = rt->numele;
    raxFree(rt);
    atomicDecr(lazyfree_objects,len);
    }

过期与逐出

redis在缓存过期与逐出期间,删除动作也可能会阻塞redis。当从节点接收到完整的rdb文件后,也需要将当前内存进行一次性清空,用来加载最新数据。
所以redis 4.0这次除了显示增加unlink、flushdb async、flushall async命令之外,还增加了4个后台删除配置项,分别为:

  • slave-lazy-flush:slave接收完RDB文件后清空数据选项
  • lazyfree-lazy-eviction:内存满逐出选项
  • lazyfree-lazy-expire:过期key删除选项
  • lazyfree-lazy-server-del:内部删除选项,比如rename srckey destkey时,如果destkey存在需要先删除destkey

以上4个选项默认为同步删除,可以通过config set [parameter] yes打开后台删除功能。