Cập nhật ứng dụng web mà không có thời gian chết


31

Đây là một ứng dụng PHP. Làm cách nào để giảm thiểu thời gian chết trong khi cập nhật toàn bộ cơ sở mã?

Câu trả lời:


44

Những gì chúng ta thường làm, tại nơi làm việc là:

  • trước khi chúng tôi cập nhật, tài liệu gốc của máy chủ là:
    • trong /www/app-2009-09-01
    • nhưng được truy cập thông qua một liên kết tượng trưng, ​​được gọi là /www/application
  • chúng tôi đặt toàn bộ cơ sở mã mới để /www/app-2009-09-08
  • một khi toàn bộ cơ sở mã là có:
    • chúng tôi xóa liên kết tượng trưng cũ
    • chúng tôi tạo ra một liên kết tượng trưng mới, vẫn được gọi /www/application, nhưng chỉ đến các nguồn mới:/www/app-2009-09-08
  • chúng tôi tải lại apache để buộc phải sửa đổi.

Tất cả quá trình này được thực hiện thông qua một tập lệnh tự động (điều duy nhất không tự động là chúng tôi khởi chạy nó khi cần thiết). Điều này có nghĩa là :

  • Mọi thứ diễn ra nhanh chóng (đặc biệt là việc chuyển đổi liên kết tượng trưng, ​​là phần quan trọng)
  • Không có rủi ro xảy ra lỗi: tập lệnh đã được kiểm tra tốt và hoạt động trong nhiều tháng / năm


Một ưu điểm khác của tiền lệ liên kết tượng trưng này là rất dễ "khôi phục" bản cập nhật nếu chúng tôi nhận thấy một lỗi nghiêm trọng chỉ sau khi đưa phiên bản mới của các nguồn vào sản xuất: chúng tôi chỉ cần chuyển lại các liên kết tượng trưng.

Tất nhiên, điều này không ngăn bạn thử nghiệm phiên bản mới trên máy chủ dàn dựng của bạn trước khi đưa nó vào sản xuất - nhưng, ai biết được ... Đôi khi, có một lỗi thực sự lớn mà không ai có thể nhìn thấy trong khi kiểm tra :-(
Chẳng hạn, vì không có kiểm tra tải được thực hiện thường xuyên trên máy dàn.
(Tôi đã thấy điều "rollback" đã sử dụng thứ gì đó như 4 hoặc 5 lần trong 3 năm - mỗi lần, nó đã lưu trong ngày - và các trang web ^^)


Đây là một ví dụ nhanh: giả sử tôi có Virtualhost này trong cấu hình Apache của mình:

<VirtualHost *>
        ServerName example.com
        DocumentRoot /www/application
        <Directory /www/application>
            # Whatever you might need here (this example is copy-pasted from a test server and test application ^^ )
            Options Indexes FollowSymLinks MultiViews +SymLinksIfOwnerMatch
            AllowOverride All
            php_value   error_reporting 6135
            php_value short_open_tag  on
        </Directory>
</VirtualHost>

Khá "chuẩn" ... Điều duy nhất /www/applicationkhông phải là một thư mục thực sự: nó chỉ là một liên kết tượng trưng đến phiên bản hiện tại của các nguồn.
Điều đó có nghĩa là khi bạn đã đặt các nguồn vào máy chủ, nhưng chưa được chuyển đổi, bạn sẽ có một cái gì đó như thế này:

root@shark:/www
# ll
total 8
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-01
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-08
lrwxrwxrwx 1 root root   19 2009-09-08 22:08 application -> /www/app-2009-09-01

Lưu ý rằng symlinc trỏ đến "phiên bản cũ"

Bây giờ, phiên bản mới đã được tải lên hoàn toàn vào máy chủ, hãy chuyển đổi:

root@shark:/www
# rm /www/application
root@shark:/www
# ln -s /www/app-2009-09-08 /www/application

Và, bây giờ, các /www/applicationđiểm đến phiên bản mới của các nguồn:

root@shark:/www
# ll
total 8
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-01
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-08
lrwxrwxrwx 1 root root   19 2009-09-08 22:09 application -> /www/app-2009-09-08

Và chúng ta phải khởi động lại Apache:

root@shark:/www
# /etc/init.d/apache2 restart
 * Restarting web server apache2

Ba bước " xóa liên kết; tạo liên kết mới; khởi động lại apache " cần được thực hiện nhanh chóng; tức là bởi một kịch bản tự động chứ không phải bởi một con người.

Sử dụng giải pháp này:

  • bạn có thể mất nhiều thời gian như bạn cần để tải lên phiên bản mới của các nguồn: apache sẽ không sử dụng chúng miễn là ký hiệu không bị thay đổi
  • khi mọi thứ đều ổn, chỉ cần chuyển đổi liên kết tượng trưng: nó sẽ nhanh hơn thay đổi ngay cả 1 hoặc 2 tệp ... Điều đó có nghĩa là hầu như không có thời gian chết :-)

Và nếu sử dụng một số opcode-cache như APC với tùy chọn stat ở mức 0, điều đó có thể có nghĩa là thậm chí ít nguy cơ ngừng hoạt động hơn, tôi cho rằng.


Tất nhiên, đây là phiên bản "đơn giản" - ví dụ: nếu bạn có một số tệp được tải lên, bạn sẽ phải sử dụng một liên kết tượng trưng khác ở đâu đó hoặc Virtualhost khác hoặc bất cứ điều gì ...


Hy vọng điều này là rõ ràng hơn :-)


Đó là một loại máy chủ hoán đổi quá. :-)
Wim ten Brink

mod_rewrite để quản lý các liên kết tượng trưng?

@gAMBOOKa: không: chỉ là vấn đề của DocumentRoot của Apache (hoặc Virtualhost DocumentRoot), đó là / www / application ;; tức là liên kết tượng trưng - bất kể nơi đó chỉ đến đâu.

2
Câu trả lời tuyệt vời. Một mẹo nữa, mặc dù: bạn có thể làm cho liên kết tượng trưng xảy ra mà không hủy liên kết nó. Như đã trích dẫn: "Ba bước nên được thực hiện nhanh chóng, tức là bằng một kịch bản tự động chứ không phải bởi một con người." Lệnh mv là một hoạt động nguyên tử, vì vậy bạn có thể tạo một liên kết tượng trưng như 'ln -s / www / app-2011-01-28 / www / application-temp' và sau đó thực hiện 'mv -T / www / application-temp / www / ứng dụng '.

1
Có một cái gì đó không được bao phủ bởi phương pháp symlink. Cách của bạn hoạt động với Apache + mod_php nhưng nó có thể thất bại trên lighttpd + fastcgi. Trong một trang web có lưu lượng truy cập cao, yêu cầu sẽ được cung cấp ở giữa việc hoán đổi liên kết rằng, sự phụ thuộc mã php sẽ thất bại với phiên bản hỗn hợp.
Dennis C

2

Bạn không thể lấy mã hiện có và di chuyển dự án vào một tệp php thử nghiệm riêng biệt và sử dụng mã đó trong khi bạn đang thực hiện các cập nhật của mình? Ý tôi là, bạn nên có một máy chủ thử nghiệm và một máy chủ sản xuất để khi bạn phải cập nhật, bạn không phải chịu bất kỳ thời gian chết nào.


1

Thiết lập máy chủ thứ hai với cơ sở mã được cập nhật và chuyển đổi chúng nhanh nhất có thể. :-)

Nếu không thể, hãy đảm bảo rằng cơ sở mã của bạn được chia thành hàng chục phần nhỏ hơn. Sau đó, thời gian chết sẽ được giới hạn chỉ một phụ một tại thời điểm đó. Các codeblocks nhỏ hơn dễ thay thế hơn và hầu hết sẽ tiếp tục chạy mà không gặp vấn đề gì. Tuy nhiên, chỉ cần thử điều này trên một môi trường thử nghiệm!


Vì ứng dụng chưa được thử nghiệm với các mô-đun bị phân mảnh, nên nó có thể dẫn đến các tình huống không mong muốn.

Điều đó có nghĩa là nó sẽ nằm trong danh sách ToDo của bạn sau khi cập nhật này. :-) Làm cho nó trở nên mô-đun hơn và bạn có thể cập nhật cho mỗi mô-đun.
Wim ten Brink

1
Đó là trong danh sách ToDo, nhưng là một mục tiêu dài hạn. Chúng tôi là một công ty khởi nghiệp trẻ, vì vậy tổ chức trong nhóm nhà phát triển sẽ tự nhiên mất một thời gian. = D

1

Trước hết, tôi thường sử dụng và thích một phương thức tương tự như phản hồi của Pascal MARTIN.

Một phương pháp khác mà tôi cũng thích là sử dụng SCM của mình để đẩy mã mới. Quá trình chính xác phụ thuộc vào loại SCM của bạn (git vs svn vs ...). Nếu bạn đang sử dụng svn, tôi muốn tạo một nhánh "trực tuyến" hoặc "sản xuất" mà tôi kiểm tra dưới dạng gốc tài liệu trên máy chủ. Sau đó, bất cứ khi nào tôi muốn đẩy mã mới từ một nhánh / thẻ / trung kế khác, tôi chỉ cần cam kết mã mới vào nhánh "trực tuyến" và chạy cập nhật svn trong thư mục gốc. Điều này cho phép khôi phục rất dễ dàng vì có một bản ghi sửa đổi hoàn chỉnh về những gì đã lên / xuống máy chủ và ai đã làm điều đó và khi nào. Bạn cũng có thể dễ dàng chạy nhánh "trực tuyến" đó trên hộp kiểm tra, cho phép bạn kiểm tra ứng dụng mà bạn sắp đẩy.

Quá trình này tương tự đối với git và các kiểu SCM khác, chỉ cần sửa đổi để tự nhiên hơn cho phong cách làm việc của họ.

Bạn muốn kéo / thăm dò ý kiến ​​thay vì đẩy cập nhật? Chỉ cần có một công việc định kỳ hoặc khác, cơ chế thông minh hơn sẽ tự động chạy cập nhật svn.

Bổ sung: Bạn cũng có thể sử dụng quy trình này để sao lưu các tệp mà ứng dụng của bạn đã ghi vào đĩa. Chỉ cần có một công việc định kỳ hoặc một số cơ chế khác chạy svn commit. Bây giờ các tệp mà ứng dụng của bạn đã tạo được sao lưu trong SCM của bạn, bản sửa đổi được ghi lại, v.v. (ví dụ: nếu người dùng cập nhật tệp trên đĩa, nhưng muốn bạn hoàn nguyên nó, chỉ cần đẩy bản sửa đổi cũ).


0

Tôi cũng sử dụng một cách tiếp cận tương tự với Pascal MARTIN. Nhưng thay vì tải nhiều phiên bản ứng dụng của tôi lên máy chủ sản xuất, tôi giữ "bản dựng" phía sau tường lửa của mình, mỗi phiên bản trong một thư mục riêng có số ngày và bản dựng. Khi tôi muốn tải lên một phiên bản mới, tôi sử dụng một tập lệnh đơn giản bao gồm "rsync -avh --delay-Updates". Cờ "delay = Updates" sẽ tải mọi thứ (khác nhau) vào một thư mục tạm thời cho đến khi tất cả các bản cập nhật ở đó, và sau đó di chuyển mọi thứ cùng một lúc khi kết thúc chuyển đến đường dẫn thích hợp của chúng để ứng dụng sẽ không bao giờ nằm ​​trong một nhà nước nửa cũ nửa mới. Nó có tác dụng tương tự như phương pháp trên, ngoại trừ tôi chỉ giữ một phiên bản của ứng dụng trên trang sản xuất (tốt nhất chỉ có các tệp thiết yếu duy nhất trên máy chủ sản xuất, IMO).

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.