网上关于Redis逐出功能和算法的文章比较多,这里就不浪费篇幅介绍,本文旨在介绍Redis 6.2以后一个Redis逐出上的重大优化(渐进式逐出),顺带整理下Redis在各个版本上逐出功能上的优化。
Redis有一个maxmemory配置,每次执行命令时如果发现当前Redis使用内存超过maxmemory时,会使用相应的策略(包含不逐出也是一种策略)把key进行逐出,直到Redis使用内存小于maxmemory,这句话包含了几个重要信息,我们分别来看下。
说明这个逐出检测是一个同步过程,如果逐出花费大量时间,Redis会长期不可用,甚至会触发切换。
策略包含如下几种,可根据相应场景进行测试,默认是NO_EVICTION
MAXMEMORY_VOLATILE_LRU
MAXMEMORY_VOLATILE_LFU
MAXMEMORY_VOLATILE_TTL
MAXMEMORY_VOLATILE_RANDOM
MAXMEMORY_ALLKEYS_LRU
MAXMEMORY_ALLKEYS_LFU
MAXMEMORY_ALLKEYS_RANDOM
MAXMEMORY_NO_EVICTION
这个使用内存可能会产生歧义,造成不符合预期的事件发生,使用内存定义
使用内存 = used_memory - AOF缓冲区 - slave缓冲区
所以如果normal客户端缓冲区突增(例如持续执行很大的命令,例如lrange 大list),可能也会造成突发逐出。
第二次灌入:1,000,000个key,观察可用性和逐出 + 800MB string (40个20MB)
./redis-cli debug populate 40 user 20971520
可以看到两个版本内存消耗几乎一致,并且在整个导入过程中未发生异常
客户端异常 | redis-cli latency | 耗时 | |
---|---|---|---|
6.0.15 | 持续发生 | min: 29, max: 347 | 52500ms |
7.0.11 | 未发生 | min: 0, max: 25330 | 51233ms |
可以看到Redis 7.0.11在同等状况下,可用性表现良好,下面来看下相关原理
文章开头已经提到:每次执行命令时如果发现当前使用内存超过maxmemory时,会使用相应的策略(包含不逐出也是一种策略)把key进行逐出,直到Redis使用内存小于maxmemory
(1) evictionTimer运行时间超过eviction_time_limit_us后,会开启evict时间事件并退出逐出,这样将逐出循环异步化并保证可用性。
//开始计时
elapsedStart(&evictionTimer);
/* Finally remove the selected key. */
if (bestkey) {
db = server.db+bestdbid;
robj *keyobj = createStringObject(bestkey,sdslen(bestkey));
delta = (long long) zmalloc_used_memory();
latencyStartMonitor(eviction_latency);
if (server.lazyfree_lazy_eviction)
dbAsyncDelete(db,keyobj);
else
dbSyncDelete(db,keyobj);
delta -= (long long) zmalloc_used_memory();
mem_freed += delta;
keys_freed++;
if (keys_freed % 16 == 0) {
if (slaves) flushSlavesOutputBuffers();
if (server.lazyfree_lazy_eviction) {
if (getMaxmemoryState(NULL,NULL,NULL,NULL) == C_OK) {
break;
}
}
/* After some time, exit the loop early - even if memory limit
* hasn't been reached. If we suddenly need to free a lot of
* memory, don't want to spend too much time here. */
if (elapsedUs(evictionTimer) > eviction_time_limit_us) {
// We still need to free memory - start eviction timer proc
startEvictionTimeProc();
break;
}
}
}
(2) eviction_time_limit_us计算方法:
可以看到新增maxmemory_eviction_tenacity参数用来控制超时:
(3) 用isEvictionProcRunning控制逐出时间事件
可以看到不同的maxmemory_eviction_tenacity值,逐出的粒度不尽相同:
下图展示了Redis在各个版本evict的相关优化和功能(如有漏掉,欢迎指正)
Redis 7.0需要大于7.0.5
is set to 100 (#11237)
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞1
添加新评论0 条评论