Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add maxmemory-reserved-scale parameter for evicting key earlier to avoid OOM #831

Open
wants to merge 2 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -2471,6 +2471,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) {
Expand All @@ -2482,6 +2495,8 @@ static int updateMaxmemory(const char **err) {
"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;
Expand Down Expand Up @@ -3181,6 +3196,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.replica_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, 64, 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 */
Expand Down
28 changes: 23 additions & 5 deletions src/evict.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,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 replicas output buffers and AOF buffer from the
* count of used memory. */
Expand All @@ -411,15 +415,29 @@ 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;
Expand Down
10 changes: 10 additions & 0 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -2621,6 +2621,11 @@ void initServer(void) {
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) {
serverLog(LL_WARNING, "Failed to configure LOCALE for invalid locale name.");
Expand Down Expand Up @@ -5512,6 +5517,7 @@ sds genValkeyInfoString(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();
Expand All @@ -5533,6 +5539,7 @@ sds genValkeyInfoString(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");
/* clang-format off */
Expand Down Expand Up @@ -5570,6 +5577,9 @@ sds genValkeyInfoString(dict *section_dict, int all_sections, int everything) {
"maxmemory:%lld\r\n", server.maxmemory,
"maxmemory_human:%s\r\n", maxmemory_hmem,
"maxmemory_policy:%s\r\n", evict_policy,
"maxmemory_reserved_scale:%d\r\n",server.maxmemory_reserved_scale,
"maxmemory_available:%lld\r\n",server.maxmemory_available,
"maxmemory_available_human:%s\r\n",maxmemory_available_hmem,
"allocator_frag_ratio:%.2f\r\n", mh->allocator_frag,
"allocator_frag_bytes:%zu\r\n", mh->allocator_frag_bytes,
"allocator_rss_ratio:%.2f\r\n", mh->allocator_rss,
Expand Down
2 changes: 2 additions & 0 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -2098,6 +2098,8 @@ struct valkeyServer {
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; /* Percent of the maxmemory value */
unsigned long long maxmemory_available; /* Max memory to store data */
int maxmemory_eviction_tenacity; /* Aggressiveness of eviction processing */
int lfu_log_factor; /* LFU logarithmic counter factor. */
int lfu_decay_time; /* LFU counter decay factor. */
Expand Down
7 changes: 7 additions & 0 deletions valkey.conf
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,13 @@ acllog-max-len 128
# in the system. It's a tradeoff between memory, CPU and latency.
#
# active-expire-effort 1
#
# It allows the valkey to evict keys earlier. The value of this parameter represents
# percent of the maxmemory value. It means how much memory the valkey 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 ####################################

Expand Down
Loading