redis/redis
Pitfalls
Operational gotchas that catch new operators of Redis. Most of these are documented in redis.conf comments, but they are easy to miss.
"I bound to 0.0.0.0 and now nothing works"
Default protected-mode yes plus default no-password configuration causes Redis to refuse external connections with a verbose error. Either set a password, or set protected-mode no (and accept the security implications).
Transparent huge pages cause latency spikes
Linux's transparent huge pages (THP) interact badly with fork() — when the parent writes during BGSAVE, the COW unit is 2 MB instead of 4 KB. The startup syscheck (src/syscheck.c) warns about this. Fix:
echo never > /sys/kernel/mm/transparent_hugepage/enabledvm.overcommit_memory = 0 breaks BGSAVE on big heaps
If the parent uses more than half of physical RAM, fork() fails with ENOMEM because the kernel's "strict overcommit" check assumes the child might dirty every page. The fix is sysctl vm.overcommit_memory=1. The startup check warns.
swapping kills performance more than running out of RAM
A swapped Redis page costs milliseconds (disk I/O) instead of nanoseconds (RAM). Better to OOM-kill cleanly than to swap silently. Set vm.swappiness=0 (or 1) on dedicated Redis hosts.
maxmemory does not include replication buffers by default
maxmemory caps the dataset. Replication output buffers, AOF buffers, Lua state, and client query buffers can push the actual RSS far above the cap. Use client-output-buffer-limit replica ... and maxmemory-clients to tighten.
Replicas don't run their own active expiration
Replicas only delete keys when the master propagates a DEL (which the master sends after expiring the key locally). If the master link is down, expired keys can remain queryable on the replica. This is intentional — see Expiration.
A replica with replica-read-only no will diverge
Writing directly to a replica when replica-read-only is no does not propagate. On the next full sync the divergent writes are wiped. Useful for caches; dangerous if you forgot you set it.
KEYS is O(N)
KEYS * walks the entire keyspace. On a database with millions of keys this blocks the main thread for seconds. Use SCAN for any production keyspace iteration.
FLUSHALL and FLUSHDB are synchronous by default
A naive FLUSHALL on a multi-GB dataset blocks the server. Pass ASYNC (FLUSHALL ASYNC) to push the work to the lazyfree thread.
MIGRATE blocks the source
MIGRATE synchronously transfers a key (or batch of keys) to another instance. Until the transfer completes, the source instance can't process other commands for those keys. Cluster slot migration (redis-cli --cluster reshard) issues many MIGRATEs back-to-back; on a busy cluster this can produce visible latency.
MULTI/EXEC is not a rollback transaction
Errors inside an EXEC do not abort subsequent commands. The transaction is a batch, not a SQL-style transaction. Watch for this when writing application code that assumes "if any command fails, none happen".
Lua scripts cannot be killed mid-write
SCRIPT KILL only works if the script has not yet performed any writes. Once it has, killing would leave the dataset half-modified, so the server refuses. The only escape is SHUTDOWN NOSAVE. Tune lua-time-limit so this is rare.
RDB and AOF can disagree if both are on
If both are enabled and the AOF is corrupt, Redis prefers the AOF on startup (more recent). If the AOF is missing but RDB is present, RDB is loaded. If both are present and consistent, AOF is loaded. Don't manually delete one and expect the other to "take over" silently.
Cluster bus port = data port + 10000 (not configurable separately)
If you port 6379, the cluster bus is 16379. There is no cluster-port directive that lets you pick. Firewall rules need to open both.
bind empty-string semantics changed
Older versions interpreted an empty bind line as "bind to all interfaces". Newer versions interpret it as "no listener". If you upgrade and your config has a stray empty bind, the server stops listening on TCP altogether.
Sentinel rewrites your config file
Sentinel writes its runtime view back to sentinel.conf whenever it learns about a new replica or completes a failover. Hand-editing sentinel.conf while Sentinel is running risks losing your edits. Use SENTINEL CONFIG SET instead.
Modules can crash the server
Redis can't sandbox modules; they run in-process with full access to the address space. A buggy module is a critical reliability risk. Pin module versions, test in a staging environment, and keep enable-module-command no in production.
Forks on huge instances hurt during BGSAVE
On a 256 GB instance, a single page write during BGSAVE causes a 4 KB COW (or 2 MB with THP). Hundreds of thousands of writes per second produce hundreds of MBps of dirty memory. The fork's lifetime is dominated by the child writing the RDB, which is bounded by disk speed. The mitigations:
- Diskless replication, so RDB writes go to the network instead of disk.
- More frequent BGSAVE (smaller dirty windows per fork).
- Smaller per-instance heaps (shard horizontally instead of vertically).
CONFIG SET doesn't persist across restarts
CONFIG SET updates the running server. To persist, also call CONFIG REWRITE (which rewrites the on-disk config file) or edit the config file by hand. Operators commonly forget this and the next restart reverts the change.
CLUSTER FORGET doesn't survive
A node that was forgotten via CLUSTER FORGET is re-discovered through gossip from other nodes. To permanently remove a node you must forget it on every node within cluster-node-timeout ms.
Pub/Sub messages are not replicated
Pub/Sub is fire-and-forget. Replicas don't see the messages. If you rely on Pub/Sub for change notifications, design for the master being the only subscriber.
Pub/Sub disconnects on slow consumers
client-output-buffer-limit pubsub 32mb 8mb 60 is the default. A subscriber whose output buffer exceeds those limits is disconnected. With many subscribers and large messages this triggers more often than expected.
WAIT doesn't make a write durable
WAIT n timeout only verifies that n replicas received the bytes. It doesn't say they fsynced. For durability use WAITAOF local 1 timeout plus appendfsync always or everysec.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.