Бигдата, ты ли это?

Возможно ли не замечать «лишних» 30 Tb данных на SSD при живом настроенном мониторинге  и героически их обслуживать? Запросто, а ответы на вопросы кто же эти наблюдательные люди, как им это удалось и причем здесь PostgreSQL — ниже.

Инфраструктура и наша «бигдата»

Основная база данных, используемая сервисами компании — PostgreSQL. Как правило, абсолютно для всех продакшн баз снятие бэкапа происходит минимум раз в сутки, при этом, wal-логи между бэкапами также пушатся в хранилище для возможности более точечного восстановления. Бэкапы — не инкрементальные. Используемый инструмент для бэкапирования — wal-g тула. Хранилище для бэкапов — s3 api compatible, в нашем случае Ceph с ssd-пулом для «горячих» бэкапов и hdd-пулом — для бэкапов, требующих длительного хранения: напрямую бэкап архивы, как и wal-логи складываются в s3-hot на SSD, затем по истечению определенного времени, некоторые из них копируются в s3-cold на hdd. Немного цифр:

  • количество обслуживаемых PostgreSQL кластеров ~ 50

  • усредненный объем данных каждого кластера ~ 300Гб, около 5 кластеров БД требуют больше 1Тb

  • время жизни одного бэкапа ~ 5 дней в s3-hot

Хьюстон, у нас проблемы!

Раз в год и палка стреляет, так согласно best practice было решено проверить восстановление БД из бэкапа. Нет-нет, такая проверка была обыденностью, однако в этот раз процесс запускался для базы большей 1Тб (регулярно данный recovery сценарий запускался для баз с гораздо более скромным размером). 

Процесс восстановления шел в штатном режиме, но, по прошествии достаточно большого количества времени и сотни гигабайт выкаченных частей бэкапа из s3, возникла ошибка, полностью блокирующая recovery process:

part_921.tar.br part_922.tar.br part_923.tar.br part_924.tar.br part_925.tar.br part_926.tar.br part_927.tar.br part_928.tar.br part_929.tar.br part_930.tar.br part_931.tar.br part_932.tar.br part_933.tar.br part_934.tar.br part_935.tar.br part_936.tar.br part_937.tar.br part_938.tar.br part_939.tar.br part_940.tar.br part_941.tar.br]'
ERROR: 2020/12/21 10:26:04.251278 Failed to fetch backup: Expect pg_control archive, but not found
github.com/wal-g/wal-g/internal.newPgControlNotFoundError
    /home/travis/gopath/src/github.com/wal-g/wal-g/internal/backup_fetch_handler.go:47

Перезапуск восстановления, как и ожидалось, привел к идентичному результату.
Из вышеупомянутого лога видно, что процесс восстановления падает, когда выкачано ~1000 файлов. Обсуждения на гитхабе подтвердили данное предположение: оказалось, в тот момент wal-g полагалась только на работу с s3 api version 2, что предполагало использование специфичных для данной версии операций, не позволяющих за один запрос работать более чем с 1к файлов. Функциональность работы с s3 api version 1 была оперативно внедрена в следующий релиз wal-g, мы же обновили наш сeph-кластер до версии с s3 api version 2 (к счастью, данное обновление было запланировано и уже обкатывалось в различных тестовых средах). Итог — бэкап размером больше 1Tb успешно накатился. 

Проблема решена, recovery сценарий для больших баз протестирован, но, одна смутная догадка омрачала момент наслаждения, наступивший после решения нетипичной ситуации…

Самый большой годовой Impact!

Ввиду нехороших подозрений, было решено проверить s3 бакет, куда складывались все бэкапы. Проведя минуту за изучением содержимого стало понятно, что опасения верны, но насколько серьезна ситуация? Тотчас же был написан скрипт, оценивающий размер 5 последних бэкапов для каждой базы, а дальше простое арифметическое действие на вычитание — как результат, полный ШОК! Если не догадались в чем дело, то вернемся к моменту выяснения проблемы с невозможностью «накатывания» бэкапа. 

В момент изучения wal-g issue на гитхабе стало ясно, что s3 api sdk используемое там работает только с 1000 файлов, поэтому полное накатывание бэкапа состоящего из более чем 1к файлов было невозможным. Напомню, в компании  обслуживалось около 5 бд  больших чем 1Tb, бэкап которых содержал более 1к файлов и успешно снимался, так как пушился частями. Старые бэкапы удалялись вызовом функции retain 5 после успешной процедуры снятия нового.

Когда стало ясно, что функциональность wal-g может работать не совсем корректно при условии наличия бэкапа превосходящего 1к файлов, появились сомнения о том, были ли полностью удалены старые бэкапы, так как они содержали более 1000 файлов. Визуальный анализ показал, что НЕТ: из каждого бэкапа было удалено 1000 файлов, но всякий раз оставался небольшой хвост, который рос пропорционально росту базы. Для оценки «дискового урона» был написан скрипт, считавший размер 5 актуальных бэкапов для каждой бд, а затем разница между общим размером «бэкапного» пространства и того, что получилось на прошлом шаге. Результат немного шокировал — около 30Tb было занято ненужными бэкапными хвостами, что с учетом репликации на ceph становилось 60Tb чистого отборного SSD.

Анализ и выводы

Как же можно было не заметить лишних 30Tb занимаемых бэкапами при настроенных метриках? Ответ один — недостаточное количество метрик.

Имелось:

  • Метрики и соответствующие алерты на успешность снятия бэкапа (бэкапы снимались регулярно без всяких проблем)

  • Общее дисковое пространство занимаемое всеми бэкапами (размер общего корневого s3 бакета). Да, он, постепенно рос, без скачков, но и размеры баз росли…

  • Дисковое пространство для каждой базы

Становиться, ясно, что не было ни одного графика соотносящего размер бэкапов с размерами баз, которые постоянно росли. Мы же просто подкидывали SSD в жерло ceph и гордились объемом поддерживаемой «BigData», которая оказалась не такой уж и big, после подчистки хвостов.

3180c7d3c822f112e9003d80c76d131c.JPG

© Habrahabr.ru