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

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

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

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

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


person Karl Glennon    schedule 29.09.2008    source источник
comment
Разве это не должно быть на ServerFault?   -  person Daniel Rodriguez    schedule 19.11.2009
comment
Возможно, но ServerFault не существовало в сентябре 2008 г.   -  person Karl Glennon    schedule 13.05.2010
comment
Может ли IIS указывать на папку с символической ссылкой? Приведет ли изменение символической ссылки к повторному использованию процесса IIS?   -  person Neil McGuigan    schedule 07.05.2012
comment
какое-либо окончательное решение с полным образцом сценария исходного кода?   -  person Kiquenet    schedule 12.12.2012
comment
Разве нельзя иметь несколько пулов приложений и переключать трафик с одного пула приложений на другой?   -  person Luke    schedule 12.01.2016


Ответы (11)


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

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

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

person Sklivvz    schedule 29.09.2008
comment
Вы также можете настроить балансировщик нагрузки так, чтобы он обслуживал существующие сеансы для данного сервера, но не принимал новые. Это позволяет избежать прерывания сессий. Однако этот метод требует ожидания завершения сеанса, и, как правило, вы захотите написать это в сценарии. - person ; 07.10.2009
comment
Этот метод имеет тенденцию терпеть неудачу, когда набор кода содержит структурные изменения в базе данных. После обновления БД для сервера 1 сервер 2 взорвется. Теперь вы можете сделать резервную копию / восстановить базу данных для тестирования на сервере 1, но тогда у вас возникнет проблема с сортировкой данных, которые изменились в живой БД во время работы параллельной копии. - person EBarr; 27.08.2010
comment
@EBarr: версия 2 вообще указывает на другую БД. Таким образом, вы можете оставить сервер 2 на версии 1 при обновлении сервера 1. - person Andrei Rînea; 04.01.2011
comment
@AndreiRinea - как вы думаете, это будет работать в OLTP-системе большого объема? Либо система выходит из синхронизации, и вы теряете данные при переходе, либо вам нужно приостановить ввод данных и написать сценарий для идентификации и переноса временных данных в новую структуру БД. - person EBarr; 06.01.2011
comment
@EBarr: В случае OLTP-системы большого объема вам нужно будет отключить для обслуживания всю систему после того, как вы заранее предупредите пользователей и запретите вход в систему после определенного момента. - person Andrei Rînea; 13.01.2011
comment
@Andrei Rinea --- именно моя точка зрения! Посмотрите на мой первый комментарий .... описанный выше метод не работает. Отсюда возникает вопрос, заданный @Recursieve - как развернуть приложение asp.net с нулевым временем простоя? - person EBarr; 20.01.2011
comment
@EBarr: Забудьте об этом, если вы не планируете вносить изменения в базу данных с нулевым временем простоя. Если вы используете хранимые процедуры, это всегда возможно (возможно, с использованием зеркалирования со свидетелем). - person Sklivvz; 20.01.2011
comment
@EBarr: и в любом случае технически у вас по-прежнему нулевое время простоя в приложении ASP.NET - вопрос не в том, как развернуть базу данных sql server с нулевым временем простоя. - person Sklivvz; 20.01.2011
comment
Это может сработать, если ваш балансировщик нагрузки (или веб-сервер) имеет возможность временно удерживать HTTP-запросы ... но я не знаю ни одного - person Jack; 17.09.2012
comment
@sklivvz, есть ли какой-нибудь пример сценария полного исходного кода об этом? это возможно, может быть Powershell - person Kiquenet; 12.12.2012
comment
Их ключ - развиваться таким образом, чтобы ваши изменения sql не были разрушительными. Вам часто приходится вносить какие-либо деструктивные изменения sql в следующую версию, когда она больше не используется. Это не сложно сделать с практикой. - person Bealer; 19.12.2013
comment
@Bealer эта проблема актуальна в любой конфигурации: если вы зависите от более чем одного компонента, каждое изменение должно быть обратно совместимо, чтобы взаимодействовать с остальными. - person Sklivvz; 19.12.2013
comment
@AminM купить или арендовать другой? :-) Помимо шуток, у вас может быть две версии, работающие на одном сервере, но вам все равно понадобится балансировщик нагрузки для направления трафика, который в этом случае также действует как обратный прокси. - person Sklivvz; 22.01.2016

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

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

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

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

  • for an existing path/url:
  • Copy new (or modified) website to server under
    • \web\app\v2.1\
  • Modify IIS metabase to change the website path
    • from \web\app\2.0\
    • в \ web \ app \ v2.1 \

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

  • Если в новой версии возникнут проблемы, вы можете легко вернуться к версии 2.0.
  • Для развертывания на нескольких физических или виртуальных серверах вы можете использовать свой сценарий для развертывания файлов. Как только на всех серверах будет установлена ​​новая версия, вы можете одновременно изменить метабазы ​​всех серверов с помощью Microsoft Web Deployment Tool.
person George Tsiokos    schedule 13.10.2008
comment
Я реализовал этот подход, адаптировав наши сценарии развертывания PowerShell. Вы можете увидеть часть сценария, которая изменяет папку сайта IIS здесь: stackoverflow.com/questions/330608/ Спасибо за указатель. - person Karl Glennon; 01.12.2008
comment
К сожалению, этот метод не учитывает структурные изменения БД. Как только вы обновите БД до версии 2.1, версия 2.0 взорвется. - person EBarr; 27.08.2010
comment
Использование TxF здесь излишне, ИМО. Ничего не повредит одновременное наличие в файловой системе версий 2.0 и 2.1. Большое изменение происходит, когда v2.1 выходит в онлайн, и к этому времени транзакция TxF уже зафиксирована. Нулевое время простоя действительно происходит из-за того, как IIS перемещается со старого AppPool на новый, а не из-за TxF. - person RickNZ; 29.08.2010
comment
Другая проблема заключается в том, что большой объем пользовательских данных хранится во вложенных папках папок приложения. - person Kenny Evitt; 06.09.2011
comment
не будет работать, если есть зависимости вне веб-приложения (например, db), потому что IIS обрабатывает старые и новые запросы ПАРАЛЛЕЛЬНО - person Jack; 17.09.2012
comment
какой-либо пример сценария полного исходного кода об этом? Powershell может быть - person Kiquenet; 12.12.2012
comment
@Kenny Evitt, вы можете не помещать пользовательские данные в папки и подпапки приложений, а затем помещать их вне папки приложения. Вы можете использовать ключ приложения Web.config для управления между разными средами =) - person Akira Yamamoto; 18.01.2013
comment
Сценарий Powershell для развертывания без простоев с использованием ARR на одном компьютере: github.com/yosoyadri/IIS-ARR-Zero-Downtime/blob/master/ - person Yosoyadri; 04.03.2013
comment
Когда это вызывает перезапуск приложения, остановит ли он все существующие запросы принудительно или сделает это корректно? - person Sam; 07.06.2013
comment
Сессия @Quandary всегда должна быть вне процесса - никогда не используйте ‹sessionState mode = InProc в производстве - person George Tsiokos; 17.03.2014
comment
Кто-нибудь может прокомментировать поддержку TxF в MsDeploy и как ее включить? Я не могу найти никакой информации по этому поводу. - person arni; 21.09.2014
comment
Это не 0-секундное развертывание, потому что необходимо запустить новое приложение. - person usr; 07.01.2015

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

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

person kavun    schedule 08.11.2015

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

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

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

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

person Rob King    schedule 19.11.2009
comment
Это помогает сократить время простоя из-за копирования файлов, но имеет ту же проблему, что и @Sklivvz - как только в ролике кода будут внесены структурные изменения в базу данных, сайт начнет бурно развиваться. - person EBarr; 27.08.2010
comment
Мне это тоже показалось интуитивно понятным, но почему нет простого встроенного способа сделать это? - person Petrus Theron; 09.03.2012
comment
@Ebarr, тогда не развертывайте деструктивные изменения sql. Например, если вам нужно удалить столбец, сделайте это в следующем выпуске, когда он больше не используется A или B. - person Bealer; 19.12.2013
comment
@Bealer - согласен (с оговоркой). Существует целая серия этих вопросов о простоях во время кодовых ролей. Мне еще предстоит найти книгу, которая действительно обсуждала бы реалии развития схемы БД. Предостережение - двухэтапные изменения схемы сопряжены с рядом сложностей. Один пример - многие ORM блокируют, если определение таблицы отличается от определения в том виде, в котором оно понимается (новые или отсутствующие столбцы). - person EBarr; 19.12.2013
comment
@Rob как можно предварительно прогреть сайт, если он остановлен? - person Andrew Gee; 29.01.2014
comment
Мне нравится этот подход для установки с одним сервером. Возможно, не вам решать, как будет выглядеть инфраструктура. - person testpattern; 07.01.2016
comment
@Rob скопирует заголовок живого хоста в B. Вы можете это объяснить? - person Justin J Stark; 15.03.2018

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

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

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

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

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

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

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

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

person Jack    schedule 07.09.2012

Хорошо, так как все голосуют против ответа, который я написал еще в 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 - в противном случае забудьте об этом).

person mike nelson    schedule 09.01.2014
comment
Но у вас все равно будет время простоя, потому что пул приложений перерабатывается. - person testpattern; 07.01.2016
comment
Нет, без простоев, потому что запросы автоматически буферизуются IIS во время перезапуска приложения - person mike nelson; 07.01.2016

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

person Sam Meldrum    schedule 29.09.2008

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

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

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

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

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

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

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

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

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

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

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

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

person gliljas    schedule 15.01.2014

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

Абсолютные минимальные системные требования:
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 
person Stefan Steiger    schedule 07.03.2014

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

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

person mike nelson    schedule 20.11.2008
comment
Привет, Майк! Вы можете удалить этот ответ. - person Sohail Ahmed; 26.02.2019