
Кэш и база данных: отличия и граница ответственности

Отличия кэша и базы данных кажутся очевидными только до первой серьёзной нагрузки. В любом растущем backend-проекте рано или поздно появляется Redis: сначала как кэш для снятия нагрузки с PostgreSQL, затем как хранилище сессий, потом как механизм ограничения запросов, временных очередей, флагов функциональности и счётчиков. Через год команда обнаруживает, что отказ Redis ломает не ускоритель, а основную функциональность продукта.
Это не ошибка одного инженера и не свойство одного инструмента. Граница между кэшем и базой данных размыта концептуально: одно и то же хранилище в памяти может быть вторичным слоем, а может стать фактическим источником истины. Разберём, где проходит эта граница, почему современные системы её стирают и как принимать архитектурные решения осознанно: когда достаточно кэша, когда нужна база данных, а когда выгоднее выбрать систему, которая работает на скорости кэша, но сохраняет гарантии БД.
Что такое кэш
Кэш — временное хранилище результатов дорогих вычислений или запросов. Его задача не владеть данными, а ускорять доступ к тому, что уже есть в другом месте: в базе данных, объектном хранилище, поисковом индексе, внешнем API или в результате вычисления.
У классического кэша три свойства. Данные в нём:
- Производные. Если кэш исчез, данные можно восстановить из источника истины. Например, результат SQL-запроса «топ-10 товаров за сегодня» можно пересчитать из заказов. Медленнее, но корректно.
- Непостоянные. Инвалидация — нормальная часть жизни кэша, а не авария. Записи протухают по TTL, удаляются при обновлении сущности, заменяются из-за политики вытеснения.
- Вторичные. Потеря кэша должна приводить к деградации производительности, но не к потере бизнес-состояния. Если кэш результатов запросов сбросился после рестарта, пользователи увидят более медленные ответы, но не потеряют оплаченный заказ, корзину или историю операций.
Простой пример — кэширование запросов к базе для страницы каталога. Приложение выполняет сложный запрос к PostgreSQL, кладёт результат в Redis на пять минут и отдаёт его из памяти. Если Redis пуст, приложение идёт в БД. Если Redis недоступен, можно временно обойтись без него: дороже, медленнее, но семантически корректно.
Чем кэш отличается от базы данных
База данных в рассматриваемом архитектурном подходе — это источник истины. В ней хранятся данные, которые нельзя просто пересчитать из более авторитетного места. У базы данных тоже есть три свойства. Данные в ней:
- Первичны. Если запись о платеже есть только в этом хранилище — это не кэш, даже если хранилище работает в RAM, имеет TTL и называется cache в переменной окружения.
- Постоянны. Потеря данных в БД — не штатный сценарий, а инцидент. Поэтому БД проектируют вокруг журналов предзаписи, снимков состояния, репликации, восстановления, резервных копий, RPO/RTO и процедур переключения при отказе.
- Консистентны в рамках выбранной модели. Это может быть строгий ACID-подход, eventual consistency, BASE или доменная модель с компенсирующими транзакциями, но гарантии должны быть явно определены. Важно не то, что БД всегда строго консистентна, а то, что система документирует, какие состояния возможны и как она восстанавливается после сбоя.
Именно здесь различие между кэшем и базой данных становится не вопросом технологии, а вопросом ответственности. Redis, PostgreSQL, Tarantool, Cassandra или любой другой инструмент можно использовать удачно или опасно. Критерий один: что произойдёт, если этот слой внезапно исчезнет.
Если команда относится к хранилищу как к кэшу, но по факту держит в нём первичные данные, она создаёт скрытую точку отказа. Пока всё работает, архитектура выглядит быстрой и простой. Но при аварии оказывается, что временные сессии содержали незавершённые платёжные сценарии, кэш ограничения запросов защищал платный API от злоупотреблений, а очередь в Redis была единственной копией задач.
Обратная ошибка тоже встречается. Иногда систему усложняют полноценной БД там, где нужен обычный кэш в памяти: добавляют транзакции, миграции, схемы, резервные копии и ручное переключение при отказе ради данных, которые легко восстановить. В итоге платят за ненужные гарантии задержкой, операционной сложностью и стоимостью поддержки.
Практическое правило простое: сначала определите семантику данных, потом выбирайте инструмент. Вопрос не в том, Redis или PostgreSQL, а в том, производные эти данные или первичные. И не в том, что кэш быстрый, а БД медленная, а в том, какие гарантии нужны конкретному состоянию.
Паттерны кэширования
Разберём четыре характерных паттернов связки приложения, кэша и базы данных.
Cache-aside (Lazy Loading)
Cache-aside — самый распространённый способ связать приложение, кэш и базу данных. Приложение само управляет жизненным циклом записи: сначала проверяет кэш, при промахе идёт в БД, кладёт результат в кэш и возвращает данные клиенту.
Сильная сторона cache-aside — экономия. В кэш попадают только реально запрошенные данные, поэтому не нужно заранее прогревать весь каталог или весь профиль пользователя. Это особенно удобно для сценариев с преобладанием чтения: каталоги, карточки товаров, справочники, настройки, публичные профили, агрегированные витрины.
Но у паттерна есть цена. При холодном старте или массовой инвалидации возникает одновременный шквал запросов к одному ключу: тысячи запросов промахиваются и идут в БД именно тогда, когда кэш должен был её защищать. Поэтому рядом с cache-aside обычно появляются схлопывание запросов, мьютекс на прогрев, вероятностное обновление до протухания, stale-while-revalidate и ограничение параллельных обращений к источнику.
Вторая проблема — устаревшие данные. Если приложение обновило запись в БД, но не удалило и не обновило соответствующий ключ, кэш продолжит отдавать старое состояние. Для новостной ленты это может быть терпимо, для баланса счёта — нет.
Write-through
Write-through работает иначе: каждая запись проходит через кэш и синхронно попадает в основную БД. После успешной операции кэш и источник истины содержат актуальное значение. Чтение при этом остаётся быстрым, потому что горячие данные уже лежат в памяти.
Плюс write-through — предсказуемая актуальность. Приложению не нужно отдельно думать, удалять ли ключ после записи: запись сама обновляет оба слоя. Это удобно для справочников, конфигураций, сессий с повышенными требованиями к доступности и данных, где устаревшее чтение заметно пользователю.
Минусы тоже прямые. Любая запись становится дороже, потому что нужно дождаться двух операций. Кроме того, кэш может заполняться данными, которые никто не читает: запись была, а последующего чтения не случилось. В системах с преобладанием записи это превращает кэш из оптимизации в дополнительную нагрузку.
Write-behind (Write-back)
Write-behind переносит запись сначала в кэш, а в БД — асинхронно. Для пользователя операция завершается быстро: приложение подтверждает запись, как только она зафиксирована во временном слое, а фоновый процесс позже выгружает изменения в долговременное хранилище.
Write-behind действительно снижает задержку записи: приложение может подтвердить операцию сразу после приёма данных промежуточным слоем, а постоянное хранилище обновляется асинхронно. Такой подход удобен для счётчиков, телеметрии, кликов, просмотров и черновой аналитики.
Но применять его к критичным данным можно только при одном условии: промежуточный слой не должен быть обычным недолговременным кэшем. Он должен обеспечивать необходимые гарантии сохранности данных — durable-запись, репликацию, восстановление после сбоев, контроль доставки и возможность безопасно повторить операцию без искажения результата.
Если такие гарантии есть, этот слой становится частью основного контура хранения: запись можно подтвердить после её надёжного приёма, а синхронизацию с основной БД выполнить позже. Если же данные сначала попадают только в память или во временный кэш, подтверждать критичную операцию нельзя: сбой до сброса в БД приведёт к потере изменений.
Поэтому для заказов, платежей, прав доступа и других бизнес-критичных данных нужен не просто «кэш перед БД», а надёжный промежуточный слой с журналом, репликацией и механизмами восстановления. В этой роли TDB может стать частью контура, который принимает записи быстро, но при этом сохраняет требуемые гарантии надёжности.
Read-through
Read-through инкапсулирует логику кэширования внутри самого слоя доступа. Приложение обращается к кэшу как к единственному интерфейсу, а кэш при промахе сам идёт в БД, получает данные, сохраняет их и возвращает ответ. Для прикладного кода источник данных выглядит единым.
Этот подход снижает дублирование логики в сервисах: не нужно в каждом микросервисе писать одинаковые ветки «проверить Redis — сходить в PostgreSQL — положить обратно». Но растёт ответственность промежуточного слоя: он должен знать, как получать данные, как инвалидировать ключи, как обрабатывать ошибки БД и как не превратиться в непрозрачную точку отказа.
Tarantool DataBase может выступать таким прозрачным слоем в архитектурах, где горячие данные живут в памяти, а логика доступа размещается рядом с данными. Но как только этот слой начинает принимать решения и хранить состояние, к нему нужно относиться не как к простому кэшу, а как к компоненту хранения.
Инвалидация кэша: главная проблема кэширования
«В программировании есть только две сложные задачи: инвалидация кэша и именование вещей» — цитата, которую обычно приписывают Филу Карлтону.
Инвалидация кэша сложна не потому, что удалить ключ трудно. Трудно гарантировать, что во всех гонках, сетевых задержках и частичных отказах пользователь не увидит недопустимо устаревшие данные.
TTL — наиболее простой вариант: запись живёт заданное время, затем протухает. Дёшево и понятно, но если значение обновилось через секунду после записи в кэш, старое состояние проживёт до конца TTL. Для каталога товаров это терпимо, для статуса платежа уже нет.
Событийный подход точнее: CDC-процесс читает журнал БД и публикует событие об изменении, по которому ключ удаляется или обновляется. Важно отдельно продумать репликацию и резервное копирование — если поток событий потерян или отстал, кэш перестаёт соответствовать источнику истины.
Версионный ключ работает иначе: при изменении сущности меняется версия ключа, старое значение становится недостижимым и со временем вытесняется. Гонок между чтением и записью меньше, но схема ключей усложняется, и контроль памяти становится менее очевидным.
Чем чаще данные обновляются и чем дороже устаревшее чтение, тем меньше пользы от отдельного кэша и тем привлекательнее быстрая БД напрямую.
Redis: кэш, который стал базой данных
Redis начинался и массово используется как хранилище пар ключ-значение в памяти для быстрых операций, но давно применяется далеко за пределами кэширования результатов запросов.
В Redis кладут сессии, счётчики ограничений, очереди задач, таблицы лидеров, геосервисы, временные блокировки, флаги функциональности. Часть этих сценариев остаётся кэш-сценариями: таблицу лидеров можно пересчитать, временный флаг — восстановить из конфигурации. Но очередь задач, где запись была единственным описанием работы, или счётчик ограничений, потеря которого открывает обход лимитов, — это уже не кэш. Если данные в Redis нельзя потерять без нарушения пользовательского опыта, денег или бизнес-процесса, Redis в этой архитектуре выполняет роль базы данных, нравится это команде или нет.
Ограничения персистентности Redis
Redis поддерживает RDB-снимки и AOF. В официальной документации Redis для AOF описаны разные политики fsync: без fsync, каждую секунду и при каждой записи. Для политики fsync every second документация прямо указывает риск потери примерно секунды записей при аварии. Redis Software также описывает AOF every 1 sec как режим с допустимой минимальной потерей данных и отдельно выделяет fsync every write как более надёжный, но более дорогой по производительности вариант.
RDB-снимки имеют другую природу: это снимки состояния с интервалом. Если авария случилась после последнего checkpoint, изменения между checkpoint и падением могут быть потеряны. Для настоящего кэша это приемлемо: кэш всё равно можно восстановить. Для сессий, очередей и лимитов нужно честно оценивать RPO.
Redis Cluster повышает доступность и масштабирование, но сам по себе не превращает любой сценарий в строго долговечную БД. При переключении при отказе нужно учитывать асинхронность репликации, настройки персистентности, подтверждения записи и бизнес-стоимость потери последних операций.
Нельзя сказать, что Redis плох, но при использовании его как базы данных нужно проектировать его как базу данных: выбирать политику персистентности, репликацию, мониторинг, восстановление и тестировать аварии. А если это становится центральной частью архитектуры, стоит рассмотреть систему, изначально спроектированную как БД.
Redis остаётся сильным инструментом для настоящих кэш-сценариев: результатов запросов, HTML-фрагментов, агрегатов, короткоживущих ключей, счётчиков ограничений с допустимой потерей части состояния, сценариев публикации-подписки, где пропуск сообщения не разрушает бизнес-процесс, временных блокировок и структур данных с ограниченным сроком жизни.
Граница проходит там, где данные перестают быть восстановимыми. Если другой авторитетной копии нет, Redis в этой архитектуре становится основным хранилищем. В таком случае его настройки персистентности, репликации и восстановления необходимо рассматривать с точки требовний бизнеса. Для каких то сценариев гарантий Redis будет достаточно, для каких-то нет.
Tarantool DataBase может закрывать горячий контур на скорости хранилища в памяти и при этом использовать механизмы БД — WAL, снимки состояния и репликацию. Конкретные гарантии зависят от настроек долговечности и репликации.
Системы, объединяющие БД и кэш
Современный подход не всегда требует держать отдельный кэш и отдельную БД. Иногда лучше использовать систему, которая работает на скорости кэша, но даёт гарантии базы данных. Данные доступны из памяти, но запись не считается просто временной.
У такой системы четыре требования: данные в RAM для горячего контура и низкой задержки; WAL на диске, чтобы подтверждённая транзакция переживала сбой процесса; репликация для доступности и сценариев переключения при отказе; транзакции и индексы, чтобы прикладная логика не рассыпалась на набор небезопасных операций с ключами.
Граница здесь стирается технически, но не семантически. Система может вести себя как хранилище в памяти по скорости, но оставаться базой данных по ответственности за состояние.
Tarantool DataBase работает именно в этой зоне. Движок memtx хранит данные в памяти; в документации Tarantool memtx описан как engine по умолчанию, а vinyl — как дисковый engine для объёмов, которые больше доступной RAM. Так горячие и более холодные данные можно разделять внутри одной платформы.
При этом Tarantool DataBase не ограничивается моделью «быстрая память без гарантий». Изменения фиксируются через WAL, используются снимки состояния, доступны транзакции, SQL и NoSQL API, вторичные индексы и серверная логика на Lua. Репликация по умолчанию асинхронная; синхронная нужна для сценариев, где транзакция не должна считаться подтверждённой до репликации на заданное число узлов.
Роль кэша — не единственая роль Tarantool. Его можно применять как слой кэширования, как первичную БД в памяти или как компонент, который объединяет обе роли.
Сценарий: когда часть связки Redis + PostgreSQL можно консолидировать в Tarantool DataBase
Типичная схема до изменений:
Приложение → Redis → PostgreSQL ↘ инвалидация ↗
PostgreSQL хранит источник истины. Redis ускоряет чтение сессий, профилей, справочников и агрегатов. Между ними находятся инвалидация кэша, двойная запись, разные механизмы мониторинга и два сценария переключения при отказе. При сбое Redis приложение деградирует или ломается, при сбое PostgreSQL — теряет основной источник данных.
Схема после консолидации:
Приложение → Tarantool ├─ memtx для горячих данных ├─ vinyl для данных больше RAM ├─ WAL/snapshot для сохранности └─ sync/async replication для доступности
Кэш как отдельный слой может оказаться не нужен: чтение горячих данных уже идёт из RAM. Источник истины становится единым, сценарий переключения при отказе — один, а логика рядом с данными сокращает число сетевых переходов. Это не универсальная замена PostgreSQL для всех задач: тяжёлая аналитика, сложные ad hoc SQL-запросы и большие исторические витрины могут оставаться в PostgreSQL, ClickHouse или OLAP-системе. Но для высоконагруженного OLTP-контура, сессий, профилей, лимитов, очередей и состояния реального времени консолидация часто снижает сложность.
Сравнение: кэш, база данных и Tarantool DataBase
| Свойство | Классический кэш (Redis) | Классическая БД (PostgreSQL) | Tarantool DataBase |
| Скорость чтения | Микросекунды/субмиллисекунды | Обычно секунды: диск, буферный пул, план запроса | Микросекунды |
| Персистентность | Зависит от AOF/RDB и политики fsync | WAL, резервные копии, ACID | WAL + снимки состояния, настройки долговечности |
| Потеря данных при аварии | Возможна при AOF everysec или после RDB checkpoint | Возможна при SSL, RLS, WAL, pgAudit | Запись через WAL до подтверждения в режиме с гарантиями |
| Транзакции | MULTI/EXEC не равен полноценной ACID-модели БД | Полный ACID | Транзакции, SQL и NoSQL API в рамках одного шарда |
| Репликация | Есть, но важно учитывать асинхронность и переключение при отказе | Sync/async в зависимости от конфигурации | Асинхронная и синхронная репликация; выборы лидера на основе Raft в актуальных версиях |
| SQL | Нет как основной модели | Полный SQL | SQL с ограничениями + NoSQL API |
| Логика рядом с данными | Ограничена командами/скриптами | PL/pgSQL и расширения | Lua-процедуры внутри сервера с ограничениями |
| Типичная роль | Кэш, временные структуры, сессии при осознанном RPO | Источник истины | Кэш + БД одновременно для горячего контура, источник истины, временные структуры и сессии |
Архитектурное решение зависит от ответственности данных. Redis хорош там, где потеря допустима или состояние восстановимо. PostgreSQL силён как универсальная системная БД. Tarantool DataBase закрывает нишу, где нужны задержка уровня хранилища в памяти и гарантии хранения в одном контуре.
Как принимать архитектурное решение: кэш, БД или оба
Перед выбором инструмента стоит ответить на три вопроса.
1. Что произойдёт при потере этих данных? Если ничего страшного — данные восстановятся из БД за приемлемое время — классический кэш подходит. Если будет деградация пользовательского опыта, нужна персистентность и продуманный RPO. Если возможна потеря денег, пользовательских данных или нарушение бизнес-процесса, нужен компонент с гарантиями базы данных.
2. Где источник истины? Если данные производны от другого хранилища, это кэш. Если другой копии нет — это база данных, независимо от названия технологии. Сессия, очередь или счётчик ограничений могут быть кэшем только тогда, когда потеря их состояния допустима по бизнес-логике.
3. Какова частота обновления относительно чтения? Данные с преобладанием чтения и редкими изменениями хорошо выигрывают от кэша. Часто обновляемые сущности могут страдать от накладных расходов: двойной записи, инвалидации, гонок и рассинхронизации. Иногда быстрее и безопаснее читать напрямую из хранилища в памяти с гарантиями БД, чем поддерживать отдельный кэш.
Чек-лист: когда вынести данные из Redis в Tarantool DataBase
Стоит рассмотреть Tarantool, если выполняется хотя бы несколько пунктов:
- Redis хранит данные, потеря которых ломает бизнес-логику.
- Инвалидация кэша стала отдельным сложным сервисом.
- PostgreSQL страдает от нагрузки, а Redis — от отсутствия нужной транзакционной модели.
- Нужны диапазонные запросы, вторичные индексы или сложная логика по данным в памяти.
- Приходится поддерживать двойную запись и разбирать рассинхронизацию между Redis и БД.
- Команда хочет убрать один уровень из стека и уменьшить число движущихся частей.
- Нужны задержка горячего контура и гарантии хранения в одном компоненте.
Если же данные полностью производные, TTL приемлем, устаревшее чтение неопасно, а потеря Redis означает только временный рост нагрузки на БД, оставляйте классический кэш. Простая архитектура лучше сложной, если она честно соответствует семантике данных.

FAQ
В чём главное отличие кэша от базы данных?
Кэш хранит производные данные: их можно восстановить из источника истины. База данных хранит первичные данные и сама выступает источником истины. При потере кэша система обычно замедляется, при потере данных в БД без восстановления бизнес теряет состояние.
Redis — это кэш или база данных?
Технически Redis — хранилище структур данных в памяти, которое можно использовать и как кэш, и как базу данных. Риск возникает, когда Redis применяют как источник истины для сессий, очередей или лимитов, но не проектируют персистентность, репликацию и восстановление на уровне требований к БД.
Что такое паттерн cache-aside?
Cache-aside, или lazy loading, — схема, где приложение само управляет кэшем: сначала проверяет ключ, при промахе идёт в БД, кладёт результат в кэш и возвращает ответ. В кэш попадают только запрошенные данные, но нужно отдельно решать проблему шквала запросов при промахе и устаревших данных.
Может ли Tarantool DataBase заменить и Redis, и PostgreSQL?
В ряде сценариев — да: особенно там, где горячие OLTP-данные требуют задержки уровня хранилища в памяти и гарантий сохранности. Tarantool хранит горячие данные в RAM, использует WAL, поддерживает транзакции, индексы, SQL/NoSQL API и репликацию. Но для тяжёлой аналитики, сложных ad hoc SQL-запросов и больших исторических витрин PostgreSQL или OLAP-системы могут оставаться в стеке.
Что такое инвалидация кэша и почему это сложно?
Инвалидация кэша — процесс удаления или обновления устаревших данных в кэше после изменения источника истины. Сложность в синхронизации двух систем при гонках, сетевых задержках, повторных событиях и частичных отказах. Чем критичнее актуальность данных, тем дороже отдельный кэш.

Узнать больше
Почитать по теме

In-memory базы данных для IoT и edge computing

Репликация и резервное копирование баз данных: в чём разница и зачем нужны оба

