Jak wdrożyć aplikację ASP.NET bez przestojów

127

Aby wdrożyć nową wersję naszej strony internetowej, wykonujemy następujące czynności:

  1. Spakuj nowy kod i prześlij go na serwer.
  2. Na aktywnym serwerze usuń cały aktywny kod z katalogu witryny sieci Web usług IIS.
  3. Wyodrębnij nowy plik ZIP z kodem do teraz pustego katalogu usług IIS

Cały ten proces jest oparty na skryptach i przebiega dość szybko, ale nadal może wystąpić przerwa w działaniu wynosząca 10–20 sekund, gdy stare pliki są usuwane, a nowe są wdrażane.

Jakieś sugestie dotyczące metody 0 sekund przestoju?

Karl Glennon
źródło
Czy nie powinno to być na ServerFault?
Daniel Rodriguez
50
Być może, ale ServerFault nie istniał we wrześniu 2008
Karl Glennon
3
Czy usługi IIS mogą wskazywać folder łączy symbolicznych? Czy zmiana łącza symbolicznego spowoduje ponowne uruchomienie procesu IIS?
Neil McGuigan
jakieś ostateczne rozwiązanie z pełnym przykładem skryptu kodu źródłowego?
Kiquenet
Czy nie jest możliwe posiadanie wielu pul aplikacji i przełączanie ruchu z jednej puli aplikacji na drugą?
Łukasz

Odpowiedzi:

79

Potrzebujesz 2 serwerów i modułu równoważenia obciążenia. Oto kroki:

  1. Włącz cały ruch na serwerze 2
  2. Wdróż na serwerze 1
  3. Serwer testowy 1
  4. Włącz cały ruch na serwerze 1
  5. Wdróż na serwerze 2
  6. Serwer testowy 2
  7. Włącz ruch na obu serwerach

Chodzi o to, że nawet w tym przypadku nadal będziesz mieć ponowne uruchomienie aplikacji i utratę sesji, jeśli używasz „trwałych sesji”. Jeśli masz sesje bazy danych lub serwer stanu, wszystko powinno być w porządku.

Sklivvz
źródło
4
Możesz również skonfigurować load balancer tak, aby obsługiwał istniejące sesje dla danego serwera, ale nie akceptował nowych. Pozwala to uniknąć porzucania sesji. Ta technika wymaga jednak czekania na zakończenie sesji i ogólnie będziesz chciał to napisać.
36
Ta metoda ma tendencję do upadku, gdy rolka kodu ma zmiany strukturalne w bazie danych. Po uaktualnieniu DB dla serwera 1, serwer 2 eksploduje. Teraz możesz wykonać kopię zapasową / przywrócić bazę danych do testowania na serwerze 1, ale wtedy masz problem z sortowaniem danych, które uległy zmianie w aktywnej bazie danych podczas wykonywania kopii równoległej.
EBarr
1
@AndreiRinea - jak przypuszczasz, że to zadziała w systemie OLTP o dużej objętości? Albo system traci synchronizację i tracisz dane po przecięciu, albo musisz wstrzymać wprowadzanie danych i napisać skrypt w celu zidentyfikowania i migracji danych przejściowych do nowej struktury bazy danych.
EBarr
11
@EBarr: w każdym razie technicznie nadal nie masz żadnych przestojów w aplikacji ASP.NET - nie chodzi o „jak wdrożyć na serwerze SQL bez przestojów”.
Sklivvz
6
Kluczem jest rozwój w taki sposób, aby zmiany w sql nie były destrukcyjne. Często trzeba dokonywać jakichkolwiek destrukcyjnych zmian sql w następnej wersji, gdy nie jest już używana. Nie jest to trudne do zrobienia z praktyką.
Bealer
60

Narzędzie Microsoft Web Deployment obsługuje to do pewnego stopnia:

Włącza obsługę transakcyjnego systemu plików Windows (TxF). Gdy obsługa formatu TxF jest włączona, operacje na plikach są atomowe; to znaczy, albo odnoszą sukces, albo całkowicie ponoszą porażkę. Zapewnia to integralność danych i zapobiega istnieniu danych lub plików w stanie „w połowie” lub uszkodzeniu. W MS Deploy TxF jest domyślnie wyłączone.

Wygląda na to, że transakcja dotyczy całej synchronizacji. Ponadto TxF jest funkcją systemu Windows Server 2008, więc ta funkcja transakcji nie będzie działać z wcześniejszymi wersjami.

Uważam, że możliwe jest zmodyfikowanie skryptu w celu wyeliminowania przestojów przy użyciu folderów jako wersji i metabazy usług IIS:

  • dla istniejącej ścieżki / adresu URL:
  • Skopiuj nową (lub zmodyfikowaną) witrynę na serwer pod
    • \ web \ app \ v2.1 \
  • Zmodyfikuj metabazę usług IIS, aby zmienić ścieżkę witryny internetowej
    • z \ web \ app \ 2.0 \
    • do \ web \ app \ v2.1 \

Ta metoda oferuje następujące korzyści:

  • W przypadku wystąpienia problemu z nową wersją można łatwo przywrócić wersję 2.0
  • Aby wdrożyć na wielu serwerach fizycznych lub wirtualnych, możesz użyć skryptu do wdrożenia plików. Gdy wszystkie serwery będą miały nową wersję, możesz jednocześnie zmieniać metabazy wszystkich serwerów za pomocą narzędzia Microsoft Web Deployment Tool.
George Tsiokos
źródło
5
Zaimplementowałem to podejście, dostosowując nasze skrypty wdrażania PowerShell. Możesz zobaczyć część skryptu, która zmienia folder witryny IIS tutaj: stackoverflow.com/questions/330608/ ... Dzięki za wskaźnik.
Karl Glennon,
17
Niestety ta metoda nie uwzględnia zmian strukturalnych w DB. Po zaktualizowaniu bazy danych do wersji 2.1 wybucha wersja 2.0.
EBarr
8
Używanie TxF to przesada, IMO. Posiadanie w systemie plików zarówno wersji 2.0, jak i wersji 2.1, nic nie szkodzi. Wielka zmiana następuje, gdy wersja 2.1 przechodzi do trybu online i do tego czasu transakcja TxF została zatwierdzona. Zero przestojów ma miejsce naprawdę ze względu na sposób, w jaki IIS przenosi się ze starego AppPool do nowego, a nie z powodu TxF.
RickNZ
5
Innym problemem jest to, że duża ilość danych użytkownika jest przechowywana w podfolderach folderów aplikacji.
Kenny Evitt,
4
To nie jest wdrożenie trwające 0 sekund, ponieważ nowa aplikacja musi zostać uruchomiona.
usr
12

Można osiągnąć zero przestojów na jednym serwerze, wykorzystując routing żądań aplikacji w usługach IIS jako programowy system równoważenia obciążenia między dwoma lokalnymi lokacjami usług IIS na różnych portach. Jest to tzw. Niebiesko-zielona strategia wdrażania, w której w danym momencie w module równoważenia obciążenia dostępna jest tylko jedna z dwóch witryn. Wdróż w witrynie, która jest „wyłączona”, rozgrzej ją i przenieś do systemu równoważenia obciążenia (zwykle przez sprawdzenie stanu routingu żądań aplikacji), a następnie wyjmij pierwotną lokację, która była aktywna, z „puli” (ponownie sprawiając, że jego kontrola stanu nie powiedzie się).

Pełen samouczek można znaleźć tutaj.

kavun
źródło
7

Niedawno przeszedłem przez to i rozwiązanie, które wymyśliłem, polegało na skonfigurowaniu dwóch witryn w IIS i przełączaniu się między nimi.

Dla mojej konfiguracji miałem katalog sieciowy dla każdej witryny A i B w następujący sposób: c: \ Intranet \ Live A \ Interface c: \ Intranet \ Live B \ Interface

W usługach IIS mam dwie identyczne witryny (te same porty, uwierzytelnianie itp.), Z których każda ma własną pulę aplikacji. Jedna z witryn jest uruchomiona (A), a druga jest zatrzymana (B). live ma również nagłówek live hosta.

Jeśli chodzi o wdrożenie na żywo, po prostu publikuję w lokalizacji STOPPED. Ponieważ mogę uzyskać dostęp do witryny B za pomocą jej portu, mogę wstępnie ją ogrzać, aby pierwszy użytkownik nie spowodował uruchomienia aplikacji. Następnie za pomocą pliku wsadowego kopiuję nagłówek hosta na żywo do B, zatrzymuję A i uruchamiam B.

Rob King
źródło
1
Pomaga to w przestojach spowodowanych kopiowaniem plików, ale ma ten sam problem co @Sklivvz - gdy tylko rolka kodu zawiera zmiany strukturalne w bazie danych, witryna zaczyna się rozwijać.
EBarr
Wydawało mi się to również intuicyjną metodą, ale dlaczego nie ma na to łatwego, wbudowanego sposobu?
Petrus Theron,
3
@Ebarr to nie wprowadzaj destrukcyjnych zmian sql. Na przykład, jeśli chcesz usunąć kolumnę, zrób to w następnej wersji, gdy nie jest już używana przez A lub B.
Bealer,
@Bealer - zgadza się (z zastrzeżeniem). Jest cała seria tych pytań na temat „przestojów podczas ról kodu”. Nie znalazłem jeszcze takiego, który naprawdę omawia realia ewolucji schematu DB. Ostrzeżenie - istnieje wiele komplikacji, które towarzyszą dwufazowym zmianom schematu. Jeden przykład - wiele elementów ORM, jeśli definicja tabeli różni się od definicji w jej rozumieniu (nowe lub brakujące kolumny).
EBarr
2
@Rob Jak można „wstępnie ogrzać” witrynę po jej zatrzymaniu?
Andrew Gee
7

Za pomocą klasy ServerManager firmy Microsoft.Web.Administration można opracować własnego agenta wdrożeniowego.

Sztuczka polega na zmianie PhysicalPath w VirtualDirectory, co skutkuje atomowym przełączaniem online między starymi i nowymi aplikacjami internetowymi.

Należy pamiętać, że może to spowodować równoległe uruchamianie starych i nowych AppDomains!

Problem w tym, jak zsynchronizować zmiany w bazach danych itp.

Dzięki odpytywaniu pod kątem istnienia domen AppDomains ze starymi lub nowymi PhysicalPaths można wykryć, kiedy stare domeny AppDomain zostały zakończone i czy nowe domeny AppDomain zostały uruchomione.

Aby wymusić uruchomienie AppDomain, należy wysłać żądanie HTTP (usługi IIS 7.5 obsługują funkcję Autostart)

Teraz potrzebujesz sposobu na blokowanie żądań dla nowej domeny AppDomain. Używam nazwanego muteksu - który jest tworzony i będący własnością agenta wdrażania, czekany przez Application_Start nowej aplikacji internetowej, a następnie zwalniany przez agenta wdrażania po wykonaniu aktualizacji bazy danych.

(Używam pliku znacznika w aplikacji internetowej, aby włączyć zachowanie oczekiwania mutex) Po uruchomieniu nowej aplikacji internetowej usuwam plik znacznika.

Jacek
źródło
6

OK, więc ponieważ wszyscy odrzucają odpowiedź, którą napisałem w 2008 roku * ...

Powiem Ci, jak robimy to teraz w 2014 roku. Nie używamy już witryn sieci Web, ponieważ używamy teraz ASP.NET MVC.

Z pewnością nie potrzebujemy do tego modułu równoważenia obciążenia i dwóch serwerów, to dobrze, jeśli masz 3 serwery na każdą utrzymywaną witrynę, ale w przypadku większości witryn jest to całkowita przesada.

Nie polegamy też na najnowszym kreatorze firmy Microsoft - jest on zbyt wolny i zawiera zbyt wiele ukrytej magii oraz jest zbyt podatny na zmianę nazwy.

Oto jak to robimy:

  1. Mamy krok po kompilacji, który kopiuje wygenerowane biblioteki DLL do folderu „bin-pub”.

  2. Używamy Beyond Compare (co jest doskonałe **) do weryfikacji i synchronizacji zmienionych plików (przez FTP, ponieważ jest to szeroko obsługiwane) do serwera produkcyjnego

  3. Na naszej stronie mamy bezpieczny adres URL zawierający przycisk, który kopiuje wszystko z „bin-pub” do „bin” (najpierw wykonuje kopię zapasową, aby umożliwić szybkie przywrócenie). W tym momencie aplikacja uruchomi się ponownie. Następnie nasz ORM sprawdza, czy są jakieś tabele lub kolumny, które należy dodać i tworzy je.

To tylko milisekundy przestoju. Ponowne uruchomienie aplikacji może zająć sekundę lub dwie, ale żądania ponownego uruchomienia są buforowane, więc przestoje są praktycznie zerowe.

Cały proces wdrażania trwa od 5 sekund do 30 minut, w zależności od tego, ile plików zostało zmienionych i ile zmian do przejrzenia.

W ten sposób nie musisz kopiować całej witryny do innego katalogu, ale tylko do folderu bin. Masz również pełną kontrolę nad procesem i dokładnie wiesz, co się zmienia.

** Zawsze szybko przyglądamy się wprowadzanym zmianom - w ostatniej chwili sprawdzamy dwukrotnie, dzięki czemu wiemy, co przetestować i jeśli coś się zepsuje, jesteśmy gotowi. Używamy Beyond Compare, ponieważ umożliwia łatwe porównywanie plików przez FTP. Nigdy nie zrobiłbym tego bez BC, nie masz pojęcia, co nadpisujesz.

* Przewiń w dół, aby to zobaczyć :( Przy okazji nie polecałbym już witryn internetowych, ponieważ są wolniejsze w tworzeniu i mogą powodować poważne awarie z częściowo skompilowanymi plikami tymczasowymi. Używaliśmy ich w przeszłości, ponieważ pozwalały na bardziej zwinne pliki po pliku Wdrażanie. Bardzo szybkie rozwiązanie drobnego problemu i możesz dokładnie zobaczyć, co wdrażasz (oczywiście jeśli używasz Beyond Compare - w przeciwnym razie zapomnij o tym).

mike nelson
źródło
Jednak nadal będziesz mieć przestoje, ponieważ pula aplikacji jest odtwarzana.
testpattern
Nie, brak przestojów, ponieważ żądania są automatycznie buforowane przez IIS podczas ponownego uruchamiania aplikacji
mike nelson
5

Jedyne metody zerowych przestojów, jakie przychodzą mi do głowy, obejmują hosting na co najmniej 2 serwerach.

Sam Meldrum
źródło
1

Uściśliłbym nieco odpowiedź George'a w następujący sposób dla pojedynczego serwera:

  1. Użyj projektu wdrażania w sieci Web, aby wstępnie skompilować witrynę do pojedynczej biblioteki DLL
  2. Spakuj nową witrynę i prześlij ją na serwer
  3. Rozpakuj go do nowego folderu znajdującego się w folderze z odpowiednimi uprawnieniami do witryny, aby rozpakowane pliki prawidłowo dziedziczyły uprawnienia (być może e: \ web, z podfolderami v20090901, v20090916 itp.)
  4. Użyj Menedżera usług IIS, aby zmienić nazwę folderu zawierającego witrynę
  5. Zachowaj stary folder przez chwilę, aby w razie problemów móc do niego wrócić

Krok 4 spowoduje odtworzenie procesu roboczego usług IIS.

To tylko zero przestojów, jeśli nie używasz sesji InProc; zamiast tego użyj trybu SQL, jeśli możesz (nawet lepiej, całkowicie unikaj stanu sesji).

Oczywiście jest to trochę bardziej skomplikowane, gdy występuje wiele serwerów i / lub zmian w bazie danych ....

RickNZ
źródło
1
Ten sam problem, co w przypadku @Sklivvz - ta metoda nie działa, gdy tylko rolka kodu zawiera zmiany strukturalne w bazie danych.
EBarr
3
Dlatego powiedziałem, że jest to bardziej zaangażowane, gdy są zmiany w bazie danych ... Wdrażanie kodu ze zmianami strukturalnymi w DB to nie tylko kwestia wdrożenia; musi być również wsparcie w kodzie i prawdopodobnie również w DB.
RickNZ
1

Aby rozwinąć odpowiedź sklivvz, która polegała na posiadaniu pewnego rodzaju modułu równoważenia obciążenia (lub po prostu kopii zapasowej na tym samym serwerze)

  1. Skieruj cały ruch do witryny / serwera 2
  2. Opcjonalnie poczekaj chwilę, aby upewnić się, że jak najmniejsza liczba użytkowników ma oczekujące przepływy pracy we wdrożonej wersji
  3. Wdróż w lokacji / serwerze 1 i rozgrzej go tak bardzo, jak to możliwe
  4. Przeprowadzaj migracje baz danych transakcyjnie (staraj się, aby było to możliwe)
  5. Natychmiast przekieruj cały ruch do lokalizacji / serwera 1
  6. Wdróż w lokacji / serwerze 2
  7. Kieruj ruch do obu witryn / serwerów

Możliwe jest wprowadzenie trochę testowania dymu, tworząc migawkę / kopię bazy danych, ale nie zawsze jest to wykonalne.

Jeśli to możliwe i potrzebne, użyj „różnic w routingu”, takich jak różne adresy URL dzierżawcy (customerX.myapp.net) lub różni użytkownicy, aby wdrożyć najpierw w nieświadomej grupie świnek morskich. Jeśli nic nie zawiedzie, zwolnij wszystkich.

Ponieważ w grę wchodzą migracje baz danych, przywrócenie poprzedniej wersji jest często niemożliwe.

Istnieją sposoby, aby aplikacje działały przyjemniej w tych scenariuszach, na przykład za pomocą kolejek zdarzeń i mechanizmów odtwarzania, ale ponieważ mówimy o wdrażaniu zmian w czymś, co jest w użyciu, naprawdę nie ma żadnego niezawodnego sposobu.

gliljas
źródło
1

Oto jak to robię:

Absolutnie minimalne wymagania systemowe:
1 serwer z

  • 1 load balancer / reverse proxy (np. Nginx) działający na porcie 80
  • 2 ASP.NET-Core / mono reverse-proxy / fastcgi chroot-jails lub docker-container nasłuchujące na 2 różnych portach TCP
    (lub nawet tylko dwie aplikacje z odwrotnym proxy na 2 różnych portach TCP bez piaskownicy)

Przepływ pracy:

rozpocznij transakcję 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 
Stefan Steiger
źródło
-7

Proponuję zachować tam stare pliki i po prostu je nadpisać. W ten sposób przestój jest ograniczony do czasu nadpisywania pojedynczego pliku, a na raz brakuje tylko jednego pliku.

Nie jestem pewien, czy to pomaga w „aplikacji sieciowej” (myślę, że właśnie tego używasz), dlatego zawsze używamy „witryn internetowych”. Również w przypadku „witryn internetowych” wdrożenie nie powoduje ponownego uruchomienia witryny i porzucenia wszystkich sesji użytkowników.

mike nelson
źródło
Cześć Mike, Możesz usunąć tę odpowiedź.
Sohail Ahmed