redis lazyfree空间懒释放的源码分析

    xiaoxiao2021-04-12  39

           redis是一个内存数据库,必然就存在比较多的内存释放,然而内存释放又是一个比较重的操作,这样就会

    影响redis的正常运转效率。所以,redis对于部分内存的释放采取了懒释放。空间懒释放就是将内存的释放交由

    专门的线程进行释放操作。

          redis懒释放的空间主要包括三种:

          1)对象空间的释放

          2)DB空间的异步释放

          3)slots-keys空间释放

    对象空间的释放

         对象释放的场景主要有del命令,过期键删除,内存淘汰等三种。对象释放是否采用懒释放取决于相关配置:      1)del命令——server.lazyfree_lazy_server_del      2)  过期键删除——server.lazyfree_lazy_expire       3)内存淘汰——lazyfree_lazy_eviction del操作 int dbDelete(redisDb *db, robj *key) { return server.lazyfree_lazy_server_del ? dbAsyncDelete(db,key):dbSyncDelete(db,key); }过期键删除 int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) { long long t = dictGetSignedIntegerVal(de); if (now > t) { …… if (server.lazyfree_lazy_expire) dbAsyncDelete(db,keyobj); else dbSyncDelete(db,keyobj); } }内存淘汰 int freeMemoryIfNeeded(void) { …… if (bestkey) { if (server.lazyfree_lazy_eviction) dbAsyncDelete(db,keyobj);// 异步释放 else dbSyncDelete(db,keyobj);//同步释放 …… } }对象空间懒释放 #define LAZYFREE_THRESHOLD 64 int dbAsyncDelete(redisDb *db, robj *key) { dictEntry *de = dictUnlink(db->dict,key->ptr); if (de) { robj *val = dictGetVal(de); size_t free_effort = lazyfreeGetFreeEffort(val);//计算释放对象的大小 //释放对象的大小大于LAZYFREE_THRESHOLD,放入异步线程组的队列,异步释放 if (free_effort > LAZYFREE_THRESHOLD) { atomicIncr(lazyfree_objects,1,lazyfree_objects_mutex); bioCreateBackgroundJob(BIO_LAZY_FREE,val,NULL,NULL); dictSetVal(db->dict,de,NULL); } }//释放对象小于LAZYFREE_THRESHOLD,直接同步释放 if (de) { dictFreeUnlinkedEntry(db->dict,de); if (server.cluster_enabled) slotToKeyDel(key); return 1; } }

    DB空间的懒释放

             当需要异步删除DB的时候,redis会申请新的哈希表作为新的DB,原DB内存的释放操作交给异步任务处理 线程执行。 //清空DB long long emptyDb(int dbnum, int flags, void(callback)(void*)) { int j, async = (flags & EMPTYDB_ASYNC); …… for (j = 0; j < server.dbnum; j++) { if (dbnum != -1 && dbnum != j) continue; removed += dictSize(server.db[j].dict); if (async) { emptyDbAsync(&server.db[j]); } …… } …… return removed; }//异步清空DB void emptyDbAsync(redisDb *db) { dict *oldht1 = db->dict, *oldht2 = db->expires; db->dict = dictCreate(&dbDictType,NULL);//创建新的DB db->expires = dictCreate(&keyptrDictType,NULL); atomicIncr(lazyfree_objects,dictSize(oldht1), lazyfree_objects_mutex); //放入异步任务处理线程队列,异步释放DB的内存空间 bioCreateBackgroundJob(BIO_LAZY_FREE,NULL,oldht1,oldht2); }

    slots-keys空间释放

              在redis cluster模式下,slots-keys用于记录键值对存放的slot对映关系,由跳跃表数据结构保存。当redis  cluster需要清空slots-keys的时候,会先创建一个新的跳跃表作为新的slots-keys,然后将老的slots-keys释放工 作交给异步任务处理线程。 long long emptyDb(int dbnum, int flags, void(callback)(void*)) { int j, async = (flags & EMPTYDB_ASYNC); …… if (server.cluster_enabled) { if (async) {// 异步清空slots-key slotToKeyFlushAsync(); } else { slotToKeyFlush(); } } } void slotToKeyFlushAsync(void) { zskiplist *oldsl = server.cluster->slots_to_keys; server.cluster->slots_to_keys = zslCreate(); atomicIncr(lazyfree_objects,oldsl->length, lazyfree_objects_mutex); //放入异步任务处理线程队列,异步释放slots_to_keys的内存空间 bioCreateBackgroundJob(BIO_LAZY_FREE,NULL,NULL,oldsl); }
    转载请注明原文地址: https://ju.6miu.com/read-667795.html

    最新回复(0)