Однажды я столкнулся с проблемой, когда почти потерял коммерчески успешный пет-проект из-за устаревших резервных копий БД (ещё до того, как он стал коммерчески неуспешным). При этом, даже после частичного восстановления, все-таки потерял ~30% прибыли от проекта, много нервов и времени.

Это подтолкнуло меня на разработку своего открытого инструмента для бекапа PostgreSQL. С разными хранилищами, уведомлениями при сбоях и health check'ом. Собственно, о том, как я потерял деньги и затем разработал проект — хочу рассказать в статье ниже.

Содержание

Про open source проект для резервных копий PostgreSQL

Я выложил в open source свой проект для мониторинга и бекапов PostgreSQL. Проект разрабатываю и использую уже более 2-х лет. Разрабатывал с ориентиром на потребности своего рабочего и "пет" проектов.

И только недавно осознал, что проект, в общем-то, помогает знакомым, имеет публично-презентабельный вид и может быть полезен для сообщества.

Стек проекта: Go, gin, gorm, React, TypeScript, PostgreSQL и всё в Docker + Docker Compose. Изначально проект был на Java, но со временем был переписан на Go.

Фактически, это UI обвязка над стандартным pg_dump. С дополнительными функциями, которые улучшают UX стандартной утилиты и добавляют интеграции с внешними сервисами для хранения бекапов и уведомлений.

Что умеет:

  • Делать резервные копии по расписанию (например, каждый день в 4 утра или каждое воскресенье в 12 ночи) для PostgreSQL с 13-й до 17-й версии.

    Бекапы хранятся в сжатом виде локально на сервере, в S3 или Google Drive. В планах добавить Яндекс Диск, NS сервера и FTP.

    После каждого бекапа вам отправляется уведомление, что всё хорошо (или наоборот — плохо). Уведомления об успешных бекапах опциональны.

  • Уведомлять в Telegram, на почту и в Slack, если БД не отвечает.

    Причём уведомляет только через n неудачных попыток (чтобы нивелировать ложные срабатывания из-за сети) и показывает график доступности.

    В планах добавить Discord, Mattermost и другие каналы связи.

Разумеется, проект бесплатный, открытый (под MIT лицензией), self hosted и с человеческим веб-интерфейсом.

Сайт проекта - https://postgresus.com/
GitHub - https://github.com/RostislavDugin/postgresus

P.S. если проект кажется полезным и если у вас есть аккаунт на GitHub, пожалуйста, поставьте звёздочку ⭐️. Первые звёзды тяжело собирать. Буду крайне признателен за поддержку!

История, как я испортил базу и не смог до конца восстановиться

В 2023-м году у меня был пет-проект, который давал доступ к ChatGPT (ещё к 3.5) в РФ без зарубежной карты и номера телефона. Обычная перепродажа доступа через API с наценкой. Проект рос, потом пошёл на спад и я его продал. БД проекта бекапилась консольной утилитой по типу PgBackRest раз в сутки на другой сервер.

Об этом у меня осталась статья 2023-го года: "Как я заработал 500 000 рублей, сделав доступ к ChatGPT. А потом Яндекс убил SEO и всё (почти) закончилось"

В момент, когда проект приносил ~$1 500 на пассиве и был в пике доходности, произошло плохое: я испортил данные в базе.

Это была пятничная ночь, я был уставший, фоново отвечал на сообщения и был максимально расфокусирован. В этот момент клиент попросил поменять почту для доступа к аккаунту.

Через SSH и psql я полез в продовую базу, ввёл запрос в духе:

UPDATE users SET email = 'customer@email.com' WHERE email ILIKE '%%'

Затем отвлёкся, чтобы посмотреть нужную почту в чате и... на автомате нажал Enter. После чего увидел что-то в духе AFFECTED ROWS: 10 000.

Это был единственный раз за много-много лет, когда у меня пробил холодный пот на спине. Буквально.

Дисклеймеры

Разумеется, я знал, что неплохо бы сначала делать SELECT, сделать SAVEPOINT и т.д. Но, как во всех таких историях, базовые правила техники безопасности были проигнорированы, что привело к фатальным последствиям.

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

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

Кое-как за оставшуюся ночь и утро я смог скриптами восстановить ~65% базы по IDшникам пользователей. Остальным пришлось отменять подписки и возвращать деньги. Было больно, неприятно и дорого.

Урок был очень сильно усвоен...

Как начал разрабатывать проект

Было принято решение: разработаю себе такой инструмент для бекапов, который будет каждый день присылать уведомления, что все хорошо! И восстанавливать всё в пару кликов! И блек джек с микросервисами! И API метод для проверки жизнеспособности утилиты сделаю!

Первую версию Postgrusus'a разработал буквально за месяц на Java. Начал использовать. Иногда давать пользоваться знакомым. Дорабатывал по мере своих потребностей и по мере поступления обратной связи.

Оказалось, что удобно. Несколько раз резервные копии спасали и меня, и не только лишь меня. Название у проекта появилось только два месяца назад, до этого репозиторий назывался "pg-web-backup".

Конкретно сейчас Postgresus решает для меня следующие задачи:

  • Выступает главным инструментом для бекапов, если проект маленький или живёт на VPS, а не в облаке с облачной базой данных.

  • Выступает резервным инструментом для бекапов, если проект большой, живёт в облаке с DBaaS и с облачными резервными копиями.

    Бекапит базы на "всякий случай" (если вдруг облако умрёт, заблокируется, база случайно удалится вместе с резервными копиями из-за неуплаты и т.д.). Всяко лучше иметь дубль бекапов, чем попасть в тот неудачный 0.01%, когда даже облако накрылось и нет плана Б.

Дальнейшие планы

Сейчас в планах дорабатывать проект в следующих направлениях:

  • Добавить больше PostgreSQL-специфичного мониторинга нагрузки (pg_stat_activity, pg_system_stat, pg_locks), но с удобным UI.

    Эдакая альтернатива postgres_exporter + Grafana, но из коробки вместе с резервными копиями.

  • Наблюдение и алертинг в случае замедления ключевых запросов.

    У меня в рабочем проекте есть таблицы и специфические функции, которые ещё рано оптимизировать (если гипотеза провалиться — можем удалить). Но потенциально могут вырасти по данными и упасть в скорости.

    Условно, если запрос INSERT INTO users (...) VALUES (...) начал занимать больше 100мс, а у нас поток новых пользователей только растёт — нам прилетит уведомление и мы пойдем оптимизировать.

  • Собирать статистику запросов по CPU time и частоте выполнения, чтобы видеть, куда уходят основные ресурсы и что стоит оптимизировать.

  • Добавлять больше источников для уведомлений и хранения данных.

Правила по работе с БД, которые я теперь внедряю во все рабочие проекты

Напомню две народные мудрости:

Системные администраторы делятся на тех, кто ещё не делает резервные копии и тех, кто уже делает резервные копии.

Не только делай резервные копии, а ещё и регулярно проверяй, что из них получается восстановиться.


С тех пор как я испортил БД своего проекта, я категорически без исключений принял на вооружение следующие правила:

  • перед любым UPDATE всегда делать SELECT и проверять, что выбирается всего 1-2 строки;

  • если изменение большое — ставить руками SAVEPOINT;

  • проводить "учения" по восстановлению минимум раз в 3 месяца. Причём как из облачной копии, так и из локальной. Чтобы в ответственный момент не оказалось, что данных нет, резервные копии не работают или восстанавливаются слишком долго.

За прошедшие 2 года были прецеденты, когда требовалось восстановление из бекапов — всегда получалось и в облаке, и из Postgresus'a. Проблем не было, потому что всё было отлажено на этапе тестов. Базовые правила техники безопасности работают.

Заключение

Надеюсь, мой проект окажется полезен для широкого круга разработчиков, DBA и DevOps'ов. Планирую развивать его дальше, повышая его полезность в боевых задачах. Буду рад любым предложениям и комментариям по улучшению.

Может быть интересно:

P.S. Ещё у меня есть Telegram канал, если вдруг интересны мои заметки о разработке.

Комментарии (18)


  1. ky0
    13.07.2025 12:13

    Что делает бизнес, чтобы не обнаружить, что восстанавливать продовую БД нужно из месячной давности бэкапа? Нанимает админа до.

    Что делает разработчик-стартапер, когда обнаруживает месячный бэкап? Пишет свою вебморду для pg_dump после :)

    Ничего не могу сказать, достойный подход.


    1. RostislavDugin Автор
      13.07.2025 12:13

      Что именно вы понимаете под "бизнес"?

      У меня был мелкий проект, где денег хватало на сервер, доступ к API и немного на маркетинг. Это не тот проект, где имеет смысл нанимать сис. админа. Собственно, проект для таких же

      Но, как я и написал — ошибка глупая, моя личная, сам виноват. Причина не в инструменте, а в человеческом факторе :). Нужно было проверять, что бекапы делаются, аккуратнее писать запрос и проблемы не было бы

      А Postgresus не для решения проблемы "бекапов" в целом, а просто маленькое улучшение UX. Чтобы на одном экране удобно добавить базы за 30 секунд без CLI, выбрать расписание и быть спокойным


      1. ky0
        13.07.2025 12:13

        Под бизнесом я имею в виду группу людей с некой идеей и желанием на ней заработать. Хорошо, когда они нанимают профессиональных управленцев, которые знают большую часть проблематичных мест, одно из которых в айти, как раз - начинать проект без предварительной подготовки инфраструктуры под него.

        Для мелкого проекта админ в штате не нужен, тут с вами соглашусь - достаточно купить несколько часов опытного фрилансера.


        1. polRk
          13.07.2025 12:13

          Или просто взять managed db


  1. sintech
    13.07.2025 12:13

    Limit 1 нервно курит в сторонке.


  1. chemtech
    13.07.2025 12:13

    Спасибо за пост. А через код можно настроить postgresus ?


    1. RostislavDugin Автор
      13.07.2025 12:13

      А зачем именно через код?

      Вообще... нет. Я наоборот старался, чтобы не нужно было ничего делать в коде \ конфигах \ .env файлах. Чтобы всё было в UI и максимально тривиально без CLI


  1. isumix
    13.07.2025 12:13

    «Люди делятся на две категории: кто еще не делает бэкапы, и кто их уже делает»


    1. xSVPx
      13.07.2025 12:13

      На три, еще бывают те, кто проверяет, что из бэкапов можно восстановиться....


  1. Timmek
    13.07.2025 12:13

    А как так вышло, что поле “email” не было ключом/только уникальным ?


    1. RostislavDugin Автор
      13.07.2025 12:13

      Не ключ и не уникальное, потому что помимо почты были другие сервисы входа. Следовательно, email мог быть много у кого NULL


      1. Timmek
        13.07.2025 12:13

        Понял, спасибо


      1. nixooyase
        13.07.2025 12:13

        Кажется недавно в постгрес добавили возможность делать nullable поля уникальными, если есть не null значение.


  1. PetyaUmniy
    13.07.2025 12:13

    Делать коробки все в одном, имхо, для опенсорса это странное решение. Разумеется если это для кровавого ынтерпрайза, да еще если это проприетарь за бешеные доллары - тогда это база.
    Совеременные IT продукты довольно сложные, в них и без того много сущностей, источников разных событий, метрик, алертов и т.д. Если вы будете для метрик, алертинга, рисования графиков использовать свои велоспеды, то вы будете сильно увеличивать сложность вашего продукта.

    Каноническим инструментов мониторинга и алертинга в современном IT является prometheus, отправщиком вебхуков - alertmanager, рисователем графиков - grafana. Почему бы не использовать их? Сколько времени можно съэкономить на отсутствии необходимости их разрабатывать и вникать в кустомные велосипеды при эксплуатации. А уж вопросы интеграции даже обсуждать нечего.

    Сам типичный инстанс postgresql бекаплю 2мя независимыми путями (все деплоится и параметризуется через ansible (включая helm), все в контейнерах, частично в кубере):

    • PITR: wal-g для wal + shell обертка вокруг wal-g генерирующая prometheus метрики/статус для basebackup'ов + скрипт python генерирующий prometheus метрики о состоянии бекапов в хранилище (например о пропущеном сегменте или отсутствии изменений в течении периода) из вывода wal-g (да, используя exeс) + cronjob python восстанавливатеть бекапов с прогоном стандартных тестов (встроенный тест целостности и pg_dump > /dev/null) и пушатель результата в prometheus pushgw.

    • Архив: shell обертка вокруг restic: получение списка баз, последовательный бекап каждой базы (pg_dump | restic backup --stdin, т.е. без сохранения промежуточного состояния на диск) в отдельный репозиторий, экспорт prometheus метрик для каждой базы. Хочу когда-нибудь прикрутить восстновление и сюда. Но беда в том что для дампов нарушается прозрачность процесса восстановления. При восстановлении нужно чтобы были созданы например роли присутствующие в дампе. Не придумал красивого решения, как это не сопровождать и чтобы оно не ломалось.

    Когда соберусь менять место работы попрошу разрешения работодателя заопенсорсить (больше для самого себя, использовать в будущем, не повторять эту работу). Сейчас увы нет времени и мотивации причесывать до такого состояния чтобы было не стыдно выкладывать в паблик.


    1. RostislavDugin Автор
      13.07.2025 12:13

      Исходя из вашего комментария, чтобы бекапить \ мониторить БД простому бекенд разработчику уровня junior-middle нужно:

      • поставить где-то экспортер данных из БД;

      • разобраться в Prometheus, развернуть и настроить;

      • разобраться в Grafana, развернуть и настроить;

      • разобраться в alertmanager и настроить, исходя из событий Prometheus;

      • написать скрипты для бекапов;

      Имхо, для человека, который не DevOps \ админ \ отвечает за инфру \ Senior'a - явный перебор. Каждый раз, когда я всё это разворачиваю - у меня уходит день-два + болит голова, а всё ли актуально \ не отвалится ли чего.

      Ну и нужно не забывать про поддержку этого, когда разработчики в команде меняются.

      А проект, который я делаю:

      • развернуть скриптом за 2 минуты;

      • добавить БД за 1 минуту;

      • подрубить ТГ бота за (если разобраться) 5 минут.

      И готово!

      Разумеется, это не подходит для серьёзного мониторинга, больших проектов и т.д. Для основного моего рабочего проекта у меня всё и настроено +- как вы описали (+ ещё метрики из облака тащу скриптами в Prometheus).

      Но для большинства маленьких-средних проектов, которым достаточно мониторить БД - Postegusus'a будет с головой. А главное быстро и удобно. Но это точно не серебрянная пуля.


      1. PetyaUmniy
        13.07.2025 12:13

        Пожалуй я с вами соглашусь. Это имеет смысл.
        Какая-то уже проф деформация, совсем не подумал что существуют проекты на 4 контнейнерах: postgres + backend + frontend + http proxy.


  1. mvv-rus
    13.07.2025 12:13

    Затем отвлёкся, чтобы посмотреть нужную почту в чате и... на автомате нажал Enter. После чего увидел что-то в духе AFFECTED ROWS: 10 000.

    Я вот когда-то давно много работал с Interbase через его утилиту Windows ISQL, и меня бы такое сообщение не привело бы в отчаяние. А всё потому, что Interbase использовал многоверсионную схему хранения, и старые записи никужа не девались. А утилита транзакцию автоматически не закрывала - нужно было руками закрыть, через интерфейс.Так что, увидев нечто неожиданное (бывало и такое), я просто откатил бы транзакцию, и всё.

    Это я к тому, что PostgreSQL тоже, говорят, поддерживает многоверсионную схему хранения, и если бы разрабочики утилиты для выполнения SQL задумались о том, чтобы не закрывать автоматом транзакции, вам было бы в тот момент легче.

    А вообще, править данные в боевой базе через SQL - это плохая практика, примерно столь же плохая, как и не делать резервные копии.

    PS А админы всё же делятся на тех, кто делает бэкап и тех, кто ещё не терял данные.


  1. aronsky
    13.07.2025 12:13

    Из предыдущей статьи автора:

    Ну я и полез в базу, чтобы обновить SQL-скриптом одну почту. Написал сначала скрипт WHERE, чтобы проверить выбор только одной почты. Затем для такого же WHERE написал уже UPDATE скрипт. И, по всей видимости, где-то не закрыл скобку. Запустил. Через секунду все ~25 000 почт стали NULL. В момент у меня пошёл холодный пот по спине и я подвис на две минуты. Но бекапы были на месте, я восстановился и пошёл менять футболку на сухую. Оказалось, дропнуть базу на проде действительно можно.

    Как будто бы та же история, а как будто и не понятно где правда.