Skip to content

Commit

Permalink
update to add new conf parameter key-eviction-memory
Browse files Browse the repository at this point in the history
  • Loading branch information
hwware committed Dec 11, 2024
1 parent 73f6724 commit 1710f7a
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 51 deletions.
47 changes: 36 additions & 11 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -2508,18 +2508,39 @@ static int updateReplBacklogSize(const char **err) {
return 1;
}

/* Adjusts `maxmemory_soft_scale` to ensure it remains within the valid range of 10 to 60, if set.
* Once adjusted, the available memory is recalculated to reflect the new soft maxmemory. */
static int updateMaxmemorySoftScale(const char **err) {
static int updateKeyEvictionMemory(const char **err) {
UNUSED(err);
if (server.maxmemory_soft_scale) {
if (server.maxmemory_soft_scale < 10) {
server.maxmemory_soft_scale = 10;
} else if (server.maxmemory_soft_scale > 60) {
server.maxmemory_soft_scale = 60;
if (server.maxmemory) {
if (!server.key_eviction_memory) {
serverLog(LL_WARNING,
"WARNING: current maxmemory value is not 0, the new key-eviction-memory value set via CONFIG SET (%llu) is "
"0. The new key-eviction-memory value is set to equal to current maxmemory (%llu) ",
server.key_eviction_memory, server.maxmemory);
server.key_eviction_memory = server.maxmemory;
} else if (server.key_eviction_memory > server.maxmemory) {
serverLog(LL_WARNING,
"WARNING: the new key-eviction-memory value set via CONFIG SET (%llu) is greater than current maxmemory, "
"The new key-eviction-memory value is set to equal to current maxmemory (%llu) ",
server.key_eviction_memory, server.maxmemory);
server.key_eviction_memory = server.maxmemory;
}
size_t used = zmalloc_used_memory() - freeMemoryGetNotCountedMemory();
if (server.key_eviction_memory < used) {
serverLog(LL_WARNING,
"WARNING: the new key-eviction-memorym 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.key_eviction_memory, used);
}
} else {
if (server.key_eviction_memory) {
serverLog(LL_WARNING,
"WARNING: current maxmemory value is 0, the new key-eviction-memory value set via CONFIG SET (%llu) is "
"greater than 0. The new key-eviction-memory value is invalid, and its value is set to 0 ",
server.key_eviction_memory);
}
server.key_eviction_memory = 0;
}
updateSoftMaxmemoryValue();
return 1;
}

Expand All @@ -2534,8 +2555,12 @@ static int updateMaxmemory(const char **err) {
"depending on the maxmemory-policy.",
server.maxmemory, used);
}
updateSoftMaxmemoryValue();
if (!server.key_eviction_memory || server.key_eviction_memory > server.maxmemory) {
server.key_eviction_memory = server.maxmemory;
}
startEvictionTimeProc();
} else {
server.key_eviction_memory = 0;
}
return 1;
}
Expand Down Expand Up @@ -3299,7 +3324,6 @@ 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-soft-scale", NULL, MODIFIABLE_CONFIG, 0, 100, server.maxmemory_soft_scale, 0, INTEGER_CONFIG, NULL, updateMaxmemorySoftScale),
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 Expand Up @@ -3353,6 +3377,7 @@ standardConfig static_configs[] = {

/* Unsigned Long Long configs */
createULongLongConfig("maxmemory", NULL, MODIFIABLE_CONFIG, 0, ULLONG_MAX, server.maxmemory, 0, MEMORY_CONFIG, NULL, updateMaxmemory),
createULongLongConfig("key-eviction-memory", NULL, MODIFIABLE_CONFIG, 0, ULLONG_MAX, server.key_eviction_memory, 0, MEMORY_CONFIG, NULL, updateKeyEvictionMemory),
createULongLongConfig("cluster-link-sendbuf-limit", NULL, MODIFIABLE_CONFIG, 0, ULLONG_MAX, server.cluster_link_msg_queue_limit_bytes, 0, MEMORY_CONFIG, NULL, NULL),

/* Size_t configs */
Expand Down
46 changes: 19 additions & 27 deletions src/evict.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ size_t freeMemoryGetNotCountedMemory(void) {
* limit.
* (Populated both for C_ERR and C_OK)
*/
int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, unsigned long long checked_maxmemory) {
int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, unsigned long long maxmemory) {
size_t mem_reported, mem_used, mem_tofree;

/* Check if we are over the memory usage limit. If we are not, no need
Expand All @@ -386,12 +386,12 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev
if (total) *total = mem_reported;

/* We may return ASAP if there is no need to compute the level. */
if (!checked_maxmemory) {
if (!maxmemory) {
if (level) *level = 0;
return C_OK;
}

if (mem_reported <= checked_maxmemory && !level) return C_OK;
if (mem_reported <= maxmemory && !level) return C_OK;

/* Remove the size of replicas output buffers and AOF buffer from the
* count of used memory. */
Expand All @@ -404,15 +404,15 @@ int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *lev
*level = (float)mem_used / (float)server.maxmemory;
}

if (mem_reported <= checked_maxmemory) return C_OK;
if (mem_reported <= maxmemory) return C_OK;

/* Check if we are still over the memory limit. */
/* if checked_maxmemory is equal to maxmemory and mem_used > checked_maxmemory then OOM */
/* if checked_maxmemory is equal to maxmemory_soft and mem_used > checked_maxmemory then there is no OOM but eviction happens */
if (mem_used <= checked_maxmemory) return C_OK;
/* if function parameter 'maxmemory' is equal to maxmemory and mem_used > maxmemory then OOM /
/ if function parameter 'maxmemory' is equal to maxmemory_soft and mem_used > function parameter 'maxmemory' then there is no OOM but eviction happens */
if (mem_used <= maxmemory) return C_OK;

/* Compute how much memory we need to free. */
mem_tofree = mem_used - server.maxmemory_soft;
mem_tofree = mem_used - server.key_eviction_memory;

if (logical) *logical = mem_used;
if (tofree) *tofree = mem_tofree;
Expand Down Expand Up @@ -527,14 +527,14 @@ int performEvictions(void) {
if (!isSafeToPerformEvictions()) return EVICT_OK;

int keys_freed = 0;
size_t mem_reported, mem_tofree;
size_t mem_reported, mem_tofree, mem_used;
long long mem_freed = 0; /* Maybe become negative */
mstime_t latency, eviction_latency;
long long delta;
int replicas = listLength(server.replicas);
int result = EVICT_FAIL;

if (getMaxmemoryState(&mem_reported, NULL, &mem_tofree, NULL, server.maxmemory_soft) == C_OK) {
if (getMaxmemoryState(&mem_reported, &mem_used, &mem_tofree, NULL, server.key_eviction_memory) == C_OK) {
result = EVICT_OK;
goto update_metrics;
}
Expand Down Expand Up @@ -702,7 +702,7 @@ int performEvictions(void) {
* across the dbAsyncDelete() call, while the thread can
* release the memory all the time. */
if (server.lazyfree_lazy_eviction) {
if (getMaxmemoryState(NULL, NULL, NULL, NULL, server.maxmemory_soft) == C_OK) {
if (getMaxmemoryState(NULL, NULL, NULL, NULL, server.key_eviction_memory) == C_OK) {
break;
}
}
Expand All @@ -717,24 +717,16 @@ int performEvictions(void) {
}
}
} else {
if (server.maxmemory_soft_scale) {
break;
} else {
goto cant_free; /* nothing to free... */
}
break;
}
}
if (server.maxmemory_soft_scale) {
size_t mem_used = zmalloc_used_memory();
size_t overhead = freeMemoryGetNotCountedMemory();
mem_used = (mem_used > overhead) ? mem_used - overhead : 0;
if (mem_used < server.maxmemory_soft) {
result = EVICT_OK;
goto update_metrics;
}

if (mem_freed >= (long long)(mem_used - server.key_eviction_memory)) {
/* at this point, the memory is OK, or we have reached the time limit */
result = (isEvictionProcRunning) ? EVICT_RUNNING : EVICT_OK;
} else {
goto cant_free;
}
/* at this point, the memory is OK, or we have reached the time limit */
result = (isEvictionProcRunning) ? EVICT_RUNNING : EVICT_OK;

cant_free:
if (result == EVICT_FAIL) {
Expand All @@ -744,7 +736,7 @@ int performEvictions(void) {
mstime_t lazyfree_latency;
latencyStartMonitor(lazyfree_latency);
while (bioPendingJobsOfType(BIO_LAZY_FREE) && elapsedUs(evictionTimer) < eviction_time_limit_us) {
if (getMaxmemoryState(NULL, NULL, NULL, NULL, server.maxmemory_soft) == C_OK) {
if (getMaxmemoryState(NULL, NULL, NULL, NULL, server.key_eviction_memory) == C_OK) {
result = EVICT_OK;
break;
}
Expand Down
15 changes: 9 additions & 6 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -2733,7 +2733,11 @@ void initServer(void) {
resetReplicationBuffer();

if (server.maxmemory) {
updateSoftMaxmemoryValue();
if (!server.key_eviction_memory || server.key_eviction_memory > server.maxmemory) {
server.key_eviction_memory = server.maxmemory;
}
} else {
server.key_eviction_memory = 0;
}

/* Make sure the locale is set on startup based on the config file. */
Expand Down Expand Up @@ -5672,7 +5676,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_soft_hmem[64];
char key_eviction_memory_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 @@ -5694,7 +5698,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_soft_hmem, sizeof(maxmemory_soft_hmem), server.maxmemory_soft);
bytesToHuman(key_eviction_memory_hmem, sizeof(key_eviction_memory_hmem), server.key_eviction_memory);

if (sections++) info = sdscat(info, "\r\n");
info = sdscatprintf(
Expand Down Expand Up @@ -5733,9 +5737,8 @@ 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_soft_scale:%d\r\n", server.maxmemory_soft_scale,
"maxmemory_soft:%lld\r\n", server.maxmemory_soft,
"maxmemory_soft_human:%s\r\n", maxmemory_soft_hmem,
"key_eviction_memory:%lld\r\n", server.key_eviction_memory,
"key_eviction_memory_human:%s\r\n", key_eviction_memory_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
5 changes: 2 additions & 3 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -2118,11 +2118,10 @@ struct valkeyServer {
/* Limits */
unsigned int maxclients; /* Max number of simultaneous clients */
unsigned long long maxmemory; /* Max number of memory bytes to use */
unsigned long long key_eviction_memory; /* Memory bytes to begin the key eviction process */
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_soft_scale; /* Percent of the soft maxmemory value */
unsigned long long maxmemory_soft; /* Soft maxmemory value 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 Expand Up @@ -3308,7 +3307,7 @@ int zslLexValueGteMin(sds value, zlexrangespec *spec);
int zslLexValueLteMax(sds value, zlexrangespec *spec);

/* Core functions */
int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, unsigned long long checked_maxmemory);
int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, unsigned long long maxmemory);
size_t freeMemoryGetNotCountedMemory(void);
int overMaxmemoryAfterAlloc(size_t moremem);
uint64_t getCommandFlags(client *c);
Expand Down
7 changes: 3 additions & 4 deletions valkey.conf
Original file line number Diff line number Diff line change
Expand Up @@ -1270,12 +1270,11 @@ acllog-max-len 128
#
# maxmemory-policy noeviction

# `maxmemory-soft-scale` defines a "soft" maxmemory threshold as a scale of the `maxmemory` limit.
# When memory usage exceeds this scale, Valkey begins proactive key eviction. However, exceeding this
# `key-eviction-memory` defines a "soft" maxmemory threshold as the `maxmemory` limit.
# When memory usage exceeds this key-eviction-memory, Valkey begins proactive key eviction. However, exceeding this
# threshold does not immediately reject new write commands; only the hard `maxmemory` limit will do so.
# This scale is specified as a percentage of `maxmemory`, with a valid range between 10 and 60.
#
# maxmemory-soft-scale 0
# key-eviction-memory <bytes>

# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated
# algorithms (in order to save memory), so you can tune it for speed or
Expand Down

0 comments on commit 1710f7a

Please sign in to comment.