One TTL does not fit the whole page

“Hello, Ivan” in the header. That is what broke the full-page cache on one project: either the whole page became uncacheable, or Ivan’s greeting was served to strangers. We managed both, in the same month. Full-page cache behind a reverse proxy is a great first step. It dies on the first personalized element. The way out is to stop thinking of the page as one object. It is regions with different speeds. The header with the user name changes per user. Navigation changes per deploy. The product list changes every few minutes. Prices and stock change every few seconds. Give all of that one TTL and you must pick the minimum, which means almost no cache at all. ...

June 16, 2025 · 2 min · Murat Useinov

TTL is not an invalidation strategy

Support ticket: a user changed his name, the site still shows the old one. The profile sits in Redis with TTL one hour. Fine, we set five minutes. A week later the hit rate drops and MySQL feels it. This seesaw has no good position. TTL is insurance, not invalidation. The obvious upgrade is cache-aside with explicit delete. Read: try the cache, miss, load from the database, write to the cache. Write: update the row, delete the key. Looks correct. It has a race. ...

February 24, 2021 · 2 min · Murat Useinov

What Redis does when memory ends

Users logged out at random. Not all, not always. Only sometimes, only in the afternoon. Afternoon is when traffic peaks. Traffic peaks fill the cache. The cache lived in the same Redis as the sessions, the instance hit maxmemory, and the eviction policy was allkeys-lru. Redis did exactly what we asked: threw away the least recently used keys, and some of them were sessions of people who went for lunch. ...

April 2, 2019 · 2 min · Murat Useinov