Debugging Lua scripts in Redis

Summary: How to use the built-in Lua debugger

Overview

Starting with version 3.2 Redis includes a complete Lua debugger, that can be
used in order to make the task of writing complex Redis scripts much simpler.

The Redis Lua debugger, codenamed LDB, has the following important features:

* It uses a server-client model, so it's a remote debugger.
The Redis server acts as the debugging server, while the default client is `redis-cli`.
However other clients can be developed by following the simple protocol implemented by the server.
* By default every new debugging session is a forked session.
It means that while the Redis Lua script is being debugged, the server does not block and is usable for development or in order to execute multiple debugging sessions in parallel.
This also means that changes are **rolled back** after the script debugging session finished, so that's possible to restart a new debugging session again, using exactly the same Redis data set as the previous debugging session.
* An alternative synchronous (non forked) debugging model is available on demand, so that changes to the dataset can be retained.
In this mode the server blocks for the time the debugging session is active.
* Support for step by step execution.
* Support for static and dynamic breakpoints.
* Support from logging the debugged script into the debugger console.
* Inspection of Lua variables.
* Tracing of Redis commands executed by the script.
* Pretty printing of Redis and Lua values.
* Infinite loops and long execution detection, which simulates a breakpoint.

Quick start

A simple way to get started with the Lua debugger is to watch this video
introduction:

<iframe width="560" height="315" src="https://www.youtube.com/embed/IMvRfStaoyM" frameborder="0" allowfullscreen></iframe>

> Important Note:  please make sure to avoid debugging Lua scripts using your Redis production server.
Use a development server instead.
Also note that using the synchronous debugging mode (which is NOT the default) results in the Redis server blocking for all the time the debugging session lasts.

To start a new debugging session using `redis-cli` do the following:

1. Create your script in some file with your preferred editor. Let's assume you are editing your Redis Lua script located at `/tmp/script.lua`.
2. Start a debugging session with:

    ./redis-cli --ldb --eval /tmp/script.lua

Note that with the `--eval` option of `redis-cli` you can pass key names and arguments to the script, separated by a comma, like in the following example:

[code example]

You'll enter a special mode where `redis-cli` no longer accepts its normal
commands, but instead prints a help screen and passes the unmodified debugging
commands directly to Redis.

The only commands which are not passed to the Redis debugger are:

* `quit` -- this will terminate the debugging session.
It's like removing all the breakpoints and using the `continue` debugging command.
Moreover the command will exit from `redis-cli`.
* `restart` -- the debugging session will restart from scratch, **reloading the new version of the script from the file**.
So a normal debugging cycle involves modifying the script after some debugging, and calling `restart` in order to start debugging again with the new script changes.
* `help` -- this command is passed to the Redis Lua debugger, that will print a list of commands like the following:

[code example]

Note that when you start the debugger it will start in **stepping mode**.
It will stop at the first line of the script that actually does something before executing it.

From this point you usually call `step` in order to execute the line and go to the next line.
While you step Redis will show all the commands executed by the server like in the following example:

[code example]

The `<redis>` and `<reply>` lines show the command executed by the line just
executed, and the reply from the server. Note that this happens only in stepping mode.
If you use `continue` in order to execute the script till the next breakpoint, commands will not be dumped on the screen to prevent too much output.

Termination of the debugging session

When the scripts terminates naturally, the debugging session ends and
`redis-cli` returns in its normal non-debugging mode. You can restart the
session using the `restart` command as usual.

Another way to stop a debugging session is just interrupting `redis-cli`
manually by pressing `Ctrl+C`. Note that also any event breaking the
connection between `redis-cli` and the `redis-server` will interrupt the
debugging session.

All the forked debugging sessions are terminated when the server is shut
down.

Abbreviating debugging commands

Debugging can be a very repetitive task. For this reason every Redis
debugger command starts with a different character, and you can use the single
initial character in order to refer to the command.

So for example instead of typing `step` you can just type `s`.

Breakpoints

Adding and removing breakpoints is trivial as described in the online help.
Just use `b 1 2 3 4` to add a breakpoint in line 1, 2, 3, 4.
The command `b 0` removes all the breakpoints. Selected breakpoints can be
removed using as argument the line where the breakpoint we want to remove is, but prefixed by a minus sign.
So for example `b -3` removes the breakpoint from line 3.

Note that adding breakpoints to lines that Lua never executes, like declaration of local variables or comments, will not work.
The breakpoint will be added but since this part of the script will never be executed, the program will never stop.

Dynamic breakpoints

Using the `breakpoint` command it is possible to add breakpoints into specific
lines. However sometimes we want to stop the execution of the program only
when something special happens. In order to do so, you can use the
`redis.breakpoint()` function inside your Lua script. When called it simulates
a breakpoint in the next line that will be executed.

[code example]
This feature is extremely useful when debugging, so that we can avoid
continuing the script execution manually multiple times until a given condition
is encountered.

Synchronous mode

As explained previously, but default LDB uses forked sessions with rollback
of all the data changes operated by the script while it has being debugged.
Determinism is usually a good thing to have during debugging, so that successive
debugging sessions can be started without having to reset the database content
to its original state.

However for tracking certain bugs, you may want to retain the changes performed
to the key space by each debugging session. When this is a good idea you
should start the debugger using a special option, `ldb-sync-mode`, in `redis-cli`.

[code example]

> Note: Redis server will be unreachable during the debugging session in this mode, so use with care.

In this special mode, the `abort` command can stop the script half-way taking the changes operated to the dataset.
Note that this is different compared to ending the debugging session normally.
If you just interrupt `redis-cli` the script will be fully executed and then the session terminated.
Instead with `abort` you can interrupt the script execution in the middle and start a new debugging session if needed.

Logging from scripts

The `redis.debug()` command is a powerful debugging facility that can be
called inside the Redis Lua script in order to log things into the debug
console:

[code example]

If the script is executed outside of a debugging session, `redis.debug()` has no effects at all.
Note that the function accepts multiple arguments, that are separated by a comma and a space in the output.

Tables and nested tables are displayed correctly in order to make values simple to observe for the programmer debugging the script.

Inspecting the program state with `print` and `eval`

While the `redis.debug()` function can be used in order to print values
directly from within the Lua script, often it is useful to observe the local
variables of a program while stepping or when stopped into a breakpoint.

The `print` command does just that, and performs lookup in the call frames
starting from the current one back to the previous ones, up to top-level.
This means that even if we are into a nested function inside a Lua script,
we can still use `print foo` to look at the value of `foo` in the context
of the calling function. When called without a variable name, `print` will
print all variables and their respective values.

The `eval` command executes small pieces of Lua scripts **outside the context of the current call frame** (evaluating inside the context of the current call frame is not possible with the current Lua internals).
However you can use this command in order to test Lua functions.

[code example]

Debugging clients

LDB uses the client-server model where the Redis server acts as a debugging server that communicates using [RESP](). While `redis-cli` is the default debug client, any client can be used for debugging as long as it meets one of the following conditions:

1. The client provides a native interface for setting the debug mode and controlling the debug session.
2. The client provides an interface for sending arbitrary commands over RESP.
3. The client allows sending raw messages to the Redis server.

For example, the [Redis plugin](https://redis.com/blog/zerobrane-studio-plugin-for-redis-lua-scripts) for [ZeroBrane Studio](http://studio.zerobrane.com/) integrates with LDB using [redis-lua](https://github.com/nrk/redis-lua). The following Lua code is a simplified example of how the plugin achieves that:

[code example]

./redis-cli --ldb --eval /tmp/script.lua mykey somekey , arg1 arg2

lua debugger> help
Redis Lua debugger help:
[h]elp               Show this help.
[s]tep               Run current line and stop again.
[n]ext               Alias for step.
[c]ontinue           Run till next breakpoint.
[l]ist               List source code around current line.
[l]ist [line]        List source code around [line].
                     line = 0 means: current position.
[l]ist [line] [ctx]  In this form [ctx] specifies how many lines
                     to show before/after [line].
[w]hole              List all source code. Alias for 'list 1 1000000'.
[p]rint              Show all the local variables.
[p]rint <var>        Show the value of the specified variable.
                     Can also show global vars KEYS and ARGV.
[b]reak              Show all breakpoints.
[b]reak <line>       Add a breakpoint to the specified line.
[b]reak -<line>      Remove breakpoint from the specified line.
[b]reak 0            Remove all breakpoints.
[t]race              Show a backtrace.
[e]val <code>        Execute some Lua code (in a different callframe).
[r]edis <cmd>        Execute a Redis command.
[m]axlen [len]       Trim logged Redis replies and Lua var dumps to len.
                     Specifying zero as <len> means unlimited.
[a]bort              Stop the execution of the script. In sync
                     mode dataset changes will be retained.

Debugger functions you can call from Lua scripts:
redis.debug()        Produce logs in the debugger console.
redis.breakpoint()   Stop execution as if there was a breakpoint in the
                     next line of code.

* Stopped at 1, stop reason = step over
-> 1   redis.call('ping')
lua debugger> step
<redis> ping
<reply> "+PONG"
* Stopped at 2, stop reason = step over

if counter > 10 then redis.breakpoint() end

./redis-cli --ldb-sync-mode --eval /tmp/script.lua

lua debugger> list
-> 1   local a = {1,2,3}
   2   local b = false
   3   redis.debug(a,b)
lua debugger> continue
<debug> line 3: {1; 2; 3}, false

lua debugger> e redis.sha1hex('foo')
<retval> "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"

local redis = require 'redis'

-- add LDB's Continue command
redis.commands['ldbcontinue'] = redis.command('C')

-- script to be debugged
local script = [[
  local x, y = tonumber(ARGV[1]), tonumber(ARGV[2])
  local result = x * y
  return result
]]

local client = redis.connect('127.0.0.1', 6379)
client:script("DEBUG", "YES")
print(unpack(client:eval(script, 0, 6, 9)))
client:ldbcontinue()


Redis Pub/sub

Summary: How to use pub/sub channels in Redis

Summary: Monitor changes to Redis keys and values in real time

Redis keyspace notifications

Overview

[`SUBSCRIBE`](), [`UNSUBSCRIBE`]() and [`PUBLISH`]() implement the [Publish/Subscribe messaging paradigm](http://en.wikipedia.org/wiki/Publish/subscribe) where (citing Wikipedia) senders (publishers) are not programmed to send their messages to specific receivers (subscribers).
Rather, published messages are categorized into channels, without knowledge of what (if any) subscribers there may be.
Subscribers express interest in one or more channels and only receive messages that are of interest, without knowledge of what (if any) publishers there are.
This decoupling of publishers and subscribers allows for greater scalability and a more dynamic network topology.

For instance, to subscribe to channels "channel11" and "ch:00" the client issues a [`SUBSCRIBE`]() providing the names of the channels:

[code example]

Messages sent by other clients to these channels will be pushed by Redis to all the subscribed clients.
Subscribers receive the messages in the order that the messages are published.

A client subscribed to one or more channels shouldn't issue commands, although it can [`SUBSCRIBE`]() and [`UNSUBSCRIBE`]() to and from other channels.
The replies to subscription and unsubscribing operations are sent in the form of messages so that the client can just read a coherent stream of messages where the first element indicates the type of message.
The commands that are allowed in the context of a subscribed RESP2 client are:

* [`PING`]()
* [`PSUBSCRIBE`]()
* [`PUNSUBSCRIBE`]()
* [`QUIT`]()
* [`RESET`]()
* [`SSUBSCRIBE`]()
* [`SUBSCRIBE`]()
* [`SUNSUBSCRIBE`]()
* [`UNSUBSCRIBE`]()

However, if RESP3 is used (see [`HELLO`]()), a client can issue any commands while in the subscribed state.

Please note that when using `redis-cli`, in subscribed mode commands such as [`UNSUBSCRIBE`]() and [`PUNSUBSCRIBE`]() cannot be used because `redis-cli` will not accept any commands and can only quit the mode with `Ctrl-C`.

Delivery semantics

Redis' Pub/Sub exhibits _at-most-once_ message delivery semantics.
As the name suggests, it means that a message will be delivered once if at all.
Once the message is sent by the Redis server, there's no chance of it being sent again.
If the subscriber is unable to handle the message (for example, due to an error or a network disconnect) the message is forever lost.

If your application requires stronger delivery guarantees, you may want to learn about [Redis Streams]().
Messages in streams are persisted, and support both _at-most-once_ as well as _at-least-once_ delivery semantics.

Format of pushed messages

A message is an [array-reply]() with three elements.

The first element is the kind of message:

* `subscribe`: means that we successfully subscribed to the channel given as the second element in the reply.
  The third argument represents the number of channels we are currently subscribed to.

* `unsubscribe`: means that we successfully unsubscribed from the channel given as second element in the reply.
  The third argument represents the number of channels we are currently subscribed to.
  When the last argument is zero, we are no longer subscribed to any channel, and the client can issue any kind of Redis command as we are outside the Pub/Sub state.

* `message`: it is a message received as a result of a [`PUBLISH`]() command issued by another client.
  The second element is the name of the originating channel, and the third argument is the actual message payload.

Database & Scoping

Pub/Sub has no relation to the key space.
It was made to not interfere with it on any level, including database numbers.

Publishing on db 10, will be heard by a subscriber on db 1.

If you need scoping of some kind, prefix the channels with the name of the environment (test, staging, production...).

Wire protocol example

[code example]

At this point, from another client we issue a [`PUBLISH`]() operation against the channel named `second`:

[code example]

This is what the first client receives:

[code example]

Now the client unsubscribes itself from all the channels using the [`UNSUBSCRIBE`]() command without additional arguments:

[code example]

Pattern-matching subscriptions

The Redis Pub/Sub implementation supports pattern matching.
Clients may subscribe to glob-style patterns to receive all the messages sent to channel names matching a given pattern.

For instance:

[code example]

Will receive all the messages sent to the channel `news.art.figurative`, `news.music.jazz`, etc.
All the glob-style patterns are valid, so multiple wildcards are supported.

[code example]

Will then unsubscribe the client from that pattern.
No other subscriptions will be affected by this call.

Messages received as a result of pattern matching are sent in a different format:

* The type of the message is `pmessage`: it is a message received as a result from a [`PUBLISH`]() command issued by another client, matching a pattern-matching subscription.
  The second element is the original pattern matched, the third element is the name of the originating channel, and the last element is the actual message payload.

Similarly to [`SUBSCRIBE`]() and [`UNSUBSCRIBE`](), [`PSUBSCRIBE`]() and [`PUNSUBSCRIBE`]() commands are acknowledged by the system sending a message of type `psubscribe` and `punsubscribe` using the same format as the `subscribe` and `unsubscribe` message format.

Messages matching both a pattern and a channel subscription

A client may receive a single message multiple times if it's subscribed to multiple patterns matching a published message, or if it is subscribed to both patterns and channels matching the message.
This is shown by the following example:

[code example]

In the above example, if a message is sent to channel `foo`, the client will receive two messages: one of type `message` and one of type `pmessage`.

The meaning of the subscription count with pattern matching

In `subscribe`, `unsubscribe`, `psubscribe` and `punsubscribe` message types, the last argument is the count of subscriptions still active.
This number is the total number of channels and patterns the client is still subscribed to.
So the client will exit the Pub/Sub state only when this count drops to zero as a result of unsubscribing from all the channels and patterns.

Sharded Pub/Sub

From Redis 7.0, sharded Pub/Sub is introduced in which shard channels are assigned to slots by the same algorithm used to assign keys to slots.
A shard message must be sent to a node that owns the slot the shard channel is hashed to.
The cluster makes sure the published shard messages are forwarded to all nodes in the shard, so clients can subscribe to a shard channel by connecting to either the master responsible for the slot, or to any of its replicas.
[`SSUBSCRIBE`](), [`SUNSUBSCRIBE`]() and [`SPUBLISH`]() are used to implement sharded Pub/Sub.

Sharded Pub/Sub helps to scale the usage of Pub/Sub in cluster mode.
It restricts the propagation of messages to be within the shard of a cluster.
Hence, the amount of data passing through the cluster bus is limited in comparison to global Pub/Sub where each message propagates to each node in the cluster.
This allows users to horizontally scale the Pub/Sub usage by adding more shards.

Programming example

Pieter Noordhuis provided a great example using EventMachine and Redis to create [a multi user high performance web chat](https://gist.github.com/pietern/348262).

Client library implementation hints

Because all the messages received contain the original subscription causing the message delivery (the channel in the case of message type, and the original pattern in the case of pmessage type) client libraries may bind the original subscription to callbacks (that can be anonymous functions, blocks, function pointers), using a hash table.

When a message is received an O(1) lookup can be done to deliver the message to the registered callback.

SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2

UNSUBSCRIBE
*3
$11
unsubscribe
$6
second
:1
*3
$11
unsubscribe
$5
first
:0


Redis keyspace notifications

Overview

Keyspace notifications allow clients to subscribe to Pub/Sub channels in order
to receive events affecting the Redis data set in some way.

Examples of events that can be received are:

* All the commands affecting a given key.
* All the keys receiving an LPUSH operation.
* All the keys expiring in the database 0.

Note: Redis Pub/Sub is *fire and forget*; that is, if your Pub/Sub client disconnects,
and reconnects later, all the events delivered during the time the client was
disconnected are lost.

Type of events

Keyspace notifications are implemented by sending two distinct types of events
for every operation affecting the Redis data space. For instance a [`DEL`]()
operation targeting the key named `mykey` in database `0` will trigger
the delivering of two messages, exactly equivalent to the following two
[`PUBLISH`]() commands:

    PUBLISH __keyspace@0__:mykey del
    PUBLISH __keyevent@0__:del mykey

The first channel listens to all the events targeting
the key `mykey` and the other channel listens only to `del` operation
events on the key `mykey`

The first kind of event, with `keyspace` prefix in the channel is called
a **Key-space notification**, while the second, with the `keyevent` prefix,
is called a **Key-event notification**.

In the previous example a `del` event was generated for the key `mykey` resulting
in two messages:

* The Key-space channel receives as message the name of the event.
* The Key-event channel receives as message the name of the key.

It is possible to enable only one kind of notification in order to deliver
just the subset of events we are interested in.

Configuration

By default keyspace event notifications are disabled because while not
very sensible the feature uses some CPU power. Notifications are enabled
using the `notify-keyspace-events` of redis.conf or via the **CONFIG SET**.

Setting the parameter to the empty string disables notifications.
In order to enable the feature a non-empty string is used, composed of multiple
characters, where every character has a special meaning according to the
following table:

    K     Keyspace events, published with __keyspace@<db>__ prefix.
    E     Keyevent events, published with __keyevent@<db>__ prefix.
    g     Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
    $     String commands
    l     List commands
    s     Set commands
    h     Hash commands
    z     Sorted set commands
    t     Stream commands
    d     Module key type events
    x     Expired events (events generated every time a key expires)
    e     Evicted events (events generated when a key is evicted for maxmemory)
    m     Key miss events generated when a key that doesn't exist is accessed (Note: not included in the 'A' class)
    n     New key events generated whenever a new key is created (Note: not included in the 'A' class)
    o     Overwritten events generated every time a key is overwritten (Note: not included in the 'A' class)
    c     Type-changed events generated every time a key's type changes (Note: not included in the 'A' class)
    A     Alias for "g$lshztdxe", so that the "AKE" string means all the events except "m", "n", "o" and "c".

At least `K` or `E` should be present in the string, otherwise no event
will be delivered regardless of the rest of the string.

For instance to enable just Key-space events for lists, the configuration
parameter must be set to `Kl`, and so forth.

You can use the string `KEA` to enable most types of events.

Events generated by different commands

Different commands generate different kind of events according to the following list.
* [`APPEND`]() generates an `append` event.
* [`COPY`]() generates a `copy_to` event.
* [`DEL`]() generates a `del` event for every deleted key.
* [`EXPIRE`]() and all its variants ([`PEXPIRE`](), [`EXPIREAT`](), [`PEXPIREAT`]()) generate an `expire` event when called with a positive timeout (or a future timestamp). Note that when these commands are called with a negative timeout value or timestamp in the past, the key is deleted and only a `del` event is generated instead.
* [`HDEL`]() generates a single `hdel` event, and an additional `del` event if the resulting hash is empty and the key is removed.
* [`HEXPIRE`]() and all its variants ([`HEXPIREAT`](), [`HPEXPIRE`](), [`HPEXPIREAT`]()) generate `hexpired` events. Furthermore, `hexpired` events are generated when fields expire.
* [`HINCRBYFLOAT`]() generates an `hincrbyfloat` event.
* [`HINCRBY`]() generates an `hincrby` event.
* [`HPERSIST`]() generates an `hpersist` event.
* [`HSET`](), [`HSETNX`]() and [`HMSET`]() all generate a single `hset` event.
* [`INCRBYFLOAT`]() generates an `incrbyfloat` events.
* [`INCR`](), [`DECR`](), [`INCRBY`](), [`DECRBY`]() commands all generate `incrby` events.
* [`LINSERT`]() generates an `linsert` event.
* [`LMOVE`]() and [`BLMOVE`]() generate an `lpop`/`rpop` event (depending on the wherefrom argument) and an `lpush`/`rpush` event (depending on the whereto argument). In both cases the order is guaranteed (the `lpush`/`rpush` event will always be delivered after the `lpop`/`rpop` event). Additionally a `del` event will be generated if the resulting list is zero length and the key is removed.
* [`LPOP`]() generates an `lpop` event. Additionally a `del` event is generated if the key is removed because the last element from the list was popped.
* [`LPUSH`]() and [`LPUSHX`]() generates a single `lpush` event, even in the variadic case.
* [`LREM`]() generates an `lrem` event, and additionally a `del` event if the resulting list is empty and the key is removed.
* [`LSET`]() generates an `lset` event.
* [`LTRIM`]() generates an `ltrim` event, and additionally a `del` event if the resulting list is empty and the key is removed.
* [`MIGRATE`]() generates a `del` event if the source key is removed.
* [`MOVE`]() generates two events, a `move_from` event for the source key, and a `move_to` event for the destination key.
* [`MSET`]() generates a separate `set` event for every key.
* [`PERSIST`]() generates a `persist` event if the expiry time associated with key has been successfully deleted.
* [`RENAME`]() generates two events, a `rename_from` event for the source key, and a `rename_to` event for the destination key.
* [`RESTORE`]() generates a `restore` event for the key.
* [`RPOPLPUSH`]() and [`BRPOPLPUSH`]() generate an `rpop` event and an `lpush` event. In both cases the order is guaranteed (the `lpush` event will always be delivered after the `rpop` event). Additionally a `del` event will be generated if the resulting list is zero length and the key is removed.
* [`RPOP`]() generates an `rpop` event. Additionally a `del` event is generated if the key is removed because the last element from the list was popped.
* [`RPUSH`]() and [`RPUSHX`]() generates a single `rpush` event, even in the variadic case.
* [`SADD`]() generates a single `sadd` event, even in the variadic case.
* [`SETRANGE`]() generates a `setrange` event.
* [`SET`]() and all its variants ([`SETEX`](), [`SETNX`](),[`GETSET`]()) generate `set` events. However [`SETEX`]() will also generate an `expire` events.
* [`SINTERSTORE`](), [`SUNIONSTORE`](), [`SDIFFSTORE`]() generate `sinterstore`, `sunionstore`, `sdiffstore` events respectively. In the special case the resulting set is empty, and the key where the result is stored already exists, a `del` event is generated since the key is removed.
* [`SMOVE`]() generates an `srem` event for the source key, and an `sadd` event for the destination key.
* [`SORT`]() generates a `sortstore` event when `STORE` is used to set a new key. If the resulting list is empty, and the `STORE` option is used, and there was already an existing key with that name, the result is that the key is deleted, so a `del` event is generated in this condition.
* [`SPOP`]() generates an `spop` event, and an additional `del` event if the resulting set is empty and the key is removed.
* [`SREM`]() generates a single `srem` event, and an additional `del` event if the resulting set is empty and the key is removed.
* [`XADD`]() generates an `xadd` event, possibly followed an `xtrim` event when used with the `MAXLEN` subcommand.
* [`XDEL`]() generates a single `xdel` event even when multiple entries are deleted.
* [`XGROUP CREATECONSUMER`]() generates an `xgroup-createconsumer` event.
* [`XGROUP CREATE`]() generates an `xgroup-create` event.
* [`XGROUP DELCONSUMER`]() generates an `xgroup-delconsumer` event.
* [`XGROUP DESTROY`]() generates an `xgroup-destroy` event.
* [`XGROUP SETID`]() generates an `xgroup-setid` event.
* [`XSETID`]() generates an `xsetid` event.
* [`XTRIM`]() generates an `xtrim` event.
* [`ZADD`]() generates a single `zadd` event even when multiple elements are added.
* [`ZDIFFSTORE`](), [`ZINTERSTORE`]() and [`ZUNIONSTORE`]() respectively generate `zdiffstore`, `zinterstore` and `zunionstore` events. In the special case the resulting sorted set is empty, and the key where the result is stored already exists, a `del` event is generated since the key is removed.
* [`ZINCRBY`]() generates a `zincr` event.
* [`ZREMRANGEBYRANK`]() generates a single `zrembyrank` event. When the resulting sorted set is empty and the key is generated, an additional `del` event is generated.
* [`ZREMRANGEBYSCORE`]() generates a single `zrembyscore` event. When the resulting sorted set is empty and the key is generated, an additional `del` event is generated.
* [`ZREM`]() generates a single `zrem` event even when multiple elements are deleted. When the resulting sorted set is empty and the key is generated, an additional `del` event is generated.
* Every time a key with a time to live associated is removed from the data set because it expired, an `expired` event is generated.
* Every time a key is evicted from the data set in order to free memory as a result of the `maxmemory` policy, an `evicted` event is generated.
* Every time a new key is added to the data set, a `new` event is generated.
* Every time a key is being overwritten, an `overwritten` event is generated.
* Every time a key's type changes, a `type_changed` event is generated.

**IMPORTANT** all the commands generate events only if the target key is really modified. For instance an [`SREM`]() deleting a non-existing element from a Set will not actually change the value of the key, so no event will be generated.

If in doubt about how events are generated for a given command, the simplest
thing to do is to watch yourself:

    $ redis-cli config set notify-keyspace-events KEA
    $ redis-cli --csv psubscribe '__key*__:*'
    Reading messages... (press Ctrl-C to quit)
    "psubscribe","__key*__:*",1

At this point use `redis-cli` in another terminal to send commands to the
Redis server and watch the events generated:

    "pmessage","__key*__:*","__keyspace@0__:foo","set"
    "pmessage","__key*__:*","__keyevent@0__:set","foo"
    ...

Timing of expired events

Keys with a time to live associated are expired by Redis in two ways:

* When the key is accessed by a command and is found to be expired.
* Via a background system that looks for expired keys in the background, incrementally, in order to be able to also collect keys that are never accessed.

The `expired` events are generated when a key is accessed and is found to be expired by one of the above systems, as a result there are no guarantees that the Redis server will be able to generate the `expired` event at the time the key time to live reaches the value of zero.

If no command targets the key constantly, and there are many keys with a TTL associated, there can be a significant delay between the time the key time to live drops to zero, and the time the `expired` event is generated.

Expired (`expired`) events are generated when the Redis server deletes the key and not when the time to live theoretically reaches the value of zero.

Events in a cluster

Every node of a Redis cluster generates events about its own subset of the keyspace as described above. However, unlike regular Pub/Sub communication in a cluster, events' notifications **are not** broadcasted to all nodes. Put differently, keyspace events are node-specific. This means that to receive all keyspace events of a cluster, clients need to subscribe to each of the nodes.

@history

*   `>= 6.0`: Key miss events were added.
*   `>= 7.0`: Event type `new` added


Client-side caching reference

Summary: Server-assisted, client-side caching in Redis

Overview

This document is intended as an in-depth reference for
client-side caching. See
[Client-side caching introduction]()
for general usage guidelines.

Client-side caching is a technique used to create high performance services.
It exploits the memory available on application servers, servers that are
usually distinct computers compared to the database nodes, to store some subset
of the database information directly in the application side.

Normally when data is required, the application servers ask the database about
such information, like in the following diagram:

    +-------------+                                +----------+
    |             | ------- GET user:1234 -------> |          |
    | Application |                                | Database |
    |             | <---- username = Alice ------- |          |
    +-------------+                                +----------+

When client-side caching is used, the application will store the reply of
popular queries directly inside the application memory, so that it can
reuse such replies later, without contacting the database again:

    +-------------+                                +----------+
    |             |                                |          |
    | Application |       ( No chat needed )       | Database |
    |             |                                |          |
    +-------------+                                +----------+
    | Local cache |
    |             |
    | user:1234 = |
    | username    |
    | Alice       |
    +-------------+

While the application memory used for the local cache may not be very big,
the time needed in order to access the local computer memory is orders of
magnitude smaller compared to accessing a networked service like a database.
Since often the same small percentage of data are accessed frequently,
this pattern can greatly reduce the latency for the application to get data
and, at the same time, the load in the database side.

Moreover there are many datasets where items change very infrequently.
For instance, most user posts in a social network are either immutable or
rarely edited by the user. Adding to this the fact that usually a small
percentage of the posts are very popular, either because a small set of users
have a lot of followers and/or because recent posts have a lot more
visibility, it is clear why such a pattern can be very useful.

Usually the two key advantages of client-side caching are:

1. Data is available with a very small latency.
2. The database system receives less queries, allowing it to serve the same dataset with a smaller number of nodes.

There are two hard problems in computer science...

A problem with the above pattern is how to invalidate the information that
the application is holding, in order to avoid presenting stale data to the
user. For example after the application above locally cached the information
for user:1234, Alice may update her username to Flora. Yet the application
may continue to serve the old username for user:1234.

Sometimes, depending on the exact application we are modeling, this isn't a
big deal, so the client will just use a fixed maximum "time to live" for the
cached information. Once a given amount of time has elapsed, the information
will no longer be considered valid. More complex patterns, when using Redis,
leverage the Pub/Sub system in order to send invalidation messages to
listening clients. This can be made to work but is tricky and costly from
the point of view of the bandwidth used, because often such patterns involve
sending the invalidation messages to every client in the application, even
if certain clients may not have any copy of the invalidated data. Moreover
every application query altering the data requires to use the [`PUBLISH`]()
command, costing the database more CPU time to process this command.

Regardless of what schema is used, there is a simple fact: many very large
applications implement some form of client-side caching, because it is the
next logical step to having a fast store or a fast cache server. For this
reason Redis 6 implements direct support for client-side caching, in order
to make this pattern much simpler to implement, more accessible, reliable,
and efficient.

The Redis implementation of client-side caching

The Redis client-side caching support is called _Tracking_, and has two modes:

* In the default mode, the server remembers what keys a given client accessed, and sends invalidation messages when the same keys are modified. This costs memory in the server side, but sends invalidation messages only for the set of keys that the client might have in memory.
* In the _broadcasting_ mode, the server does not attempt to remember what keys a given client accessed, so this mode costs no memory at all in the server side. Instead clients subscribe to key prefixes such as `object:` or `user:`, and receive a notification message every time a key matching a subscribed prefix is touched.

To recap, for now let's forget for a moment about the broadcasting mode, to
focus on the first mode. We'll describe broadcasting in more detail later.

1. Clients can enable tracking if they want. Connections start without tracking enabled.
2. When tracking is enabled, the server remembers what keys each client requested during the connection lifetime (by sending read commands about such keys).
3. When a key is modified by some client, or is evicted because it has an associated expire time, or evicted because of a _maxmemory_ policy, all the clients with tracking enabled that may have the key cached, are notified with an _invalidation message_.
4. When clients receive invalidation messages, they are required to remove the corresponding keys, in order to avoid serving stale data.

This is an example of the protocol:

* Client 1 `->` Server: CLIENT TRACKING ON
* Client 1 `->` Server: GET foo
* (The server remembers that Client 1 may have the key "foo" cached)
* (Client 1 may remember the value of "foo" inside its local memory)
* Client 2 `->` Server: SET foo SomeOtherValue
* Server `->` Client 1: INVALIDATE "foo"

This looks great superficially, but if you imagine 10k connected clients all
asking for millions of keys over long living connection, the server ends up
storing too much information. For this reason Redis uses two key ideas in
order to limit the amount of memory used server-side and the CPU cost of
handling the data structures implementing the feature:

* The server remembers the list of clients that may have cached a given key in a single global table. This table is called the **Invalidation Table**. The invalidation table can contain a maximum number of entries. If a new key is inserted, the server may evict an older entry by pretending that such key was modified (even if it was not), and sending an invalidation message to the clients. Doing so, it can reclaim the memory used for this key, even if this will force the clients having a local copy of the key to evict it.
* Inside the invalidation table we don't really need to store pointers to clients' structures, that would force a garbage collection procedure when the client disconnects: instead what we do is just store client IDs (each Redis client has a unique numerical ID). If a client disconnects, the information will be incrementally garbage collected as caching slots are invalidated.
* There is a single keys namespace, not divided by database numbers. So if a client is caching the key `foo` in database 2, and some other client changes the value of the key `foo` in database 3, an invalidation message will still be sent. This way we can ignore database numbers reducing both the memory usage and the implementation complexity.

Two connections mode

Using the new version of the Redis protocol, RESP3, supported by Redis 6, it is possible to run the data queries and receive the invalidation messages in the same connection. However many client implementations may prefer to implement client-side caching using two separated connections: one for data, and one for invalidation messages. For this reason when a client enables tracking, it can specify to redirect the invalidation messages to another connection by specifying the "client ID" of a different connection. Many data connections can redirect invalidation messages to the same connection, this is useful for clients implementing connection pooling. The two connections model is the only one that is also supported for RESP2 (which lacks the ability to multiplex different kind of information in the same connection).

Here's an example of a complete session using the Redis protocol in the old RESP2 mode involving the following steps: enabling tracking redirecting to another connection, asking for a key, and getting an invalidation message once the key gets modified.

To start, the client opens a first connection that will be used for invalidations, requests the connection ID, and subscribes via Pub/Sub to the special channel that is used to get invalidation messages when in RESP2 modes (remember that RESP2 is the usual Redis protocol, and not the more advanced protocol that you can use, optionally, with Redis 6 using the [`HELLO`]() command):

[code example]

Now we can enable tracking from the data connection:

[code example]

The client may decide to cache `"foo" => "bar"` in the local memory.

A different client will now modify the value of the "foo" key:

[code example]

As a result, the invalidations connection will receive a message that invalidates the specified key.

[code example]
The client will check if there are cached keys in this caching slot, and will evict the information that is no longer valid.

Note that the third element of the Pub/Sub message is not a single key but
is a Redis array with just a single element. Since we send an array, if there
are groups of keys to invalidate, we can do that in a single message.
In case of a flush ([`FLUSHALL`]() or [`FLUSHDB`]()), a `null` message will be sent.

A very important thing to understand about client-side caching used with
RESP2 and a Pub/Sub connection in order to read the invalidation messages,
is that using Pub/Sub is entirely a trick **in order to reuse old client
implementations**, but actually the message is not really sent to a channel
and received by all the clients subscribed to it. Only the connection we
specified in the `REDIRECT` argument of the [`CLIENT`]() command will actually
receive the Pub/Sub message, making the feature a lot more scalable.

When RESP3 is used instead, invalidation messages are sent (either in the
same connection, or in the secondary connection when redirection is used)
as `push` messages (read the RESP3 specification for more information).

What tracking tracks

As you can see clients do not need, by default, to tell the server what keys
they are caching. Every key that is mentioned in the context of a read-only
command is tracked by the server, because it *could be cached*.

This has the obvious advantage of not requiring the client to tell the server
what it is caching. Moreover in many clients implementations, this is what
you want, because a good solution could be to just cache everything that is not
already cached, using a first-in first-out approach: we may want to cache a
fixed number of objects, every new data we retrieve, we could cache it,
discarding the oldest cached object. More advanced implementations may instead
drop the least used object or alike.

Note that anyway if there is write traffic on the server, caching slots
will get invalidated during the course of the time. In general when the
server assumes that what we get we also cache, we are making a tradeoff:

1. It is more efficient when the client tends to cache many things with a policy that welcomes new objects.
2. The server will be forced to retain more data about the client keys.
3. The client will receive useless invalidation messages about objects it did not cache.

So there is an alternative described in the next section.

Opt-in and Opt-out caching

Opt-in

Clients implementations may want to cache only selected keys, and communicate
explicitly to the server what they'll cache and what they will not. This will
require more bandwidth when caching new objects, but at the same time reduces
the amount of data that the server has to remember and the amount of
invalidation messages received by the client.

In order to do this, tracking must be enabled using the OPTIN option:

    CLIENT TRACKING ON REDIRECT 1234 OPTIN

In this mode, by default, keys mentioned in read queries *are not supposed to be cached*, instead when a client wants to cache something, it must send a special command immediately before the actual command to retrieve the data:

    CLIENT CACHING YES
    +OK
    GET foo
    "bar"

The `CACHING` command affects the command executed immediately after it.
However, in case the next command is [`MULTI`](), all the commands in the
transaction will be tracked. Similarly, in case of Lua scripts, all the
commands executed by the script will be tracked.

Opt-out

Opt-out caching allows clients to automatically cache keys locally without explicitly opting in for each key.
This approach ensures that all keys are cached by default unless specified otherwise.
Opt-out caching can simplify the implementation of client-side caching by reducing the need for explicit commands to enable caching for individual keys.

Tracking must be enabled using the OPTOUT option to enable opt-out caching:

    CLIENT TRACKING ON OPTOUT

If you want to exclude a specific key from being tracked and cached, use the CLIENT UNTRACKING command:

    CLIENT UNTRACKING key

Broadcasting mode

So far we described the first client-side caching model that Redis implements.
There is another one, called broadcasting, that sees the problem from the
point of view of a different tradeoff, does not consume any memory on the
server side, but instead sends more invalidation messages to clients.
In this mode we have the following main behaviors:

* Clients enable client-side caching using the `BCAST` option, specifying one or more prefixes using the `PREFIX` option. For instance: `CLIENT TRACKING on REDIRECT 10 BCAST PREFIX object: PREFIX user:`. If no prefix is specified at all, the prefix is assumed to be the empty string, so the client will receive invalidation messages for every key that gets modified. Instead if one or more prefixes are used, only keys matching one of the specified prefixes will be sent in the invalidation messages.
* The server does not store anything in the invalidation table. Instead it uses a different **Prefixes Table**, where each prefix is associated to a list of clients.
* No two prefixes can track overlapping parts of the keyspace. For instance, having the prefix "foo" and "foob" would not be allowed, since they would both trigger an invalidation for the key "foobar". However, just using the prefix "foo" is sufficient.
* Every time a key matching any of the prefixes is modified, all the clients subscribed to that prefix, will receive the invalidation message.
* The server will consume CPU proportional to the number of registered prefixes. If you have just a few, it is hard to see any difference. With a big number of prefixes the CPU cost can become quite large.
* In this mode the server can perform the optimization of creating a single reply for all the clients subscribed to a given prefix, and send the same reply to all. This helps to lower the CPU usage.

The NOLOOP option

By default client-side tracking will send invalidation messages to the
client that modified the key. Sometimes clients want this, since they
implement very basic logic that does not involve automatically caching
writes locally. However, more advanced clients may want to cache even the
writes they are doing in the local in-memory table. In such case receiving
an invalidation message immediately after the write is a problem, since it
will force the client to evict the value it just cached.

In this case it is possible to use the `NOLOOP` option: it works both
in normal and broadcasting mode. Using this option, clients are able to
tell the server they don't want to receive invalidation messages for keys
that they modified.

Avoiding race conditions

When implementing client-side caching redirecting the invalidation messages
to a different connection, you should be aware that there is a possible
race condition. See the following example interaction, where we'll call
the data connection "D" and the invalidation connection "I":

    [D] client -> server: GET foo
    [I] server -> client: Invalidate foo (somebody else touched it)
    [D] server -> client: "bar" (the reply of "GET foo")

As you can see, because the reply to the GET was slower to reach the
client, we received the invalidation message before the actual data that
is already no longer valid. So we'll keep serving a stale version of the
foo key. To avoid this problem, it is a good idea to populate the cache
when we send the command with a placeholder:

    Client cache: set the local copy of "foo" to "caching-in-progress"
    [D] client-> server: GET foo.
    [I] server -> client: Invalidate foo (somebody else touched it)
    Client cache: delete "foo" from the local cache.
    [D] server -> client: "bar" (the reply of "GET foo")
    Client cache: don't set "bar" since the entry for "foo" is missing.

Such a race condition is not possible when using a single connection for both
data and invalidation messages, since the order of the messages is always known
in that case.

What to do when losing connection with the server

Similarly, if we lost the connection with the socket we use in order to
get the invalidation messages, we may end with stale data. In order to avoid
this problem, we need to do the following things:

1. Make sure that if the connection is lost, the local cache is flushed.
2. Both when using RESP2 with Pub/Sub, or RESP3, ping the invalidation channel periodically (you can send PING commands even when the connection is in Pub/Sub mode!). If the connection looks broken and we are not able to receive ping backs, after a maximum amount of time, close the connection and flush the cache.

What to cache

Clients may want to run internal statistics about the number of times
a given cached key was actually served in a request, to understand in the
future what is good to cache. In general:

* We don't want to cache many keys that change continuously.
* We don't want to cache many keys that are requested very rarely.
* We want to cache keys that are requested often and change at a reasonable rate. For an example of key not changing at a reasonable rate, think of a global counter that is continuously [`INCR`]()emented.

However simpler clients may just evict data using some random sampling just
remembering the last time a given cached value was served, trying to evict
keys that were not served recently.

Other hints for implementing client libraries

* Handling TTLs: make sure you also request the key TTL and set the TTL in the local cache if you want to support caching keys with a TTL.
* Putting a max TTL on every key is a good idea, even if it has no TTL. This protects against bugs or connection issues that would make the client have old data in the local copy.
* Limiting the amount of memory used by clients is absolutely needed. There must be a way to evict old keys when new ones are added.

Limiting the amount of memory used by Redis

Be sure to configure a suitable value for the maximum number of keys remembered by Redis or alternatively use the BCAST mode that consumes no memory at all on the Redis side. Note that the memory consumed by Redis when BCAST is not used, is proportional both to the number of keys tracked and the number of clients requesting such keys.

(Connection 1 -- used for invalidations)
CLIENT ID
:4
SUBSCRIBE __redis__:invalidate
*3
$9
subscribe
$20
__redis__:invalidate
:1

(Connection 2 -- data connection)
CLIENT TRACKING on REDIRECT 4
+OK

GET foo
$3
bar

(Some other unrelated connection)
SET foo bar
+OK

(Connection 1 -- used for invalidations)
*3
$7
message
$20
__redis__:invalidate
*1
$3
foo


Redis client handling

Summary: How the Redis server manages client connections

Overview

This document provides information about how Redis handles clients at the network layer level: connections, timeouts, buffers, and other similar topics are covered here.

The information contained in this document is **only applicable to Redis version 2.6 or greater**.

Accepting Client Connections

Redis accepts clients connections on the configured TCP port and on the Unix socket if enabled. When a new client connection is accepted the following operations are performed:

* The client socket is put in the non-blocking state since Redis uses multiplexing and non-blocking I/O.
* The `TCP_NODELAY` option is set in order to ensure that there are no delays to the connection.
* A *readable* file event is created so that Redis is able to collect the client queries as soon as new data is available to read on the socket.

After the client is initialized, Redis checks if it is already at the limit
configured for the number of simultaneous clients (configured using the `maxclients` configuration directive, see the next section of this document for further information).

When Redis can't accept a new client connection because the maximum number of clients
has been reached, it tries to send an error to the client in order to
make it aware of this condition, closing the connection immediately.
The error message will reach the client even if the connection is
closed immediately by Redis because the new socket output buffer is usually
big enough to contain the error, so the kernel will handle transmission
of the error.

What Order are Client Requests Served In?

The order is determined by a combination of the client socket file descriptor
number and order in which the kernel reports events, so the order should be
considered as unspecified.

However, Redis does the following two things when serving clients:

* It only performs a single `read()` system call every time there is something new to read from the client socket. This ensures that if we have multiple clients connected, and a few send queries at a high rate, other clients are not penalized and will not experience latency issues.
* However once new data is read from a client, all the queries contained in the current buffers are processed sequentially. This improves locality and does not need iterating a second time to see if there are clients that need some processing time.

Maximum Concurrent Connected Clients

In Redis 2.4 there was a hard-coded limit for the maximum number of clients
that could be handled simultaneously.

In Redis 2.6 and newer, this limit is configurable using the `maxclients` directive in `redis.conf`. The default is 10,000 clients.

However, Redis checks with the kernel what the maximum number of file
descriptors that we are able to open is (the *soft limit* is checked). If the
limit is less than the maximum number of clients we want to handle, plus
32 (that is the number of file descriptors Redis reserves for internal uses),
then the maximum number of clients is updated to match the number
of clients it is *really able to handle* under the current operating system
limit.

When `maxclients` is set to a number greater than Redis can support, a message is logged at startup:

[code example]

When Redis is configured in order to handle a specific number of clients it
is a good idea to make sure that the operating system limit for the maximum
number of file descriptors per process is also set accordingly.

Under Linux these limits can be set both in the current session and as a
system-wide setting with the following commands:

* `ulimit -Sn 100000 # This will only work if hard limit is big enough.`
* `sysctl -w fs.file-max=100000`

Output Buffer Limits

Redis needs to handle a variable-length output buffer for every client, since
a command can produce a large amount of data that needs to be transferred to the
client.

However it is possible that a client sends more commands producing more output
to serve at a faster rate than that which Redis can send the existing output to the
client. This is especially true with Pub/Sub clients in case a client is not
able to process new messages fast enough.

Both conditions will cause the client output buffer to grow and consume
more and more memory. For this reason by default Redis sets limits to the
output buffer size for different kind of clients. When the limit is reached
the client connection is closed and the event logged in the Redis log file.

There are two kind of limits Redis uses:

* The **hard limit** is a fixed limit that when reached will make Redis close the client connection as soon as possible.
* The **soft limit** instead is a limit that depends on the time, for instance a soft limit of 32 megabytes per 10 seconds means that if the client has an output buffer bigger than 32 megabytes for, continuously, 10 seconds, the connection gets closed.

Different kind of clients have different default limits:

* **Normal clients** have a default limit of 0, that means, no limit at all, because most normal clients use blocking implementations sending a single command and waiting for the reply to be completely read before sending the next command, so it is always not desirable to close the connection in case of a normal client.
* **Pub/Sub clients** have a default hard limit of 32 megabytes and a soft limit of 8 megabytes per 60 seconds.
* **Replicas** have a default hard limit of 256 megabytes and a soft limit of 64 megabyte per 60 seconds.

It is possible to change the limit at runtime using the [`CONFIG SET`]() command or in a permanent way using the Redis configuration file `redis.conf`. See the example `redis.conf` in the Redis distribution for more information about how to set the limit.

Query Buffer Hard Limit

Every client is also subject to a query buffer limit. This is a non-configurable hard limit that will close the connection when the client query buffer (that is the buffer we use to accumulate commands from the client) reaches 1 GB, and is actually only an extreme limit to avoid a server crash in case of client or server software bugs.

Client Eviction

Redis is built to handle a very large number of client connections.
Client connections tend to consume memory, and when there are many of them, the aggregate memory consumption can be extremely high, leading to data eviction or out-of-memory errors.
These cases can be mitigated to an extent using [output buffer limits](#output-buffer-limits), but Redis allows us a more robust configuration to limit the aggregate memory used by all clients' connections.

This mechanism is called **client eviction**, and it's essentially a safety mechanism that will disconnect clients once the aggregate memory usage of all clients is above a threshold.
The mechanism first attempts to disconnect clients that use the most memory.
It disconnects the minimal number of clients needed to return below the `maxmemory-clients` threshold.

`maxmemory-clients` defines the maximum aggregate memory usage of all clients connected to Redis.
The aggregation takes into account all the memory used by the client connections: the [query buffer](#query-buffer-hard-limit), the output buffer, and other intermediate buffers.

Note that replica and master connections aren't affected by the client eviction mechanism. Therefore, such connections are never evicted.

`maxmemory-clients` can be set permanently in the configuration file (`redis.conf`) or via the [`CONFIG SET`]() command.
This setting can either be 0 (meaning no limit), a size in bytes (possibly with `mb`/`gb` suffix),
or a percentage of `maxmemory` by using the `%` suffix (e.g. setting it to `10%` would mean 10% of the `maxmemory` configuration).

The default setting is 0, meaning client eviction is turned off by default.
However, for any large production deployment, it is highly recommended to configure some non-zero `maxmemory-clients` value.
A value `5%`, for example, can be a good place to start.

It is possible to flag a specific client connection to be excluded from the client eviction mechanism.
This is useful for control path connections.
If, for example, you have an application that monitors the server via the [`INFO`]() command and alerts you in case of a problem, you might want to make sure this connection isn't evicted.
You can do so using the following command (from the relevant client's connection):

[`CLIENT NO-EVICT`]() `on`

And you can revert that with:

[`CLIENT NO-EVICT`]() `off`

For more information and an example refer to the `maxmemory-clients` section in the default `redis.conf` file.

Client eviction is available from Redis 7.0.

Client Timeouts

By default recent versions of Redis don't close the connection with the client
if the client is idle for many seconds: the connection will remain open forever.

However if you don't like this behavior, you can configure a timeout, so that
if the client is idle for more than the specified number of seconds, the client connection will be closed.

You can configure this limit via `redis.conf` or simply using `CONFIG SET timeout <value>`.

Note that the timeout only applies to normal clients and it **does not apply to Pub/Sub clients**, since a Pub/Sub connection is a *push style* connection so a client that is idle is the norm.

Even if by default connections are not subject to timeout, there are two conditions when it makes sense to set a timeout:

* Mission critical applications where a bug in the client software may saturate the Redis server with idle connections, causing service disruption.
* As a debugging mechanism in order to be able to connect with the server if a bug in the client software saturates the server with idle connections, making it impossible to interact with the server.

Timeouts are not to be considered very precise: Redis avoids setting timer events or running O(N) algorithms in order to check idle clients, so the check is performed incrementally from time to time. This means that it is possible that while the timeout is set to 10 seconds, the client connection will be closed, for instance, after 12 seconds if many clients are connected at the same time.

The CLIENT Command

The Redis [`CLIENT`]() command allows you to inspect the state of every connected client, to kill a specific client, and to name connections. It is a very powerful debugging tool if you use Redis at scale.

[`CLIENT LIST`]() is used in order to obtain a list of connected clients and their state:

[code example]

In the above example two clients are connected to the Redis server. Let's look at what some of the data returned represents:

* **addr**: The client address, that is, the client IP and the remote port number it used to connect with the Redis server.
* **fd**: The client socket file descriptor number.
* **name**: The client name as set by [`CLIENT SETNAME`]().
* **age**: The number of seconds the connection existed for.
* **idle**: The number of seconds the connection is idle.
* **flags**: The kind of client (N means normal client, check the [full list of flags]()).
* **omem**: The amount of memory used by the client for the output buffer.
* **cmd**: The last executed command.

See the [[`CLIENT LIST`]()](/commands/client-list) documentation for the full listing of fields and their purpose.

Once you have the list of clients, you can close a client's connection using the [`CLIENT KILL`]() command, specifying the client address as its argument.

The commands [`CLIENT SETNAME`]() and [`CLIENT GETNAME`]() can be used to set and get the connection name. Starting with Redis 4.0, the client name is shown in the
[`SLOWLOG`]() output, to help identify clients that create latency issues.

TCP keepalive

From version 3.2 onwards, Redis has TCP keepalive (`SO_KEEPALIVE` socket option) enabled by default and set to about 300 seconds. This option is useful in order to detect dead peers (clients that cannot be reached even if they look connected). Moreover, if there is network equipment between clients and servers that need to see some traffic in order to take the connection open, the option will prevent unexpected connection closed events.

$ ./redis-server --maxclients 100000
[41422] 23 Jan 11:28:33.179 # Unable to set the max number of files limit to 100032 (Invalid argument), setting the max clients configuration to 10112.

redis 127.0.0.1:6379> client list
addr=127.0.0.1:52555 fd=5 name= age=855 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
addr=127.0.0.1:52787 fd=6 name= age=6 idle=5 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping


Redis command arguments

Summary: How Redis commands expose their documentation programmatically

Overview

The [`COMMAND DOCS`]() command returns documentation-focused information about available Redis commands.
The map reply that the command returns includes the _arguments_ key.
This key stores an array that describes the command's arguments.

Every element in the _arguments_ array is a map with the following fields:

* **name:** the argument's name, always present.
  The name of an argument is given for identification purposes alone.
  It isn't displayed during the command's syntax rendering.
  The same name can appear more than once in the entire argument tree, but it is unique compared to other sibling arguments' names.
  This allows obtaining a unique identifier for each argument (the concatenation of all names in the path from the root to any argument).
* **display_text:** the argument's display string, present in arguments that have a displayable representation (all arguments that aren't oneof/block).
  This is the string used in the command's syntax rendering.
* **type:** the argument's type, always present.
  An argument must have one of the following types:
  - **string:** a string argument.
  - **integer:** an integer argument.
  - **double:** a double-precision argument.
  - **key:** a string that represents the name of a key.
  - **pattern:** a string that represents a glob-like pattern.
  - **unix-time:** an integer that represents a Unix timestamp.
  - **pure-token:** an argument is a token, meaning a reserved keyword, which may or may not be provided.
    Not to be confused with free-text user input.
  - **oneof**: the argument is a container for nested arguments.
    This type enables choice among several nested arguments (see the [`XADD`]() example below).
  - **block:** the argument is a container for nested arguments.
    This type enables grouping arguments and applying a property (such as _optional_) to all (see the [`XADD`]() example below).
* **key_spec_index:** this value is available for every argument of the _key_ type.
  It is a 0-based index of the specification in the command's [key specifications][tr] that corresponds to the argument.
* **token**: a constant literal that precedes the argument (user input) itself.
* **summary:** a short description of the argument.
* **since:** the debut Redis version of the argument (or for module commands, the module version).
* **deprecated_since:** the Redis version that deprecated the command (or for module commands, the module version).
* **flags:** an array of argument flags.
  Possible flags are:
  - **optional**: denotes that the argument is optional (for example, the _GET_ clause of the  [`SET`]() command).
  - **multiple**: denotes that the argument may be repeated (such as the _key_ argument of [`DEL`]()).
  - **multiple-token:** denotes the possible repetition of the argument with its preceding token (see [`SORT`]()'s `GET pattern` clause).
* **value:** the argument's value.
  For arguments types other than _oneof_ and _block_, this is a string that describes the value in the command's syntax.
  For the _oneof_ and _block_ types, this is an array of nested arguments, each being a map as described in this section.

[tr]: /develop/reference/key-specs.md

Example

The trimming clause of [`XADD`](), i.e., `[MAXLEN|MINID [=|~] threshold [LIMIT count]]`, is represented at the top-level as _block_-typed argument.

It consists of four nested arguments:

1. **trimming strategy:** this nested argument has an _oneof_ type with two nested arguments.
  Each of the nested arguments, _MAXLEN_ and _MINID_, is typed as _pure-token_.
2. **trimming operator:** this nested argument is an optional _oneof_ type with two nested arguments.
  Each of the nested arguments, _=_ and _~_, is a _pure-token_.
3. **threshold:** this nested argument is a _string_.
4. **count:** this nested argument is an optional _integer_ with a _token_ (_LIMIT_).

Here's [`XADD`]()'s arguments array:

[code example]

1) 1) "name"
   2) "key"
   3) "type"
   4) "key"
   5) "value"
   6) "key"
2)  1) "name"
    2) "nomkstream"
    3) "type"
    4) "pure-token"
    5) "token"
    6) "NOMKSTREAM"
    7) "since"
    8) "6.2"
    9) "flags"
   10) 1) optional
3) 1) "name"
   2) "trim"
   3) "type"
   4) "block"
   5) "flags"
   6) 1) optional
   7) "value"
   8) 1) 1) "name"
         2) "strategy"
         3) "type"
         4) "oneof"
         5) "value"
         6) 1) 1) "name"
               2) "maxlen"
               3) "type"
               4) "pure-token"
               5) "token"
               6) "MAXLEN"
            2) 1) "name"
               2) "minid"
               3) "type"
               4) "pure-token"
               5) "token"
               6) "MINID"
               7) "since"
               8) "6.2"
      2) 1) "name"
         2) "operator"
         3) "type"
         4) "oneof"
         5) "flags"
         6) 1) optional
         7) "value"
         8) 1) 1) "name"
               2) "equal"
               3) "type"
               4) "pure-token"
               5) "token"
               6) "="
            2) 1) "name"
               2) "approximately"
               3) "type"
               4) "pure-token"
               5) "token"
               6) "~"
      3) 1) "name"
         2) "threshold"
         3) "type"
         4) "string"
         5) "value"
         6) "threshold"
      4)  1) "name"
          2) "count"
          3) "type"
          4) "integer"
          5) "token"
          6) "LIMIT"
          7) "since"
          8) "6.2"
          9) "flags"
         10) 1) optional
         11) "value"
         12) "count"
4) 1) "name"
   2) "id_or_auto"
   3) "type"
   4) "oneof"
   5) "value"
   6) 1) 1) "name"
         2) "auto_id"
         3) "type"
         4) "pure-token"
         5) "token"
         6) "*"
      2) 1) "name"
         2) "id"
         3) "type"
         4) "string"
         5) "value"
         6) "id"
5) 1) "name"
   2) "field_value"
   3) "type"
   4) "block"
   5) "flags"
   6) 1) multiple
   7) "value"
   8) 1) 1) "name"
         2) "field"
         3) "type"
         4) "string"
         5) "value"
         6) "field"
      2) 1) "name"
         2) "value"
         3) "type"
         4) "string"
         5) "value"
         6) "value"


Redis command tips

Summary: Get additional information about a command

Overview

Command tips are an array of strings.
These provide Redis clients with additional information about the command.
The information can instruct Redis Cluster clients as to how the command should be executed and its output processed in a clustered deployment.

Unlike the command's flags (see the 3rd element of [`COMMAND`]()'s reply), which are strictly internal to the server's operation, tips don't serve any purpose other than being reported to clients.

Command tips are arbitrary strings.
However, the following sections describe proposed tips and demonstrate the conventions they are likely to adhere to.

nondeterministic_output

This tip indicates that the command's output isn't deterministic.
That means that calls to the command may yield different results with the same arguments and data.
That difference could be the result of the command's random nature (e.g., [`RANDOMKEY`]() and [`SPOP`]()); the call's timing (e.g., [`TTL`]()); or generic differences that relate to the server's state (e.g., [`INFO`]() and [`CLIENT LIST`]()).

**Note:**
Prior to Redis 7.0, this tip was the _random_ command flag.

nondeterministic_output_order

The existence of this tip indicates that the command's output is deterministic, but its ordering is random (e.g., [`HGETALL`]() and [`SMEMBERS`]()).

**Note:**
Prior to Redis 7.0, this tip was the _sort_\__for_\__script_ flag.

request_policy

This tip can help clients determine the shards to send the command in clustering mode.
The default behavior a client should implement for commands without the _request_policy_ tip is as follows:

1. The command doesn't accept key name arguments: the client can execute the command on an arbitrary shard.
1. For commands that accept one or more key name arguments: the client should route the command to a single shard, as determined by the hash slot of the input keys.

In cases where the client should adopt a behavior different than the default, the _request_policy_ tip can be one of:

- **all_nodes:** the client should execute the command on all nodes - masters and replicas alike.
  An example is the [`CONFIG SET`]() command.
  This tip is in-use by commands that don't accept key name arguments.
  The command operates atomically per shard.
* **all_shards:** the client should execute the command on all master shards (e.g., the [`DBSIZE`]() command).
  This tip is in-use by commands that don't accept key name arguments.
  The command operates atomically per shard.
- **multi_shard:** the client should execute the command on several shards.
  The client should split the inputs according to the hash slots of its input key name arguments.
  For example, the command `DEL {foo} {foo}1 bar` should be split to `DEL {foo} {foo}1` and `DEL bar`.
  If the keys are hashed to more than a single slot, the command must be split even if all the slots are managed by the same shard.
  Examples for such commands include [`MSET`](), [`MGET`]() and [`DEL`]().
  However, note that [`SUNIONSTORE`]() isn't considered as _multi_shard_ because all of its keys must belong to the same hash slot.
- **special:** indicates a non-trivial form of the client's request policy, such as the [`SCAN`]() command.

response_policy

This tip can help clients determine the aggregate they need to compute from the replies of multiple shards in a cluster.
The default behavior for commands without a _request_policy_ tip only applies to replies with of nested types (i.e., an array, a set, or a map).
The client's implementation for the default behavior should be as follows:

1. The command doesn't accept key name arguments: the client can aggregate all replies within a single nested data structure.
For example, the array replies we get from calling [`KEYS`]() against all shards.
These should be packed in a single in no particular order.
1. For commands that accept one or more key name arguments: the client needs to retain the same order of replies as the input key names.
For example, [`MGET`]()'s aggregated reply.

The _response_policy_ tip is set for commands that reply with scalar data types, or when it's expected that clients implement a non-default aggregate.
This tip can be one of:

* **one_succeeded:** the clients should return success if at least one shard didn't reply with an error.
  The client should reply with the first non-error reply it obtains.
  If all shards return an error, the client can reply with any one of these.
  For example, consider a [`SCRIPT KILL`]() command that's sent to all shards.
  Although the script should be loaded in all of the cluster's shards, the [`SCRIPT KILL`]() will typically run only on one at a given time.
* **all_succeeded:** the client should return successfully only if there are no error replies.
  Even a single error reply should disqualify the aggregate and be returned.
  Otherwise, the client should return one of the non-error replies.
  As an example, consider the [`CONFIG SET`](), [`SCRIPT FLUSH`]() and [`SCRIPT LOAD`]() commands.
* **agg_logical_and:** the client should return the result of a logical _AND_ operation on all replies (only applies to integer replies, usually from commands that return either _0_ or _1_).
  Consider the [`SCRIPT EXISTS`]() command as an example.
  It returns an array of _0_'s and _1_'s that denote the existence of its given SHA1 sums in the script cache.
  The aggregated response should be _1_ only when all shards had reported that a given script SHA1 sum is in their respective cache.
* **agg_logical_or:** the client should return the result of a logical _OR_ operation on all replies (only applies to integer replies, usually from commands that return either _0_ or _1_).
* **agg_min:** the client should return the minimal value from the replies (only applies to numerical replies).
  The aggregate reply from a cluster-wide [`WAIT`]() command, for example, should be the minimal value (number of synchronized replicas) from all shards.
* **agg_max:** the client should return the maximal value from the replies (only applies to numerical replies).
* **agg_sum:** the client should return the sum of replies (only applies to numerical replies).
  Example: [`DBSIZE`]().
* **special:** this type of tip indicates a non-trivial form of reply policy.
  [`INFO`]() is an excellent example of that.

Example

[code example]

redis> command info ping
1)  1) "ping"
    2) (integer) -1
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
       2) @connection
    8) 1) "request_policy:all_shards"
       2) "response_policy:all_succeeded"
    9) (empty array)
   10) (empty array)


Key eviction

Summary: Overview of Redis key eviction policies (LRU, LFU, etc.)

Overview

Redis is commonly used as a cache to speed up read accesses to a slower server
or database. Since cache entries are copies of persistently-stored data, it
is usually safe to evict them when the cache runs out of memory (they can be
cached again in the future if necessary).

Redis lets you specify an eviction policy to evict keys automatically
when the size of the cache exceeds a set memory limit. Whenever a client
runs a new command that adds more data to the cache, Redis checks the memory usage.
If it is greater than the limit, Redis evicts keys according to the chosen
eviction policy until the total memory used is back below the limit.

Note that when a command adds a lot of data to the cache (for example, a big set
intersection stored into a new key), this might temporarily exceed the limit by
a large amount.

The sections below explain how to [configure the memory limit](#maxmem) for the cache
and also describe the available [eviction policies](#eviction-policies) and when to
use them.

Using the `maxmemory` configuration directive {#maxmem}

The `maxmemory` configuration directive specifies
the maximum amount of memory to use for the cache data. You can
set `maxmemory` with the [`redis.conf`](https://github.com/redis/redis/blob/7.4.0/redis.conf)
file at startup time. For example, to configure a memory limit of 100 megabytes,
you can use the following directive inside `redis.conf`:

[code example]

You can also use [`CONFIG SET`]() to
set `maxmemory` at runtime using [`redis-cli`]():

[code example]

Set `maxmemory` to zero to specify that you don't want to limit the memory
for the dataset. This is the default behavior for 64-bit systems, while 32-bit
systems use an implicit memory limit of 3GB.

When the size of your cache exceeds the limit set by `maxmemory`, Redis will
enforce your chosen [eviction policy](#eviction-policies) to prevent any
further growth of the cache.

Setting `maxmemory` for a replicated or persisted instance

If you are using
[replication]()
or [persistence]()
for a server, Redis will use some RAM as a buffer to store the set of updates waiting
to be written to the replicas or AOF files.
The memory used by this buffer is not included in the total that
is compared to `maxmemory` to see if eviction is required.

This is because the key evictions themselves generate updates that must be added
to the buffer. If the updates were counted among the used
memory then in some circumstances, the memory saved by
evicting keys would be immediately used up by the update data added to the buffer.
This, in turn, would trigger even more evictions and the resulting feedback loop
could evict many items from the cache unnecessarily.

If you are using replication or persistence, we recommend that you set
`maxmemory` to leave a little RAM free to store the buffers. Note that this is not
necessary for the `noeviction` policy (see [the section below](#eviction-policies)
for more information about eviction policies).

The [`INFO`]() command returns a
`mem_not_counted_for_evict` value in the `memory` section (you can use
the `INFO memory` option to see just this section). This is the amount of
memory currently used by the buffers. Although the exact amount will vary,
you can use it to estimate how much to subtract from the total available RAM
before setting `maxmemory`.

Eviction policies

Use the `maxmemory-policy` configuration directive to select the eviction
policy you want to use when the limit set by `maxmemory` is reached.

The following policies are available:

-   `noeviction`: Keys are not evicted but the server will return an error
    when you try to execute commands that cache new data. If your database uses replication
    then this condition only applies to the primary database. Note that commands that only
    read existing data still work as normal.
-   `allkeys-lru`: Evict the [least recently used](#apx-lru) (LRU) keys.
-   `allkeys-lrm`: Evict the [least recently modified](#lrm-eviction) (LRM) keys.
-   `allkeys-lfu`: Evict the [least frequently used](#lfu-eviction) (LFU) keys.
-   `allkeys-random`: Evict keys at random.
-   `volatile-lru`: Evict the least recently used keys that have an associated expiration (TTL).
-   `volatile-lrm`: Evict the least recently modified keys that have an associated expiration (TTL).
-   `volatile-lfu`: Evict the least frequently used keys that have an associated expiration (TTL).
-   `volatile-random`: Evicts random keys that have an associated expiration (TTL).
-   `volatile-ttl`: Evict keys with an associated expiration (TTL) that have the shortest remaining TTL value.

The `volatile-xxx` policies behave like `noeviction` if no keys have an associated expiration.

You should choose an eviction policy that fits the way your app
accesses keys. You may be able to predict the access pattern in advance
but you can also use information from the `INFO` command at runtime to
check or improve your choice of policy (see
[Using the `INFO` command](#using-the-info-command) below for more information).

As a rule of thumb:

-   Use `allkeys-lru` when you expect that a subset of elements will be accessed far
    more often than the rest. This is a very common case according to the
    [Pareto principle](https://en.wikipedia.org/wiki/Pareto_principle), so
    `allkeys-lru` is a good default option if you have no reason to prefer any others.
-   Use `allkeys-lrm` when you want to preserve frequently read data but evict data
    that hasn't been modified recently. This is useful for read-heavy workloads where
    you want to distinguish between data that's actively being updated versus data
    that's only being read.
-   Use `allkeys-random` when you expect all keys to be accessed with roughly equal
    frequency. An example of this is when your app reads data items in a repeating cycle.
-   Use `volatile-ttl` if your code can estimate which keys are good candidates for eviction
    and assign short TTLs to them. Note also that if you make good use of
    key expiration, then you are less likely to run into the cache memory limit because keys
    will often expire before they need to be evicted.

The `volatile-lru`, `volatile-lrm`, and `volatile-random` policies are mainly useful when you want to use
a single Redis instance for both caching and for a set of persistent keys. However,
you should consider running two separate Redis instances in a case like this, if possible.

Also note that setting an `expire` value for a key costs memory, so a
policy like `allkeys-lru` is more memory efficient since it doesn't need an
`expire` value to operate.

Using the `INFO` command

The [`INFO`]() command provides several pieces
of data that are useful for checking the performance of your cache. In particular,
the `INFO stats` section includes two important entries, `keyspace_hits` (the number of
times keys were successfully found in the cache) and `keyspace_misses` (the number
of times a key was requested but was not in the cache). The calculation below gives
the percentage of attempted accesses that were satisfied from the cache:

[code example]

Check that this is roughly equal to what you would expect for your app
(naturally, a higher percentage indicates better cache performance).

 When the [`EXISTS`]()
command reports that a key is absent then this is counted as a keyspace miss.

If the percentage of hits is lower than expected, then this might
mean you are not using the best eviction policy. For example, if
you believe that a small subset of "hot" data (that will easily fit into the
cache) should account for about 75% of accesses, you could reasonably
expect the percentage of keyspace hits to be around 75%. If the actual
percentage is lower, check the value of `evicted_keys` (also returned by
`INFO stats`). A high proportion of evictions would suggest that the
wrong keys are being evicted too often by your chosen policy
(so `allkeys-lru` might be a good option here). If the
value of `evicted_keys` is low and you are using key expiration, check
`expired_keys` to see how many keys have expired. If this number is high,
you might be using a TTL that is too low or you are choosing the wrong
keys to expire and this is causing keys to disappear from the cache
before they should.

Other useful pieces of information returned by `INFO` include:

-   `used_memory_dataset`: (`memory` section) The amount of memory used for
    cached data. If this is greater than `maxmemory`, then the difference
    is the amount by which `maxmemory` has been exceeded.
-   `current_eviction_exceeded_time`: (`stats` section) The time since
    the cache last started to exceed `maxmemory`.
-   `commandstats` section: Among other things, this reports the number of
    times each command issued to the server has been rejected. If you are
    using `noeviction` or one of the `volatile_xxx` policies, you can use
    this to find which commands are being stopped by the `maxmemory` limit
    and how often it is happening.

Approximated LRU algorithm {#apx-lru}

The Redis LRU algorithm uses an approximation of the least recently used
keys rather than calculating them exactly. It samples a small number of keys
at random and then evicts the ones with the longest time since last access.

From Redis 3.0 onwards, the algorithm also tracks a pool of good
candidates for eviction. This improves the performance of the algorithm, making
it a close approximation to a true LRU algorithm.

(Redis Open Source only) You can tune the performance of the algorithm by changing the number of samples to check
before every eviction with the `maxmemory-samples` configuration directive:

[code example]

See these pages for information on eviction policies in: (1) [Redis Software]() and (2) [Redis Cloud]().

The reason Redis does not use a true LRU implementation is because it
costs more memory. However, the approximation is virtually equivalent for an
application using Redis. This figure compares
the LRU approximation used by Redis with true LRU.

![LRU comparison](lru_comparison.png)

The test to generate the above graphs filled a Redis server with a given number of keys. The keys were accessed from the first to the last. The first keys are the best candidates for eviction using an LRU algorithm. Later more 50% of keys are added, in order to force half of the old keys to be evicted.

You can see three kind of dots in the graphs, forming three distinct bands.

* The light gray band are objects that were evicted.
* The gray band are objects that were not evicted.
* The green band are objects that were added.

In a theoretical LRU implementation we expect that, among the old keys, the first half will be expired. The Redis LRU algorithm will instead only *probabilistically* expire the older keys.

As you can see Redis 3.0 does a better job with 5 samples compared to Redis 2.8, however most objects that are among the latest accessed are still retained by Redis 2.8. Using a sample size of 10 in Redis 3.0 the approximation is very close to the theoretical performance of Redis 3.0.

Note that LRU is just a model to predict how likely a given key will be accessed in the future. Moreover, if your data access pattern closely
resembles the power law, most of the accesses will be in the set of keys
the LRU approximated algorithm can handle well.

In simulations we found that using a power law access pattern, the difference between true LRU and Redis approximation were minimal or non-existent.

However you can raise the sample size to 10 at the cost of some additional CPU
usage to closely approximate true LRU, and check if this makes a
difference in your cache misses rate.

To experiment in production with different values for the sample size by using
the `CONFIG SET maxmemory-samples <count>` command, is very simple.

LFU eviction

Starting with Redis 4.0, the [Least Frequently Used eviction mode](http://antirez.com/news/109) is available. This mode may work better (provide a better
hits/misses ratio) in certain cases. In LFU mode, Redis will try to track
the frequency of access of items, so the ones used rarely are evicted. This means
the keys used often have a higher chance of remaining in memory.

To configure the LFU mode, the following policies are available:

* `volatile-lfu` Evict using approximated LFU among the keys with an expire set.
* `allkeys-lfu` Evict any key using approximated LFU.

LFU is approximated like LRU: it uses a probabilistic counter, called a [Morris counter](https://en.wikipedia.org/wiki/Approximate_counting_algorithm) to estimate the object access frequency using just a few bits per object, combined with a decay period so that the counter is reduced over time. At some point we no longer want to consider keys as frequently accessed, even if they were in the past, so that the algorithm can adapt to a shift in the access pattern.

That information is sampled similarly to what happens for LRU (as explained in the previous section of this documentation) to select a candidate for eviction.

However unlike LRU, LFU has certain tunable parameters: for example, how fast
should a frequent item lower in rank if it gets no longer accessed? It is also possible to tune the Morris counters range to better adapt the algorithm to specific use cases.

By default Redis is configured to:

* Saturate the counter at, around, one million requests.
* Decay the counter every one minute.

Those should be reasonable values and were tested experimentally, but the user may want to play with these configuration settings to pick optimal values.

Instructions about how to tune these parameters can be found inside the example `redis.conf` file in the source distribution. Briefly, they are:

[code example]

The decay time is the obvious one, it is the amount of minutes a counter should be decayed, when sampled and found to be older than that value. A special value of `0` means: we will never decay the counter.

The counter *logarithm factor* changes how many hits are needed to saturate the frequency counter, which is just in the range 0-255. The higher the factor, the more accesses are needed to reach the maximum. The lower the factor, the better is the resolution of the counter for low accesses, according to the following table:

[code example]

So basically the factor is a trade off between better distinguishing items with low accesses VS distinguishing items with high accesses. More information is available in the example `redis.conf` file.

LRM eviction {#lrm-eviction}

Starting with Redis 8.6, the Least Recently Modified (LRM) eviction policy is available. LRM is similar to LRU but only updates the timestamp on write operations, not read operations. This makes it useful for evicting keys that haven't been modified recently, regardless of how frequently they are read.

The key difference between LRU and LRM is:

- **LRU (Least Recently Used)**: Updates the access timestamp on both read and write operations
- **LRM (Least Recently Modified)**: Updates the access timestamp only on write operations

This distinction makes LRM particularly useful in scenarios where:

- Your application has a clear distinction between read-heavy and write-heavy workloads
- You want to evict stale data that hasn't been updated, regardless of read activity

To configure LRM eviction, the following policies are available:

* `volatile-lrm` Evict using LRM among the keys with an an associated expiration (TTL).
* `allkeys-lrm` Evict any key using LRM.

Like LRU, LRM uses an approximation algorithm that samples a small number of keys at random and evicts the ones with the longest time since last modification. The same `maxmemory-samples` configuration directive that affects LRU performance also applies to LRM.

keyspace_hits / (keyspace_hits + keyspace_misses) * 100


Redis and the Gopher protocol

Summary: The Redis Gopher protocol implementation

Overview

** Note: Support for Gopher was removed in Redis 7.0 **

Redis contains an implementation of the Gopher protocol, as specified in
the [RFC 1436](https://www.ietf.org/rfc/rfc1436.txt).

The Gopher protocol was very popular in the late '90s. It is an alternative
to the web, and the implementation both server and client side is so simple
that the Redis server has just 100 lines of code in order to implement this
support.

What do you do with Gopher nowadays? Well Gopher never *really* died, and
lately there is a movement in order for the Gopher more hierarchical content
composed of just plain text documents to be resurrected. Some want a simpler
internet, others believe that the mainstream internet became too much
controlled, and it's cool to create an alternative space for people that
want a bit of fresh air.

Anyway, for the 10th birthday of the Redis, we gave it the Gopher protocol
as a gift.

How it works

The Redis Gopher support uses the inline protocol of Redis, and specifically
two kind of inline requests that were anyway illegal: an empty request
or any request that starts with "/" (there are no Redis commands starting
with such a slash). Normal RESP2/RESP3 requests are completely out of the
path of the Gopher protocol implementation and are served as usually as well.

If you open a connection to Redis when Gopher is enabled and send it
a string like "/foo", if there is a key named "/foo" it is served via the
Gopher protocol.

In order to create a real Gopher "hole" (the name of a Gopher site in Gopher
talking), you likely need a script such as the one in [https://github.com/antirez/gopher2redis](https://github.com/antirez/gopher2redis).

SECURITY WARNING

If you plan to put Redis on the internet in a publicly accessible address
to server Gopher pages **make sure to set a password** to the instance.
Once a password is set:

1. The Gopher server (when enabled, not by default) will kill serve content via Gopher.
2. However other commands cannot be called before the client will authenticate.

So use the `requirepass` option to protect your instance.

To enable Gopher support use the following configuration line.

    gopher-enabled yes

Accessing keys that are not strings or do not exit will generate
an error in Gopher protocol format.


Redis reference

Summary: Specifications and protocols

Redis command tips

Client-side caching reference

Summary: Introduction to writing Redis modules

Redis modules API

Summary: How to build clients for Redis Sentinel

Sentinel client spec

Summary: What are command key specification and how to use them in your client

Command key specifications

Summary: Redis serialization protocol (RESP) is the wire protocol that clients implement

Redis serialization protocol specification

Redis client handling

Key eviction

Redis command arguments

Redis and the Gopher protocol