Hãy hình dung thế này: Bây giờ là 2 giờ sáng. Điện thoại của bạn đổ chuông. Đó là một cảnh báo: ‘Web Server 1 DOWN.’ Bạn vội vàng bật dậy khỏi giường, tim đập thình thịch, cố gắng tìm hiểu lý do tại sao ứng dụng của mình đột nhiên không thể truy cập được. Cái điểm lỗi duy nhất đó đã gây ra hậu quả nghiêm trọng cho bạn. Người dùng của bạn đang thấy lỗi, và bạn đang trong chế độ chữa cháy khẩn cấp. Nghe có quen không?
Các load balancer là tuyến phòng thủ đầu tiên của bạn chống lại downtime, đảm bảo ứng dụng của bạn luôn trực tuyến ngay cả khi một backend server gặp sự cố bất ngờ. Chúng không chỉ phân phối lưu lượng truy cập. Hôm nay, tôi sẽ hướng dẫn bạn cách thiết lập High Availability (HA) cho các ứng dụng web của bạn bằng cách sử dụng hai công cụ mạnh mẽ: HAProxy và Nginx.
Bắt đầu nhanh (5 phút): Chạy một HAProxy Load Balancer cơ bản
Khi một sự cố xảy ra, việc khắc phục nhanh chóng là tối quan trọng. Dưới đây là cách để bạn có thể thiết lập HAProxy cơ bản chạy nhanh chóng, phân phối lưu lượng truy cập trên hai backend web server. Đối với ví dụ này, giả sử bạn có hai web server (như Nginx hoặc Apache) đã chạy trên 192.168.1.101:80 và 192.168.1.102:80, và HAProxy server của bạn nằm ở 192.168.1.100.
Bước 1: Cài đặt HAProxy
Trên load balancer server của bạn (192.168.1.100):
sudo apt update
sudo apt install haproxy -y
Đối với các hệ thống RHEL/CentOS, bạn sẽ sử dụng sudo yum install haproxy -y hoặc sudo dnf install haproxy -y.
Bước 2: Cấu hình HAProxy
Mở tệp cấu hình HAProxy: sudo nano /etc/haproxy/haproxy.cfg
Xóa hoặc comment nội dung hiện có của nó và thêm cấu hình tối thiểu này:
frontend web_frontend
bind *:80
mode http
default_backend web_servers
backend web_servers
mode http
balance roundrobin
server web1 192.168.1.101:80 check
server web2 192.168.1.102:80 check
Giải thích nhanh:
frontend web_frontend: Phần này định nghĩa điểm vào cho các yêu cầu đến.bind *:80: HAProxy lắng nghe kết nối trên tất cả các giao diện mạng khả dụng ở cổng 80.mode http: HAProxy hoạt động ở Tầng 7 (tầng HTTP), cho phép định tuyến nâng cao dành riêng cho HTTP.default_backend web_servers: Tất cả lưu lượng nhận được bởi frontend này sẽ được chuyển hướng đến nhóm backendweb_servers.backend web_servers: Phần này định nghĩa nhóm các máy chủ web thực tế sẽ xử lý các yêu cầu từ client.balance roundrobin: Lưu lượng được phân phối tuần tự, gửi từng yêu cầu một đến mỗi máy chủ trong nhóm backend.server web1 ... check: Dòng này định nghĩa một máy chủ backend cụ thể và bật tính năng kiểm tra tình trạng liên tục để theo dõi khả năng hoạt động của nó.
Bước 3: Bật và Khởi động HAProxy
sudo systemctl enable haproxy
sudo systemctl start haproxy
sudo systemctl status haproxy
Bước 4: Kiểm tra thiết lập của bạn
Mở trình duyệt web của bạn và điều hướng đến địa chỉ IP của HAProxy server (ví dụ: http://192.168.1.100). Bạn sẽ thấy nội dung từ một trong các backend web server của mình. Làm mới trình duyệt vài lần, và bạn sẽ thấy phản hồi từ máy chủ khác.
Để thực sự kiểm tra high availability, hãy thử dừng một trong các backend web server của bạn—ví dụ, bằng cách chạy sudo systemctl stop nginx trên 192.168.1.101. HAProxy sẽ nhanh chóng phát hiện lỗi và ngừng gửi lưu lượng truy cập đến nó, đảm bảo ứng dụng của bạn vẫn trực tuyến. Tin tôi đi, việc debug trong tình huống áp lực lúc 2 giờ sáng là một trải nghiệm bạn muốn tránh.
Tìm hiểu sâu: Hiểu các nguyên tắc cơ bản về Load Balancing và HAProxy
Mặc dù thiết lập nhanh đó có thể là cứu cánh, nhưng điều cần thiết là phải hiểu các cơ chế cơ bản và cách xây dựng một hệ thống mạnh mẽ hơn.
Load Balancing là gì?
Một load balancer phân phối lưu lượng mạng đến trên nhiều backend server. Điều này không chỉ là về việc tối ưu hóa tốc độ; nó còn rất quan trọng đối với:
- High Availability (HA): Nếu một máy chủ bị lỗi, load balancer sẽ định tuyến lưu lượng đến các máy chủ khỏe mạnh, ngăn ngừa downtime.
- Scalability: Khi lượng người dùng của bạn tăng lên, bạn có thể thêm nhiều máy chủ backend mà không cần cấu hình lại phía client.
- Performance: Phân phối các yêu cầu giúp ngăn chặn bất kỳ máy chủ nào trở thành nút thắt cổ chai.
Các nguyên tắc cơ bản của HAProxy: Cỗ máy đáng tin cậy
HAProxy (High Availability Proxy) là một giải pháp mã nguồn mở, miễn phí nổi tiếng về khả năng load balancing và reverse proxy hiệu suất cao, đáng tin cậy cho các ứng dụng dựa trên TCP và HTTP. Đây thường là lựa chọn ưu tiên của tôi cho các tác vụ load balancing chuyên dụng.
Các phần cấu hình chính:
global: Phần này định nghĩa các tham số toàn hệ thống, như cài đặt ghi log, quyền người dùng/nhóm và số lượng kết nối tối đa.defaults: Các cài đặt này áp dụng mặc định cho tất cả các phầnlisten,frontendvàbackendtrừ khi được ghi đè rõ ràng.frontend: Khối này định nghĩa listener hướng ra công cộng—địa chỉ IP và cổng mà HAProxy chấp nhận các kết nối client đến.backend: Phần này định nghĩa nhóm các máy chủ thực tế mà frontend sẽ chuyển tiếp các yêu cầu của client đến.listen: Là sự kết hợp tiện lợi của khốifrontendvàbackend, thường được sử dụng cho các cấu hình đơn giản, tự chứa.
Các thuật toán Load Balancing:
roundrobin: Phân phối các yêu cầu tuần tự đến mỗi máy chủ trong nhóm. Đây là một phương pháp đơn giản, được sử dụng rộng rãi và hiệu quả.leastconn: Chuyển các kết nối mới đến máy chủ hiện đang xử lý ít kết nối hoạt động nhất. Thuật toán này đặc biệt hiệu quả cho các ứng dụng có kết nối tồn tại lâu dài.source: Phương pháp này băm địa chỉ IP nguồn của client để đảm bảo rằng cùng một client luôn kết nối đến cùng một máy chủ backend. Nó hữu ích để duy trì session persistence mà không cần dựa vào cookie.uri/url_param/hdr: Đây là các phương pháp nâng cao hơn, phân phối các yêu cầu dựa trên các thành phần cụ thể của yêu cầu HTTP, chẳng hạn như URI, tham số URL hoặc HTTP header.
Health Checks: Nhịp tim của HA
Từ khóa check, mà chúng ta đã sử dụng trong ví dụ trước, hướng dẫn HAProxy định kỳ thăm dò các backend server để kiểm tra trạng thái hoạt động của chúng. Bạn có thể tinh chỉnh hành vi này với các tham số bổ sung:
inter <delay>ms: Khoảng thời gian giữa các lần kiểm tra tình trạng (ví dụ,inter 2000mskiểm tra mỗi 2 giây).rise <count>: Số lượng kiểm tra thành công liên tiếp cần thiết để một máy chủ được coi là ‘hoạt động’ và tham gia lại nhóm.fall <count>: Số lượng kiểm tra thất bại liên tiếp sau đó một máy chủ được đánh dấu là ‘ngừng hoạt động’ và bị loại khỏi nhóm hoạt động.
Ví dụ cấu hình HAProxy chi tiết
Hãy mở rộng cấu hình trước đó của chúng ta để bao gồm các cài đặt cấp độ production phổ biến hơn, như trang stats và SSL termination (hoặc passthrough).
global
log /dev/log local0
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
maxconn 20000 # Một giá trị cao, phù hợp cho các load balancer bận rộn. Điều chỉnh dựa trên lưu lượng dự kiến.
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http_in
bind *:80
mode http
# Bỏ comment dòng dưới đây để chuyển hướng HTTP sang HTTPS, buộc sử dụng SSL cho tất cả lưu lượng.
# redirect scheme https code 301 if !{ ssl_fc }
default_backend web_servers
frontend https_in
bind *:443 ssl crt /etc/ssl/certs/yourdomain.pem
mode http
option httplog
default_backend web_servers
backend web_servers
mode http
balance leastconn
option httpchk GET /healthz
cookie SERVERID insert indirect nocache
server web1 192.168.1.101:80 check cookie web1_id inter 2s rise 2 fall 3 weight 100
server web2 192.168.1.102:80 check cookie web2_id inter 2s rise 2 fall 3 weight 100
server web3 192.168.1.103:80 check cookie web3_id inter 2s rise 2 fall 3 weight 50 backup
listen stats
bind *:8080
mode http
stats enable
stats uri /haproxy?stats
stats realm Haproxy\ Statistics
stats auth admin:password
stats refresh 5s
Hãy chú ý chỉ thị option httpchk GET /healthz. Điều này chỉ đạo HAProxy thực hiện một yêu cầu HTTP GET đến endpoint /healthz trên mỗi backend server để xác định tình trạng của nó, cung cấp một kiểm tra mạnh mẽ hơn so với kết nối TCP đơn giản. Phương pháp này đáng tin cậy hơn nhiều cho các ứng dụng web.
Ngoài ra, dòng cookie SERVERID insert indirect nocache cho phép session persistence, một khái niệm tôi sẽ trình bày chi tiết trong phần mẹo. Tham số weight 100 (hoặc weight 50 cho web3) kiểm soát tỷ lệ lưu lượng tương đối mà một máy chủ nhận được; trọng số cao hơn có nghĩa là nhiều yêu cầu hơn. Cá nhân tôi đã triển khai cách tiếp cận này trong các môi trường production, và kết quả đã liên tục chứng minh sự ổn định, ngay cả dưới tải nặng, ngăn ngừa nhiều sự cố ngừng hoạt động tiềm ẩn.
Hãy nhớ thay thế /etc/ssl/certs/yourdomain.pem bằng chuỗi chứng chỉ SSL thực tế của bạn và chọn một mật khẩu mạnh cho trang stats.
Sử dụng nâng cao: Nginx làm Load Balancer
Mặc dù HAProxy là một load balancer chuyên dụng, Nginx—chủ yếu được công nhận là một web server và reverse proxy mạnh mẽ—cũng cung cấp các khả năng load balancing mạnh mẽ. Nếu Nginx đã là một phần trong công nghệ của bạn, việc hợp nhất các vai trò này thường có thể đơn giản hóa cơ sở hạ tầng của bạn.
Tại sao nên dùng Nginx cho Load Balancing?
- Hợp nhất: Nếu Nginx đã phục vụ các tệp tĩnh hoặc hoạt động như một reverse proxy, việc tích hợp load balancing vào cấu hình hiện có của nó thường khá đơn giản.
- Đơn giản (cho HTTP/HTTPS): Đối với load balancing HTTP/HTTPS cơ bản, cú pháp cấu hình của Nginx có thể dễ hiểu hơn, đặc biệt đối với những người đã quen thuộc với khả năng máy chủ web của nó.
- Các tính năng HTTP phong phú: Ngoài load balancing, Nginx còn cung cấp một bộ tính năng HTTP nâng cao, bao gồm caching, compression và URL rewriting.
Các khái niệm Load Balancing của Nginx:
upstreamblock: Khối này định nghĩa một nhóm logic các máy chủ backend mà Nginx sẽ phân phối các yêu cầu đến.proxy_pass: Chỉ thị này chuyển các yêu cầu đến từ một khốiserverđến một nhómupstreamđược chỉ định.- Các phương pháp Load Balancing của Nginx:
round-robin(mặc định): Phân phối các yêu cầu đến một cách đều đặn và tuần tự giữa các máy chủ trong nhómupstream.least_conn: Chuyển các yêu cầu đến máy chủ có ít kết nối hoạt động nhất, lý tưởng cho các kết nối client tồn tại lâu dài.ip_hash: Phương pháp này sử dụng hàm băm của địa chỉ IP của client để xác định máy chủ nào nhận yêu cầu, đảm bảo rằng một client cụ thể luôn kết nối đến cùng cùng một máy chủ backend để duy trì session persistence.hash key: Phân phối các yêu cầu dựa trên một khóa tùy chỉnh mà bạn định nghĩa, chẳng hạn như URI, một header cụ thể hoặc sự kết hợp của các biến.random: Phân phối các yêu cầu ngẫu nhiên trên các máy chủ backend.- Health Checks: Phiên bản mã nguồn mở của Nginx bao gồm các kiểm tra tình trạng cơ bản, thụ động được định nghĩa bởi các tham số
fail_timeoutvàmax_fails. Đối với các kiểm tra tình trạng chủ động, nâng cao hơn, bạn sẽ cần Nginx Plus (phiên bản thương mại) hoặc tích hợp với các công cụ giám sát bên ngoài.
Ví dụ cấu hình Nginx Load Balancer
Hãy cấu hình Nginx trên 192.168.1.100 để load balance lưu lượng đến hai backend web server của chúng ta.
Bước 1: Cài đặt Nginx
sudo apt update
sudo apt install nginx -y
Bước 2: Cấu hình Nginx
Mở tệp cấu hình Nginx: sudo nano /etc/nginx/nginx.conf hoặc tạo một tệp mới trong /etc/nginx/conf.d/loadbalancer.conf.
http {
upstream web_backend {
# mặc định là round-robin
server 192.168.1.101:80 weight=5; # 'weight' xác định tỷ lệ yêu cầu mà máy chủ này nhận được.
server 192.168.1.102:80 weight=5;
# Bạn có thể thêm nhiều máy chủ hơn, ví dụ: 'server 192.168.1.103:80 weight=1 backup;'
# Ví dụ về least_conn: bỏ comment dòng dưới đây để sử dụng
# least_conn;
# Ví dụ về ip_hash cho session persistence: bỏ comment dòng dưới đây
# ip_hash;
}
server {
listen 80;
server_name yourdomain.com 192.168.1.100;
location / {
proxy_pass http://web_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Tùy chọn: Load Balancing HTTPS
server {
listen 443 ssl;
server_name yourdomain.com 192.168.1.100;
ssl_certificate /etc/nginx/ssl/yourdomain.crt;
ssl_certificate_key /etc/nginx/ssl/yourdomain.key;
location / {
proxy_pass http://web_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
Hãy nhớ tạo thư mục SSL và đặt chứng chỉ của bạn vào đó nếu bạn đang sử dụng HTTPS, và điều chỉnh yourdomain.com cùng địa chỉ IP cho phù hợp.
Bước 3: Kiểm tra và Bật Nginx
sudo nginx -t # Kiểm tra cú pháp cấu hình
sudo systemctl enable nginx
sudo systemctl restart nginx
sudo systemctl status nginx
Với cấu hình này, Nginx giờ đây sẽ hoạt động như một load balancer. Các tham số fail_timeout và max_fails, mà bạn có thể thêm vào mỗi dòng server trong khối upstream, cho phép thực hiện các kiểm tra tình trạng thụ động cơ bản. Ví dụ, server 192.168.1.101:80 max_fails=3 fail_timeout=30s; có nghĩa là nếu ba yêu cầu đến 192.168.1.101:80 thất bại trong vòng 30 giây, Nginx sẽ đánh dấu máy chủ đó là tạm thời không khả dụng trong 30 giây tiếp theo.
Mẹo thực tế và các phương pháp hay nhất
Mặc dù việc thiết lập một load balancer là một bước khởi đầu tuyệt vời, nhưng để thực sự đảm bảo high availability và hoạt động liền mạch đòi hỏi phải xem xét các mẹo thực tế sau:
1. Giám sát mọi thứ
Đừng chỉ cấu hình load balancer của bạn rồi quên nó đi. Việc giám sát liên tục cả load balancer và tất cả các backend server là rất quan trọng. Trang stats tích hợp của HAProxy (như đã cấu hình trong khối listen stats trước đó) cung cấp thông tin chi tiết vô giá theo thời gian thực về trạng thái máy chủ, các kết nối đang hoạt động và các mẫu lưu lượng truy cập. Đối với Nginx, bạn thường sẽ dựa vào các công cụ giám sát bên ngoài để thu thập log hoặc tận dụng module Nginx stub status để có các chỉ số cơ bản.
2. Session Persistence (Sticky Sessions)
Một số ứng dụng yêu cầu người dùng phải luôn kết nối đến cùng một backend server trong suốt phiên của họ — ví dụ, nếu dữ liệu phiên được lưu trữ cục bộ trên máy chủ cụ thể đó. Hành vi này được gọi là session persistence, hay ‘sticky sessions’.
- HAProxy: Sử dụng chỉ thị
cookietrong phầnbackend(như đã hiển thị trong cấu hình chi tiết:cookie SERVERID insert indirect nocache). - Nginx: Sử dụng phương pháp load balancing
ip_hashtrong khốiupstreamcủa bạn. Lưu ý rằng nếu IP của người dùng thay đổi (ví dụ: mạng di động), họ có thể được chuyển đến một máy chủ mới.
Chỉ triển khai sticky sessions khi thực sự cần thiết, vì chúng có thể cản trở việc phân phối tải tối ưu và giảm hiệu quả của load balancer của bạn.
3. Chiến lược SSL/TLS Termination
Quyết định nơi xử lý mã hóa và giải mã SSL/TLS là một lựa chọn kiến trúc quan trọng.
- Tại Load Balancer: Trong mô hình này, load balancer giải mã lưu lượng SSL/TLS đến và sau đó chuyển tiếp lưu lượng đã được giải mã hoặc được mã hóa lại đến các máy chủ backend. Cách tiếp cận này giúp giảm tải các hoạt động mã hóa đòi hỏi CPU cao từ các máy chủ web của bạn, cho phép chúng tập trung vào việc phục vụ nội dung ứng dụng. (Ví dụ HAProxy:
bind *:443 ssl crt /etc/ssl/certs/yourdomain.pem) - Tại Backend Servers: Ngoài ra, load balancer có thể đơn giản chuyển tiếp lưu lượng được mã hóa trực tiếp đến các máy chủ backend, nơi chúng tự xử lý việc giải mã. Mặc dù điều này đơn giản hóa cấu hình của load balancer, nhưng nó đặt gánh nặng xử lý lớn hơn lên các máy chủ ứng dụng backend của bạn. (Ví dụ HAProxy:
mode tcpvàbind *:443không cóssl crt, sau đóserver web1 192.168.1.101:443 check).
Thông thường, việc terminating SSL tại load balancer được ưu tiên để cải thiện hiệu suất và quản lý chứng chỉ hợp lý hơn.
4. Dự phòng cho chính Load Balancer
Điều gì sẽ xảy ra nếu chính load balancer của bạn bị lỗi? Nó ngay lập tức trở thành một điểm lỗi duy nhất mới. Để đạt được high availability thực sự, việc triển khai ít nhất hai load balancer là điều cần thiết.
Các công nghệ như VRRP (Virtual Router Redundancy Protocol) kết hợp với keepalived có thể thiết lập một floating IP address tự động chuyển đổi giữa một load balancer đang hoạt động và một load balancer dự phòng. Thiết lập này là một bước tiếp theo quan trọng cho bất kỳ môi trường production nào, và tôi có thể xác nhận rằng việc bỏ qua các thử nghiệm dự phòng này chắc chắn sẽ dẫn đến các vấn đề sau này. Tôi đã học được điều này một cách khó khăn trong một cửa sổ bảo trì theo kế hoạch mà không ngờ lại gặp sự cố.
5. Kiểm tra kỹ lưỡng
Trước khi triển khai vào môi trường production, hãy kiểm tra nghiêm ngặt thiết lập load balancer của bạn. Mô phỏng các kịch bản lỗi khác nhau:
- Dừng một backend server và xác minh lưu lượng được chuyển hướng.
- Khởi động lại máy chủ bị lỗi và đảm bảo nó tham gia lại vào nhóm.
- Tăng tải mô phỏng để xem thuật toán bạn chọn hoạt động như thế nào.
- Kiểm tra các trường hợp biên như network partitions.
Việc triển khai một load balancer đánh dấu một bước cơ bản hướng tới việc xây dựng các ứng dụng web mạnh mẽ và có khả năng mở rộng. Cho dù bạn chọn sức mạnh chuyên dụng của HAProxy hay tính linh hoạt của Nginx, việc hiểu rõ các khái niệm này chắc chắn sẽ giúp bạn tránh khỏi những cuộc gọi sự cố lúc 2 giờ sáng đáng sợ và giữ cho dịch vụ của bạn hoạt động trơn tru.

