diff --git a/redis.conf b/redis.conf index 408d0c25800..697b1848f94 100644 --- a/redis.conf +++ b/redis.conf @@ -1209,6 +1209,14 @@ acllog-max-len 128 # in the system. It's a tradeoff between memory, CPU and latency. # # active-expire-effort 1 +# +# It allows the redis to evict keys earlier. The value of this parameter represents +# percent of the maxmemory value. It means how much memory the redis instance want to hold +# not to store the data. +# Default is 0, and the value could be set between 10 to 60. +# +# maxmemory-reserved-scale 0 + ############################# LAZY FREEING #################################### diff --git a/src/config.c b/src/config.c index 9de4ecd41b6..7aae22444d4 100644 --- a/src/config.c +++ b/src/config.c @@ -2463,6 +2463,19 @@ static int updateReplBacklogSize(const char **err) { return 1; } +static int updateMaxmemoryReserved(const char **err) { + UNUSED(err); + if (server.maxmemory_reserved_scale) { + if (server.maxmemory_reserved_scale < 10) { + server.maxmemory_reserved_scale = 10; + } else if (server.maxmemory_reserved_scale > 60) { + server.maxmemory_reserved_scale = 60; + } + } + server.maxmemory_available= (unsigned long long)server.maxmemory / 100.0 * (100 - server.maxmemory_reserved_scale); + return 1; +} + static int updateMaxmemory(const char **err) { UNUSED(err); if (server.maxmemory) { @@ -2470,6 +2483,7 @@ static int updateMaxmemory(const char **err) { if (server.maxmemory < used) { serverLog(LL_WARNING,"WARNING: the new maxmemory value set via CONFIG SET (%llu) is smaller than the current memory usage (%zu). This will result in key eviction and/or the inability to accept new write commands depending on the maxmemory-policy.", server.maxmemory, used); } + server.maxmemory_available= (unsigned long long)server.maxmemory / 100.0 * (100 - server.maxmemory_reserved_scale); startEvictionTimeProc(); } return 1; @@ -3124,6 +3138,7 @@ standardConfig static_configs[] = { createIntConfig("lfu-decay-time", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.lfu_decay_time, 1, INTEGER_CONFIG, NULL, NULL), createIntConfig("replica-priority", "slave-priority", MODIFIABLE_CONFIG, 0, INT_MAX, server.slave_priority, 100, INTEGER_CONFIG, NULL, NULL), createIntConfig("repl-diskless-sync-delay", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.repl_diskless_sync_delay, 5, INTEGER_CONFIG, NULL, NULL), + createIntConfig("maxmemory-reserved-scale", NULL, MODIFIABLE_CONFIG, 0, 100, server.maxmemory_reserved_scale, 0, INTEGER_CONFIG, NULL, updateMaxmemoryReserved), createIntConfig("maxmemory-samples", NULL, MODIFIABLE_CONFIG, 1, INT_MAX, server.maxmemory_samples, 5, INTEGER_CONFIG, NULL, NULL), createIntConfig("maxmemory-eviction-tenacity", NULL, MODIFIABLE_CONFIG, 0, 100, server.maxmemory_eviction_tenacity, 10, INTEGER_CONFIG, NULL, NULL), createIntConfig("timeout", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.maxidletime, 0, INTEGER_CONFIG, NULL, NULL), /* Default client timeout: infinite */ diff --git a/src/evict.c b/src/evict.c index 41712b926b1..71209fb11be 100644 --- a/src/evict.c +++ b/src/evict.c @@ -407,7 +407,11 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev if (level) *level = 0; return C_OK; } - if (mem_reported <= server.maxmemory && !level) return C_OK; + + if (server.maxmemory_reserved_scale) { + if (mem_reported <= server.maxmemory_available && !level) return C_OK; + } else if (mem_reported <= server.maxmemory && !level) + return C_OK; /* Remove the size of slaves output buffers and AOF buffer from the * count of used memory. */ @@ -416,15 +420,27 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev mem_used = (mem_used > overhead) ? mem_used-overhead : 0; /* Compute the ratio of memory usage. */ - if (level) *level = (float)mem_used / (float)server.maxmemory; + if (level) { + if (server.maxmemory_reserved_scale) + *level = (float)mem_used / (float)server.maxmemory_available; + else + *level = (float)mem_used / (float)server.maxmemory; + } - if (mem_reported <= server.maxmemory) return C_OK; + if (server.maxmemory_reserved_scale) { + if (mem_reported <= server.maxmemory_available) return C_OK; + } else if (mem_reported <= server.maxmemory) return C_OK; /* Check if we are still over the memory limit. */ - if (mem_used <= server.maxmemory) return C_OK; + if (server.maxmemory_reserved_scale) { + if (mem_used <= server.maxmemory_available) return C_OK; + } else if (mem_used <= server.maxmemory) return C_OK; /* Compute how much memory we need to free. */ - mem_tofree = mem_used - server.maxmemory; + if (server.maxmemory_reserved_scale) { + mem_tofree = mem_used - server.maxmemory_available; + } else + mem_tofree = mem_used - server.maxmemory; if (logical) *logical = mem_used; if (tofree) *tofree = mem_tofree; @@ -547,7 +563,7 @@ int performEvictions(void) { long long delta; int slaves = listLength(server.slaves); int result = EVICT_FAIL; - + if (getMaxmemoryState(&mem_reported,NULL,&mem_tofree,NULL) == C_OK) { result = EVICT_OK; goto update_metrics; diff --git a/src/server.c b/src/server.c index 8b4ec28e497..84a94289560 100644 --- a/src/server.c +++ b/src/server.c @@ -2537,6 +2537,9 @@ void initServer(void) { server.reply_buffer_resizing_enabled = 1; server.client_mem_usage_buckets = NULL; resetReplicationBuffer(); + if (server.maxmemory) { + server.maxmemory_available = (unsigned long long)server.maxmemory / 100.0 * (100 - server.maxmemory_reserved_scale); + } /* Make sure the locale is set on startup based on the config file. */ if (setlocale(LC_COLLATE,server.locale_collate) == NULL) { @@ -5521,6 +5524,7 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { char used_memory_scripts_hmem[64]; char used_memory_rss_hmem[64]; char maxmemory_hmem[64]; + char maxmemory_available_hmem[64]; size_t zmalloc_used = zmalloc_used_memory(); size_t total_system_mem = server.system_memory_size; const char *evict_policy = evictPolicyToString(); @@ -5543,6 +5547,7 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { bytesToHuman(used_memory_scripts_hmem,sizeof(used_memory_scripts_hmem),mh->lua_caches + mh->functions_caches); bytesToHuman(used_memory_rss_hmem,sizeof(used_memory_rss_hmem),server.cron_malloc_stats.process_rss); bytesToHuman(maxmemory_hmem,sizeof(maxmemory_hmem),server.maxmemory); + bytesToHuman(maxmemory_available_hmem,sizeof(maxmemory_available_hmem),server.maxmemory_available); if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, @@ -5579,6 +5584,9 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { "maxmemory:%lld\r\n" "maxmemory_human:%s\r\n" "maxmemory_policy:%s\r\n" + "maxmemory_reserved_scale:%d\r\n" + "maxmemory_available:%lld\r\n" + "maxmemory_available_human:%s\r\n" "allocator_frag_ratio:%.2f\r\n" "allocator_frag_bytes:%zu\r\n" "allocator_rss_ratio:%.2f\r\n" @@ -5630,6 +5638,9 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) { server.maxmemory, maxmemory_hmem, evict_policy, + server.maxmemory_reserved_scale, + server.maxmemory_available, + maxmemory_available_hmem, mh->allocator_frag, mh->allocator_frag_bytes, mh->allocator_rss, diff --git a/src/server.h b/src/server.h index bf0a154593d..9d3bd9e1433 100644 --- a/src/server.h +++ b/src/server.h @@ -1830,6 +1830,8 @@ struct redisServer { ssize_t maxmemory_clients; /* Memory limit for total client buffers */ int maxmemory_policy; /* Policy for key eviction */ int maxmemory_samples; /* Precision of random sampling */ + int maxmemory_reserved_scale; + unsigned long long maxmemory_available; int maxmemory_eviction_tenacity;/* Aggressiveness of eviction processing */ int lfu_log_factor; /* LFU logarithmic counter factor. */ int lfu_decay_time; /* LFU counter decay factor. */