Существует множество фреймворков, которые поставляются с ORM (объектно-реляционными картами), которые позволяют вам выполнять миграцию базы данных как часть вашего развертывания.Миграция базы данных схемы — это процесс обновления базы данных до новой схемы вместе с любыми данными. требуются манипуляции. Идея достаточно проста: вы пишете код, требующий новой таблицы в базе данных, и упаковываете его с помощью миграции. Миграция — это код, выполняемый инструментом миграции, который сообщает базе данных, какие изменения нужно внести — в данном случае, создание новой таблицы.

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

Чем полезны инструменты миграции

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

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

Недостатки инструментов миграции схемы

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

Хотя каждое шифрование занимает всего 1 мс, с 1 000 000 пользователей это займет более 16 минут. 16 минут простоя для наших пользователей. Большинство фреймворков настаивают на том, чтобы версии базы данных соответствовали желаемой версии, и даже если это не так, код ожидает, что пароли будут хешированы сейчас. Большинство пользователей не смогут войти в систему в течение этого времени, и те, кто уже вошли в систему, тоже будут в беде — вся эта математика забивает мой веб-сервер!

Хорошо, все ваши пароли уже криптографически защищены, и вы следуете лучшим отраслевым практикам, так что это, вероятно, плохой пример. Но иногда миграции могут быть проблематичными и в реальном мире. Magento недавно выпустила версию 2.2своей платформы для электронной коммерции, и они перешли от хранения сериализованных массивов в базе данных к представлению их в виде JSON для защиты от атак с удаленным выполнением кода. В рамках миграции они взять все существующие сериализованные массивы и преобразовать их в JSON, что может быть долгим процессом, поскольку журналы хранятся в виде сериализованных массивов. Как и в приведенном выше примере, вы столкнетесь с проблемами простоя, но если вы заранее очистите журналы, это будет довольно быстрая операция. В теории.

Однако в нашем случае был записан недавний сериализованный массив длиной 260 символов, а в одной из таблиц есть сериализованное поле с ограничением данных всего в 255 символов. Когда скрипт обновления пытается десериализовать данные, он обнаруживает, что они недействительны, и выдает необработанное исключение. Теоретически задача быстрой миграции умирает. Вы остаетесь с несогласованной базой данных, кодом, который отказывается выполняться, потому что базу данных необходимо обновить, и сбойным сценарием миграции. И что еще хуже, у команды разработчиков не будет хорошего понимания проблемы, потому что они не написали никакого кода: это все фреймворк. Определенно, это не быстрое решение!

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

Устранение проблем

Итак, как решить эти проблемы, сохранив при этом преимущества миграции? Ответ: путем отделения миграции схемы базы данных от развертывания кода.

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

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

Однако эти изменения могут быть платными:

  • Дополнительная сложность за счет дополнительных изменений: необходимо выполнить два (или более) набора обновлений, чтобы обеспечить дедупликацию базы данных.
  • Несколько версий для отслеживания: код может работать с набором версий базы данных, которые сложнее отслеживать, чем одну.

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

Как разделение помогло LiveJournal расти

Мы уже давно знаем о проблемах с миграцией баз данных. В книге Кодеры за работой Брэд Фитцпатрик — автор memcached и создатель LiveJournal — описывает сценарий 1995 года, когда его компания в фоновом режиме выполняла миграцию базы данных более месяца. Поскольку пользовательская база продолжала быстро расти, команда инженеров поняла, что текущая структура базы данных не будет продолжать масштабироваться. Они знали, что им необходимо внести изменения, но реструктуризация могла стать серьезным испытанием, сопряженным с риском простоя и неопределенностью.

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

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

Определение лучшей стратегии миграции для вашего проекта

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

Чтобы начать работу над своим проектом, вы можете попробовать один из множества автономных инструментов, который сделает это за вас, напримерFlyAwayилиLiquiBase. . Люди также извлекли код миграции Ruby on Rails в качестве автономного инструмента, и возможно, то же самое было сделано с выбранной вами платформой, если вы уже используете миграции в своем проекте.

Никогда не пропустите ни одного поста. Подпишитесь на еженедельную рассылку 100 ТБ и следите за нами в Facebook и Twitter.

Первоначально опубликовано на blog.100tb.com.