Memcached client read timeouts: safe connection reuse limits and miss-vs-error policy for timed-out gets
0 reputation · 04 Jan 2024, 00:29 UTC
0 reputation · 04 Jan 2024, 00:29 UTC
I'm designing the timeout policy for a service that fronts memcached (assume a recent 1.6.x server, defaults not assumed). Since the server has no in-flight command cancellation, a client-side read deadline is the only way to bound latency, and my understanding is that once a command is on the wire the server will still process it and may emit a late response.
The constraints I'm working under: the connection pool currently reuses sockets after a timeout, which I suspect risks a late get response being misread as the answer to the next command on that connection. We also run multiget batches over shared connections, so one slow response can stall a whole batch. On the policy side, a timed-out get could either be treated as a cache miss (falling through to the backing database) or surfaced as an error to the caller, and I'm unsure how to weigh the stampede risk of the miss path.
Our server limits are configurable at startup, so I plan to confirm actual values via stats settings rather than assume the documented defaults.
Specific questions:
32775 reputation · 04 Jan 2024, 10:45 UTC
Closing and reconnecting is the only safe option after a read timeout. Because the Memcached protocol does not use sequence IDs or request correlation tokens, there is no reliable way to resynchronize the stream once a deadline is exceeded.
If a client times out while waiting for a response, the server continues to process the command and will eventually emit the response to the socket. If that socket is returned to a pool and reused, the next command issued on that connection will read the previous command's late response. This leads to critical data misalignment, where a client may associate a value with the wrong key or fail to parse the response entirely.
In pipelined multigets, the server processes the batch and returns responses sequentially. A single slow key (due to slab contention or large value serialization) stalls the entire response stream for that batch.
The decision to treat a timeout as a cache miss or a hard error depends on your backend's capacity to handle sudden load spikes.
| Policy | Pros | Cons/Risks |
|---|---|---|
| Treat as Miss | Higher availability; the user gets data from the DB. | Thundering Herd: A cache slowdown can trigger a surge of DB requests, potentially crashing the backend. |
| Treat as Error | Protects the backend; provides a fast-fail signal. | Reduced availability; the user sees an error even if the DB is healthy. |
Recommendation: Treat timeouts as errors unless your backend implements request collapsing (e.g., using a singleflight pattern) or strict rate limiting. If the cache is timing out, it is often a signal of network congestion or server saturation; adding backend pressure usually exacerbates the system-wide failure.
To verify your implementation, you can use the tc (traffic control) utility on a Linux test node to inject artificial latency and ensure that timed-out connections are discarded rather than reused.
# Add 500ms latency to the memcached port to trigger client timeouts
sudo tc qdisc add dev eth0 root netem delay 500ms
After testing, monitor stats settings to ensure that the "close-and-reconnect" strategy is not causing a connection churn that exceeds the server's maxconn limit.
Missing Diagnostic: Does your backend database employ a request-collapsing mechanism for identical keys? If so, the "Treat as Miss" policy becomes significantly safer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.