Достижение нулевого времени простоя развертывания

40

Я пытаюсь добиться развертывания без простоев, чтобы я мог развертывать меньше в нерабочее время и больше в «более медленные» часы - или в любое время, теоретически.

Моя текущая настройка несколько упрощена:

  • Веб-сервер A (приложение .NET)
  • Веб-сервер B (приложение .NET)
  • Сервер базы данных (SQL Server)

Мой текущий процесс развертывания:

  1. «Остановить» сайты на веб-сервере A и B
  2. Обновите схему базы данных для версии развертываемого приложения.
  3. Обновить веб-сервер A
  4. Обновить веб-сервер B
  5. Верните все в онлайн

Текущая проблема

Это приводит к небольшому количеству простоев каждый месяц - около 30 минут. Я делаю это в нерабочее время, так что это не большая проблема, но я бы хотел от этого уйти.

Кроме того, нет никакого способа действительно вернуться назад. Я обычно не делаю сценарии отката БД - только сценарии обновления.

Использование балансировщика нагрузки

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

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

Возможное решение

Текущее решение, которое я рассматриваю, заключается в принятии следующих правил:

  • Никогда не удаляйте таблицу базы данных.
  • Никогда не удаляйте столбец базы данных.
  • Никогда не переименовывайте столбец базы данных.
  • Никогда не переупорядочивайте столбец.
  • Каждая хранимая процедура должна быть версионной.
    • Значение - spFindAllThings станет spFindAllThings_2 при редактировании.
    • Затем он становится «spFindAllThings_3» при повторном редактировании.
    • То же правило относится к представлениям.

Хотя это кажется немного экстремальным - я думаю, что это решает проблему. Каждая версия приложения будет бесперебойно работать с БД. Код ожидает определенных результатов от представлений / хранимых процедур - и это сохраняет этот «контракт» действительным. Проблема в том, что он просто просачивается. Я знаю, что могу вычистить старые хранимые процедуры после того, как приложение будет развернуто некоторое время, но оно просто кажется грязным. Кроме того - это зависит от всех разработчиков, придерживающихся этого правила, что в основном произойдет, но я предполагаю, что кто-то допустит ошибку.

Наконец - мой вопрос

  • Это неряшливый или хакерский?
  • Кто-нибудь еще делает это так?
  • Как другие люди решают эту проблему?
MattW
источник
2
Где ваш план отступления? Как вы проверяете, что все работает и нет регрессий?
Охотник на оленей
3
Вам не нужно «никогда»: вам «только» нужно убедиться, что каждые две смежные версии могут работать одновременно. Это ограничивает ваши пути обновления, но не настолько серьезно, как никогда, когда вы не сможете существенно изменить схему БД.
Иоахим Зауэр
Спасибо, Йоахим ... Мне нравится говорить в абсолютах, чтобы основная идея была ясна - но вы правы, у нас может быть политика обратной совместимости с N выпусками, после чего мы можем удалить ненужные объекты БД.
MattW
2
Вы хотите иметь план отката на месте. Однажды вам это понадобится.
Торбьерн Равн Андерсен
1
По моему опыту, для большинства сайтов ваше возможное решение хуже, чем проблема, которую он решает. Сложность, которую он добавит, будет дороже, чем вы можете ожидать сейчас. Возможно, во много раз больше времени / усилий для внесения изменений и добавления функций. Я бы рассмотреть его только для сайтов , которые абсолютно не могут любые имеют простои, когда - либо .
MGOwen

Ответы:

14

Это очень прагматичный подход к обновлениям программного обеспечения при поддержке баз данных. Он был описан Мартином Фаулером и Прамодом Садаладжем в 2003 году и впоследствии написан в « Рефакторинг баз данных: эволюционный дизайн баз данных» .

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

Майк Партридж
источник
5

«Нулевое время простоя» - лишь одна из многих возможных причин такого подхода. Поддержание обратной совместимости модели данных таким образом поможет вам справиться с множеством различных проблем:

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

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

  • импорт / экспорт архивных данных в текущую версию базы данных намного проще

Вот дополнительное правило для вашего списка

  • каждый новый столбец должен иметь значение NULL или содержать значимое значение по умолчанию

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

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

Док Браун
источник
4

Виды варьируются от одного развертывания к другому.

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

Вопрос, который вам нужно задать себе, заключается в том, изменяет ли каждый отдельный выпуск схему таким образом, чтобы она не была обратно совместимой?

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

Две вещи, которые я видел, помогают при развертывании с минимальным временем простоя:

  1. Стремитесь к обратной совместимости - по крайней мере, в одном выпуске. Вы не всегда достигнете этого, но могу поспорить, что вы можете достичь этого на 90% или более ваших выпусков, особенно если каждый выпуск небольшой.
  2. Иметь сценарий базы данных до и после выпуска. Это позволяет обрабатывать переименования или изменения интерфейса, создавая новый объект до развертывания кода приложения, а затем удаляя старый после развертывания кода приложения. Если вы добавите новый столбец без значения NULL, вы можете добавить его в NULL в своем предварительном выпуске сценария с помощью триггера, который заполняет значение по умолчанию. Затем в своем пост-релизе вы можете сбросить курок.

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

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

  • Можете ли вы встроить обратную совместимость в свой код? Например, есть ли способ, которым ваш код может поддерживать несколько типов наборов результатов? Если вам нужно изменить столбец с int на double, код вашего приложения может прочитать его как строку и проанализировать. Что-то вроде хакерства, но если это временный код для прохождения процесса релиза, это может быть не конец света.
  • Хранимые процедуры могут помочь защитить код вашего приложения от изменений схемы. Это может пойти только так далеко, но это немного помогает.
Brandon
источник
2

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

  1. Резервное копирование базы данных путем экспорта
  2. Импортируйте резервную копию, но переименуйте ее с версией выпуска, например, myDb_2_1
  3. Выполнить выпуск базы данных на myDB_2_1
  4. «Остановить» пул приложений на веб-сервере A или вынуть его из балансировщика нагрузки
  5. Обновите веб-сервер A, запустите тесты после внедрения и откат при необходимости
  6. Отбросьте сеанс веб-сервера B и снова включите веб-сервер A
  7. Обновите веб-сервер B и верните его в балансировщик нагрузки.

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

LeoLambrettra
источник
1
Что если (когда) приложение на сервере A записывает данные в свою БД после того, как вы сохранили резервную копию, но до того, как вы остановили сервер A? Всегда есть «окно уязвимости». Эти записи будут потеряны, что может быть неприемлемо.
слеске