两层、三层nginx百万级QPS设计
温馨提示:
本文最后更新于 2025年09月28日,已超过 257 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我。
启动命令:最后的参数可以将前端项目直接复制到 nginx节点中,无此参数 则直接生成默认的主页,以便区分 节点
./cn 2 3 80 /data/configs /root/dist 两层、三层nginx百万级QPS设计 可以搭建2层、3层nginx,并直接将 前端项目 打包进 最后一层 nginx中
#!/bin/bash
# 在脚本一开始启用日志记录
exec &> >(tee -a Nginx_Architecture.log)
# 颜色定义 - 扩展颜色数组以支持更多节点
declare -a colors=("red" "blue" "green" "orange" "purple" "cyan" "yellow" "pink" "lightblue" "lightgreen" "lavender" "coral")
# HTML目录定义
HTML_DIR="html"
# 添加层级选择对话框
echo "请输入您要创建的nginx层级,2 代表2层,3 代表3层:"
read -p "请选择架构层级 (2/3): " NGINX_LEVEL
# 验证输入
if [[ "$NGINX_LEVEL" != "2" && "$NGINX_LEVEL" != "3" ]]; then
echo "Error: 请输入有效的层级 (2 或 3)"
exit 1
fi
# 参数处理
if [ $# -gt 5 ]; then
echo "Usage: $0 [cluster_size] [lb_cluster_size] [host_port] [config_dir] [source_dir]"
echo " cluster_size: 后端节点数量 (默认: 3)"
echo " lb_cluster_size: 负载均衡器数量 (最小: 1)"
echo " host_port: 暴露的主机端口 (默认: 8080)"
echo " config_dir: 配置文件存储目录 (默认: ./nginx-configs)"
echo " source_dir: 要复制到从节点的源文件夹路径"
exit 1
fi
# 参数解析
CLUSTER_SIZE=${1:-3}
LB_CLUSTER_SIZE=${2:-2}
HOST_PORT=${3:-8080}
CONFIG_DIR=${4:-./nginx-configs}
SOURCE_DIR=${5}
# 参数验证
if ! [[ "$CLUSTER_SIZE" =~ ^[0-9]+$ ]] || [ "$CLUSTER_SIZE" -le 0 ]; then
echo "Error: Cluster size must be a positive integer"
exit 1
fi
if ! [[ "$LB_CLUSTER_SIZE" =~ ^[0-9]+$ ]] || [ "$LB_CLUSTER_SIZE" -lt 1 ]; then
echo "Error: Load balancer cluster size must be at least 1"
exit 1
fi
if ! [[ "$HOST_PORT" =~ ^[0-9]+$ ]] || [ "$HOST_PORT" -lt 1024 ] || [ "$HOST_PORT" -gt 65535 ]; then
echo "Error: Port must be between 1024 and 65535"
exit 1
fi
# 路径验证
if [ -e "$CONFIG_DIR" ] && [ ! -d "$CONFIG_DIR" ]; then
echo "Error: Config path exists but is not a directory"
exit 1
fi
# 验证源目录(如果提供)
if [ -n "$SOURCE_DIR" ] && [ ! -d "$SOURCE_DIR" ]; then
echo "Error: Source directory does not exist or is not a directory"
exit 1
fi
# 网络配置
NETWORK_NAME=nginx-cluster
# 创建配置目录
mkdir -p "$CONFIG_DIR"
CONFIG_ROOT=$(cd "$CONFIG_DIR" && pwd)
# 文件定义
MAIN_CONF="nginx.conf"
LB_DIR="lb"
BUS_DIR="bus"
# 清理旧资源
echo "清理旧资源..."
docker rm -f nginx-node-* nginx-lb-* nginx-bus 2>/dev/null
docker network rm $NETWORK_NAME 2>/dev/null
rm -rf "$CONFIG_ROOT"
mkdir -p "$CONFIG_ROOT"
# 创建自定义网络
echo "创建自定义网络..."
docker network create -d bridge --subnet=192.168.1.0/24 $NETWORK_NAME 2>/dev/null
# 生成主配置文件 - 百万级QPS优化版本
cat <<'EOF' > "$CONFIG_ROOT/$MAIN_CONF"
user nginx;
worker_processes auto;
# 增加最大打开文件数限制
worker_rlimit_nofile 100000;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
# 优化事件处理模型
use epoll;
worker_connections 20000;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 高并发优化设置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 缓冲区优化
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
# 超时优化
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
keepalive_timeout 30;
keepalive_requests 1000;
# Gzip 压缩优化
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# 文件缓存优化
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# 代理优化
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_temp_file_write_size 32k;
# 关闭访问日志提升性能(生产环境中可选择性开启)
access_log off;
include /etc/nginx/conf.d/*.conf;
}
EOF
# 启动后端节点
for i in $(seq 1 $CLUSTER_SIZE); do
# 创建节点目录结构
NODE_DIR="$CONFIG_ROOT/node-$i"
mkdir -p "$NODE_DIR/conf.d" "$NODE_DIR/$HTML_DIR"
# 如果提供了源目录,则复制文件到HTML目录
if [ -n "$SOURCE_DIR" ]; then
cp -r "$SOURCE_DIR"/* "$NODE_DIR/$HTML_DIR/" 2>/dev/null || echo "Warning: Failed to copy files from $SOURCE_DIR"
else
# 生成节点页面
# 使用模运算确保颜色索引不会超出范围
COLOR_INDEX=$(( (i-1) % ${#colors[@]} ))
cat < "$NODE_DIR/$HTML_DIR/index.html"
Node $i
Node $i
Backend Server
Container ID: Placeholder
EOF
fi
# 生成节点配置文件 - 百万级QPS优化版本
cat < "$NODE_DIR/conf.d/default.conf"
server {
listen 80 reuseport;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files \$uri \$uri/ =404;
# 静态文件优化
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
# 先尝试停止并删除可能存在的容器
docker stop nginx-node-$i 2>/dev/null
docker rm nginx-node-$i 2>/dev/null
# 启动容器(使用自定义网络)- 添加系统优化参数
if docker run -d \
--name nginx-node-$i \
--network $NETWORK_NAME \
--ip 192.168.1.$((i+10)) \
--ulimit nofile=100000:100000 \
-v "$NODE_DIR/conf.d:/etc/nginx/conf.d" \
-v "$NODE_DIR/$HTML_DIR:/usr/share/nginx/html" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest nginx -g 'daemon off;'; then
echo "成功启动 nginx-node-$i"
# 显示容器IP
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx-node-$i 2>/dev/null)
if [ -n "$CONTAINER_IP" ]; then
echo "容器IP: $CONTAINER_IP"
fi
else
echo "警告: 容器 nginx-node-$i 启动失败"
fi
done
# 创建负载均衡器配置
mkdir -p "$CONFIG_ROOT/$LB_DIR/conf.d"
LB_CONF="$CONFIG_ROOT/$LB_DIR/conf.d/default.conf"
# 生成负载均衡配置 - 百万级QPS优化版本
cat < $LB_CONF
upstream backend {
least_conn;
keepalive 1000;
keepalive_requests 10000;
keepalive_time 300s;
$(for i in $(seq 1 $CLUSTER_SIZE); do echo " server nginx-node-$i:80 max_fails=3 fail_timeout=30s;"; done)
}
server {
listen 80 reuseport;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_cache_bypass \$http_upgrade;
# 代理超时优化
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
location /_status {
stub_status on;
access_log off;
allow all;
}
}
EOF
# 启动负载均衡器集群
for i in $(seq 1 $LB_CLUSTER_SIZE); do
# 先尝试停止并删除可能存在的容器
docker stop nginx-lb-$i 2>/dev/null
docker rm nginx-lb-$i 2>/dev/null
# 启动容器(使用自定义网络)- 添加系统优化参数
if docker run -d \
--name nginx-lb-$i \
--network $NETWORK_NAME \
--ip 192.168.1.$((252-i)) \
-p $((HOST_PORT+i-1)):80 \
--ulimit nofile=100000:100000 \
-v "$CONFIG_ROOT/lb/conf.d:/etc/nginx/conf.d" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest nginx -g 'daemon off;'; then
echo "成功启动 nginx-lb-$i"
# 显示容器IP
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx-lb-$i 2>/dev/null)
if [ -n "$CONTAINER_IP" ]; then
echo "容器IP: $CONTAINER_IP"
fi
else
echo "警告: 容器 nginx-lb-$i 启动失败"
fi
done
# 根据选择的架构层级决定是否创建总线nginx
if [ "$NGINX_LEVEL" = "3" ]; then
# 添加总线nginx端口输入对话框
while true; do
read -p "总线nginx对外暴露的端口: " BUS_PORT
# 验证端口输入
if ! [[ "$BUS_PORT" =~ ^[0-9]+$ ]] || [ "$BUS_PORT" -lt 1024 ] || [ "$BUS_PORT" -gt 65535 ]; then
echo "Error: 端口必须是1024到65535之间的数字"
continue
fi
# 检查端口是否被占用
if netstat -tuln | grep -q ":$BUS_PORT "; then
echo "Error: 端口 $BUS_PORT 已被占用,请重新输入"
continue
else
echo "端口 $BUS_PORT 可用"
break
fi
done
# 创建总线nginx配置
mkdir -p "$CONFIG_ROOT/$BUS_DIR/conf.d"
BUS_CONF="$CONFIG_ROOT/$BUS_DIR/conf.d/default.conf"
# 生成总线nginx配置,负载均衡到所有负载均衡器节点 - 百万级QPS优化版本
cat < $BUS_CONF
upstream loadbalancers {
least_conn;
keepalive 1000;
keepalive_requests 10000;
keepalive_time 300s;
$(for i in $(seq 1 $LB_CLUSTER_SIZE); do echo " server nginx-lb-$i:80 max_fails=3 fail_timeout=30s;"; done)
}
server {
listen 80 reuseport;
location / {
proxy_pass http://loadbalancers;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_cache_bypass \$http_upgrade;
# 代理超时优化
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
}
EOF
# 启动总线nginx容器
docker stop nginx-bus 2>/dev/null
docker rm nginx-bus 2>/dev/null
# 启动总线nginx容器(使用自定义网络)- 添加系统优化参数
if docker run -d \
--name nginx-bus \
--network $NETWORK_NAME \
--ip 192.168.1.254 \
-p $BUS_PORT:80 \
--ulimit nofile=100000:100000 \
-v "$CONFIG_ROOT/bus/conf.d:/etc/nginx/conf.d" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest nginx -g 'daemon off;'; then
echo "成功启动 nginx-bus"
# 显示总线nginx容器IP
BUS_CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx-bus 2>/dev/null)
if [ -n "$BUS_CONTAINER_IP" ]; then
echo "容器IP: $BUS_CONTAINER_IP"
fi
else
echo "警告: 容器 nginx-bus 启动失败"
fi
fi
# 等待容器初始化
sleep 3
# 更新页面中的容器ID
for i in $(seq 1 $CLUSTER_SIZE); do
if docker ps | grep -q "nginx-node-$i"; then
CONTAINER_ID=$(docker inspect --format='{{.Id}}' nginx-node-$i | cut -c1-12)
sed -i "s/Placeholder/$CONTAINER_ID/" "$CONFIG_ROOT/node-$i/$HTML_DIR/index.html"
docker cp "$CONFIG_ROOT/node-$i/$HTML_DIR/index.html" nginx-node-$i:/usr/share/nginx/html/index.html 2>/dev/null
fi
done
# 输出信息
echo "✅ 百万级QPS优化的负载均衡集群已启动"
echo "配置目录: $CONFIG_ROOT"
echo "后端集群规模: $CLUSTER_SIZE 节点"
echo "负载均衡器集群规模: $LB_CLUSTER_SIZE 实例"
if [ "$NGINX_LEVEL" = "3" ]; then
echo "架构层级: 3层 (包含总线nginx)"
echo "总线nginx地址: http://$(hostname):$BUS_PORT"
else
echo "架构层级: 2层 (不包含总线nginx)"
fi
echo "访问地址: http://$(hostname):$HOST_PORT (端口映射: $HOST_PORT->$((HOST_PORT+LB_CLUSTER_SIZE-1)))"
if [ -n "$SOURCE_DIR" ]; then
echo "源文件目录: $SOURCE_DIR"
fi
echo "节点样式:"
for i in $(seq 1 $CLUSTER_SIZE); do
COLOR_INDEX=$(( (i-1) % ${#colors[@]} ))
echo "Node $i -> 背景颜色: ${colors[$COLOR_INDEX]}"
done
特点
这个脚本 `nginx3层架构_百万级QPS优化.bash` 是一个用于构建高性能 Nginx 集群的自动化部署脚本,支持构建 2 层或 3 层架构,旨在实现百万级 QPS 的性能优化。
## ? 脚本功能概述
- 支持构建 2 层或 3 层 Nginx 集群架构
- 自动创建 Docker 容器和自定义网络
- 配置高性能 Nginx 参数(适用于百万级 QPS 场景)
- 自动生成 HTML 页面用于测试和展示
- 支持自定义源文件目录复制到节点中
## ? 使用方法
```bash
./nginx3层架构_百万级QPS优化.bash [cluster_size] [lb_cluster_size] [host_port] [config_dir] [source_dir]
```
### 参数说明
| 参数名 | 说明 | 默认值 |
|--------|------|--------|
| `cluster_size` | 后端节点数量 | 3 |
| `lb_cluster_size` | 负载均衡器数量 | 2 |
| `host_port` | 暴露的主机端口(起始端口) | 8080 |
| `config_dir` | 配置文件存储目录 | ./nginx-configs |
| `source_dir` | 要复制到从节点的源文件夹路径 | 无 |
### 示例
```bash
# 基本使用,默认参数
./nginx3层架构_百万级QPS优化.bash
# 自定义参数:5个后端节点,3个负载均衡器,起始端口9000
./nginx3层架构_百万级QPS优化.bash 5 3 9000 ./my-configs ./web-content
```
## ?️ 运行时交互
脚本运行时会提示用户输入以下信息:
1. **架构层级选择**:
- 输入 `2` 表示构建 2 层架构(客户端 -> 负载均衡器 -> 后端节点)
- 输入 `3` 表示构建 3 层架构(客户端 -> 总线nginx -> 负载均衡器 -> 后端节点)
2. **总线nginx端口(仅3层架构时)**:
- 如果选择 3 层架构,需要输入总线 nginx 对外暴露的端口号
## ? 目录结构
脚本会自动生成以下目录结构:
```
nginx-configs/
├── nginx.conf # 主配置文件
├── lb/ # 负载均衡器配置
│ └── conf.d/
│ └── default.conf
├── bus/ # 总线nginx配置(仅3层架构)
│ └── conf.d/
│ └── default.conf
└── node-X/ # 每个后端节点的配置
├── conf.d/
│ └── default.conf
└── html/
└── index.html
```
## ? 访问方式
- **2层架构**:直接通过 `http://:` 访问
- **3层架构**:通过 `http://:` 访问
## ⚠️ 注意事项
1. 确保 Docker 服务正在运行
2. 确保指定的端口未被占用
3. 脚本会自动清理之前的容器和网络配置
4. 如需生产环境使用,建议根据实际需求调整配置参数
## ? 输出信息
脚本执行完成后会显示:
- 集群配置信息
- 访问地址
- 各节点的背景颜色
- 容器IP地址等详细信息
日志会被记录在 `Nginx_Architecture.log` 文件中。 两层nginx百万级QPS设计
#!/bin/bash
# 颜色定义 - 扩展颜色数组以支持更多节点
declare -a colors=("red" "blue" "green" "orange" "purple" "cyan" "yellow" "pink" "lightblue" "lightgreen" "lavender" "coral")
# HTML目录定义
HTML_DIR="html"
# 参数处理
if [ $# -gt 5 ]; then
echo "Usage: $0 [cluster_size] [lb_cluster_size] [host_port] [config_dir] [source_dir]"
echo " cluster_size: 后端节点数量 (默认: 3)"
echo " lb_cluster_size: 负载均衡器数量 (最小: 1)"
echo " host_port: 暴露的主机端口 (默认: 8080)"
echo " config_dir: 配置文件存储目录 (默认: ./nginx-configs)"
echo " source_dir: 要复制到从节点的源文件夹路径"
exit 1
fi
# 参数解析
CLUSTER_SIZE=${1:-3}
LB_CLUSTER_SIZE=${2:-2}
HOST_PORT=${3:-8080}
CONFIG_DIR=${4:-./nginx-configs}
SOURCE_DIR=${5}
# 参数验证
if ! [[ "$CLUSTER_SIZE" =~ ^[0-9]+$ ]] || [ "$CLUSTER_SIZE" -le 0 ]; then
echo "Error: Cluster size must be a positive integer"
exit 1
fi
if ! [[ "$LB_CLUSTER_SIZE" =~ ^[0-9]+$ ]] || [ "$LB_CLUSTER_SIZE" -lt 1 ]; then
echo "Error: Load balancer cluster size must be at least 1"
exit 1
fi
if ! [[ "$HOST_PORT" =~ ^[0-9]+$ ]] || [ "$HOST_PORT" -lt 1024 ] || [ "$HOST_PORT" -gt 65535 ]; then
echo "Error: Port must be between 1024 and 65535"
exit 1
fi
# 路径验证
if [ -e "$CONFIG_DIR" ] && [ ! -d "$CONFIG_DIR" ]; then
echo "Error: Config path exists but is not a directory"
exit 1
fi
# 验证源目录(如果提供)
if [ -n "$SOURCE_DIR" ] && [ ! -d "$SOURCE_DIR" ]; then
echo "Error: Source directory does not exist or is not a directory"
exit 1
fi
# 网络配置
NETWORK_NAME=nginx-cluster
# 创建配置目录
mkdir -p "$CONFIG_DIR"
CONFIG_ROOT=$(cd "$CONFIG_DIR" && pwd)
# 文件定义
MAIN_CONF="nginx.conf"
LB_DIR="lb"
# 清理旧资源
echo "清理旧资源..."
docker rm -f nginx-node-* nginx-lb-* 2>/dev/null
docker network rm $NETWORK_NAME 2>/dev/null
rm -rf "$CONFIG_ROOT"
mkdir -p "$CONFIG_ROOT"
# 创建自定义网络
echo "创建自定义网络..."
docker network create -d bridge --subnet=192.168.1.0/24 $NETWORK_NAME 2>/dev/null
# 生成主配置文件 - 百万级QPS优化配置
cat <<'EOF' > "$CONFIG_ROOT/$MAIN_CONF"
user nginx;
worker_processes auto;
# 绑定worker进程到CPU核心
worker_cpu_affinity auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
# 调整worker_connections以支持高并发
events {
use epoll;
worker_connections 65535;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log off; # 关闭访问日志以提高性能
error_log /var/log/nginx/error.log crit;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 调整超时设置以优化性能
keepalive_timeout 30;
keepalive_requests 1000;
# Gzip 设置 - 优化压缩级别
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private must-revalidate auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss;
gzip_comp_level 1;
# 设置缓冲区以处理更多请求
client_body_buffer_size 128k;
client_max_body_size 50m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
# 设置文件缓存
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# 设置连接处理优化
reset_timedout_connection on;
# 设置请求限制
limit_req_zone $binary_remote_addr zone=general:10m rate=1000r/s;
include /etc/nginx/conf.d/*.conf;
}
EOF
# 启动后端节点
for i in $(seq 1 $CLUSTER_SIZE); do
# 创建节点目录结构
NODE_DIR="$CONFIG_ROOT/node-$i"
mkdir -p "$NODE_DIR/conf.d" "$NODE_DIR/$HTML_DIR"
# 如果提供了源目录,则复制文件到HTML目录
if [ -n "$SOURCE_DIR" ]; then
cp -r "$SOURCE_DIR"/* "$NODE_DIR/$HTML_DIR/" 2>/dev/null || echo "Warning: Failed to copy files from $SOURCE_DIR"
else
# 生成节点页面
# 使用模运算确保颜色索引不会超出范围
COLOR_INDEX=$(( (i-1) % ${#colors[@]} ))
cat < "$NODE_DIR/$HTML_DIR/index.html"
Node $i
Node $i
Backend Server
Container ID: Placeholder
EOF
fi
# 生成节点配置文件 - 百万级QPS优化配置
cat < "$NODE_DIR/conf.d/default.conf"
server {
listen 80 reuseport;
# 应用请求限制
# limit_req zone=general burst=200 nodelay;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files \$uri \$uri/ =404;
# 启用缓存头
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
# 先尝试停止并删除可能存在的容器
docker stop nginx-node-$i 2>/dev/null
docker rm nginx-node-$i 2>/dev/null
# 启动容器(使用自定义网络)
# 修改IP地址分配,避免与负载均衡器冲突
if docker run -d \
--name nginx-node-$i \
--network $NETWORK_NAME \
--ip 192.168.1.$((i+10)) \
--ulimit nofile=1000000:1000000 \ # 设置文件描述符限制
-v "$NODE_DIR/conf.d:/etc/nginx/conf.d" \
-v "$NODE_DIR/$HTML_DIR:/usr/share/nginx/html" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest; then
echo "成功启动 nginx-node-$i"
else
echo "警告: 容器 nginx-node-$i 启动失败"
fi
done
# 创建负载均衡器配置
mkdir -p "$CONFIG_ROOT/$LB_DIR/conf.d"
LB_CONF="$CONFIG_ROOT/$LB_DIR/conf.d/default.conf"
# 生成负载均衡配置 - 百万级QPS优化配置
cat < $LB_CONF
upstream backend {
least_conn;
keepalive 32;
keepalive_requests 1000;
keepalive_timeout 30s;
$(for i in $(seq 1 $CLUSTER_SIZE); do echo " server nginx-node-$i:80;"; done)
}
server {
listen 80 reuseport;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_cache_bypass \$http_upgrade;
# 启用代理缓存
proxy_cache_valid 200 302 10m;
proxy_cache_valid 301 1h;
proxy_cache_valid any 1m;
}
location /_status {
stub_status on;
access_log off;
allow all;
}
}
EOF
# 启动负载均衡器集群
for i in $(seq 1 $LB_CLUSTER_SIZE); do
# 先尝试停止并删除可能存在的容器
docker stop nginx-lb-$i 2>/dev/null
docker rm nginx-lb-$i 2>/dev/null
# 启动容器(使用自定义网络)
# 修改IP地址分配,确保不会与后端节点冲突
# 将负载均衡器的IP地址从100开始分配,避免冲突
if docker run -d \
--name nginx-lb-$i \
--network $NETWORK_NAME \
--ip 192.168.1.$((i+100)) \
--ulimit nofile=1000000:1000000 \ # 设置文件描述符限制
-p $((HOST_PORT+i-1)):80 \
-v "$CONFIG_ROOT/lb/conf.d:/etc/nginx/conf.d" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest; then
echo "成功启动 nginx-lb-$i"
else
echo "警告: 容器 nginx-lb-$i 启动失败"
fi
done
# 等待容器初始化
sleep 3
# 更新页面中的容器ID
for i in $(seq 1 $CLUSTER_SIZE); do
if docker ps | grep -q "nginx-node-$i"; then
CONTAINER_ID=$(docker inspect --format='{{.Id}}' nginx-node-$i | cut -c1-12)
sed -i "s/Placeholder/$CONTAINER_ID/" "$CONFIG_ROOT/node-$i/$HTML_DIR/index.html"
docker cp "$CONFIG_ROOT/node-$i/$HTML_DIR/index.html" nginx-node-$i:/usr/share/nginx/html/index.html 2>/dev/null
fi
done
# 输出信息
echo "✅ 基础负载均衡集群已启动"
echo "配置目录: $CONFIG_ROOT"
echo "后端集群规模: $CLUSTER_SIZE 节点"
echo "负载均衡器集群规模: $LB_CLUSTER_SIZE 实例"
echo "访问地址: http://$(hostname):$HOST_PORT (端口映射: $HOST_PORT->$((HOST_PORT+LB_CLUSTER_SIZE-1)))"
if [ -n "$SOURCE_DIR" ]; then
echo "源文件目录: $SOURCE_DIR"
fi
echo "节点样式:"
for i in $(seq 1 $CLUSTER_SIZE); do
COLOR_INDEX=$(( (i-1) % ${#colors[@]} ))
echo "Node $i -> 背景颜色: ${colors[$COLOR_INDEX]}"
done
特点
这个优化后的脚本包含了以下百万级 QPS 优化措施:
主配置文件优化 (nginx.conf):
启用 worker_cpu_affinity 绑定工作进程到 CPU 核心
增加 worker_connections 到 65535
启用 epoll 事件模型和 multi_accept
关闭访问日志以提高性能
优化 keepalive 设置
调整 TCP 相关参数 (tcp_nopush, tcp_nodelay)
优化 Gzip 压缩设置
设置各种缓冲区大小
启用文件缓存
添加请求限制机制
容器启动优化:
设置 --ulimit nofile=1000000:1000000 增加文件描述符限制
启用 reuseport 选项提高性能
后端节点配置优化:
启用 reuseport
添加缓存头设置
负载均衡器配置优化:
启用 reuseport
优化 keepalive 相关设置
设置 proxy_set_header Connection "" 以启用 HTTP keep-alive
添加代理缓存配置
这些优化能够显著提升 Nginx 集群处理高并发请求的能力,使其更接近百万级 QPS 的性能要求。 2 | 3 层nginx创建 自定义ip分配
#!/bin/bash
# 在脚本一开始启用日志记录
exec &> >(tee -a Nginx_Architecture.log)
# 后端节点的ip偏移量
Node_Usage=2
# 负载节点的ip偏移量
Load_Usage=3
# 2层架构 是否加入nginx总线负载均衡
Add_Nginx_Bus=false
# 颜色定义 - 扩展颜色数组以支持更多节点
declare -a colors=("red" "blue" "green" "orange" "purple" "cyan" "yellow" "pink" "lightblue" "lightgreen" "lavender" "coral")
# HTML目录定义
HTML_DIR="html"
# 添加层级选择对话框
echo "请输入您要创建的nginx层级,2 代表2层,3 代表3层:"
read -p "请选择架构层级 (2/3): " NGINX_LEVEL
# 验证输入
if [[ "$NGINX_LEVEL" != "2" && "$NGINX_LEVEL" != "3" ]]; then
echo "Error: 请输入有效的层级 (2 或 3)"
exit 1
fi
# 参数处理
if [ $# -gt 5 ]; then
echo "Usage: $0 [cluster_size] [lb_cluster_size] [host_port] [config_dir] [source_dir]"
echo " cluster_size: 后端节点数量 (默认: 3)"
echo " lb_cluster_size: 负载均衡器数量 (最小: 1)"
echo " host_port: 暴露的主机端口 (默认: 8080)"
echo " config_dir: 配置文件存储目录 (默认: ./nginx-configs)"
echo " source_dir: 要复制到从节点的源文件夹路径"
exit 1
fi
# 参数解析
CLUSTER_SIZE=${1:-3}
LB_CLUSTER_SIZE=${2:-2}
HOST_PORT=${3:-8080}
CONFIG_DIR=${4:-./nginx-configs}
SOURCE_DIR=${5}
# 参数验证
if ! [[ "$CLUSTER_SIZE" =~ ^[0-9]+$ ]] || [ "$CLUSTER_SIZE" -le 0 ]; then
echo "Error: Cluster size must be a positive integer"
exit 1
fi
if ! [[ "$LB_CLUSTER_SIZE" =~ ^[0-9]+$ ]] || [ "$LB_CLUSTER_SIZE" -lt 1 ]; then
echo "Error: Load balancer cluster size must be at least 1"
exit 1
fi
if ! [[ "$HOST_PORT" =~ ^[0-9]+$ ]] || [ "$HOST_PORT" -lt 1024 ] || [ "$HOST_PORT" -gt 65535 ]; then
echo "Error: Port must be between 1024 and 65535"
exit 1
fi
# 路径验证
if [ -e "$CONFIG_DIR" ] && [ ! -d "$CONFIG_DIR" ]; then
echo "Error: Config path exists but is not a directory"
exit 1
fi
# 验证源目录(如果提供)
if [ -n "$SOURCE_DIR" ] && [ ! -d "$SOURCE_DIR" ]; then
echo "Error: Source directory does not exist or is not a directory"
exit 1
fi
# 网络配置
NETWORK_NAME=nginx-cluster
# 创建配置目录
mkdir -p "$CONFIG_DIR"
CONFIG_ROOT=$(cd "$CONFIG_DIR" && pwd)
# 文件定义
MAIN_CONF="nginx.conf"
LB_DIR="lb"
BUS_DIR="bus"
# 清理旧资源
echo "清理旧资源..."
docker rm -f nginx-node-* nginx-lb-* nginx-bus 2>/dev/null
docker network rm $NETWORK_NAME 2>/dev/null
rm -rf "$CONFIG_ROOT"
mkdir -p "$CONFIG_ROOT"
# 创建自定义网络
echo "创建自定义网络..."
docker network create -d bridge --subnet=192.168.1.0/24 $NETWORK_NAME 2>/dev/null
# 生成主配置文件 - 百万级QPS优化版本
cat <<'EOF' > "$CONFIG_ROOT/$MAIN_CONF"
user nginx;
worker_processes auto;
# 增加最大打开文件数限制
worker_rlimit_nofile 100000;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
# 优化事件处理模型
use epoll;
worker_connections 20000;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 高并发优化设置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 缓冲区优化
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
# 超时优化
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
keepalive_timeout 30;
keepalive_requests 1000;
# Gzip 压缩优化
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# 文件缓存优化
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# 代理优化
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
proxy_temp_file_write_size 32k;
# 关闭访问日志提升性能(生产环境中可选择性开启)
access_log off;
include /etc/nginx/conf.d/*.conf;
}
EOF
# 启动后端节点
for i in $(seq 1 $CLUSTER_SIZE); do
# 计算实际索引
actual_index=$((i + Node_Usage))
# 创建节点目录结构
NODE_DIR="$CONFIG_ROOT/node-$actual_index"
mkdir -p "$NODE_DIR/conf.d" "$NODE_DIR/$HTML_DIR"
# 如果提供了源目录,则复制文件到HTML目录
if [ -n "$SOURCE_DIR" ]; then
cp -r "$SOURCE_DIR"/* "$NODE_DIR/$HTML_DIR/" 2>/dev/null || echo "Warning: Failed to copy files from $SOURCE_DIR"
else
# 生成节点页面
# 使用模运算确保颜色索引不会超出范围
COLOR_INDEX=$(( (actual_index-1) % ${#colors[@]} ))
cat < "$NODE_DIR/$HTML_DIR/index.html"
Node $actual_index
Node $actual_index
Backend Server
Container ID: Placeholder
EOF
fi
# 生成节点配置文件 - 百万级QPS优化版本
cat < "$NODE_DIR/conf.d/default.conf"
server {
listen 80 reuseport;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files \$uri \$uri/ =404;
# 静态文件优化
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
# 先尝试停止并删除可能存在的容器
docker stop nginx-node-$actual_index 2>/dev/null
docker rm nginx-node-$actual_index 2>/dev/null
# 启动容器(使用自定义网络)- 添加系统优化参数
if docker run -d \
--name nginx-node-$actual_index \
--network $NETWORK_NAME \
--ip 192.168.1.$((actual_index)) \
--ulimit nofile=100000:100000 \
-v "$NODE_DIR/conf.d:/etc/nginx/conf.d" \
-v "$NODE_DIR/$HTML_DIR:/usr/share/nginx/html" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest nginx -g 'daemon off;'; then
echo "成功启动 nginx-node-$actual_index"
# 显示容器IP
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx-node-$actual_index 2>/dev/null)
if [ -n "$CONTAINER_IP" ]; then
echo "容器IP: $CONTAINER_IP"
fi
else
echo "警告: 容器 nginx-node-$actual_index 启动失败"
fi
done
# 创建负载均衡器配置
mkdir -p "$CONFIG_ROOT/$LB_DIR/conf.d"
LB_CONF="$CONFIG_ROOT/$LB_DIR/conf.d/default.conf"
# 生成负载均衡配置 - 百万级QPS优化版本
cat < $LB_CONF
upstream backend {
least_conn;
keepalive 1000;
keepalive_requests 10000;
keepalive_time 300s;
$(for i in $(seq 1 $CLUSTER_SIZE); do
actual_index=$((i + Node_Usage))
echo " server nginx-node-$actual_index:80 max_fails=3 fail_timeout=30s;";
done)
}
server {
listen 80 reuseport;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_cache_bypass \$http_upgrade;
# 代理超时优化
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
location /_status {
stub_status on;
access_log off;
allow all;
}
}
EOF
# 启动负载均衡器集群
for i in $(seq 1 $LB_CLUSTER_SIZE); do
# 计算实际索引
actual_index=$((i + Load_Usage))
# 先尝试停止并删除可能存在的容器
docker stop nginx-lb-$actual_index 2>/dev/null
docker rm nginx-lb-$actual_index 2>/dev/null
# 启动容器(使用自定义网络)- 添加系统优化参数
if docker run -d \
--name nginx-lb-$actual_index \
--network $NETWORK_NAME \
--ip 192.168.1.$((252-Load_Usage-i)) \
-p $((HOST_PORT+i-1)):80 \
--ulimit nofile=100000:100000 \
-v "$CONFIG_ROOT/lb/conf.d:/etc/nginx/conf.d" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest nginx -g 'daemon off;'; then
echo "成功启动 nginx-lb-$actual_index"
# 显示容器IP
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx-lb-$actual_index 2>/dev/null)
if [ -n "$CONTAINER_IP" ]; then
echo "容器IP: $CONTAINER_IP"
fi
else
echo "警告: 容器 nginx-lb-$actual_index 启动失败"
fi
done
# 根据选择的架构层级决定是否创建总线nginx
create_bus_nginx() {
# 添加总线nginx端口输入对话框
while true; do
read -p "总线nginx对外暴露的端口: " BUS_PORT
# 验证端口输入
if ! [[ "$BUS_PORT" =~ ^[0-9]+$ ]] || [ "$BUS_PORT" -lt 1024 ] || [ "$BUS_PORT" -gt 65535 ]; then
echo "Error: 端口必须是1024到65535之间的数字"
continue
fi
# 检查端口是否被占用
if netstat -tuln | grep -q ":$BUS_PORT "; then
echo "Error: 端口 $BUS_PORT 已被占用,请重新输入"
continue
else
echo "端口 $BUS_PORT 可用"
break
fi
done
# 创建总线nginx配置
mkdir -p "$CONFIG_ROOT/$BUS_DIR/conf.d"
BUS_CONF="$CONFIG_ROOT/$BUS_DIR/conf.d/default.conf"
# 生成总线nginx配置,负载均衡到所有负载均衡器节点 - 百万级QPS优化版本
cat < $BUS_CONF
upstream loadbalancers {
least_conn;
keepalive 1000;
keepalive_requests 10000;
keepalive_time 300s;
$(for i in $(seq 1 $LB_CLUSTER_SIZE); do
actual_index=$((i + Load_Usage))
echo " server nginx-lb-$actual_index:80 max_fails=3 fail_timeout=30s;";
done)
}
server {
listen 80 reuseport;
location / {
proxy_pass http://loadbalancers;
proxy_http_version 1.1;
proxy_set_header Connection "";
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_cache_bypass \$http_upgrade;
# 代理超时优化
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
}
EOF
# 启动总线nginx容器
docker stop nginx-bus 2>/dev/null
docker rm nginx-bus 2>/dev/null
# 启动总线nginx容器(使用自定义网络)- 添加系统优化参数
if docker run -d \
--name nginx-bus \
--network $NETWORK_NAME \
--ip 192.168.1.254 \
-p $BUS_PORT:80 \
--ulimit nofile=100000:100000 \
-v "$CONFIG_ROOT/bus/conf.d:/etc/nginx/conf.d" \
-v "$CONFIG_ROOT/$MAIN_CONF:/etc/nginx/nginx.conf" \
nginx:latest nginx -g 'daemon off;'; then
echo "成功启动 nginx-bus"
# 显示总线nginx容器IP
BUS_CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx-bus 2>/dev/null)
if [ -n "$BUS_CONTAINER_IP" ]; then
echo "容器IP: $BUS_CONTAINER_IP"
fi
else
echo "警告: 容器 nginx-bus 启动失败"
fi
}
# 判断是否需要创建总线nginx
should_create_bus=false
if [ "$NGINX_LEVEL" = "3" ]; then
should_create_bus=true
elif [ "$NGINX_LEVEL" = "2" ] && [ "$Add_Nginx_Bus" = "true" ]; then
should_create_bus=true
fi
if [ "$should_create_bus" = "true" ]; then
create_bus_nginx
fi
# 等待容器初始化
sleep 3
# 更新页面中的容器ID
for i in $(seq 1 $CLUSTER_SIZE); do
actual_index=$((i + Node_Usage))
if docker ps | grep -q "nginx-node-$actual_index"; then
CONTAINER_ID=$(docker inspect --format='{{.Id}}' nginx-node-$actual_index | cut -c1-12)
sed -i "s/Placeholder/$CONTAINER_ID/" "$CONFIG_ROOT/node-$actual_index/$HTML_DIR/index.html"
docker cp "$CONFIG_ROOT/node-$actual_index/$HTML_DIR/index.html" nginx-node-$actual_index:/usr/share/nginx/html/index.html 2>/dev/null
fi
done
# 输出信息
echo "✅ 百万级QPS优化的负载均衡集群已启动"
echo "配置目录: $CONFIG_ROOT"
echo "后端集群规模: $CLUSTER_SIZE 节点"
echo "负载均衡器集群规模: $LB_CLUSTER_SIZE 实例"
if [ "$NGINX_LEVEL" = "3" ]; then
echo "架构层级: 3层 (包含总线nginx)"
echo "总线nginx地址: http://$(hostname):$BUS_PORT"
elif [ "$NGINX_LEVEL" = "2" ] && [ "$Add_Nginx_Bus" = "true" ]; then
echo "架构层级: 2层 (包含总线nginx)"
echo "总线nginx地址: http://$(hostname):$BUS_PORT"
else
echo "架构层级: 2层 (不包含总线nginx)"
fi
echo "访问地址: http://$(hostname):$HOST_PORT (端口映射: $HOST_PORT->$((HOST_PORT+LB_CLUSTER_SIZE-1)))"
if [ -n "$SOURCE_DIR" ]; then
echo "源文件目录: $SOURCE_DIR"
fi
echo "节点样式:"
for i in $(seq 1 $CLUSTER_SIZE); do
actual_index=$((i + Node_Usage))
COLOR_INDEX=$(( (actual_index-1) % ${#colors[@]} ))
echo "Node $actual_index -> 背景颜色: ${colors[$COLOR_INDEX]}"
done
说明
根据提供的 [nginx_init.bash](file://C:\demo\src\main\resources\shell脚本\nginx集群\nginx_init.bash) 脚本内容,以下是该脚本的使用说明:
## 1. 脚本功能概述
这个脚本用于快速部署一个基于 Docker 的 Nginx 集群环境,支持构建 2 层或 3 层架构:
- **后端节点**:处理实际请求的 Nginx 服务器
- **负载均衡器**:负责将请求分发到后端节点
- **总线 Nginx(可选)**:在 3 层架构中作为统一入口,将请求转发给负载均衡器
## 2. 使用方法
### 基本命令格式
```bash
./nginx_init.bash [cluster_size] [lb_cluster_size] [host_port] [config_dir] [source_dir]
```
### 参数说明
| 参数名 | 默认值 | 描述 |
|--------|--------|------|
| `cluster_size` | 3 | 后端节点数量(正整数) |
| `lb_cluster_size` | 2 | 负载均衡器数量(至少为1) |
| `host_port` | 8080 | 暴露的主机起始端口(1024-65535之间) |
| `config_dir` | ./nginx-configs | 配置文件存储目录 |
| `source_dir` | (可选) | 自定义网页文件源目录 |
### 示例用法
```bash
# 最简调用,使用所有默认参数
./nginx_init.bash
# 自定义配置:5个后端节点,3个负载均衡器,从8000端口开始映射
./nginx_init.bash 5 3 8000 ./my-configs
# 使用自定义网页文件
./nginx_init.bash 3 2 8080 ./nginx-configs /path/to/my/web/files
```
## 3. 运行时交互
脚本运行时会提示用户输入以下信息:
1. **架构层级选择**
```
请输入您要创建的nginx层级,2 代表2层,3 代表3层:
请选择架构层级 (2/3):
```
2. **总线 Nginx 端口(仅在需要创建总线 Nginx 时出现)**
```
总线nginx对外暴露的端口:
```
## 4. 架构选项说明
### 2层架构
- 包含后端节点和负载均衡器
- 请求流程:客户端 → 负载均衡器 → 后端节点
- 可通过修改 `Add_Nginx_Bus` 变量为 `true` 来添加总线 Nginx
### 3层架构
- 包含后端节点、负载均衡器和总线 Nginx
- 请求流程:客户端 → 总线 Nginx → 负载均衡器 → 后端节点
## 5. 输出信息
脚本执行完成后会显示:
- 集群状态概览
- 配置目录位置
- 各组件规模信息
- 访问地址
- 各节点的颜色标识
## 6. 注意事项
- 脚本会自动清理之前的同名容器和网络
- 需要 Docker 环境支持
- 确保指定的端口未被占用
- 如提供 `source_dir` 参数,需确保目录存在且包含有效网页文件 正文到此结束
- 本文标签: Linux
- 本文链接: http://119.91.109.247:8443//article/142
- 版权声明: 本文由张亚东原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权