Memory and eviction
HotKV keeps all data in memory. By default it uses as much as the data
needs. Set maxmemory to cap it, and maxmemory-policy to decide what
happens at the cap: refuse new data, or evict existing keys to make room.
That choice depends on whether HotKV is your cache (evict) or your system of
record (refuse).
Setting a memory limit
Section titled “Setting a memory limit”maxmemory 4gbmaxmemory-policy allkeys-lruor in hotkv.toml:
[memory]maxmemory = "4gb"maxmemory_policy = "allkeys-lru"maxmemory 0 (the default) means no limit. Sizes take the Redis units:
k, m and g are powers of 1000, kb, mb and gb powers of 1024.
Both settings can be changed at runtime with CONFIG SET and take effect
at once:
127.0.0.1:6379> CONFIG SET maxmemory 2gbOK127.0.0.1:6379> CONFIG SET maxmemory-policy allkeys-lfuOKThe limit applies to the memory the data uses and to the replication backlog,
up to repl-backlog-size, as in
Redis. What replicas that lag hold beyond the backlog, and the AOF buffers, do
not count (INFO memory shows them as mem_not_counted_for_evict). Leave
headroom between maxmemory and the machine’s RAM for those buffers, client
output buffers, and the operating system.
The replication backlog
Section titled “The replication backlog”A primary keeps its recent writes in the backlog so that a replica that
reconnects can continue where it left off (see Replication).
The backlog fills as the primary takes writes, and it counts toward maxmemory
as it fills. mem_replication_backlog in INFO memory shows how much it
holds. Here a primary with a 128 MB limit and one replica took twenty values
of 1 MB each:
127.0.0.1:6379> INFO memory...used_memory:34352784maxmemory:134217728mem_replication_backlog:8000464mem_not_counted_for_evict:45used_memory holds the 20 MB of data, the 8 MB of backlog so far and the
server’s own base. The backlog is 64 MiB unless you set repl-backlog-size
(or replication.backlog-size). When maxmemory is set at start and no
backlog size is given, the default is a sixteenth of maxmemory if that is
less than 64 MiB:
$ hotkv --maxmemory 128mb127.0.0.1:6379> CONFIG GET repl-backlog-size1) "repl-backlog-size"2) "8388608"A size you give is always kept as you gave it, and a maxmemory set later with
CONFIG SET leaves the backlog size as it is. CONFIG SET repl-backlog-size
resizes the backlog at once. If you set maxmemory on a primary, size it for
the data plus the backlog.
Eviction policies
Section titled “Eviction policies”maxmemory-policy takes the eight policies Redis has:
| Policy | Which keys may be evicted | How they are chosen |
|---|---|---|
noeviction (default) |
None | Commands that would add data get an OOM error |
allkeys-lru |
Any key | Least recently used first |
allkeys-lfu |
Any key | Least frequently used first |
allkeys-random |
Any key | At random |
volatile-lru |
Keys with a TTL | Least recently used first |
volatile-lfu |
Keys with a TTL | Least frequently used first |
volatile-random |
Keys with a TTL | At random |
volatile-ttl |
Keys with a TTL | Nearest expiry first |
Some guidance for choosing one:
- Cache of data that lives elsewhere:
allkeys-lru, orallkeys-lfuwhen a small set of keys is read far more than the rest. - Mix of cache entries and data you must keep: give the cache entries a
TTL and use a
volatile-*policy, so keys without a TTL are never evicted. - Primary data store:
noeviction, so a full server refuses writes instead of silently dropping data.
LRU, LFU and TTL choices are approximate, as in Redis: HotKV samples keys
and evicts the best candidates among them. maxmemory-samples (default 5,
from 1 to 64) sets how many are sampled; more samples pick closer to the
exact order at a little more CPU per eviction. For the LFU policies,
lfu-log-factor (default 10) sets how slowly a key’s frequency counter
rises and lfu-decay-time (default 1) the minutes it takes to decay by
one. OBJECT FREQ key shows a key’s counter while an LFU policy is
selected.
What happens at the limit
Section titled “What happens at the limit”Before running a command while memory is over maxmemory, HotKV evicts keys
under the policy until memory is back under the limit. Evicted keys are
deleted as if by DEL: they fire evicted keyspace notifications (when
enabled), and replicas and the AOF receive the deletes.
When nothing can be evicted, because the policy is noeviction or no key
matches it (a volatile-* policy with no keys that have a TTL), commands
that can add data are refused:
127.0.0.1:6379> SET session:42 "..."(error) OOM command not allowed when used memory > 'maxmemory'.Commands that only read or remove data (GET, DEL, UNLINK, EXPIRE,
LPOP, FLUSHDB and the like) still run, so you can always free memory.
Inside MULTI, such a command gets the OOM error when it is queued, and
EXEC replies EXECABORT; a transaction queued earlier whose EXEC finds
memory still full is aborted the same way. In a script, a write that needs
memory is refused with the same error.
Two cases where HotKV does not evict:
- Replicas. A replica never evicts on its own and does not refuse
writes from its primary for memory: the primary’s evictions reach it as
deletes. Give replicas the same
maxmemoryas their primary, and enough RAM. - While clients are paused with
CLIENT PAUSE, the data is left as it is.
To see how often you hit the limit, watch these INFO fields:
| Field | Section | Meaning |
|---|---|---|
used_memory, used_memory_human |
memory | Memory in use |
maxmemory, maxmemory_policy |
memory | The limit and the policy in force |
evicted_keys |
stats | Keys evicted since start (or CONFIG RESETSTAT) |
evicted_clients |
stats | Clients closed by maxmemory-clients |
total_eviction_exceeded_time |
stats | Total milliseconds spent over maxmemory |
current_eviction_exceeded_time |
stats | Milliseconds the current period over maxmemory has lasted |
The Prometheus endpoint exports
hotkv_used_memory_bytes and hotkv_evicted_keys for alerting.
Lazy freeing
Section titled “Lazy freeing”HotKV has no lazy-freeing settings. The lazyfree-* directives from
redis.conf are accepted with a warning and have no effect. UNLINK
deletes keys the same way DEL does, and FLUSHALL and FLUSHDB accept
ASYNC and SYNC for compatibility and flush at once with either.
Other Redis memory settings that are accepted and ignored include
maxmemory-eviction-tenacity, replica-ignore-maxmemory (replicas never
evict, see above) and the activedefrag family.
Client memory
Section titled “Client memory”maxmemory limits the data. maxmemory-clients
limits what the client connections themselves hold: input waiting to run,
queued transactions, subscriptions and replies that are waiting to be sent. A few
clients that stop reading, or that queue large commands, can otherwise use more
memory than the data does.
maxmemory-clients 200mbA number is bytes (with the usual units), and N% is that share of maxmemory
(no limit while maxmemory is 0). 0, the default, turns it off. A limit
under 128kb is raised to 128kb, so that no setting cuts every client off;
CONFIG GET still shows the value you gave. CONFIG SET applies it at once, and
so does a new maxmemory for a percentage: clients are evicted then if they
hold more than the limit allows.
127.0.0.1:6379> CONFIG SET maxmemory-clients 200kbOK127.0.0.1:6379> CONFIG GET maxmemory-clients1) "maxmemory-clients"2) "204800"127.0.0.1:6379> CONFIG SET maxmemory-clients 10%OKWhat counts as a client’s memory
Section titled “What counts as a client’s memory”The figure for each client is its tot-mem in CLIENT LIST
and CLIENT INFO. It is the sum of:
- the connection itself, a small fixed amount;
- its input that has not run yet (
qbuf), counted with the room the buffer has beyond the input (qbuf-free); - the commands queued by
MULTI(multi-mem); - the keys it watches;
- its subscriptions, to channels, patterns and shard channels;
- the prefixes of its client-side caching
BCASTtracking; - the fieldsets it prepared with HIMPORT;
- the replies and pushes waiting to be sent to it (
omem).
When a client says that an argument will be large, the room for the whole argument counts from that moment: a client that announces a value larger than the limit is evicted before its data arrives.
What is evicted
Section titled “What is evicted”When the clients together hold more than the limit, HotKV closes them, the
largest first, one after the other, until the rest fit. Each one is logged
(Client evicted for its memory, with its CLIENT LIST line, its size and the
limit) and counted in evicted_clients in INFO stats (CONFIG RESETSTAT
clears it). What the client had not been sent is dropped. The memory is checked
as a client grows and when its command has run, so a command with a huge argument
is evicted before it runs. A client that has been evicted, or that holds more than
the limit and is about to be, is not listed by CLIENT LIST.
CLIENT NO-EVICT ON exempts a connection. Its
memory still counts, so when it is the one that holds too much, the clients that
can be evicted are closed in its place. A replica’s link, the connection of an
atomic slot migration and another cluster node’s own connection are never
evicted and not counted.
Where to look
Section titled “Where to look”| Where | What it shows |
|---|---|
INFO memory: mem_clients_normal, mem_clients_slaves |
What the clients and subscribers hold (the figure the limit judges), and what the replicas’ links hold. |
INFO stats: evicted_clients |
Clients closed by the limit. |
INFO clients: client_recent_max_input_buffer, client_recent_max_output_buffer |
The largest input and output buffers of any client. |
MEMORY STATS: clients.normal, clients.slaves |
The same two totals. |
CLIENT LIST: tot-mem |
Each client. |
Inspecting memory
Section titled “Inspecting memory”MEMORY USAGE
Section titled “MEMORY USAGE”MEMORY USAGE key [SAMPLES count] estimates the
bytes a key and its value use. For a collection, the first 5 elements are
measured and the rest assumed to be the same size, as in Redis; SAMPLES 0
measures every element. A missing key returns nil:
127.0.0.1:6379> MEMORY USAGE no-such-key(nil)MEMORY STATS
Section titled “MEMORY STATS”MEMORY STATS returns a breakdown with Redis’s
field names, including peak.allocated, total.allocated,
startup.allocated, replication.backlog, clients.normal, aof.buffer,
lua.caches, functions.caches, overhead.total, keys.count,
dataset.bytes, dataset.percentage, peak.percentage and
fragmentation.
MEMORY DOCTOR
Section titled “MEMORY DOCTOR”MEMORY DOCTOR returns a short report in plain
text. On a server using less than 5 MB it says there is nothing to report.
Otherwise it points out:
- the process holding much more memory than the data uses (fragmentation
after a peak or many deletes), with a suggestion to run
MEMORY PURGE - a peak well above current use
- memory in use above 90% of
maxmemory, and whether writes will then be refused or keys evicted - a client with more than 32 MB of unread replies (find it by
omeminCLIENT LIST) - a replication backlog that takes a large share of memory
MEMORY PURGE asks the process to return freed
memory to the operating system. MEMORY MALLOC-STATS returns allocator
statistics as text.
INFO memory
Section titled “INFO memory”INFO memory reports used_memory, used_memory_rss, used_memory_peak,
used_memory_dataset, maxmemory, maxmemory_policy,
mem_fragmentation_ratio and the rest of Redis’s memory fields, so
dashboards built for Redis find them where they expect. See
Monitoring.
Next steps
Section titled “Next steps”- Monitoring
- Keys and expiration
- Configuration reference
- Client-side caching: invalidations count in a client’s memory.
- Memory on the target of a reshard:
maxmemoryapplies to each node of a cluster.
Was this page helpful?
Thanks for the feedback.