Phân tích tải trọng HTTP trong Nginx - Cân bằng tải tầng 7

Phân tích tải trọng HTTP trong Nginx - Cân bằng tải tầng 7

Mục lục- Phân tích tải trọng HTTP trong Nginx - Cân bằng tải tầng 7

  • Tổng quan về cân bằng tải Nginx
  • Cấu hình cân bằng tải Nginx
  • Thuật toán phân phối trong Nginx
  • Trạng thái máy chủ phía sau
  • Kiểm tra sức khỏe máy chủ

Tổng quan về cân bằng tải Nginx

Tại sao cần sử dụng cân bằng tải?

Khi máy chủ web trực tiếp phục vụ người dùng, nó phải xử lý hàng loạt yêu cầu đồng thời, điều này khiến một máy chủ đơn lẻ khó có thể đáp ứng. Vì vậy, việc sử dụng nhiều máy chủ web để tạo thành cụm, với Nginx làm cân bằng tải phía trước, giúp phân tán các yêu cầu đến cụm máy chủ phía sau, từ đó nâng cao hiệu suất hệ thống, khả năng xử lý và độ tin cậy.

Cân bằng tải SLB (Server Load Balance) là phổ biến nhất, các nút điều phối và nút dịch vụ thường nằm trong cùng một khu vực logic. Nó đảm bảo tính thời gian thực và phản hồi tốt cho một số dịch vụ trong phạm vi nhỏ này.

Khi lượng lớn yêu cầu đến, chúng sẽ được chuyển đến nút điều phối đầu tiên, sau đó nút điều phối chuyển yêu cầu đến nút dịch vụ tương ứng. Nút dịch vụ xử lý xong yêu cầu rồi trả lại cho nút điều phối, cuối cùng nút điều phối gửi kết quả về cho người dùng.

Cân bằng tải còn gọi là Load Balance hoặc LB, trong môi trường đám mây công cộng được gọi là:

  • SLB - Load Balancer của Alibaba Cloud
  • QLB - Load Balancer của QingCloud
  • CLB - Load Balancer của Tencent Cloud
  • ULB - Load Balancer của UCloud

Các phần mềm cân bằng tải phổ biến bao gồm: Nginx, HAProxy và LVS (chỉ tầng 4)

Ứng dụng cân bằng tải tầng 4

Tầng 4 (giao thức truyền vận) trong mô hình OSI, Nginx hỗ trợ TCP/IP nên chỉ cần chuyển tiếp gói tin TCP/IP là đủ để thực hiện cân bằng tải. Ưu điểm là tốc độ rất nhanh, chỉ cần xử lý ở cấp độ cơ sở mà không cần logic phức tạp.

Ứng dụng cân bằng tải tầng 7

Tầng 7 (giao thức ứng dụng) trong mô hình OSI, có thể xử lý nhiều giao thức ứng dụng như HTTP, hỗ trợ chỉnh sửa thông tin header, kiểm soát quy tắc bảo mật, khớp URL, chuyển hướng, rewrite, v.v.

Gói dữ liệu được phân phối ở tầng thấp trong cân bằng tải tầng 4, còn tầng 7 phân phối ở tầng cao nhất, do đó hiệu suất thấp hơn nhưng gần với dịch vụ hơn. Ví dụ như HTTP, có thể duy trì phiên làm việc, khớp đường dẫn URL, chỉnh sửa header, những điều mà cân bằng tải tầng 4 không thể thực hiện.

Lưu ý: Cân bằng tải tầng 4 không nhận diện tên miền, còn tầng 7 thì có

Cấu hình cân bằng tải Nginx

Để thực hiện cân bằng tải trong Nginx, cần sử dụng module proxy_pass.

Khác biệt giữa proxy và cân bằng tải là một location chỉ có thể proxy đến một máy chủ, trong khi cân bằng tải sẽ chuyển tiếp yêu cầu đến một nhóm máy chủ ảo upstream.

Tóm tắt module

Module ngx_http_upstream_module định nghĩa nhóm máy chủ có thể được tham chiếu bởi các chỉ thị proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass và grpc_pass.

# Định nghĩa nhóm máy chủ. Máy chủ có thể lắng nghe trên các cổng khác nhau. Có thể kết hợp lắng nghe TCP và UNIX-domain socket.
Syntax: upstream name { ... }
Default: -
Context: http

Ví dụ:

resolver 10.0.0.1;

upstream dynamic {
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;
    server backend3.example.com      resolve;
    server backend4.example.com      service=http resolve;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

server {
    location / {
        proxy_pass http://dynamic;
        health_check;
    }
}

  • weight=number thiết lập trọng số máy chủ, mặc định là 1.
  • max_fails=number

Số lần thử kết nối thất bại trong khoảng thời gian fail_timeout. Mặc định là 1. 0 để tắt. Các lần thất bại được xác định bởi các chỉ thị proxy_next_upstream, fastcgi_next_upstream, uwsgi_next_upstream, scgi_next_upstream, memcached_next_upstream và grpc_next_upstream.

  • fail_timeout=time thời gian chờ thất bại liên tục khi kết nối với máy chủ. Mặc định là 10 giây.
  • backup đánh dấu máy chủ là máy chủ dự phòng, chỉ hoạt động khi máy chủ chính không khả dụng. Không thể dùng chung với hash, ip_hashrandom.
  • resolve giám sát thay đổi địa chỉ IP của tên miền máy chủ và tự động cập nhật cấu hình upstream mà không cần restart Nginx. Nhóm máy chủ phải nằm trong bộ nhớ chia sẻ. resolver phải được khai báo trong khối http hoặc khối upstream.
  • service=name

Kích hoạt phân giải bản ghi DNS SRV và thiết lập tên dịch vụ name. Cần có tham số resolve và tên máy chủ không có cổng. Bản ghi SRV có độ ưu tiên cao nhất (có giá trị ưu tiên thấp nhất) được phân giải thành máy chủ chính, các bản ghi còn lại thành máy chủ dự phòng. Nếu máy chủ có tham số backup, bản ghi SRV ưu tiên cao được phân giải thành máy chủ dự phòng, các bản ghi còn lại bị bỏ qua.

Module ngx_http_proxy_module cho phép chuyển tiếp yêu cầu đến máy chủ khác.

Syntax:	    proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | non_idempotent | off ...;
Default:	proxy_next_upstream error timeout;
Context:	http, server, location

proxy_next_upstream chỉ định khi nào chuyển yêu cầu sang máy chủ khác

  • error lỗi khi kết nối, gửi yêu cầu hoặc đọc tiêu đề phản hồi từ máy chủ;
  • timeout hết thời gian khi kết nối, gửi yêu cầu hoặc đọc tiêu đề phản hồi;
  • invalid_header máy chủ trả về phản hồi trống hoặc không hợp lệ;
  • http_500|http_502|http_503|http_504|http_403|http_404|http_429
  • non_idempotent cho phép thử lại với phương thức yêu cầu không có tính chất lặp lại (POST, LOCK, PATCH);
  • off tắt việc chuyển yêu cầu sang máy chủ khác.

Chỉ có thể chuyển yêu cầu nếu chưa gửi gì cho khách hàng. Nếu xảy ra lỗi hoặc quá hạn trong quá trình truyền phản hồi, không thể chuyển tiếp.

Chuẩn bị môi trường:

Vai trò IP公网(NAT) IP内网(LAN) Tên máy
lb01 eth0:10.0.0.5 eth1:172.16.1.5 lb01
web01 eth0:10.0.0.7 eth1:172.16.1.7 web01
web02 eth0:10.0.0.8 eth1:172.16.1.8 web02

Cấu hình web01:

[root@web01 ~]# cat > /etc/nginx/conf.d/node.conf <<EOF
server {
    listen 80;
    server_name node.oldboy.com;
    location / {
        root /node;
        index index.html;
    }
}
EOF
[root@web01 ~]# mkdir /node
[root@web01 ~]# echo "Web01..." > /node/index.html
[root@web01 ~]# systemctl reload nginx

Cấu hình web02:

[root@web02 ~]# cat > /etc/nginx/conf.d/node.conf <<EOF
server {
    listen 80;
    server_name node.oldboy.com;
    location / {
        root /node;
        index index.html;
    }
}
EOF
[root@web02 ~]# mkdir /node
[root@web02 ~]# echo "Web02..." > /node/index.html
[root@web02 ~]# systemctl reload nginx

Cấu hình lb01:

[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_node.conf <<EOF
upstream node {
    server 172.16.1.7:80;
    server 172.16.1.8:80;
}
server {
    listen 80;
    server_name node.oldboy.com;
 
    location / {
        proxy_pass http://node;
        include proxy_params;
    }
}
EOF

[root@lb01 ~]# vim /etc/nginx/proxy_params
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
 
proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;

[root@lb01 ~]# systemctl reload nginx

Cấu hình Windows:

Trong tệp C:\Windows\System32\drivers\etc\hosts, thêm dòng 10.0.0.5 node.oldboy.com

Kiểm tra bằng trình duyệt: http://node.oldboy.com

Làm mới nhanh thấy chuyển đổi giữa web01 và web02

Lưu ý:

  • Nếu máy chủ phía sau mất kết nối, Nginx sẽ chuyển yêu cầu sang máy chủ khác dựa trên cấu hình cân bằng tải.
  • Nếu máy chủ hoạt động bình thường nhưng trả về mã lỗi (504, 502, 500), cần cấu hình proxy_next_upstream để chuyển tiếp yêu cầu sang máy chủ khác, tăng tỷ lệ thành công truy cập.
server {
    listen 80;
    server_name www.oldboy.com;

    location / {
        proxy_pass http://node;
        proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    }
}

Cấu hình lb01 cân bằng tải cho WordPress và WeCenter trên web01 và web02

[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_web.conf <> /etc/hosts

Tắt php-fpm trên web01 để kiểm tra:

[root@web01 ~]# systemctl stop php-fpm.service
[root@lb01 ~]# curl -I blog.oldboy.com
HTTP/1.1 502 Bad Gateway
Server: nginx/1.16.1
Date: Mon, 21 Sep 2020 02:05:58 GMT
Content-Type: text/html
Content-Length: 157
Connection: keep-alive
[root@lb01 ~]# curl -I blog.oldboy.com
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Mon, 21 Sep 2020 02:05:58 GMT
Content-Type: text/html
Content-Length: 4833
Connection: keep-alive
Last-Modified: Fri, 16 May 2014 15:12:48 GMT
ETag: "53762af0-12e1"
Accept-Ranges: bytes

Sửa cấu hình lb01:

[root@lb01 ~]# cat > /etc/nginx/conf.d/www.conf <> /etc/hosts
[root@lb01 ~]# cat /etc/nginx/conf.d/proxy_node.conf
upstream node {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name node.oldboy.com;

location / {
proxy_pass http://node;
include proxy_params;
}
}
[root@lb01 ~]# curl node.oldboy.com
Web01...
[root@lb01 ~]# curl node.oldboy.com
Web02...

Thử nghiệm trạng thái down: 172.16.1.8 không tham gia, curl luôn trả về Web01...

[root@lb01 ~]# cat > /etc/nginx/conf.d/proxy_node.conf < /etc/nginx/conf.d/proxy_node.conf < /etc/nginx/conf.d/proxy_node.conf < /etc/nginx/conf.d/node.conf < /etc/nginx/conf.d/proxy_node.conf </etc/nginx/conf.d/proxy_php.conf << EOF
upstream php {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name php.oldboy.com;
location / {
proxy_pass http://php;
include proxy_params;
}
}
EOF
[root@lb01 ~]# systemctl reload nginx

  1. Cấu hình Windows:

Sửa dòng trong tệp C:\Windows\System32\drivers\etc\hosts thành 10.0.0.5 php.oldboy.com

  1. Kiểm tra: không thể đăng nhập

Mỗi lần kết nối máy chủ tạo cookie mới, đăng nhập thành công thì PHP mặc định lưu cookie:session vào tệp cục bộ. Gửi yêu cầu đăng nhập, sẽ phân phối sang máy chủ khác, máy chủ mới tạo cookie mới nhưng không có session cũ, nên đăng nhập thất bại. Vòng lặp vô tận...

Sử dụng Redis để duy trì phiên

  1. Cài đặt Redis
[root@db01 ~]# yum -y install redis

  1. Cấu hình Redis lắng nghe 172.16.1.51
[root@db01 ~]# sed  -i '/^bind/c bind 127.0.0.1 172.16.1.51' /etc/redis.conf

  1. Khởi động Redis và thêm vào khởi động tự động
[root@db01 ~]# systemctl start redis
[root@db01 ~]# systemctl enable redis

  1. Sửa cấu hình PHP để kết nối Redis cho session
[root@web01 ~]# sed -i '/session.save_handler/c session.save_handler = redis' /etc/php.ini
[root@web01 ~]# sed -i '/;session.save_path/c session.save_path = "tcp://172.16.1.51:6379"' /etc/php.ini
[root@web01 ~]# sed -i '/session.auto_start/c session.auto_start = 1' /etc/php.ini

;session.save_path = "tcp://172.16.1.51:6379?auth=123"  # Redis có mật khẩu

  1. Sửa cấu hình PHP-FPM
# Trong /etc/php-fpm.d/www.conf, comment hai dòng sau, nếu không session vẫn ghi vào /var/lib/php/session
①[root@web01 ~]#;php_value[session.save_handler] = files
  [root@web01 ~]#;php_value[session.save_path]    = /var/lib/php/session
②[root@web01 ~]# sed -i 's/^php_value\[session.save_handler\].*/;&/' /etc/php-fpm.d/www.conf
  [root@web01 ~]# sed -i 's/^php_value\[session.save_path\].*/;&/' /etc/php-fpm.d/www.conf

  1. Đẩy /etc/php.ini/etc/php-fpm.d/www.conf từ web01 sang web02
[root@web01 code]# scp /etc/php.ini root@172.16.1.8:/etc/php.ini  
[root@web01 code]# scp /etc/php-fpm.d/www.conf root@172.16.1.8:/etc/php-fpm.d/www.conf 

  1. Tải lại PHP-FPM
[root@web01 ~]# systemctl reload php-fpm
[root@web02 ~]# systemctl reload php-fpm

  1. Kiểm tra Redis cookie và trang web
[root@db01 ~]# redis-cli 
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:645649c6fa3a53663331348320e20fcd"

  1. Làm mới nhiều lần cookie giữ nguyên

Thẻ: nginx Load Balancing http proxy php

Đăng vào ngày 9 tháng 8 lúc 08:05