Sıfır kesinti süresiyle bir ASP.NET Uygulaması nasıl dağıtılır


127

Web sitemizin yeni bir sürümünü dağıtmak için aşağıdakileri yapıyoruz:

  1. Yeni kodu sıkıştırın ve sunucuya yükleyin.
  2. Canlı sunucuda, tüm canlı kodu IIS web sitesi dizininden silin.
  3. Yeni kod zip dosyasını şimdi boş olan IIS dizinine çıkarın

Bu işlemin tamamı komut dosyası ile yazılmıştır ve oldukça hızlı bir şekilde gerçekleşir, ancak eski dosyalar silinirken ve yeni dosyalar dağıtılırken yine de 10-20 saniyelik bir kesinti olabilir.

0 saniyelik bir kesinti yöntemi hakkında herhangi bir öneriniz var mı?


Bunun ServerFault üzerinde olması gerekmez mi?
Daniel Rodriguez

49
Belki, ancak ServerFault Eylül '08'de yoktu
Karl Glennon

3
IIS bir symlink klasörünü gösterebilir mi? Sembolik bağın değiştirilmesi IIS işleminin geri dönüşümüne neden olur mu?
Neil McGuigan

tam kaynak kod komut dosyası örneğiyle herhangi bir nihai çözüm var mı?
Kiquenet

Birden fazla uygulama havuzuna sahip olmak ve trafiği bir uygulama havuzundan diğerine geçirmek mümkün değil mi?
Luke

Yanıtlar:


79

2 sunucuya ve bir yük dengeleyiciye ihtiyacınız var. İşte adımlar:

  1. Sunucu 2'deki tüm trafiği açın
  2. Sunucu 1'e dağıtın
  3. Test Sunucusu 1
  4. Sunucu 1'deki tüm trafiği açın
  5. Sunucu 2'ye dağıtın
  6. Test Sunucusu 2
  7. Her iki sunucuda trafiği açın

Mesele şu ki, bu durumda bile "yapışkan oturumları" kullanıyorsanız, uygulama yeniden başlatılır ve oturum kaybı olur. Veritabanı oturumlarınız veya bir durum sunucunuz varsa, her şey yolunda gitmelidir.


4
Yük dengeleyiciyi, belirli bir sunucu için mevcut oturumlara hizmet verecek, ancak yenilerini kabul etmeyecek şekilde de yapılandırabilirsiniz. Bu, seansları düşürmekten kaçınmanızı sağlar. Ancak bu teknik, oturumların bitmesini beklemeyi gerektirir ve genel olarak bunu senaryo yazmak isteyeceksiniz.

35
Bu yöntem, kod rulosu veritabanında yapısal değişikliklere sahip olduğunda düşme eğilimindedir. Sunucu 1 için DB'yi yükselttiğinizde, sunucu 2 patlayacaktır. Artık, sunucu 1'de test için veritabanını yedekleyebilir / geri yükleyebilirsiniz, ancak daha sonra paralel kopya çalışırken canlı DB'de değişen verileri sıralama sorunuyla karşılaşırsınız.
EBarr

1
@AndreiRinea - bunun yüksek hacimli bir OLTP sisteminde nasıl çalışacağını düşünüyorsunuz? Ya sistem senkronizasyonu bozar ve keserken verileri kaybedersiniz ya da geçici verileri tanımlamak ve yeni DB yapısına taşımak için veri girişini duraklatmanız ve bir komut dosyası yazmanız gerekir.
EBarr

9
@EBarr: ve her durumda teknik olarak ASP.NET uygulamasında hala sıfır kesinti süresine sahipsiniz - soru "sıfır kesinti süresiyle bir sql sunucu veritabanına nasıl dağıtılacağı" değil.
Sklivvz

6
Anahtar, sql değişikliklerinizin yıkıcı olmayacağı bir şekilde gelişmektir. Aşağıdaki sürümde, artık kullanılmadığında, genellikle yıkıcı sql değişiklikleri yapmanız gerekir. Pratik yapmak zor değil.
Bealer

60

Microsoft Web Dağıtım Aracı bir dereceye kadar bu destekler:

Windows İşlem Dosya Sistemi (TxF) desteğini etkinleştirir. TxF desteği etkinleştirildiğinde, dosya işlemleri atomiktir; yani ya başarılı olurlar ya da tamamen başarısız olurlar. Bu, veri bütünlüğünü sağlar ve verilerin veya dosyaların "yarı yolda" veya bozuk durumda bulunmasını önler. MS Deploy'da, TxF varsayılan olarak devre dışıdır.

Görünüşe göre işlem tüm senkronizasyon için. Ayrıca TxF, Windows Server 2008'in bir özelliğidir, bu nedenle bu işlem özelliği önceki sürümlerde çalışmayacaktır.

Klasörleri sürüm olarak ve IIS metatabanını kullanarak komut dosyanızı 0 kesinti süresi için değiştirmenin mümkün olduğuna inanıyorum:

  • mevcut bir yol / url için:
  • Yeni (veya değiştirilmiş) web sitesini sunucuya kopyalayın.
    • \ Web \ app \ v2.1 \
  • Web sitesi yolunu değiştirmek için IIS metatabanını değiştirin
    • dan \ web \ app \ 2.0 \
    • için \ web \ app \ v2.1 \

Bu yöntem aşağıdaki faydaları sağlar:

  • Yeni sürümde bir sorun olması durumunda, kolayca v2.0'a geri dönebilirsiniz.
  • Birden çok fiziksel veya sanal sunucuya dağıtmak için komut dosyanızı dosya dağıtımı için kullanabilirsiniz. Tüm sunucular yeni sürüme sahip olduktan sonra, Microsoft Web Dağıtım Aracını kullanarak tüm sunucuların metatabanlarını aynı anda değiştirebilirsiniz.

5
Bu yaklaşımı powershell dağıtım komut dosyalarımızı uyarlayarak uyguladım. Komut dosyasının IIS site klasörünü değiştiren kısmını burada görebilirsiniz: stackoverflow.com/questions/330608/… İşaretçi için teşekkürler.
Karl Glennon

17
Ne yazık ki, bu yöntem DB'deki yapısal değişiklikleri hesaba katmaz. DB'yi v2.1 için yükselttiğinizde v.2.0 patlar.
EBarr

8
TxF kullanmak burada aşırıdır, IMO. Dosya sisteminde aynı anda hem v2.0 hem de v2.1'e sahip olmak hiçbir şeye zarar vermez. Büyük değişiklik, v2.1 çevrimiçi olduğunda gerçekleşir ve o zamana kadar TxF işlemi tamamlanmış olur. Sıfır kesinti süresi, IIS'nin eski bir AppPool'dan yenisine TxF nedeniyle değil, gerçekten geçme biçimi nedeniyle gerçekleşir.
RickNZ

5
Bununla ilgili başka bir sorun, uygulama klasörlerinin alt klasörlerinde büyük miktarda kullanıcı verisinin depolanmasıdır.
Kenny Evitt

4
Yeni uygulamanın başlaması gerektiğinden bu 0 saniyelik dağıtım değildir.
usr

12

Farklı bağlantı noktalarındaki iki yerel IIS sitesi arasında bir yazılım yük dengeleyicisi olarak IIS'de Uygulama İsteği Yönlendirmesini kullanarak tek bir sunucuda sıfır kesinti süresi dağıtımı elde edebilirsiniz. Bu, herhangi bir zamanda yük dengeleyicide iki siteden yalnızca birinin mevcut olduğu mavi yeşil bir dağıtım stratejisi olarak bilinir . "Kapalı" olan siteye dağıtın, ısıtın ve onu yük dengeleyiciye getirin (genellikle bir Uygulama İsteği Yönlendirme sağlık denetimini geçerek), ardından yukarıda olan orijinal siteyi "havuz" dan (tekrar sağlık kontrolünün başarısız olmasını sağlayarak).

Tam bir eğitim burada bulunabilir.


7

Son zamanlarda bunu denedim ve bulduğum çözüm IIS'de iki site kurmak ve aralarında geçiş yapmaktı.

Yapılandırmam için, her A ve B sitesi için aşağıdaki gibi bir web dizinim vardı: c: \ Intranet \ Live A \ Interface c: \ Intranet \ Live B \ Interface

IIS'de, her biri kendi uygulama havuzuna sahip iki özdeş sitem (aynı bağlantı noktaları, kimlik doğrulama vb.) Var. Sitelerden biri çalışıyor (A) ve diğeri durduruldu (B). canlı olan da canlı ana bilgisayar başlığına sahiptir.

Konu canlı yayına geldiğinde, sadece STOPPED sitenin konumunda yayınlıyorum. B sitesine portunu kullanarak erişebildiğim için, siteyi önceden ısıtabilirim, böylece ilk kullanıcı bir uygulamanın başlamasına neden olmaz. Sonra bir toplu iş dosyası kullanarak canlı ana bilgisayar başlığını B'ye kopyalarım, A'yı durdurur ve B'yi başlatırım.


1
Bu, dosya kopyası nedeniyle kesinti süresine yardımcı olur, ancak @Sklivvz ile aynı soruna sahiptir - kod rulosu veritabanında yapısal değişiklikler yapar yapmaz site patlama olur.
EBarr

Bu benim için de sezgisel bir yol gibi göründü, ama neden bunu yapmanın kolay ve yerleşik bir yolu yok?
Petrus Theron

3
@Ebarr sonra yıkıcı sql değişiklikleri yapmayın. Örneğin, bir sütunu kaldırmanız gerekiyorsa, bunu bir sonraki sürümde, artık A veya B tarafından kullanılmadığında yapın.
Bealer

@Bealer - kabul etti (ihtar ile). "Kod rolleri sırasında kesinti" ile ilgili bu soruların bir dizi var. Henüz bir DB şeması geliştirmenin gerçeklerini gerçekten tartışan bir tane bulamadım. Uyarı - şemada iki aşamalı değişikliklerle birlikte gelen çeşitli komplikasyonlar vardır. Bir örnek - tablo tanımı, anladığı şekliyle tanımdan farklıysa, ORM'lerin çoğu barf (yeni veya eksik sütunlar).
EBarr

2
@Rob durdurulursa siteyi nasıl "önceden ısıtabilirsiniz"?
Andrew Gee

7

Microsoft.Web.Administration'ın ServerManager sınıfını kullanarak kendi dağıtım aracınızı geliştirebilirsiniz.

İşin püf noktası, VirtualDirectory'nin PhysicalPath'ini değiştirmektir, bu da eski ve yeni web uygulamaları arasında çevrimiçi bir atomik geçişle sonuçlanır.

Bunun eski ve yeni AppDomains'in paralel olarak yürütülmesine neden olabileceğini unutmayın!

Sorun, değişikliklerin veritabanlarında vb. Nasıl senkronize edileceğidir.

Eski veya yeni FizikselYollarla AppDomain'lerin varlığını sorgulayarak, eski AppDomain'lerin ne zaman sona erdiğini ve yeni AppDomain'lerin başlatılıp başlatılmadığını tespit etmek mümkündür.

Bir AppDomain'i başlamaya zorlamak için bir HTTP isteği yapmanız gerekir (IIS 7.5 Otomatik Başlatma özelliğini destekler)

Artık yeni AppDomain için istekleri engellemenin bir yoluna ihtiyacınız var. Dağıtım aracısı tarafından oluşturulan ve sahip olunan, yeni web uygulamasının Application_Start tarafından bekletilen ve ardından veritabanı güncellemeleri yapıldıktan sonra dağıtım aracısı tarafından serbest bırakılan adlandırılmış bir muteks kullanıyorum.

(Mutex bekleme davranışını etkinleştirmek için web uygulamasında bir işaret dosyası kullanıyorum) Yeni web uygulaması çalıştıktan sonra işaret dosyasını siliyorum.


6

Tamam, 2008'de yazdığım cevabı herkes olumsuz oyladığından * ...

Şimdi 2014 yılında nasıl yapacağımızı size anlatacağım. Artık ASP.NET MVC kullandığımız için Web Sitelerini kullanmıyoruz.

Bunu yapmak için kesinlikle bir yük dengeleyiciye ve iki sunucuya ihtiyacımız yok, sürdürdüğünüz her web sitesi için 3 sunucunuz varsa sorun değil, ancak çoğu web sitesi için tamamen fazla.

Ayrıca, Microsoft'un en son sihirbazına güvenmiyoruz - çok yavaş ve çok fazla gizli sihir ve adını değiştirmeye çok yatkın.

İşte bunu nasıl yapıyoruz:

  1. Oluşturulan DLL'leri bir 'bin-pub' klasörüne kopyalayan bir post build adımımız var.

  2. Değiştirilen dosyaları (yaygın olarak desteklendiği için FTP üzerinden) doğrulamak ve üretim sunucusuna senkronize etmek için Beyond Compare'i (mükemmel **) kullanıyoruz

  3. Web sitesinde, 'bin-pub'daki her şeyi' bin'e kopyalayan bir düğmeyi içeren güvenli bir URL'ye sahibiz (hızlı geri dönüşü etkinleştirmek için önce bir yedek alır). Bu noktada uygulama kendini yeniden başlatır. Daha sonra ORM'miz eklenmesi gereken tablo veya sütun olup olmadığını kontrol eder ve bunları oluşturur.

Bu sadece milisaniye kesinti süresidir. Uygulamanın yeniden başlatılması bir veya iki saniye sürebilir, ancak yeniden başlatma istekleri arabelleğe alınır, böylece etkin bir şekilde sıfır kesinti süresi olur.

Tüm dağıtım süreci, kaç dosyanın değiştirildiğine ve kaç değişikliğin gözden geçirileceğine bağlı olarak 5 saniye ile 30 dakika arasında sürer.

Bu şekilde, bir web sitesinin tamamını farklı bir dizine değil, yalnızca bin klasörüne kopyalamanız gerekmez. Ayrıca süreç üzerinde tam kontrole sahipsiniz ve neyin değiştiğini tam olarak biliyorsunuz.

** Uyguladığımız değişiklikleri her zaman hızlıca gözden geçiririz - son dakikada iki kez kontrol olarak, neyi test edeceğimizi biliriz ve herhangi bir sorun olursa hazır oluruz. Beyond Compare'i kullanıyoruz çünkü bu, dosyaları FTP üzerinden kolayca ayırt etmenize izin veriyor. Bunu BC olmadan asla yapmazdım, neyin üzerine yazdığınız hakkında hiçbir fikriniz yok.

* Görmek için aşağıya kaydırın :( BTW Web Sitelerini artık tavsiye etmiyorum çünkü derlemeleri daha yavaş ve yarı derlenmiş geçici dosyalar ile kötü bir şekilde çökebiliyorlar.Onları geçmişte kullandık çünkü dosya bazında daha çevikliğe izin veriyorlardı Küçük bir sorunu çözmek için çok hızlıdır ve tam olarak ne dağıttığınızı görebilirsiniz (Tabii ki Beyond Compare'i kullanıyorsanız - aksi takdirde unutun).


Ancak, uygulama havuzu geri döndüğü için hala kesinti yaşayacaksınız.
testpattern

Hayır, kesinti yok çünkü istekler, uygulamanın yeniden başlatılması sırasında IIS tarafından otomatik olarak arabelleğe alınır
mike nelson

5

Düşünebildiğim tek sıfır kesinti yöntemi en az 2 sunucuda barındırmayı içerir.


1

George'un cevabını tek bir sunucu için aşağıdaki gibi biraz hassaslaştırırdım:

  1. Siteyi tek bir DLL olarak önceden derlemek için bir Web Dağıtımı Projesi kullanın
  2. Yeni siteyi sıkıştırın ve sunucuya yükleyin
  3. Bunu, site için doğru izinlere sahip bir klasörde bulunan yeni bir klasöre açın, böylece açılan dosyalar izinleri doğru bir şekilde devralır (belki e: \ web, v20090901, v20090916, vb. Alt klasörlerle)
  4. Siteyi içeren klasörün adını değiştirmek için IIS Yöneticisi'ni kullanın
  5. Eski klasörü bir süre etrafta saklayın, böylece sorun çıkması durumunda ona geri dönebilirsiniz.

4. Adım, IIS alt işleminin geri dönüştürülmesine neden olacaktır.

Bu, InProc oturumlarını kullanmıyorsanız yalnızca sıfır kesinti süresidir; Yapabiliyorsanız bunun yerine SQL modunu kullanın (daha da iyisi, oturum durumundan tamamen kaçının).

Tabii ki, birden fazla sunucu ve / veya veritabanı değişikliği olduğunda biraz daha karmaşıktır ...


1
@Sklivvz ile aynı sorun - Kod rulosu veritabanında yapısal değişikliklere sahip olur olmaz bu yöntem düşer.
EBarr

3
Bu yüzden, DB değişiklikleri olduğunda daha fazla dahil olduğunu söyledim ... DB'ye yapısal değişikliklerle kod sunmak sadece bir dağıtım sorunu değildir; ayrıca kodda ve muhtemelen DB'de de destek olması gerekir.
RickNZ

1

Sklivvz'in bir çeşit yük dengeleyiciye (veya aynı sunucuda sadece bir yedek kopyaya) sahip olmasına dayanan cevabını genişletmek için

  1. Tüm trafiği Site / Sunucu 2'ye yönlendirin
  2. İsteğe bağlı olarak, dağıtılmış sürümde mümkün olduğunca az kullanıcının bekleyen iş akışlarına sahip olmasını sağlamak için biraz bekleyin
  3. Site / Sunucu 1'e konuşlandırın ve mümkün olduğunca ısıtın
  4. Veritabanı geçişlerini işlemsel olarak yürütün (bunu mümkün kılmak için çabalayın)
  5. Tüm trafiği anında Site / Sunucu 1'e yönlendirin
  6. Site / Sunucu 2'ye Dağıt
  7. Her iki siteye / sunucuya doğrudan trafik

Bir veritabanı anlık görüntüsü / kopyası oluşturarak biraz duman testi uygulamak mümkündür, ancak bu her zaman mümkün değildir.

Mümkünse ve gerekiyorsa, önce bilinmeyen bir kobay grubuna dağıtmak için farklı kiracı URL'leri (customerX.myapp.net) veya farklı kullanıcılar gibi "yönlendirme farklılıkları" kullanın. Hiçbir şey başarısız olmazsa, herkese bırakın.

Veritabanı geçişleri söz konusu olduğundan, önceki bir sürüme geri dönmek genellikle imkansızdır.

Bu senaryolarda, olay kuyruklarını ve oynatma mekanizmalarını kullanmak gibi uygulamaların daha iyi çalışmasını sağlamanın yolları vardır, ancak kullanımda olan bir şeye değişiklikleri dağıtmaktan bahsettiğimiz için, gerçekten aptalca bir kanıt yoktur.


1

Ben böyle yaparım:

Mutlak minimum sistem gereksinimleri:
1 sunucu

  • 80 numaralı bağlantı noktasında çalışan 1 yük dengeleyici / ters proxy (ör. Nginx)
  • 2 farklı TCP bağlantı noktasında dinleyen 2 ASP.NET-Core / mono ters-proxy / fastcgi chroot-jails veya docker-container
    (hatta herhangi bir sandbox olmadan 2 farklı TCP bağlantı noktasında sadece iki ters-proxy uygulaması)

İş Akışı:

işlem myupdate'i başlat

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

Eski dosyaları orada tutmanızı ve basitçe üzerine yazmanızı öneririm. Bu şekilde, kesinti süresi tek dosyanın üzerine yazma süreleriyle sınırlıdır ve her seferinde yalnızca bir dosya eksiktir.

Bunun bir "web uygulamasında" yardımcı olduğundan emin değilim (kullandığınızın bu olduğunu söylüyorsunuz), bu yüzden her zaman "web siteleri" kullanıyoruz. Ayrıca "web siteleri" ile dağıtım, sitenizi yeniden başlatmaz ve tüm kullanıcı oturumlarını düşürmez.


Merhaba Mike, Bu yanıtı kaldırmak isteyebilirsin.
Sohail Ahmed
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.