skip to content

SLOWLOG & Latency Tracking

You will learn the built-in diagnosis kit for a slow Redis: the slowlog of expensive commands and the latency monitor's per-event history and advice. Interviewers ask you to debug 'Redis is slow' and expect fork stalls, swapping, big commands, and expire bursts as suspects.

part ofRedisoverview, primer and where to startread it →
on this pageshow

questions

5

Redis has a SLOWLOG facility. What exactly does it record, how do you configure and read it, and what part of a request's total time does it NOT include?

level: middleimportance: must knowfreq 60%

answer

  1. ring buffer, lost on restart
  2. slowlog-log-slower-than = MICROseconds, default 10000
  3. GET / LEN / RESET; 128 entries default
  4. args truncated: 32 args, 128 bytes
  5. execution only — no network, no queue wait

basics

~20 s

SLOWLOG stores the last N commands whose execution exceeded slowlog-log-slower-than microseconds. Read with SLOWLOG GET/LEN, clear with SLOWLOG RESET. It times only command execution inside the server — not network transfer, not time spent waiting in the queue behind other commands.

solid answer

~50 s

SLOWLOG is an in-memory ring buffer of slow command executions. Two settings drive it: `slowlog-log-slower-than` (microseconds; 10000 = 10ms by default, 0 logs everything, negative disables) and `slowlog-max-len` (entries retained, default 128 — old entries are dropped, not persisted). `SLOWLOG GET [n]` returns entries with an id, timestamp, duration in microseconds, the argument vector (truncated to 32 args / 128 bytes each), and since Redis 4.0 the client address and name. `SLOWLOG LEN` counts them, `SLOWLOG RESET` clears. The critical caveat: the recorded duration covers only execution of the command inside the server. It excludes time reading the request off the socket, writing the reply, and — most importantly — time the command spent queued behind a slow predecessor. So a client can observe 200ms while SLOWLOG shows a single 190ms `KEYS *` and nothing else: the victims are invisible. SLOWLOG finds the culprit, not the casualties.

code

text · 16 lines
text
# threshold in MICROseconds: log anything over 1ms
CONFIG SET slowlog-log-slower-than 1000
CONFIG SET slowlog-max-len 1024

SLOWLOG RESET          # start clean
# ... let traffic run ...
SLOWLOG LEN
SLOWLOG GET 5

1) 1) (integer) 14        # entry id
   2) (integer) 1723641900 # unix time
   3) (integer) 193450     # duration in microseconds (193ms)
   4) 1) "KEYS"
      2) "session:*"
   5) "10.0.3.7:51244"     # client addr (Redis 4.0+)
   6) "web-api-3"          # client name

go deeper

for a junior

Know the three subcommands (GET/LEN/RESET), that the threshold is in microseconds, and that it shows commands that took too long to execute.

for a middle

Add the two config directives and their defaults, argument truncation, and the crucial point that the duration excludes network and queueing time.

for a senior

Frame it as culprit-finding: connect a single slow entry to a fleet-wide p99 spike, tune the threshold to the SLO, export entries by id into monitoring, and pair with INFO commandstats.

for a principal

Discuss it as one signal among several — SLOWLOG for blocking commands, the latency monitor for process-level stalls, client-side percentiles for truth — and the policy of banning O(N) commands rather than observing them.

## What SLOWLOG is Redis executes commands one at a time on a single command-processing thread. Any command that takes a long time to execute delays every other client. SLOWLOG is the built-in record of which commands were slow, so you can find that command without attaching a profiler or running `MONITOR` (which itself costs throughput). It is a **fixed-size in-memory ring buffer**. Entries are lost on restart, are not replicated, and are not written to any file. It is a diagnostic aid, not an audit log. ## Configuration Two directives, settable in `redis.conf` or at runtime with `CONFIG SET`: - `slowlog-log-slower-than <microseconds>` — the threshold. Default `10000`, i.e. 10 milliseconds. Note the unit is **microseconds**, a classic mistake: setting `10` means 10µs and will log nearly everything. Setting `0` logs every command (useful for a few seconds of sampling on a test node, dangerous under load). A **negative** value disables logging entirely. - `slowlog-max-len <count>` — how many entries the ring keeps. Default `128`. Entries are cheap (they hold a truncated copy of the argument vector), so raising this to a few thousand is normal on a busy instance; memory cost is bounded because arguments are truncated. ## Reading it - `SLOWLOG GET [count]` — newest first. Each entry is: unique incrementing **id**; **unix timestamp** of when the command completed; **duration in microseconds**; the **argument array**; and (Redis 4.0+) the **client IP:port** and **client name** set via `CLIENT SETNAME`. Redis 7 accepts `SLOWLOG GET -1` for all entries. - `SLOWLOG LEN` — current number of entries. - `SLOWLOG RESET` — empties the buffer. Reset before a test so you know everything you see is from the window you care about. Arguments are truncated: at most 32 arguments are kept, each at most 128 bytes, with a trailing marker like `... (2 more arguments)`. That is deliberate — logging a 1MB `SET` payload into the ring would be a memory leak by another name. It also means SLOWLOG shows you the *shape* of the offending command, not necessarily the exact key. ## What the duration does and does not cover The timer starts when the command begins executing and stops when it finishes, **inside the server**. Excluded: 1. **Network time** — transfer from the client and back. 2. **Queueing/waiting time** — if command B arrives while a 200ms command A is executing, B waits ~200ms before its own timer even starts. B's own execution may be 20µs, so B never appears in SLOWLOG at all, even though *its client* saw 200ms. 3. **Reply-write time for huge responses** — building the reply is counted, but flushing megabytes to a slow client happens later in the event loop. 4. **Fork stalls, swap-in, and other whole-process pauses** are not attributed to a command; they show up as everything being slow with an empty SLOWLOG. This is why SLOWLOG is a *culprit finder*, not a latency measurement. The correct mental model: a client-side p99 spike plus a single SLOWLOG entry of comparable size usually means that one entry caused the whole spike for many clients. ## What typically lands in it - `KEYS`, `SMEMBERS`, `HGETALL`, `LRANGE 0 -1` on large collections — O(N) commands over big values. - `SORT`, `ZRANGEBYSCORE` with huge ranges, `SUNION`/`ZUNIONSTORE` over large sets. - Big `DEL`/`FLUSHALL` of large aggregates (freeing memory is O(N); `UNLINK` and lazy-free move this off the main thread). - Long-running Lua scripts / Functions, which execute atomically and block everything. - Sometimes `DEBUG SLEEP`, `SAVE`, or a `MIGRATE` during resharding. ## How to use it in practice Set the threshold to something meaningful for your SLO — if your budget for a cache hit is 1ms, a 10ms threshold is far too coarse; 1000 (1ms) or even 500 is more useful. Scrape `SLOWLOG GET` on an interval into your metrics/log pipeline keyed by entry id so you do not double-count, and alert on the *rate* of new entries rather than on any single one. Pair it with `INFO commandstats` (per-command call count, total and average microseconds, and in Redis 7 latency percentiles) to distinguish "one pathological call" from "a command that is mildly slow a million times a second".

  • A client reports 200ms p99 against Redis, but SLOWLOG shows only one 190ms entry per minute. Explain that.
    The single 190ms command blocks the command-processing thread, so every other command that arrives during that window waits behind it. Those victims execute in microseconds, so they never cross the SLOWLOG threshold themselves — only the client's own stopwatch sees the queueing delay. One slow command per minute is enough to poison p99 for all clients in that same second. Fix the culprit (replace the O(N) command), don't raise the threshold.
  • How would you keep SLOWLOG useful over time instead of reading it ad hoc?
    Poll `SLOWLOG GET` from a monitoring agent on a short interval, track the last-seen entry id so entries are exported exactly once, and emit them as structured events with duration, command name, and client name. Alert on the rate of new entries above a threshold, not on individual entries. Raise `slowlog-max-len` so a burst does not overflow the ring between polls, and set `slowlog-log-slower-than` near your latency budget rather than leaving the 10ms default.
  • Why are the logged arguments truncated?
    Each entry keeps at most 32 arguments of at most 128 bytes each, with a marker for the rest. Without truncation a single `SET key <1MB value>` would copy a megabyte into the ring buffer, and 128 such entries would silently consume real memory in a database whose whole point is memory. The truncation preserves the command shape and key prefix, which is what you need to identify the offender.

SLOWLOG is the tachograph of the one lane in a one-lane tunnel: it records the truck that crawled through, not the hundred cars that were stuck behind it.

saying these in an interview costs you the question

  • Reading slowlog-log-slower-than as milliseconds and setting it to 10, which effectively logs every command
  • Believing the recorded duration is what the client experienced end-to-end
  • Assuming SLOWLOG is durable or replicated — it is an in-memory ring lost on restart
  • Concluding 'SLOWLOG is empty, so Redis is fine' when fork stalls or swap cause whole-process pauses
  • Leaving the threshold at the 10ms default while the service SLO for a cache read is 1ms

context

open as a page

A Redis instance serves sub-millisecond responses most of the time but shows recurring multi-hundred-millisecond spikes. Walk through the causes you would investigate and the evidence that distinguishes them.

level: seniorimportance: must knowfreq 50%

basics

~20 s

Check four families: a blocking O(N) command or long Lua script (SLOWLOG); a fork for RDB/AOF rewrite (LATENCY fork, latest_fork_usec); memory pressure — swapping or eviction cycles at maxmemory; and bulk key expiry (LATENCY expire-cycle). Confirm the host floor with redis-cli --intrinsic-latency.

open as a page

Before blaming Redis for a slow endpoint, how would you measure an individual Redis server's own response latency and its floor on that machine, using tools shipped with Redis?

level: juniorimportance: should knowfreq 40%

basics

~20 s

Run redis-cli --latency (or --latency-history) from a client host: it sends PING in a loop and reports min/avg/max round-trip in milliseconds. Run redis-cli --intrinsic-latency <seconds> on the server itself to measure the machine's own scheduling floor with no network involved.

open as a page

Redis includes a built-in latency monitoring framework exposed through the LATENCY family of commands. How does it work, how do you turn it on, and what does it show you that a log of slow commands cannot?

level: seniorimportance: should knowfreq 32%

basics

~20 s

Set latency-monitor-threshold to a millisecond value; Redis then records time-series samples for named event types (fork, expire-cycle, command, aof-fsync-always, eviction-cycle...). LATENCY LATEST shows the newest and worst per event, LATENCY HISTORY <event> the samples, LATENCY RESET clears, LATENCY DOCTOR explains them in prose.

open as a page

You own a fleet of Redis instances shared by a dozen services and need a latency observability strategy rather than ad-hoc debugging. What signals would you collect, what would you alert on, and where would you accept blind spots?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Treat client-side percentiles as the SLO signal and server-side facts as explanations: scrape SLOWLOG entries by id, LATENCY LATEST per event, INFO commandstats/latencystats, fork and eviction counters. Alert on client p99 and on rates of slow entries or stall events — not on single samples. Accept that queueing victims and per-tenant attribution stay blind spots.

open as a page