Memcached for pages, Redis for the lock
The stack already had two memory stores. Each one now has one job. HTML lives in Memcached. Queues, sessions, and rebuild locks live in Redis.
CACHE_STORE pointed at Memcached. QUEUE_CONNECTION and SESSION_DRIVER pointed at Redis. Treating them as interchangeable mixed page blobs with reserved jobs under one eviction policy. When Redis hit maxmemory, a news list and a Horizon lock could leave together. That mix is a stampede and a stuck queue on the same afternoon.
Memcached is fast at get/set of HTML and bad at locks. A GET that misses cannot promise that only one caller rebuilds. Redis can. SET key NX EX 5 is a lock with a TTL, and the same instance already runs the queue.
The rebuild path
On a miss the worker tries the Redis lock. If it gets it, it reads MySQL, writes Memcached, deletes the lock. If it does not, it serves the previous HTML from a twin key that lives until the next successful write. Two seconds of stale HTML beats a herd of list queries.
Cache keys carry the resource, the locale, and a version segment. Bumping the version drops a group without a wildcard delete. Public lists live minutes. Anything derived from one write dies on that write.
nginx in front
Anonymous hits also go through a short microcache in nginx. The key is scheme, host, uri, and locale. Requests with auth_token bypass it, so a signed-in user never receives a public fragment.
The split is now the rule for this site. New cached reads get Memcached for the blob and Redis for the lock. Redis is not a second page store. Memcached is not a session store. That is the whole update.
