Страницу книги в магазине открывают тысячу раз в минуту, и каждый раз сервер спрашивает PostgreSQL одно и то же: название, автора, цену «Мастера и Маргариты». Цена меняется раз в неделю, а база отвечает на один и тот же вопрос тысячу раз. В первом уроке раздела кэш стоял первым в списке задач Redis. Пора разобраться, как он устроен в приложении.
Стикер с номером
Тебе надо часто звонить в поликлинику. Номер ты находишь в толстом справочнике: долго, зато точно. После первого поиска ты пишешь номер на стикер и клеишь на холодильник. Дальше смотришь на стикер, справочник не нужен. Если стикер потерялся, снова лезешь в справочник и пишешь новый. А если поликлиника сменила номер, стикер надо выбросить, иначе будешь звонить в никуда.
Здесь справочник это база данных, а стикер это кэш. Нашёл на стикере значит попадание, не нашёл значит промах. Выбросить устаревший стикер значит инвалидировать кэш.
Как работает cache-aside
Приложение отвечает на запрос «покажи книгу 1» так:
запрос книги 1
│
▼
GET cache:book:1 ──── есть ────▶ отдать из кэша (попадание)
│
нет (промах)
│
▼
SELECT ... FROM books WHERE id = 1
│
▼
SET cache:book:1 ... EX 300
│
▼
отдать ответ
Это cache-aside, по-русски «кэш сбоку». Redis ничего не знает о базе: всю работу делает приложение. Оно смотрит в кэш, при промахе идёт в базу и само кладёт ответ в кэш. Поэтому паттерн ещё называют ленивой загрузкой: в кэш попадает только то, что кто-то запросил.
То же в redis-cli
Пройдём путь руками. Первое чтение ничего не находит:
127.0.0.1:6379> GET cache:book:1
(nil)
Промах. Приложение выполняет запрос к PostgreSQL, как в уроке про SELECT, упаковывает строку в JSON и кладёт в Redis на пять минут:
127.0.0.1:6379> SET cache:book:1 "{\"id\":1,\"title\":\"Master and Margarita\",\"price\":690}" EX 300
OK
127.0.0.1:6379> GET cache:book:1
"{\"id\":1,\"title\":\"Master and Margarita\",\"price\":690}"
127.0.0.1:6379> TTL cache:book:1
(integer) 300
Следующие пять минут все читатели получают книгу из Redis. TTL у тебя покажет чуть меньше 300, если между командами прошло время.
Теперь цену снизили. Приложение обновляет строку в базе и удаляет копию:
127.0.0.1:6379> DEL cache:book:1
(integer) 1
127.0.0.1:6379> GET cache:book:1
(nil)
Следующий читатель промахнётся, возьмёт из базы новую цену и положит свежую копию:
127.0.0.1:6379> SET cache:book:1 "{\"id\":1,\"title\":\"Master and Margarita\",\"price\":650}" EX 300
OK
Карточку мы храним строкой JSON, а не хешем из урока 9: копия всегда читается и пишется целиком, поля по отдельности не меняются.
урок из курса
Урок из курса «Redis с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.