
«Что там с базами, не пора ли добавлять ресурсов?» — казалось бы, звучит как дежурная реплика менеджера, и классический ответ на неё: «всё ок, до конца недели должно хватить!».
На деле этот безобидный на первый взгляд вопрос может быть сигналом о целом ворохе проблем. Важно разобраться, почему его задают (можно ведь посмотреть алерты и мониторинг), о чём именно речь (у нас точно всё ок с архитектурой?), как часто вопрос возникает (сколько денег мы тратим на содержание баз?).
Однажды на вопрос «что там с базами?» мы в команде решили ответить несколько иначе. Вместо «до конца недели должно хватить» — сказали: «давайте мигрируем базы в единый кластер, а тяжёлые файлы перенесём в S3».
О том, что из этого вышло, читайте под катом.
Привет, Хабр! Я Ахмед, заместитель CTO в финансовом маркетплейсе Сравни. Сегодня расскажу историю миграции наших баз данных в кластер и переноса тяжелых файлов в S3; в том числе о том, что пошло не по плану и об обратной стороне размещения баз в едином кластере.
Надеюсь, статья будет полезна разработчикам, которые работают с базами данных и топят за technical excellence, а также продактам и проджектам, желающим быть в теме.
Как мы поняли, что пора
Однажды у нас в Сравни появился новый продукт — кредитный конвейер, автоматизированная система обработки заявок на кредитование и принятия решений. За пару лет система доросла до 13 микросервисов и такого же количества БД. Для каждой БД мы с запасом выделяли ресурсы по CPU, RAM, дисковому пространству, которое заполнялось бешеными темпами.
Продукт делали в режиме честного MVP — когда ради оперативной проверки гипотез и скорой раскатки бизнес-фичей допустимо выбирать не самые оптимальные, но быстрые технические решения. В результате (классика!) архитектура у нас «сложилась исторически».
Например, мы хранили тяжелые файлы непосредственно в БД. Очевидные последствия: файлы копились, базы «пухли», нам то и дело приходили алерты о переполнении той или БД. Приходилось вручную добавлять памяти, что отнимало много времени.
В бэклоге появилась задача — изъять бинарники из БД и хранить их отдельно в S3. Мы решили объединить этот таск с миграцией в единый кластер. Так БД будет удобнее менеджерить, а обслуживание выйдет дешевле. Когда все БД работают в одном кластере, не нужно выделять на каждый отдельный инстанс свои значения по памяти и по процессору. Есть одно общее значение — и базы берут себе, сколько нужно. Это существенная экономия в деньгах: по нашим расчетам, кластер должен обходиться в полтора раза дешевле.
Перенос файлов и миграция: хронология
Поскольку базы содержали множество файлов, мы столкнулись с весьма трудоёмким процессом – нужно было перенести более терабайта данных по сети из одного места в другое.
Как поступили? Сперва анализировали каждую базу на предмет наличия бинарников, а затем все их переносили в S3. Базы становились значительно легче (каждая — на 70%), и это позволяло нам ускорить миграцию в кластер.
Файлы в S3 переносили итерационно: одну унесли — посмотрели, как работает в течение недели; потом за две недели перенести все остальное. На старте постарались выбрать ту БД, которая наименее всего повлияет на клиентский путь.
Последовательность шагов по переносу файлов в S3 была такой:
Добавляем в БД колонку с признаком, где хранится файл (БД или S3). Значение для текущих файлов = БД.
Пишем логику, которая в зависимости от значения признака скачивает файл из БД или S3. То же самое для сохранения файлов.
Включаем сохранение новых файлов в S3.
Создаем джобу, которая в фоне перекладывает существующие файлы из БД в S3 и соответственно меняет значение признака на S3.
Ждем окончания работы джобы. Теперь все файлы перенесены в S3.
Поскольку мы использовали для хранения в БД механизм «large objects» и не использовали lo_unlink, то фактически файлы не удалились из БД. Чтобы они действительно удалились, пользуемся утилитой vacuumlo.
Сначала завершили работу по переносу бинарников в S3 по всем БД, а затем — приступили к миграции БД в единый кластер.
Мигрировали, начиная от самых некритичных баз: их переносили в рабочее время. Миграцию более критичных БД проводили во время наименьшей активности клиентов. На время переноса вешали заглушку, что тот или иной сервис временно недоступен.
Порядок действий по миграции, в свою очередь, был таким:
Создаём новую базу в кластере.
Переводим сервис на реплику боевой базы (реплика всегда в read-only), снимаем дамп pg_dump с мастера.
В новой базе с помощью команды pg_restore восстанавливаем дамп.
Во время исполнения pg_restore пишется лог. Обязательно анализируем лог и в процессе восстановления, и по окончанию.
Если рестор упал, то возвращаем коннект на мастер и идём разбираться, в чём дело.
После успешного pg_restore проверяем, что данные перенеслись без потерь (несколько селектов с получением самых первых и последних записей).
Меняем Connection String на новый, перезапускаем приложение, чтобы сервис подцепил новую БД.
Наши БД устроены по классике: по два инстанса — мастер и слэйв; снимаем бэкапы ежедневно. При этом в ходе миграции никаких бэкапов нам не требовалось, поскольку старая БД не была затронута — и удалялась сильно позднее, когда мы уже были уверены, что миграция прошла успешно.
В целом на перенос каждой базы уходило от одного до нескольких часов — за счёт того, что все тяжёлые файлы были предварительно вынесены в S3. Всего 13 сервисов перенесли за неделю.
Перенос файлов и миграция БД: что может пойти не так
Не обошлось без проблем. Когда мы унесли файлы из первой БД в S3, тестирование показало, что все работает хорошо. Однако после релиза получили свой первый инфаркт: S3 отказывался отдавать нам файлы! Приехали — положили продакшен. Оказалось, дело в банальной невнимательности: подложили на прод тестовый secret.
Ошибку исправили, но осадочек остался. А с ним и паранойя перед следующими итерациями. Поэтому решили действовать осторожно: добавили несколько степеней защиты:
Перехватываем любой эксепшн при чтении.
Перехватываем любой эксепшн при записи.
Делаем пробное подключение к бакету при старте сервера. Если к бакету S3 не получается подключиться, то сервер не поднимется и откатится к предыдущему состоянию.
Меры предосторожности помогли с большей уверенностью перетащить данные из второго сервиса.
Что может пойти не так — вопрос не только про процесс миграции, но и про жизнь после. У размещения БД в едином кластере есть обратная сторона. Если из 10 независимых баз в инстансах переполняется одна, то перестает работать только один сервис. А если все базы расположены в едином кластере, то при переполнении дискового пространства кластера перестают работать все сервисы. Потому что режим read-only и невозможность сохранения вешаются сразу на весь кластер.
Поэтому при при переезде с отдельных инстансов в кластер обязательно нужно слать заблаговременный алерт при достижении определенного порога переполнения БД, чтобы не пропустить момент, когда всё повиснет. В нашем случае алерты приходят при заполнении кластера до 85% и 90% — сигнал о том, что нужно пойти и добавить ресурсов.
Еще одна трудность: чем тяжелее база, тем дольше выполняется дамп и рестор. Важно сделать тестовые замеры этих команд, чтобы понимать итоговое время простоя сервиса — и правильно выбрать техническое окно для проведения работ, оповестить клиентов.
Стоило оно того?
Спустя месяц после переноса файлов в S3 и миграции БД в единый кластер мы получили такие результаты:
Перенос в S3 удешевил затраты на хранение файлов в шесть раз.
Переезд всех инстансов БД в общий кластер снизил затраты на инфраструктуру БД в 1,5 раза.
Доработка системы мониторинга и алертинга во время миграции повысила контроль за стабильностью работы БД (без переезда был риск не так скоро добраться до этих доработок).
Как понять, когда пора мигрировать
В идеальном мире файлы сразу лежат, где полагается, а базы добропорядочно живут в кластерах. В реальном мире есть MVP, технические компромиссы и «так сложилось исторически». Всё это может затянуться — в моей истории продукт прожил пару лет до того, как дело дошло до честной работы с техническим долгом.
Разумеется, проще и дешевле оптимизировать все на ранних этапах, при первых признаках проблемы. Но как понять, что пора мигрировать? Какие в пользу этого могут быть аргументы?
Посмотрите, насколько процентов в день прирастает ваша база. Подойдет любая профильная система мониторинга. Если прирост составляет десятые доли процента в день, то, возможно, базы можно пока не трогать. Если же это процент в день, уже стоит задуматься об улучшениях.

При подготовке процесса стоит учитывать, что и перенос файлов в S3, и миграция БД в кластер обычно не требуют много ресурсов. В нашем случае один разработчик оказался вполне способен в спокойном режиме перевезти один сервис за день.
***
Пора ли переносить файлы из БД в облако? Пора ли мигрировать БД в единый кластер? Как правило, за подобными вопросами кроется ещё один, более глобальный: «Как определить правильный момент, чтобы заняться техническим долгом?». И когда вы в следующий раз услышите: «Что там с базами, не пора ли добавлять ресурсов?» — обратите внимание; возможно, это тот самый момент!
На вопросы о нашем кейсе и о том, как мы в целом работаем с базами данных, с радостью ответим в комментариях.