Как развернуть приложение ASP.NET с нулевым временем простоя

127

Чтобы развернуть новую версию нашего сайта, мы делаем следующее:

  1. Заархивируйте новый код и загрузите его на сервер.
  2. На рабочем сервере удалите весь живой код из каталога веб-сайта IIS.
  3. Извлеките новый zip-файл с кодом в уже пустой каталог IIS.

Этот процесс полностью запрограммирован и происходит довольно быстро, но все же может быть 10-20 секундный простой, когда старые файлы удаляются, а новые файлы развертываются.

Есть предложения по методу простоя 0 секунд?

Карл Гленнон
источник
Разве это не должно быть на ServerFault?
Daniel Rodriguez
49
Возможно, но ServerFault не существовал в сентябре 2008 г.
Карл Гленнон
3
Может ли IIS указывать на папку с символической ссылкой? Приведет ли изменение символической ссылки к повторному использованию процесса IIS?
Нил Макгиган
любое окончательное решение с полным образцом сценария исходного кода?
Kiquenet
Разве нельзя иметь несколько пулов приложений и переключать трафик из одного пула приложений в другой?
Люк,

Ответы:

79

Вам нужно 2 сервера и балансировщик нагрузки. Вот шаги:

  1. Включите весь трафик на Сервер 2
  2. Развернуть на сервере 1
  3. Тестовый сервер 1
  4. Включите весь трафик на Сервер 1
  5. Развернуть на сервере 2
  6. Тестовый сервер 2
  7. Включите трафик на обоих серверах

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

Sklivvz
источник
4
Вы также можете настроить балансировщик нагрузки так, чтобы он обслуживал существующие сеансы для данного сервера, но не принимал новые. Это позволяет избежать прерывания сессий. Однако этот метод требует ожидания завершения сеанса, и, как правило, вы захотите написать сценарий.
35
Этот метод имеет тенденцию терпеть неудачу, когда набор кода содержит структурные изменения в базе данных. После обновления БД для сервера 1 сервер 2 взорвется. Теперь вы можете сделать резервную копию / восстановить базу данных для тестирования на сервере 1, но тогда у вас возникнет проблема с сортировкой данных, которые изменились в реальной БД во время работы параллельной копии.
EBarr
1
@AndreiRinea - как вы думаете, это будет работать в OLTP-системе большого объема? Либо система выходит из синхронизации, и вы теряете данные при переключении, либо вам нужно приостановить ввод данных и написать сценарий для идентификации и переноса временных данных в новую структуру БД.
EBarr 05
9
@EBarr: и в любом случае технически у вас по-прежнему нулевое время простоя в приложении ASP.NET - вопрос не в том, «как развернуть базу данных sql server с нулевым временем простоя».
Sklivvz
6
Их ключ - развиваться таким образом, чтобы ваши изменения sql не были разрушительными. Вам часто приходится вносить какие-либо деструктивные изменения sql в следующий выпуск, когда он больше не используется. Это не сложно сделать с практикой.
Bealer
60

Инструмент Microsoft Web Deployment поддерживает это в некоторой степени:

Включает поддержку транзакционной файловой системы Windows (TxF). Когда включена поддержка TxF, файловые операции атомарны; то есть они либо преуспевают, либо полностью проиграют. Это гарантирует целостность данных и предотвращает появление данных или файлов в «наполовину» или поврежденном состоянии. В MS Deploy TxF по умолчанию отключен.

Похоже, транзакция предназначена для всей синхронизации. Кроме того, TxF - это функция Windows Server 2008, поэтому эта функция транзакции не будет работать с более ранними версиями.

Я считаю, что можно изменить ваш сценарий для нулевого простоя, используя папки в качестве версий и метабазу IIS:

  • для существующего пути / URL:
  • Скопируйте новый (или измененный) сайт на сервер под
    • \ Web \ приложение \ v2.1 \
  • Измените метабазу IIS, чтобы изменить путь к веб-сайту
    • из \ web \ app \ 2.0 \
    • в \ web \ app \ v2.1 \

Этот метод дает следующие преимущества:

  • Если в новой версии возникнут проблемы, вы можете легко вернуться к версии 2.0.
  • Для развертывания на нескольких физических или виртуальных серверах вы можете использовать свой сценарий для развертывания файлов. Как только на всех серверах будет установлена ​​новая версия, вы можете одновременно изменить метабазы ​​всех серверов с помощью Microsoft Web Deployment Tool.
Георгий Циокос
источник
5
Я реализовал этот подход, адаптировав наши сценарии развертывания PowerShell. Вы можете увидеть часть сценария, которая изменяет папку сайта IIS здесь: stackoverflow.com/questions/330608/… Спасибо за указатель.
Карл Гленнон,
17
К сожалению, этот метод не учитывает структурные изменения БД. Как только вы обновите БД до версии 2.1, версия 2.0 взорвется.
EBarr
8
Использование TxF здесь излишне, ИМО. Ничего не повредит одновременное наличие в файловой системе версий 2.0 и 2.1. Большое изменение происходит, когда v2.1 выходит в сеть, и к этому времени транзакция TxF уже зафиксирована. Нулевое время простоя действительно происходит из-за того, как IIS перемещается со старого AppPool на новый, а не из-за TxF.
RickNZ
5
Другая проблема заключается в том, что большой объем пользовательских данных хранится во вложенных папках папок приложения.
Кенни Эвитт, 06
4
Это не 0-секундное развертывание, потому что необходимо запустить новое приложение.
usr
12

Вы можете добиться нулевого времени простоя при развертывании на одном сервере, используя маршрутизацию запросов приложений в IIS в качестве программного балансировщика нагрузки между двумя локальными сайтами IIS на разных портах. Это известно как сине-зеленая стратегия развертывания, при которой только один из двух сайтов доступен в балансировщике нагрузки в любой момент времени. Разверните на «неработающем» сайте, прогрейте его и перенесите в подсистему балансировки нагрузки (обычно путем прохождения проверки работоспособности маршрутизации запросов приложений), затем возьмите исходный сайт, который был запущен, из «пула» (опять же путем сбоя проверки работоспособности).

Полное руководство можно найти здесь.

Кавун
источник
7

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

Для моей конфигурации у меня был веб-каталог для каждого сайта A и B, например: c: \ Intranet \ Live A \ Interface c: \ Intranet \ Live B \ Interface

В IIS у меня есть два идентичных сайта (одинаковые порты, аутентификация и т. Д.), Каждый со своим собственным пулом приложений. Один из сайтов работает (A), а другой остановлен (B). живой также имеет заголовок живого хоста.

Когда дело доходит до развертывания в реальном времени, я просто публикую на сайте ОСТАНОВЛЕННЫЙ. Поскольку я могу получить доступ к сайту B, используя его порт, я могу предварительно прогреть сайт, чтобы первый пользователь не вызвал запуск приложения. Затем с помощью командного файла я копирую заголовок живого хоста в B, останавливаю A и запускаю B.

Роб Кинг
источник
1
Это помогает сократить время простоя из-за копирования файлов, но имеет ту же проблему, что и @Sklivvz - как только в ролике кода будут внесены структурные изменения в базу данных, сайт начнет бурно развиваться.
EBarr
Мне это тоже показалось интуитивно понятным, но почему нет простого встроенного способа сделать это?
Петрус Терон
3
@Ebarr, тогда не запускайте деструктивные изменения sql. Например, если вам нужно удалить столбец, сделайте это в следующем выпуске, когда он больше не используется А или Б.
Билер,
@Bealer - согласен (с оговоркой). Существует целая серия этих вопросов о «простоях во время кодовых ролей». Мне еще предстоит найти книгу, которая действительно обсуждала бы реалии развития схемы БД. Предостережение - двухэтапные изменения схемы сопряжены с рядом сложностей. Один пример - многие ORM блокируют, если определение таблицы отличается от определения в том виде, в котором оно понимается (новые или отсутствующие столбцы).
EBarr
2
@Rob, как можно "прогреть" сайт, если он остановлен?
Эндрю Джи
7

Используя класс ServerManager Microsoft.Web.Administration, вы можете разработать свой собственный агент развертывания.

Хитрость заключается в том, чтобы изменить PhysicalPath VirtualDirectory, что приводит к атомарному переключению между старыми и новыми веб-приложениями.

Имейте в виду, что это может привести к параллельному выполнению старых и новых доменов приложений!

Проблема в том, как синхронизировать изменения в базах данных и т. Д.

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

Чтобы принудительно запустить AppDomain, вы должны сделать HTTP-запрос (IIS 7.5 поддерживает функцию автозапуска)

Теперь вам нужен способ блокировать запросы для нового домена приложения. Я использую именованный мьютекс, который создается и принадлежит агенту развертывания, ожидает его Application_Start нового веб-приложения, а затем освобождает агент развертывания после обновления базы данных.

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

разъем
источник
6

Хорошо, так как все опускают ответ, который я написал еще в 2008 году * ...

Я расскажу вам, как мы это делаем сейчас, в 2014 году. Мы больше не используем веб-сайты, потому что сейчас мы используем ASP.NET MVC.

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

Кроме того, мы не полагаемся на последний мастер от Microsoft - он слишком медленный, слишком много скрытого волшебства и слишком склонен к смене имени.

Вот как мы это делаем:

  1. У нас есть этап пост-сборки, который копирует сгенерированные библиотеки DLL в папку bin-pub.

  2. Мы используем Beyond Compare (что отлично **) для проверки и синхронизации измененных файлов (через FTP, потому что это широко поддерживается) до рабочего сервера.

  3. У нас есть защищенный URL-адрес на веб-сайте, содержащий кнопку, которая копирует все, что находится в bin-pub, в bin (сначала делается резервная копия, чтобы обеспечить быстрый откат). На этом этапе приложение перезапускается. Затем наша ORM проверяет, есть ли какие-либо таблицы или столбцы, которые нужно добавить, и создает их.

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

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

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

** Мы всегда внимательно следим за изменениями, которые мы развертываем - в качестве двойной проверки в последнюю минуту, чтобы мы знали, что тестировать, и если что-то ломается, мы готовы. Мы используем Beyond Compare, потому что он позволяет легко сравнивать файлы по FTP. Я бы никогда этого не сделал без BC, вы понятия не имеете, что перезаписываете.

* Прокрутите вниз, чтобы увидеть это :( Кстати, я бы больше не рекомендовал веб-сайты, потому что они медленнее строятся и могут сильно вылетать из-за наполовину скомпилированных временных файлов. Мы использовали их в прошлом, потому что они позволяли более гибкие файлы для файлов Развертывание. Очень быстро исправить мелкую проблему, и вы сможете точно увидеть, что развертываете (если, конечно, используете Beyond Compare - иначе забудьте об этом).

Майк Нельсон
источник
Но вы все равно получите простои, потому что пул приложений перерабатывается.
testpattern 07
Нет, без простоев, потому что запросы автоматически буферизуются IIS во время перезапуска приложения
Майк Нельсон,
5

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

Сэм Мелдрам
источник
1

Я бы немного уточнить ответ Джорджа для одного сервера следующим образом:

  1. Используйте проект веб-развертывания для предварительной компиляции сайта в единую DLL.
  2. Заархивируйте новый сайт и загрузите его на сервер
  3. Разархивируйте его в новую папку, расположенную в папке с правильными разрешениями для сайта, чтобы распакованные файлы правильно наследовали разрешения (возможно, e: \ web с подпапками v20090901, v20090916 и т. Д.)
  4. Используйте диспетчер IIS, чтобы изменить имя папки, содержащей сайт
  5. Сохраните старую папку на некоторое время, чтобы вы могли вернуться к ней в случае проблем.

Шаг 4 вызовет перезапуск рабочего процесса IIS.

Это просто нулевое время простоя, если вы не используете сеансы InProc; вместо этого используйте режим SQL, если можете (даже лучше, полностью избегать состояния сеанса).

Конечно, это немного сложнее, когда есть несколько серверов и / или изменений в базе данных ....

RickNZ
источник
1
Та же проблема, что и у @Sklivvz - этот метод перестает работать, как только в ролике кода происходят структурные изменения в базе данных.
EBarr
3
Вот почему я сказал, что это более активно, когда происходят изменения БД ... Развертывание кода со структурными изменениями в БД - это не просто проблема развертывания; также должна быть поддержка в коде и, вероятно, в БД тоже.
RickNZ
1

Чтобы расширить ответ sklivvz, который полагался на наличие какого-то балансировщика нагрузки (или просто резервной копии на том же сервере)

  1. Направлять весь трафик на Сайт / Сервер 2
  2. При желании немного подождите, чтобы убедиться, что как можно меньше пользователей имеют ожидающие рабочие процессы в развернутой версии.
  3. Разверните на Site / Server 1 и максимально разогрейте его
  4. Выполнять миграции базы данных транзакционным способом (стремиться сделать это возможным)
  5. Немедленно направлять весь трафик на Сайт / Сервер 1
  6. Развернуть на сайт / сервер 2
  7. Прямой трафик на оба сайта / сервера

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

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

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

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

gliljas
источник
1

Вот как я это делаю:

Абсолютные минимальные системные требования:
1 сервер с

  • 1 балансировщик нагрузки / обратный прокси (например, nginx), работающий на порту 80
  • 2 ASP.NET-Core / mono reverse-proxy / fastcgi chroot-jails или docker-контейнеры, прослушивающие 2 разных TCP-порта
    (или даже два приложения обратного прокси на 2 разных TCP-портах без какой-либо песочницы)

Процедура:

начать транзакцию myupdate

try
    Web-Service: Tell all applications on all web-servers to go into primary read-only mode 
    Application switch to primary read-only mode, and responds 
    Web sockets begin notifying all clients 
    Wait for all applications to respond

    wait (custom short interval)

    Web-Service: Tell all applications on all web-servers to go into secondary read-only mode 
    Application switch to secondary read-only mode (data-entry fuse)
    Updatedb - secondary read-only mode (switches database to read-only)

    Web-Service: Create backup of database 
    Web-Service: Restore backup to new database
    Web-Service: Update new database with new schema 

    Deploy new application to apt-repository 
    (for windows, you will have to write your own custom deployment web-service)
    ssh into every machine in array_of_new_webapps
    run apt-get update
    then either 
    apt-get dist-upgrade
    OR
    apt-get install <packagename>
    OR 
    apt-get install --only-upgrade <packagename>
    depending on what you need
    -- This deploys the new application to all new chroots (or servers/VMs)

    Test: Test new application under test.domain.xxx
    -- everything that fails should throw an exception here
    commit myupdate;

    Web-Service: Tell all applications to send web-socket request to reload the pages to all clients at time x (+/- random number)
    @client: notify of reload and that this causes loss of unsafed data, with option to abort 

    @ time x:  Switch load balancer from array_of_old_webapps to array_of_new_webapps 
    Decomission/Recycle array_of_old_webapps, etc.

catch
        rollback myupdate 
        switch to read-write mode
        Web-Service: Tell all applications to send web-socket request to unblock read-only mode
end try 
Стефан Штайгер
источник
-7

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

Не уверен, что это помогает в «веб-приложении» (я думаю, вы говорите, что это то, что вы используете), поэтому мы всегда используем «веб-сайты». Также при развертывании «веб-сайтов» ваш сайт не перезапускается и не прерываются все пользовательские сеансы.

Майк Нельсон
источник
Привет, Майк! Вы можете удалить этот ответ.
Сохаил Ахмед