Почему sqlite может заменить сложную инфраструктуру
Помню, как в одном проекте мы подняли Redis для очереди задач, потом добавили RabbitMQ для надёжности, а сверху прикрутили отдельный сервис для отслеживания состояния. Четыре сервиса, чтобы гарантировать, что задача не потеряется. Четыре точки отказа. Четыре конфигурации, которые нужно мониторить.
А потом я наткнулся на аргумент: для большого класса задач всё это не нужно. Достаточно SQLite.
Надёжность без лишних сущностей
Автор статьи, блог Obelisk, разбирает идею, которая на первый взгляд звучит странно. Durable execution — надёжное выполнение процессов — обычно ассоциируется с отдельной инфраструктурой. Kafka для сообщений, Postgres для состояния, Redis для кэша. Каждый сервис отвечает за свой кусочек.
Но автор предлагает другой угол зрения. Надёжность — это сохранение состояния процесса. Всё остальное — вычисления — может быть дешёвым и одноразовым. Упал воркер? Запустился новый, прочитал состояние из базы, продолжил работу.
И вот для этого состояния SQLite подходит идеально.
Почему именно sqlite
Всё упирается в простоту. SQLite — это файл базы данных, который живёт рядом с приложением. Нет сетевого запроса к внешнему серверу, нет отдельного сервиса, который может упасть, нет лишнего слоя абстракции.
Для многих проектов это именно тот уровень сложности, который нужен. Локальный файл, транзакции ACID, и никаких проблем с сетью.
Конечно, есть проблема: что если сервер умрёт вместе с файлом? Здесь на помощь приходит Litestream. Это инструмент, который асинхронно копирует изменения SQLite в S3-совместимое хранилище. Облако, бэкап, восстановление — всё на месте, а работаете вы всё ещё с локальным файлом.
Правда, автор честно предупреждает: Litestream копирует асинхронно. Если диск умрёт до следующей синхронизации, последние данные потеряются. Для большинства AI-экспериментов и прототипов это приемлемо. Для финансовых транзакций — уже нет.
РЕЖИМ РАБОТЫ С SQLite + LITESTREAM
───────────────────────────────────
┌─────────────┐ файлы ┌─────────────┐
│ Приложение │ ──── WAL ──── │ SQLite │
│ (воркер) │ │ (локально) │
└─────────────┘ └──────┬───────┘
│ поток
▼
┌─────────────┐
│ S3 storage │
│ (бэкап) │
└─────────────┘
Где это работает, а где нет
Меня особенно зацепил аргумент про AI-агентов. Эти системы часто живут отдельными экспериментами: один агент — один файл базы данных. Запустил, погонял, посмотрел что получилось, удалил.
Классическая модель с общим Postgres тут выглядит избыточно. Вместо одного большого сервера, который должен быть всегда онлайн, можно развернуть кучу маленьких инстансов, каждый со своей SQLite. Упал один — остальные работают. Дешевле, проще, изоляция лучше.
Но есть случаи, когда SQLite — не ответ. Если нужен общий доступ из нескольких серверов, если требуется высокая доступность, если потеря данных даже за последние секунды недопустима — тогда Postgres остаётся правильным выбором.
Автор это признаёт открыто и даже указывает, что Obelisk поддерживает оба варианта. SQLite как разумный дефолт, Postgres для случаев, когда он действительно нужен.
Практическая схема
Если отбросить философию и свести к конкретике, то схема выглядит так:
- Приложение пишет в локальную SQLite в режиме WAL.
- Транзакции обеспечивают атомарность: либо записалось всё, либо ничего.
- Уникальные ключи гарантируют идемпотентность: повторный запуск не создаст дубликатов.
- Litestream фоном копирует изменения в S3.
- При падении новый воркер поднимает базу, читает состояние, продолжает работу.
Звучит просто — и это, кажется, главное. Меньше магии, меньше скрытых состояний, меньше «а почему оно упало именно сейчас».
ЖИЗНЕННЫЙ ЦИКЛ ЗАДАЧИ
─────────────────────
Задача поступила Задача в работе
│ │
▼ ▼
┌─────────┐ ┌──────────┐
│ INSERT │ ────▶ │ UPDATE │
│ (новое) │ │ (прогресс)│
└─────────┘ └────┬─────┘
│
┌────────────┴────────────┐
▼ ▼
Завершено успешно Ошибка / ретрай
│ │
▼ ▼
UPDATE (done) UPDATE (retry count)
──────────────────────────────────────────
Если retry < max → вернуться в работу
Если retry >= max → ошибка
Стоит ли оно того
У меня эта идея вызвала двойственное чувство. С одной стороны, простота привлекает. Четыре сервиса для очереди — это вчерашний день, если можно обойтись одним файлом.
С другой — я видел проекты, где «простое решение» через год превращалось в «а давайте добавим ещё одно хранилище». SQLite отлично работает для одного сервера, но масштабировать его горизонтально — боль.
Думаю, автор прав в главном: многие проекты начинают с Postgres там, где хватило бы SQLite. Инфраструктура растёт раньше, чем требования к ней. И если вы делаете прототип AI-агента, очередь фоновых задач или систему обработки событий — попробуйте начать с файла. Сложность инфраструктуры — это тоже технический долг, просто менее очевидный.
Выводы
- Для durable workflows часто важнее сохранить состояние, чем строить сложную инфраструктуру.
- SQLite закрывает многие задачи дешевле и проще, чем связка из нескольких сервисов.
- Litestream помогает добавить бэкап и восстановление, но не заменяет синхронную репликацию.
- Если нужен multi-writer, высокая доступность или нулевая потеря данных, Postgres остаётся предпочтительнее.
Ссылки
- SQLite is All You Need for Durable Workflows — оригинальная статья
- Litestream — инструмент для репликации SQLite в S3
- Obelisk — фреймворк для durable workflows, упоминаемый в статье
Дмитрий Полухин — продуктовый дизайнер. Пишу про разработку, AI и дизайн интерфейсов. Обо мне, контакты и профили.