Redis 7.0 的 maxmemory-clients 能否限制所有客户端内存总使用量?
摘要:背景 之前分享个 case(Redis 内存突增时,如何定量分析其内存使用情况),一个 Redis 实例的内存突增,used_memory最大时达到了 78.9G,而该实例的maxmemory配置却只有 16G,最终导致实例中的数据被大量驱
背景
之前分享个 case(Redis 内存突增时,如何定量分析其内存使用情况),一个 Redis 实例的内存突增,used_memory最大时达到了 78.9G,而该实例的maxmemory配置却只有 16G,最终导致实例中的数据被大量驱逐。
导致这个问题的一个常见原因是客户端占用的内存过多。
Redis 中,客户端内存主要包括三部分:输入缓冲区(暂存客户端命令)、输出缓冲区(缓存发送给客户端的数据),以及客户端对象本身的开销。
其中,输入缓冲区可通过client-query-buffer-limit限制,输出缓冲区可通过client-output-buffer-limit限制。
但这两个参数只能限制单个客户端。
在客户端数量较多的情况下,即使单个客户端占用不大,客户端内存的总量仍可能失控。
为了解决这一问题,Redis 7.0 引入了maxmemory-clients,用于限制所有客户端可使用的内存总量。
下面看看具体的实现细节。
配置
standardConfig static_configs[] = {
...
createSSizeTConfig("maxmemory-clients",NULL, MODIFIABLE_CONFIG,-100, SSIZE_MAX, server.maxmemory_clients,0, MEMORY_CONFIG | PERCENT_CONFIG,NULL, applyClientMaxMemoryUsage),
...
};
maxmemory-clients的默认值为 0,最小值为 -100,对应的内部变量是server.maxmemory_clients。
该参数既可以设置为正数,也可以设置为负数:
正数:表示客户端内存总使用量的上限。因为该参数的类型是 MEMORY_CONFIG,所以可以指定 kb/mb/gb 之类的单位。不指定,则默认是字节。
负数:表示按 maxmemory 的百分比限制客户端内存。例如:maxmemory-clients = -50表示客户端内存总量不得超过 maxmemory 的 50%。
这一点是在getClientEvictionLimit函数中实现的。
size_tgetClientEvictionLimit(void){
size_tmaxmemory_clients_actual = SIZE_MAX;
if(server.maxmemory_clients <0&& server.maxmemory >0) {
unsignedlonglongmaxmemory_clients_bytes = (unsignedlonglong)((double)server.maxmemory * -(double) server.maxmemory_clients /100);
if(maxmemory_clients_bytes <= SIZE_MAX)
maxmemory_clients_actual = maxmemory_clients_bytes;
}
elseif(server.maxmemory_clients >0)
maxmemory_clients_actual = server.maxmemory_clients;
else
return0;
/* Don't allow a too small maxmemory-clients to avoid cases where we can't communicate
* at all with the server because of bad configuration */
if(maxmemory_clients_actual <1024*128)
maxmemory_clients_actual =1024*128;
returnmaxmemory_clients_actual;
}
实现细节
当通过CONFIG SET命令调整maxmemory-clients的值时,会调用applyClientMaxMemoryUsage函数进行处理。
