redis is a memory database, there must be more memory release, but memory release is a heavy operation, so it will be
It affects the normal operation efficiency of redis. So redis lazily releases some memory. Spatial lazy release is the release of memory by hand
Special threads perform release operations.
There are three main types of space released by redis laziness: redis laziness, redis laziness, redis laziness, redis laziness, redis laziness, redis laziness, redis laziness and redis laziness.
1) Release of object space
2) Asynchronous release of DB space
3) slots-keys space release
Release of Object Space
Object release scenarios include del command, deletion of expired keys, memory obsolescence and so on. Whether object release is lazy depends on the configuration:
Del command - server.lazyfree_lazy_server_del
2) Delete expired keys - server.lazyfree_lazy_expire
3) Memory Elimination - lazyfree_lazy_eviction
del operation
Delete expired keysint dbDelete(redisDb *db, robj *key) { return server.lazyfree_lazy_server_del ? dbAsyncDelete(db,key):dbSyncDelete(db,key); }
Memory obsolescenceint 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); } }
Lazy Release of Object Spaceint freeMemoryIfNeeded(void) { ...... if (bestkey) { if (server.lazyfree_lazy_eviction) dbAsyncDelete(db,keyobj);// Asynchronous release else dbSyncDelete(db,keyobj);//Synchronized release ...... } }
#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);//Calculate the size of the released object //Release object size is larger than LAZYFREE_THRESHOLD, put in the queue of asynchronous thread group, asynchronous release if (free_effort > LAZYFREE_THRESHOLD) { atomicIncr(lazyfree_objects,1,lazyfree_objects_mutex); bioCreateBackgroundJob(BIO_LAZY_FREE,val,NULL,NULL); dictSetVal(db->dict,de,NULL); } }//Release object less than LAZYFREE_THRESHOLD, direct synchronous release if (de) { dictFreeUnlinkedEntry(db->dict,de); if (server.cluster_enabled) slotToKeyDel(key); return 1; } }
Lazy Release of DB Space
When DB is deleted asynchronously, redis requests a new hash table as the new DB, and the release of the original DB memory is handed over to the asynchronous task.
Thread execution.
//Clear 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; }//Asynchronous Cleaning of DB void emptyDbAsync(redisDb *db) { dict *oldht1 = db->dict, *oldht2 = db->expires; db->dict = dictCreate(&dbDictType,NULL);//Create a new DB db->expires = dictCreate(&keyptrDictType,NULL); atomicIncr(lazyfree_objects,dictSize(oldht1), lazyfree_objects_mutex); //Put in the asynchronous task processing thread queue and asynchronously release DB's memory space bioCreateBackgroundJob(BIO_LAZY_FREE,NULL,oldht1,oldht2); }
slots-keys space release
In redis cluster mode, slots-keys are used to record the slot mapping relationship stored by key-value pairs and are saved by jump table data structure. When redis
When cluster needs to empty slots-keys, it creates a new jump table as a new slots-keys, and then releases the old slots-keys.
Handle threads for asynchronous tasks.
long long emptyDb(int dbnum, int flags, void(callback)(void*)) { int j, async = (flags & EMPTYDB_ASYNC); ...... if (server.cluster_enabled) { if (async) {// Asynchronous clearing 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); //Put in the asynchronous task processing thread queue and asynchronously release slots_to_keys memory space bioCreateBackgroundJob(BIO_LAZY_FREE,NULL,NULL,oldsl); }