«Что там с базами, не пора ли добавлять ресурсов?» — казалось бы, звучит как дежурная реплика менеджера, и классический ответ на неё: «всё ок, до конца недели должно хватить!». 

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

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

О том, что из этого вышло, читайте под катом.


Привет, Хабр! Я Ахмед, заместитель CTO в финансовом маркетплейсе Сравни. Сегодня расскажу историю миграции наших баз данных в кластер и переноса тяжелых файлов в S3; в том числе о том, что пошло не по плану и об обратной стороне размещения баз в едином кластере. 

Надеюсь, статья будет полезна разработчикам, которые работают с базами данных и топят за technical excellence, а также продактам и проджектам, желающим быть в теме.

Как мы поняли, что пора

Однажды у нас в Сравни появился новый продукт — кредитный конвейер, автоматизированная система обработки заявок на кредитование и принятия решений. За пару лет система доросла до 13 микросервисов и такого же количества БД. Для каждой БД мы с запасом выделяли ресурсы по CPU, RAM, дисковому пространству, которое заполнялось бешеными темпами. 

Продукт делали в режиме честного MVP — когда ради оперативной проверки гипотез и скорой раскатки бизнес-фичей допустимо выбирать не самые оптимальные, но быстрые технические решения. В результате (классика!) архитектура у нас «сложилась исторически».

Например, мы хранили тяжелые файлы непосредственно в БД. Очевидные последствия: файлы копились, базы «пухли», нам то и дело приходили алерты о переполнении той или БД. Приходилось вручную добавлять памяти, что отнимало много времени.

В бэклоге появилась задача — изъять бинарники из БД и хранить их отдельно в S3. Мы решили объединить этот таск с миграцией в единый кластер. Так БД будет удобнее менеджерить, а обслуживание выйдет дешевле. Когда все БД работают в одном кластере, не нужно выделять на каждый отдельный инстанс свои значения по памяти и по процессору. Есть одно общее значение — и базы берут себе, сколько нужно. Это существенная экономия в деньгах: по нашим расчетам, кластер должен обходиться в полтора раза дешевле.

Перенос файлов и миграция: хронология

Поскольку базы содержали множество файлов, мы столкнулись с весьма трудоёмким процессом – нужно было перенести более терабайта данных по сети из одного места в другое. 

Как поступили? Сперва анализировали каждую базу на предмет наличия бинарников, а затем все их переносили в S3. Базы становились значительно легче (каждая — на 70%), и это позволяло нам ускорить миграцию в кластер. 

Файлы в S3 переносили итерационно: одну унесли — посмотрели, как работает в течение недели; потом за две недели перенести все остальное. На старте постарались выбрать ту БД, которая наименее всего повлияет на клиентский путь.

Последовательность шагов по переносу файлов в S3 была такой:

  1. Добавляем в БД колонку с признаком, где хранится файл (БД или S3). Значение для текущих файлов = БД.

  2. Пишем логику, которая в зависимости от значения признака скачивает файл из БД или S3. То же самое для сохранения файлов. 

  3. Включаем сохранение новых файлов в S3.

  4. Создаем джобу, которая в фоне перекладывает существующие файлы из БД в S3 и соответственно меняет значение признака на S3. 

  5. Ждем окончания работы джобы. Теперь все файлы перенесены в S3.

  6. Поскольку мы использовали для хранения в БД механизм «large objects» и не использовали lo_unlink, то фактически файлы не удалились из БД. Чтобы они действительно удалились, пользуемся утилитой vacuumlo.

Сначала завершили работу по переносу бинарников в S3 по всем БД, а затем — приступили к миграции БД в единый кластер. 

Мигрировали, начиная от самых некритичных баз: их переносили в рабочее время. Миграцию более критичных БД проводили во время наименьшей активности клиентов. На время переноса вешали заглушку, что тот или иной сервис временно недоступен.

Порядок действий по миграции, в свою очередь, был таким:

  1. Создаём новую базу в кластере.

  2. Переводим сервис на реплику боевой базы (реплика всегда в read-only), снимаем дамп pg_dump с мастера.

  3. В новой базе с помощью команды pg_restore восстанавливаем дамп.

  4. Во время исполнения pg_restore пишется лог. Обязательно анализируем лог и в процессе восстановления, и по окончанию.

  5. Если рестор упал, то возвращаем коннект на мастер и идём разбираться, в чём дело.

  6. После успешного pg_restore проверяем, что данные перенеслись без потерь (несколько селектов с получением самых первых и последних записей).

  7. Меняем Connection String на новый, перезапускаем приложение, чтобы сервис подцепил новую БД.

Наши БД устроены по классике: по два инстанса — мастер и слэйв; снимаем бэкапы ежедневно. При этом в ходе миграции никаких бэкапов нам не требовалось, поскольку старая БД не была затронута — и удалялась сильно позднее, когда мы уже были уверены, что миграция прошла успешно.

В целом на перенос каждой базы уходило от одного до нескольких часов — за счёт того, что все тяжёлые файлы были предварительно вынесены в S3. Всего 13 сервисов перенесли за неделю. 

Перенос файлов и миграция БД: что может пойти не так

Не обошлось без проблем. Когда мы унесли файлы из первой БД в S3, тестирование показало, что все работает хорошо. Однако после релиза получили свой первый инфаркт: S3 отказывался отдавать нам файлы! Приехали — положили продакшен. Оказалось, дело в банальной невнимательности: подложили на прод тестовый secret.

Ошибку исправили, но осадочек остался. А с ним и паранойя перед следующими итерациями. Поэтому решили действовать осторожно: добавили несколько степеней защиты:

  1. Перехватываем любой эксепшн при чтении.

  2. Перехватываем любой эксепшн при записи.

  3. Делаем пробное подключение к бакету при старте сервера. Если к бакету S3 не получается подключиться, то сервер не поднимется и откатится к предыдущему состоянию.

Меры предосторожности помогли с большей уверенностью перетащить данные из второго сервиса.

Что может пойти не так — вопрос не только про процесс миграции, но и про жизнь после. У размещения БД в едином кластере есть обратная сторона. Если из 10 независимых баз в инстансах переполняется одна, то перестает работать только один сервис. А если все базы расположены в едином кластере, то при переполнении дискового пространства кластера перестают работать все сервисы. Потому что режим read-only и невозможность сохранения вешаются сразу на весь кластер.

Поэтому при при переезде с отдельных инстансов в кластер обязательно нужно слать заблаговременный алерт при достижении определенного порога переполнения БД, чтобы не пропустить момент, когда всё повиснет. В нашем случае алерты приходят при заполнении кластера до 85% и 90% — сигнал о том, что нужно пойти и добавить ресурсов.

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

Стоило оно того?

Спустя месяц после переноса файлов в S3 и миграции БД в единый кластер мы получили такие результаты:

  • Перенос в S3 удешевил затраты на хранение файлов в шесть раз.

  • Переезд всех инстансов БД в общий кластер снизил затраты на инфраструктуру БД в 1,5 раза. 

  • Доработка системы мониторинга и алертинга во время миграции повысила контроль за стабильностью работы БД (без переезда был риск не так скоро добраться до этих доработок).

Как понять, когда пора мигрировать

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

Разумеется, проще и дешевле оптимизировать все на ранних этапах, при первых признаках проблемы. Но как понять, что пора мигрировать? Какие в пользу этого могут быть аргументы?

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

Динамика прироста нашей базы
Динамика прироста нашей базы

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

***

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

На вопросы о нашем кейсе и о том, как мы в целом работаем с базами данных, с радостью ответим в комментариях.

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


  1. NikitchenkoSergey
    29.08.2024 12:00
    +2

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


    1. akhsakhmedov Автор
      29.08.2024 12:00
      +1

      Изрядно покопавшись в чертогах разума, так и не вспомнил аргументов к такому решению. И вы абсолютно правы, такое решение было не просто странным, оно было ошибочным. Однако мы ошибок не боимся, признаем их и всегда готовы исправлять


    1. Ivan22
      29.08.2024 12:00

      ну бывает, сперва в базу тексты кладут, потом фоточки, а потом понеслась


  1. vagon333
    29.08.2024 12:00

    Если я правильно понял:
    - изначально архитектор решил хранить бинарники в базе.
    - баз было 2+.
    - данных вместе с бинарниками в 1TB???.

    Когда базы начали закономерно тупить вы решили:
    - перенести бинарники в S3, хостимый в облаке
    - объединить все базы на единый сервер или кластер, также хостимый в облаке.

    Я бы постеснялся это решение описывать как красивое.
    За хранение бинарников в базе архитектора на курсы.
    Переход в облако с имеющегося железа - решение для 2014, но не 2024, когда достоинства и недостатки on-prem vs cloud в детских книжках.

    S3 можно поднять локально, или просто файловое хранилище.
    Некоторые базы поддерживают работу с файлами как File Storage - бинарники на диске с контролем из базы.


    1. akhsakhmedov Автор
      29.08.2024 12:00

      Спасибо за комментарий!
      Вся инфраструктура нашей компании хостится в Облаке, поэтому мы ничего не уносили с железок.
      Насчет просчета с хранилищем на старте, даже не буду спорить, я честно описал наш провал )

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


      1. werter_l
        29.08.2024 12:00
        +1

        Надеюсь, бэкапы из Облака к себе (локально) вы делаете :)

        А то бывали случаи когда и ДЦ сгорали.


  1. AirLight
    29.08.2024 12:00

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