Открыть список
Как стать автором
Обновить
73,36
Рейтинг
Miro
Online collaborative whiteboard platform

Как мы мигрировали базу данных из Redis и Riak KV в PostgreSQL. Часть 1: процесс

Блог компании MiroPostgreSQLАдминистрирование баз данных
Это первая часть статьи, в которой я расскажу о том, как мы построили процесс работы над большим проектом по миграции БД: про безопасные эксперименты, командное планирование и кросс-командное взаимодействие. В следующих статьях подробней расскажу про технические проблемы, которые мы решали: про масштабирование и отказоустойчивость PostgreSQL и нагрузочное тестирование.



Долгое время основной базой данных в Miro (экс-RealtimeBoard) был Redis. Мы хранили в нём всю основную информацию: данные о пользователях, аккаунтах, досках и т.д. Всё работало быстро, но мы столкнулись с рядом проблем.

Проблемы с Redis

  1. Зависимость от сетевой задержки. Сейчас в нашем облаке она составляет порядка 20 мск, но при её увеличении приложение начнёт работать очень медленно.
  2. Отсутствие индексов, которые нужны нам на уровне бизнес-логики. Их самостоятельная реализация может усложнить бизнес-логику и привести к неконсистентности данных.
  3. Сложность кода также усложняет обеспечение консистентности данных.
  4. Ресурсоёмкость запросов с выборками.

Эти проблемы вместе с ростом количества данных на серверах послужили причиной для миграции БД.

Постановка задачи


Решение о миграции принято. Следующий шаг — понять, какая из БД подойдёт для нашей модели данных.

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

Упрощённо архитектура нашего приложения выглядела так: есть Application Servers, которые через слой работы с данными обращаются в Redis и RiakKV.

Наш Application Server — это монолитное Java-приложение. Бизнес-логика написана на фреймворке, который адаптирован под NoSQL. В приложении реализована своя транзакционная система, которая позволяет обеспечивать работу множества пользователей на любой из наших досок.

RiakKV мы использовали для хранения данных архивных досок, которые не открывались в течение 7 дней.

Добавляем в эту схему PostgreSQL. Делаем так, чтобы Application servers работали с новой базой данных. Копируем данные из Redis и RiakKV в PostgreSQL. Задача решена!

Ничего сложного, но есть нюансы:

  • У нас 2,2 млн зарегистрированных пользователей. Ежедневно в Miro работают 50 тысяч пользователей, пиковая нагрузка — до 14 тысяч одновременно. Пользователи не должны столкнуться с ошибками из-за наших работ, они вообще не должны заметить момент переезда на новую базу.
  • 1 Тб данных в БД или 410 млн объектов.
  • Непрерывный выпуск новых фич другими командами, чьей работе мы не должны мешать.

Варианты решения задачи


Перед нами стоял выбор из двух вариантов миграции данных:

  1. Остановить разработку сервиса → переписать код на сервере → протестировать функциональность → запустить новую версию.
  2. Провести плавную миграцию: постепенно переводить части продукта на новую базу данных, поддерживая одновременно PostgreSQL и Redis и не прерывая разработки новых фичей.

Остановка развития сервиса — это потеря времени, которое мы могли бы использовать для роста, а это значит — потеря пользователей и долей рынка. Для нас это критично, поэтому выбрали вариант с плавной миграцией. Несмотря на то, что по сложности этот процесс можно сравнить с заменой колёс на автомобиле во время движения.


При оценке работ мы разбили наш продукт на основные блоки: пользователи, аккаунты, доски и так далее. Отдельно вынесли работы по созданию инфраструктуры PostgreSQL. И заложили в оценку риски на случай, если что-то пойдёт не так (так оно и вышло).

Спринты и цели


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

У нас есть две точки: начало работы над задачей и конечная цель. Идеально, когда мы движемся к цели прямым путем. Но часто случается, что мы хотим идти прямым путём, а получается так:



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

Возможна ситуация, при которой мы вообще не придём к цели. Например, если уйдём в глубокий рефакторинг или переписывание всего приложения.



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

У каждой итерации есть своя цель, которая двигает команду к конечному большому результату.



Если во время спринта появляется новая задача, мы оцениваем, приближает ли нас к цели её выполнение. Да — берём в следующий спринт или меняем приоритеты в текущем, если нет — не берёмся за неё. Если появляются ошибки — ставим им высокий приоритет и быстро исправляем.

Бывает, что разработчики внутри спринта должны выполнять задачи в строго определённой последовательности. Или, например, разработчик передаёт готовую задачу QA-инженеру для срочного тестирования. На этапе планирования мы стараемся выстраивать подобные зависимости между задачами для каждого участника команды. Это позволяет всей команде видеть, кто, что и когда будет делать, не забывая про зависимость от других.

В команде есть ежедневные и еженедельные синхроны. Ежедневно по утрам мы обсуждаем, кто, что и в каком приоритете будет делать сегодня. После каждого спринта синхронизируемся друг с другом, чтобы быть уверенными, что все движутся в правильном направлении. Обязательно составляем план на крупные или сложные релизы. Назначаем дежурных разработчиков, которые, если нужно, присутствуют во время релиза и мониторят, что всё в порядке.

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

Так выглядит один из наших спринтов. Ведём всё на доске Miro:



Режимы и безопасные эксперименты


Во время миграции мы должны были гарантировать стабильную работу сервиса в боевых условиях. Для этого нужно быть уверенными в том, что всё протестировано и нигде нет ошибок. Чтобы добиться этой цели, мы решили сделать нашу плавную миграцию ещё более плавной.

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

В первом режиме “Redis Read/ Write” работает только старая база данных — Redis.



Во втором режиме “PostgreSQL Passive Write” мы можем убедиться, что запись в новую базу происходит корректно и базы консистентны.



Третий режим “PostgreSQL Read/Write, Redis Passive Write” позволяет убедиться в корректности чтения данных из PostgreSQL и посмотреть, как ведёт себя новая БД в боевых условиях. Основной базой при этом остаётся Redis, что давало нам возможность находить специфичные случаи работы с досками, которые могли приводить к ошибкам.



В последнем режиме “PostgreSQL Read/ Write” работает только новая база данных.



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

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

Timeline запуска экспериментов с режимами получился такой:

  • Январь-февраль: Redis read/write
  • Март-апрель: PostgreSQL passive write
  • Май-июнь: PostgreSQL read/write, основная база — Redis
  • Июль-август: PostgreSQL read/write
  • Сентябрь-декабрь: полная миграция.

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

Кросс-командное взаимодействие


Во время миграции мы часто пересекались с командами, которые выпускали новые фичи. У нас единая code base, и в рамках своих работ команды могли изменять в новой БД существующие структуры или создавать новые. При этом могли происходить пересечения команд по разработке и выводу новых фич. Например, одна из продуктовых команд пообещала команде маркетинга выпустить новую фичу к конкретной дате; команда маркетинга запланировала рекламную кампанию на этот срок; команда продаж ждёт фичу и кампанию, чтобы начать общаться с новыми клиентами. Получается, все зависят друг от друга, и затягивание сроков одной командой срывает планы другой.

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

Выводы


Чему мы научились за время этого проекта:

  1. Не бояться браться за сложные проекты. После декомпозиции, оценки и выработки подходов к работе сложные проекты перестают казаться невыполнимыми.
  2. Не жалеть времени и сил на предварительные оценки, декомпозицию и планирование. Это помогает глубже разобраться в задаче до того, как вы начнёте работу над ней, и понять объём и трудоёмкость работ.
  3. Закладывать риски в тяжелые технические и организационные проекты. В процессе работ вы обязательно встретитесь с проблемой, которая не была учтена при планировании.
  4. Не делать миграцию, если в этом нет необходимости.

В следующих статьях я подробнее расскажу о технических проблемах, которые мы решали во время миграции.
Теги:riakredispostgresqlpostgresdatabase migrationsмиграция базы данныхRealtimeBoardmiro
Хабы: Блог компании Miro PostgreSQL Администрирование баз данных
Всего голосов 19: ↑19 и ↓0 +19
Просмотры6.8K

Комментарии 27

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

Похожие публикации

Лучшие публикации за сутки

Информация

Дата основания
Местоположение
Россия
Сайт
miro.com
Численность
501–1 000 человек
Дата регистрации
Представитель
Сергей Шабалин

Блог на Хабре