Upgrade Nginx on production: Let’s do it without downtime!


Các web system admin hẳn cũng từng biết một trong các hạn chế của Nginx so với Apache HTTP Server là nó hiện thiếu cơ chế dynamically loaded modules nên nếu muốn bổ sung một module nào đó (ví dụ, ngx_http_ssl_module) cho Nginx thì việc đầu tiên nhất thiết phải làm là biên dịch lại (re-compile) Nginx từ source code để file binary/executable mới được tích hợp module này.

Trong một số trường hợp như môi trường development, staging thì việc làm này khá đơn giản và không đáng ngại nhưng nếu như Nginx đang phải phục vụ rất nhiều connection cho môi trường production thì việc re-complie và restart lại Nginx theo cách thông thường sẽ làm giết chết master process và các work process cũ dẫn đến việc phục vụ bị gián đoạn, ví dụ, nếu người dùng đang wget một file thì sẽ nhận thông báo sau và phải khởi chạy lại lệnh wget nhưng không thể resume quá trình download được:

upgrade-nginx-without-downtime-demo-2

Nếu đây là tình huống cần phải tránh thì có thể tham khảo hướng dẫn sau “Upgrading Executable on the Fly” [1].

Dưới đây là tóm tắt và giải thích lại các bước với giả định process Nginx vẫn đang chạy với main folder là /opt/nginx. Và user đang download file 300.mkv từ con Nginx (10.76.1.76)

1. Tiến hành re-compile Nginx từ source có chứa setting/module cần thiết để được file binary mới nằm ở

/opt/nginx/newbin/nginx

2. Thực hiện backup cho file binary cũ

cp /opt/nginx/sbin/nginx /opt/nginx/sbin/nginx.old

3. Ghi đè binary cũ bằng binary mới

/bin/cp -f /opt/nginx/newbin/nginx /opt/nginx/sbin/

4. Gửi signal USR2 tới master process cũ để chạy song song với master process mới được tạo ra. Lúc này, Nginx master process mới sẽ sử dụng chung configuration với cái cũ và bản thân nó cũng sẽ sinh ra các worker process mới để đón nhận và xử lý các connection mới. Các connection cũ trước đó vẫn đang được handle bởi các worker process cũ.

kill -USR2 $(cat /opt/nginx/logs/nginx.pid)

Có thể dùng lệnh ps sau để thấy rằng các Nginx process cũ và mới đều đang chạy đồng thời với các PID khác nhau (tất nhiên rồi :)).

ps -ef|grep nginx

Ngoài ra thì sau bước này file nginx.pid sẽ được tự động thêm suffix đằng sau thành nginx.pid.oldbin.

5. Gửi signal WINCH tới master process cũ để kêu gọi nó thực hiện graceful shutdown các worker process cũ do nó tạo ra. Kết quả là các worker process cũ… vẫn sẽ phục vụ cho xong các connection mà chúng handle từ đầu, sau đó thì mới bị tiêu diệt. Như vậy tình trạng downtime sẽ không xảy ra, bởi các connection mới sẽ do các worker process mới xử lý, còn những cái còn tồn đọng sẽ vẫn được các worker process cũ giải quyết.

kill -WINCH $(cat /opt/nginx/logs/nginx.pid.oldbin)

Quan sát kỹ hơn nữa (xem hình dưới đây) thì có thể thấy là tiến trình download file 300.mkv từ Nginx có chút gián đoạn khi trình wget báo connection bị đóng khi đang download tới byte thứ 287721216. Nhưng việc kết nối lại tới các worker process mới để resume quá trình download diễn ra thành công, tự động mà không cần tới sự tương tác từ bên ngoài.

upgrade-nginx-without-downtime-demo-1

6. Tại thời điểm này thì có thể kiểm tra xem các module mới đưa vào có làm được việc thông qua các worker process mới hay không. Ví dụ, module mới là SSL thì vào thử một trang HTTPS trên Nginx xem sao.

Nếu mọi thứ diễn ra như mong đợi thì sau cùng chỉ cần gửi signal QUIT tới master process cũ để graceful shutdown nó. Lúc này, chỉ còn master + worker process mới chạy mà thôi, có thể kiểm tra lần cuối cũng với lệnh ps sau:

ps -ef|grep nginx

Xong :)

[1] http://nginx.org/en/docs/control.html

-mt.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s