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

1 сентября 2026 г.
Евгений Левашов2.png
Евгений Левашов
Автор статьи
Group 1321316912.png

Отличия кэша и базы данных кажутся очевидными только до первой серьёзной нагрузки. В любом растущем 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-системы могут оставаться в стеке.

Что такое инвалидация кэша и почему это сложно?

Инвалидация кэша — процесс удаления или обновления устаревших данных в кэше после изменения источника истины. Сложность в синхронизации двух систем при гонках, сетевых задержках, повторных событиях и частичных отказах. Чем критичнее актуальность данных, тем дороже отдельный кэш.

Теги: Tarantool
Ссылка скопирована
Поделиться

Почитать по теме

8.jpg
28 мая

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

6.jpg
7 апреля

Шардирование и зачем оно нужно при росте данных