12 мая 2026 · заметки · 2 мин

SQLite в проде, год спустя

Год назад я выкинул Postgres из своего пет-проекта и поставил один файл .db рядом с бинарником. С тех пор база пережила два переезда, четыре релиза и одно бухое воскресенье. Делюсь что выяснилось.

Что я ожидал получить

Ноль операционной нагрузки. Никаких RDS, никаких pg_hba.conf, никаких странных таймаутов в три ночи. Бэкап — это cp. Миграция — это scp. Восстановление — это уже выученный наизусть пароль от ssh.

Что получил на самом деле

Всё то же самое, плюс одна неожиданная штука: я наконец начал думать о схеме данных до, а не после. Когда база — это файл, который ты можешь скачать и открыть в DB Browser за две секунды, ленивые миграции «потом починим» внезапно становятся непростительно ленивыми. Файл лежит перед тобой целиком, врать ему некуда.

Где всё-таки прижало

Записей было немного, но они шли пачками. По дефолту SQLite отдаёт SQLITE_BUSY, как только два писателя сталкиваются лбами. Лечится одной строчкой:

PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;

WAL разводит читателей и писателя по разным углам, а busy_timeout говорит драйверу не паниковать, а подождать. После этого «конкурентность» в моём масштабе (десятки запросов в секунду, не тысячи) перестала быть темой для разговора вообще.

Второе, что укусило, — это типизация. SQLite хранит что положишь, а не что объявил. Строка в колонке INTEGER? Пожалуйста. Спасает либо строгий режим (STRICT таблицы), либо дисциплина на уровне приложения. Я выбрал STRICT и ни разу не пожалел.

Бэкап, который не врёт

cp живого файла под нагрузкой — это лотерея. Правильный способ ровно один:

sqlite3 app.db ".backup '/backups/app-$(date +%F).db'"

Эта команда снимает консистентный снапшот, не блокируя писателей надолго. Кладёшь в cron, рядом — restic в S3-совместимое хранилище, и спишь спокойно. Весь «бэкап-пайплайн» — пять строк в скрипте.

Итого

SQLite — это не «база для бедных». Это осознанный выбор в пользу простоты, когда ты честно понимаешь свой профиль нагрузки. Один файл, ноль демонов, бэкап копированием. Postgres вернётся в мою жизнь в тот день, когда мне реально понадобится то, что умеет только он. Пока — не понадобился.