Cách triển khai Ứng dụng ASP.NET với thời gian chết bằng không


127

Để triển khai một phiên bản mới của trang web của chúng tôi, chúng tôi làm như sau:

  1. Nén mã mới và tải nó lên máy chủ.
  2. Trên máy chủ trực tiếp, xóa tất cả mã trực tiếp khỏi thư mục trang web IIS.
  3. Trích xuất mã zipfile mới vào thư mục IIS hiện trống

Quá trình này hoàn toàn theo kịch bản và diễn ra khá nhanh, nhưng vẫn có thể có thời gian ngừng hoạt động 10-20 giây khi các tệp cũ đang bị xóa và các tệp mới đang được triển khai.

Bất kỳ đề xuất về một phương pháp thời gian chết 0 giây?


Điều này có nên trên ServerFault không?
Daniel Rodriguez

49
Có lẽ, nhưng ServerFault đã không tồn tại vào tháng 9 năm 08
Karl Glennon

3
IIS có thể trỏ đến một thư mục symlink không? Việc thay đổi liên kết tượng trưng sẽ khiến quá trình IIS tái chế?
Neil McGuigan

bất kỳ giải pháp cuối cùng với mẫu mã nguồn đầy đủ?
Kiquenet

Không thể có nhiều nhóm ứng dụng và chuyển lưu lượng truy cập từ nhóm ứng dụng này sang nhóm ứng dụng khác?
Lu-ca

Câu trả lời:


79

Bạn cần 2 máy chủ và một bộ cân bằng tải. Đây là các bước:

  1. Bật tất cả lưu lượng trên Máy chủ 2
  2. Triển khai trên máy chủ 1
  3. Máy chủ thử nghiệm 1
  4. Bật tất cả lưu lượng trên Máy chủ 1
  5. Triển khai trên máy chủ 2
  6. Máy chủ thử nghiệm 2
  7. Bật lưu lượng trên cả hai máy chủ

Điều quan trọng là, ngay cả trong trường hợp này, bạn vẫn sẽ khởi động lại ứng dụng và mất phiên nếu bạn đang sử dụng "phiên dính". Nếu bạn có phiên cơ sở dữ liệu hoặc máy chủ trạng thái, thì mọi thứ sẽ ổn.


4
Bạn cũng có thể định cấu hình bộ cân bằng tải để nó phục vụ các phiên hiện có cho một máy chủ nhất định, nhưng không chấp nhận các phiên mới. Điều đó cho phép bạn tránh các phiên giảm. Tuy nhiên, kỹ thuật này đòi hỏi phải chờ các phiên kết thúc và nói chung bạn sẽ muốn kịch bản này.

35
Phương pháp này có xu hướng rơi xuống khi cuộn mã có thay đổi cấu trúc cơ sở dữ liệu. Khi bạn nâng cấp DB cho Máy chủ 1, máy chủ 2 sẽ phát nổ. Bây giờ bạn có thể sao lưu / khôi phục cơ sở dữ liệu để kiểm tra trên máy chủ 1, nhưng sau đó bạn gặp vấn đề sắp xếp dữ liệu đã thay đổi trong DB trực tiếp trong khi bản sao song song đang chạy.
EBarr

1
@AndreiRinea - làm thế nào để bạn cho rằng điều này sẽ hoạt động trong một hệ thống OLTP khối lượng lớn? Hệ thống không đồng bộ và bạn mất dữ liệu khi cắt, hoặc bạn cần tạm dừng nhập dữ liệu và viết tập lệnh để xác định và di chuyển dữ liệu tạm thời sang cấu trúc DB mới.
EBarr

9
@EBarr: và trong mọi trường hợp về mặt kỹ thuật, bạn vẫn không có thời gian chết trên ứng dụng ASP.NET - câu hỏi không phải là "làm thế nào để triển khai db máy chủ sql với thời gian chết bằng không".
Sklivvz

6
Chìa khóa của họ là phát triển theo cách mà những thay đổi sql của bạn không phá hủy. Bạn thường phải thực hiện bất kỳ thay đổi sql phá hoại nào trong bản phát hành sau khi nó không còn được sử dụng. Không khó để thực hành.
Bealer

60

Các Microsoft Web Deployment Tool hỗ trợ này ở một mức độ:

Cho phép hỗ trợ Hệ thống tệp giao dịch Windows (TxF). Khi hỗ trợ TxF được kích hoạt, các hoạt động của tệp là nguyên tử; nghĩa là họ thành công hoặc thất bại hoàn toàn. Điều này đảm bảo tính toàn vẹn dữ liệu và ngăn dữ liệu hoặc tệp tồn tại ở trạng thái "nửa đường" hoặc bị hỏng. Trong MS Deploy, TxF bị tắt theo mặc định.

Có vẻ như giao dịch là cho toàn bộ đồng bộ hóa. Ngoài ra, TxF là một tính năng của Windows Server 2008, vì vậy tính năng giao dịch này sẽ không hoạt động với các phiên bản trước.

Tôi tin rằng có thể sửa đổi tập lệnh của bạn trong 0 thời gian chết bằng cách sử dụng các thư mục làm phiên bản và cơ sở dữ liệu IIS:

  • cho một đường dẫn / url hiện có:
  • Sao chép trang web mới (hoặc sửa đổi) vào máy chủ theo
    • \ web \ ứng dụng \ v2.1 \
  • Sửa đổi IIS metabase để thay đổi đường dẫn trang web
    • từ \ web \ app \ 2.0 \
    • tới \ web \ app \ v2.1 \

Phương pháp này cung cấp các lợi ích sau:

  • Trong trường hợp phiên bản mới có sự cố, bạn có thể dễ dàng quay lại v2.0
  • Để triển khai đến nhiều máy chủ vật lý hoặc ảo, bạn có thể sử dụng tập lệnh của mình để triển khai tệp. Khi tất cả các máy chủ có phiên bản mới, bạn có thể đồng thời thay đổi cơ sở dữ liệu của tất cả các máy chủ bằng Công cụ Triển khai Web của Microsoft.

5
Tôi đã thực hiện phương pháp này bằng cách điều chỉnh các kịch bản triển khai quyền hạn của chúng tôi. Bạn có thể thấy một phần của tập lệnh thay đổi thư mục trang web IIS tại đây: stackoverflow.com/questions/330608/ Khăn Cảm ơn con trỏ.
Karl Glennon

17
Thật không may, phương pháp này không giải thích cho các thay đổi cấu trúc đối với DB. Khi bạn nâng cấp DB cho v2.1 thì v.2.0 sẽ phát nổ.
EBarr

8
Sử dụng TxF là quá mức cần thiết ở đây, IMO. Không có bất cứ điều gì để có cả v2.0 và v2.1 trong hệ thống tập tin cùng một lúc. Sự thay đổi lớn xảy ra khi v2.1 lên mạng và vào thời điểm đó, giao dịch TxF đã được thực hiện. Thời gian chết bằng không thực sự xảy ra do cách IIS chuyển từ AppPool cũ sang một ứng dụng mới, chứ không phải vì TxF.
RickNZ

5
Một vấn đề khác với điều này là nếu một lượng lớn dữ liệu người dùng được lưu trữ trong các thư mục con của các thư mục ứng dụng.
Kenny Evitt

4
Đây không phải là 0 giây triển khai vì ứng dụng mới cần khởi động.
usr

12

Bạn có thể đạt được triển khai thời gian chết bằng không trên một máy chủ bằng cách sử dụng Định tuyến yêu cầu ứng dụng trong IIS làm bộ cân bằng tải phần mềm giữa hai trang IIS cục bộ trên các cổng khác nhau. Đây được gọi là chiến lược triển khai màu xanh lục trong đó chỉ có một trong hai trang web có sẵn trong bộ cân bằng tải tại bất kỳ thời điểm nào. Triển khai đến trang web "xuống", làm ấm nó và đưa nó vào bộ cân bằng tải (thường bằng cách vượt qua kiểm tra sức khỏe Định tuyến yêu cầu ứng dụng), sau đó đưa trang web ban đầu lên, ra khỏi "hồ bơi" (một lần nữa bằng cách kiểm tra sức khỏe của nó thất bại).

Một hướng dẫn đầy đủ có thể được tìm thấy ở đây.


7

Tôi đã trải qua điều này gần đây và giải pháp tôi đưa ra là có hai trang web được thiết lập trong IIS và chuyển đổi giữa chúng.

Đối với cấu hình của tôi, tôi đã có một thư mục web cho mỗi trang A và B như thế này: c: \ Intranet \ Live A \ Interface c: \ Intranet \ Live B \ Interface

Trong IIS, tôi có hai trang web giống hệt nhau (cùng một cổng, xác thực, v.v.) mỗi trang có nhóm ứng dụng riêng. Một trong những trang đang chạy (A) và trang kia bị dừng (B). người sống cũng có tiêu đề máy chủ trực tiếp.

Khi bắt đầu triển khai, tôi chỉ cần xuất bản đến vị trí của trang STOPPED. Vì tôi có thể truy cập trang B bằng cổng của nó, tôi có thể làm ấm trước trang để người dùng đầu tiên không gây ra khởi động ứng dụng. Sau đó, sử dụng tệp bó tôi sao chép tiêu đề máy chủ trực tiếp vào B, dừng A và bắt đầu B.


1
Điều này giúp giảm thời gian chết do sao chép tệp, nhưng có cùng một vấn đề như @Sklivvz - ngay khi cuộn mã có các thay đổi cấu trúc đối với cơ sở dữ liệu, trang web sẽ bùng nổ.
EBarr

Điều này có vẻ giống như cách trực quan với tôi, nhưng tại sao không có cách dễ dàng, tích hợp để làm điều này?
Petrus Theron

3
@Ebarr sau đó không tung ra các thay đổi sql phá hoại. Ví dụ: nếu bạn cần xóa một cột, hãy làm như vậy trong bản phát hành tiếp theo khi nó không còn được sử dụng bởi A hoặc B.
Bealer 19/12/13

@Bealer - đã đồng ý (có cảnh báo). Có cả một loạt các câu hỏi về "thời gian chết trong vai trò mã". Tôi vẫn chưa tìm thấy một cái nào thực sự thảo luận về thực tế phát triển lược đồ DB. Hãy cẩn thận - có một loạt các biến chứng đi kèm với thay đổi hai pha đối với lược đồ. Một ví dụ - nhiều barf ORM nếu định nghĩa bảng khác với định nghĩa vì nó hiểu nó (các cột mới hoặc thiếu).
EBarr

2
@Rob làm thế nào bạn có thể "làm ấm" trang web nếu nó bị dừng?
Andrew Gee

7

Sử dụng lớp ServerManager của Microsoft.Web.Ad, bạn có thể phát triển tác nhân triển khai của riêng mình.

Mẹo nhỏ là thay đổi PhysPath của VirtualDirectory, kết quả là chuyển đổi nguyên tử trực tuyến giữa các ứng dụng web cũ và mới.

Xin lưu ý rằng điều này có thể dẫn đến việc các AppDomain cũ và mới thực thi song song!

Vấn đề là làm thế nào để đồng bộ hóa các thay đổi với cơ sở dữ liệu, v.v.

Bằng cách bỏ phiếu cho sự tồn tại của AppDomains với PhysPath cũ hoặc mới, có thể phát hiện khi nào (các) AppDomain cũ đã kết thúc và nếu (các) AppDomain mới đã khởi động.

Để buộc AppDomain bắt đầu, bạn phải tạo một yêu cầu HTTP (IIS 7.5 hỗ trợ tính năng Tự khởi động)

Bây giờ bạn cần một cách để chặn các yêu cầu cho AppDomain mới. Tôi sử dụng một mutex có tên - được tạo và sở hữu bởi tác nhân triển khai, được Application_Start của ứng dụng web mới chờ đợi và sau đó được phát hành bởi tác nhân triển khai sau khi cập nhật cơ sở dữ liệu.

(Tôi sử dụng tệp đánh dấu trong ứng dụng web để kích hoạt hành vi chờ đợi của mutex) Khi ứng dụng web mới đang chạy, tôi xóa tệp đánh dấu.


6

Được rồi vì mọi người đều hạ thấp câu trả lời tôi đã viết lại từ năm 2008 * ...

Tôi sẽ cho bạn biết làm thế nào chúng ta làm điều đó ngay bây giờ trong năm 2014. Chúng tôi không còn sử dụng Trang web nữa vì hiện tại chúng tôi đang sử dụng ASP.NET MVC.

Chúng tôi chắc chắn không cần một bộ cân bằng tải và hai máy chủ để làm điều đó, thật tốt nếu bạn có 3 máy chủ cho mỗi trang web bạn duy trì nhưng nó hoàn toàn quá mức cho hầu hết các trang web.

Ngoài ra, chúng tôi không dựa vào trình hướng dẫn mới nhất của Microsoft - quá chậm và quá nhiều phép thuật ẩn giấu và quá dễ thay đổi tên của nó.

Đây là cách chúng tôi làm điều đó:

  1. Chúng tôi có một bước xây dựng bài đăng sao chép các tệp DLL được tạo vào thư mục 'bin-pub'.

  2. Chúng tôi sử dụng Beyond So sánh (rất tuyệt vời **) để xác minh và đồng bộ hóa các tệp đã thay đổi (qua FTP vì được hỗ trợ rộng rãi) cho đến máy chủ sản xuất

  3. Chúng tôi có một URL an toàn trên trang web có chứa một nút sao chép mọi thứ trong 'bin-pub' thành 'bin' (trước tiên hãy sao lưu để bật lại nhanh). Tại thời điểm này, ứng dụng tự khởi động lại. Sau đó, ORM của chúng tôi sẽ kiểm tra xem có bất kỳ bảng hoặc cột nào cần được thêm và tạo chúng không.

Đó chỉ là một phần nghìn giây thời gian chết. Việc khởi động lại ứng dụng có thể mất một hoặc hai giây nhưng trong quá trình khởi động lại, các yêu cầu khởi động lại được đệm nên không có thời gian chết thực sự.

Toàn bộ quá trình triển khai mất từ ​​5 giây đến 30 phút, tùy thuộc vào số lượng tệp được thay đổi và số lượng thay đổi để xem xét.

Bằng cách này, bạn không phải sao chép toàn bộ trang web vào một thư mục khác mà chỉ cần thư mục bin. Bạn cũng có toàn quyền kiểm soát quá trình và biết chính xác những gì đang thay đổi.

** Chúng tôi luôn thực hiện nhanh chóng các thay đổi mà chúng tôi đang triển khai - như là một kiểm tra kép vào phút cuối, vì vậy chúng tôi biết phải kiểm tra những gì và nếu có bất cứ điều gì phá vỡ chúng tôi đã sẵn sàng. Chúng tôi sử dụng Beyond So sánh vì nó cho phép bạn dễ dàng tìm các tệp khác nhau qua FTP. Tôi sẽ không bao giờ làm điều này mà không có BC, bạn không biết bạn đang viết gì.

* Cuộn xuống phía dưới để xem nó :( BTW Tôi sẽ không còn đề xuất Trang web nữa vì chúng chậm xây dựng hơn và có thể bị lỗi nặng với một nửa tệp tạm thời được biên dịch. Chúng tôi đã sử dụng chúng trước đây vì chúng cho phép tệp nhanh hơn triển khai. Rất nhanh chóng để khắc phục một sự cố nhỏ và bạn có thể thấy chính xác những gì bạn đang triển khai (nếu sử dụng Beyond So sánh tất nhiên - nếu không hãy quên nó).


Nhưng, bạn vẫn sẽ nhận được thời gian chết vì nhóm ứng dụng tái chế.
thử nghiệm

Không, không có thời gian chết vì các yêu cầu được đệm tự động bởi IIS trong khi khởi động lại ứng dụng
mike nelson

5

Các phương pháp ngừng hoạt động bằng không duy nhất tôi có thể nghĩ đến liên quan đến việc lưu trữ trên ít nhất 2 máy chủ.


1

Tôi sẽ tinh chỉnh câu trả lời của George một chút, như sau, cho một máy chủ:

  1. Sử dụng Dự án triển khai web để biên dịch trước trang web thành một DLL duy nhất
  2. Nén trang web mới và tải nó lên máy chủ
  3. Giải nén nó vào một thư mục mới nằm trong một thư mục có quyền phù hợp cho trang web, vì vậy các tệp được giải nén sẽ kế thừa các quyền một cách chính xác (có lẽ e: \ web, với các thư mục con v20090901, v20090916, v.v.)
  4. Sử dụng IIS Manager để thay đổi tên của thư mục chứa trang web
  5. Giữ thư mục cũ xung quanh một lúc, để bạn có thể dự phòng trong trường hợp có vấn đề

Bước 4 sẽ khiến quy trình công nhân IIS tái chế.

Đây chỉ là thời gian chết bằng không nếu bạn không sử dụng các phiên InProc; sử dụng chế độ SQL thay vì nếu bạn có thể (thậm chí tốt hơn, tránh hoàn toàn trạng thái phiên).

Tất nhiên, nó liên quan nhiều hơn một chút khi có nhiều máy chủ và / hoặc thay đổi cơ sở dữ liệu ....


1
Vấn đề tương tự như @Sklivvz - Phương pháp này rơi xuống ngay khi cuộn mã có các thay đổi cấu trúc đối với cơ sở dữ liệu.
EBarr

3
Đó là lý do tại sao tôi nói nó liên quan nhiều hơn khi có các thay đổi DB ... Việc triển khai mã với các thay đổi cấu trúc đối với DB không chỉ là vấn đề triển khai; cũng phải có sự hỗ trợ trong mã và có lẽ trong DB cũng vậy.
RickNZ

1

Để mở rộng câu trả lời của sklivvz, dựa trên việc có một số loại cân bằng tải (hoặc chỉ là một bản sao dự phòng trên cùng một máy chủ)

  1. Hướng tất cả lưu lượng truy cập đến Trang web / Máy chủ 2
  2. Tùy chọn chờ một chút, để đảm bảo rằng càng ít người dùng càng có các luồng công việc đang chờ xử lý trên phiên bản đã triển khai
  3. Triển khai đến Site / Server 1 và làm nóng nó càng nhiều càng tốt
  4. Thực hiện di chuyển cơ sở dữ liệu một cách giao dịch (cố gắng để làm điều này có thể)
  5. Ngay lập tức hướng tất cả lưu lượng truy cập đến Trang web / Máy chủ 1
  6. Triển khai đến Trang web / Máy chủ 2
  7. Lưu lượng truy cập trực tiếp đến cả hai trang web / máy chủ

Có thể giới thiệu một chút thử nghiệm khói, bằng cách tạo ảnh chụp / sao chép cơ sở dữ liệu, nhưng điều đó không phải lúc nào cũng khả thi.

Nếu có thể và cần sử dụng "khác biệt định tuyến", chẳng hạn như URL đối tượng thuê khác nhau: s (customerX.myapp.net) hoặc những người dùng khác nhau, để triển khai đến một nhóm lợn guinea không biết trước. Nếu không có gì thất bại, phát hành cho tất cả mọi người.

Vì việc di chuyển cơ sở dữ liệu có liên quan, việc quay trở lại phiên bản trước thường là không thể.

Có nhiều cách để làm cho các ứng dụng chơi đẹp hơn trong các tình huống này, chẳng hạn như sử dụng hàng đợi sự kiện và cơ chế phát lại, nhưng vì chúng ta đang nói về việc triển khai các thay đổi cho thứ gì đó đang được sử dụng, nên thực sự không có cách chứng minh ngu ngốc nào.


1

Đây là cách tôi làm điều đó:

Yêu cầu hệ thống tối thiểu tuyệt đối:
1 máy chủ với

  • Cân bằng tải 1 / proxy ngược (ví dụ nginx) đang chạy trên cổng 80
  • 2 chroot-jails hoặc container docker-proxy / fastcgi đảo ngược lắng nghe trên 2 cổng TCP khác nhau
    (hoặc thậm chí chỉ có hai ứng dụng proxy ngược trên 2 cổng TCP khác nhau mà không cần hộp cát)

Quy trình làm việc:

bắt đầu giao dịch 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

Tôi sẽ đề nghị giữ các tập tin cũ ở đó và chỉ cần ghi đè lên chúng. Theo cách đó, thời gian chết được giới hạn ở thời gian ghi đè một tệp và mỗi lần chỉ có một tệp bị thiếu.

Không chắc chắn điều này sẽ giúp trong một "ứng dụng web" (tôi nghĩ bạn đang nói đó là những gì bạn đang sử dụng), đó là lý do tại sao chúng tôi luôn sử dụng "các trang web". Ngoài ra với việc "trang web" triển khai không khởi động lại trang web của bạn và bỏ tất cả các phiên người dùng.


Xin chào Mike, Bạn có thể muốn xóa câu trả lời này.
Sohail Ahmed
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.