🔗 基于Nginx的负载均衡部署
随着业务增长,单个应用实例可能无法满足高并发需求。本章节介绍如何使用Nginx实现若依应用的负载均衡部署,提升系统的可用性和处理能力。
🔗 负载均衡架构说明
🔗 架构组件
- Nginx负载均衡器:作为入口,分发请求到后端应用实例
- 多个应用实例:提供冗余和负载分担
- 共享数据层:MySQL和Redis供所有应用实例共享
🔗 优势
- 提高系统吞吐量
- 增强服务可用性
- 支持滚动更新
- 故障自动转移
🔗 Nginx配置文件
创建 docker/nginx/nginx.conf
:
text
# Nginx主配置文件
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
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" '
'upstream_addr=$upstream_addr upstream_status=$upstream_status '
'request_time=$request_time upstream_response_time=$upstream_response_time';
access_log /var/log/nginx/access.log main;
# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 50M;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
application/javascript application/xml+rss application/json;
# 若依应用负载均衡配置
upstream app_backend {
# 负载均衡策略:默认轮询
# 可选策略:ip_hash, least_conn, random
# 应用实例1
server app-1:8080 weight=1 max_fails=3 fail_timeout=30s;
# 应用实例2
server app-2:8080 weight=1 max_fails=3 fail_timeout=30s;
# 健康检查配置
keepalive 32;
}
server {
listen 80;
server_name localhost;
# 访问日志
access_log /var/log/nginx/app_access.log main;
# 健康检查端点
location /nginx-health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
# 主应用代理
location / {
proxy_pass http://app_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;
# 超时设置
proxy_connect_timeout 30s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 8 8k;
# 连接复用
proxy_http_version 1.1;
proxy_set_header Connection "";
}
# 静态资源缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
proxy_pass http://app_backend;
proxy_set_header Host $host;
# 缓存配置
expires 1d;
add_header Cache-Control "public, immutable";
}
# API接口代理
location /api/ {
proxy_pass http://app_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;
# API特殊配置
proxy_read_timeout 120s;
}
}
# 负载均衡状态页面
server {
listen 8090;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 172.16.0.0/12; # 允许内网访问
deny all;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
🔗 负载均衡Docker Compose配置
创建docker-compose-loadbalancer.yml
:
yml
services:
# MySQL数据库(共享)
mysql:
image: mysql:8.0
container_name: app-mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: ry
MYSQL_USER: app
MYSQL_PASSWORD: 123456
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./docker/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf
- ./docker/mysql/init:/docker-entrypoint-initdb.d
- mysql_logs:/var/log/mysql
command: --default-authentication-plugin=mysql_native_password
networks:
- app-network
# Redis缓存(共享)
redis:
image: redis:7-alpine
container_name: app-redis
restart: always
ports:
- "6379:6379"
volumes:
- redis_data:/data
- ./docker/redis/redis.conf:/etc/redis/redis.conf
command: redis-server /etc/redis/redis.conf
networks:
- app-network
# 应用实例1
app-1:
build:
context: .
dockerfile: Dockerfile
container_name: app-1
restart: always
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=druid
- TZ=Asia/Shanghai
- SERVER_PORT=8080
- INSTANCE_NAME=app-1
volumes:
- app1_logs:/app/logs
- app_upload:/app/upload # 共享上传目录
depends_on:
- mysql
- redis
networks:
- app-network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# 应用实例2
app-2:
build:
context: .
dockerfile: Dockerfile
container_name: app-2
restart: always
ports:
- "8081:8080"
environment:
- SPRING_PROFILES_ACTIVE=druid
- TZ=Asia/Shanghai
- SERVER_PORT=8080
- INSTANCE_NAME=app-2
volumes:
- app2_logs:/app/logs
- app_upload:/app/upload # 共享上传目录
depends_on:
- mysql
- redis
networks:
- app-network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# Nginx负载均衡器
nginx:
image: nginx:1.24-alpine
container_name: app-nginx
restart: always
ports:
- "80:80"
- "8090:8090" # 状态监控端口
volumes:
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- nginx_logs:/var/log/nginx
depends_on:
- app-1
- app-2
networks:
- app-network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost/nginx-health"]
interval: 30s
timeout: 10s
retries: 3
# 网络配置
networks:
app-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
# 数据卷配置
volumes:
mysql_data:
driver: local
mysql_logs:
driver: local
redis_data:
driver: local
app1_logs:
driver: local
app2_logs:
driver: local
app_upload:
driver: local
nginx_logs:
driver: local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
🔗 负载均衡部署步骤
🔗 创建目录结构
bash
# 创建Nginx配置目录
mkdir -p docker/nginx
# 复制配置文件
# 将上述nginx.conf内容保存到docker/nginx/nginx.conf
1
2
3
4
5
2
3
4
5
🔗 修改Dockerfile支持健康检查
更新Dockerfile添加wget支持:
dockerfile
# 使用OpenJDK 8作为基础镜像
FROM openjdk:8-jre-alpine
# 设置维护者信息
LABEL maintainer="app@example.com"
# 安装wget用于健康检查
RUN apk add --no-cache wget tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建应用目录
WORKDIR /app
# 复制jar包到容器
COPY target/app-admin.jar app.jar
# 暴露端口
EXPOSE 8080
# 设置JVM参数
ENV JAVA_OPTS="-Xmx512m -Xms512m"
# 启动应用
ENTRYPOINT exec java $JAVA_OPTS -jar app.jar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
🔗 启动负载均衡集群
bash
# 清理并打包项目
mvn clean package -DskipTests
# 使用负载均衡配置启动服务
docker-compose -f docker-compose-loadbalancer.yml up -d
# 查看所有服务状态
docker-compose -f docker-compose-loadbalancer.yml ps
# 查看Nginx日志
docker-compose -f docker-compose-loadbalancer.yml logs -f nginx
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🔗 验证负载均衡效果
🔗 基础连通性测试
bash
# 测试Nginx代理
curl -I http://localhost/
# 测试健康检查
curl http://localhost/nginx-health
# 查看Nginx状态
curl http://localhost:8090/nginx_status
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
🔗 负载分发测试
创建测试脚本 test_loadbalance.sh
:
bash
#!/bin/bash
echo "开始负载均衡测试..."
# 发送10个请求,观察负载分发情况
for i in {1..10}; do
echo "请求 $i:"
curl -s -H "Cache-Control: no-cache" http://localhost/ | grep -o "实例.*" || echo " 请求处理完成"
sleep 1
done
echo "查看Nginx访问日志(最后10条):"
docker exec app-nginx tail -10 /var/log/nginx/app_access.log
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
🔗 故障转移测试
bash
# 停止一个应用实例
docker stop app-1
# 测试服务是否仍可用
curl http://localhost/
# 查看Nginx错误日志
docker exec app-nginx tail -20 /var/log/nginx/error.log
# 重启停止的实例
docker start app-1
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🔗 监控和调优
🔗 实时监控脚本
创建 monitor_cluster.sh
:
bash
#!/bin/bash
echo "=== 若依集群监控面板 ==="
while true; do
clear
echo "时间: $(date)"
echo "================================="
# 容器状态
echo "容器状态:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep app
echo ""
# Nginx状态
echo "Nginx状态:"
curl -s http://localhost:8090/nginx_status 2>/dev/null || echo "Nginx状态页面不可用"
echo ""
# 系统资源
echo "资源使用:"
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" | grep app
echo ""
echo "按Ctrl+C退出监控"
sleep 5
done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
🔗 性能调优建议
🔗 Nginx调优参数
nginx
# 在nginx.conf的http块中添加
worker_processes auto;
worker_connections 2048;
# 优化upstream配置
upstream app_backend {
least_conn; # 使用最少连接负载均衡
server app-1:8080 weight=1 max_fails=2 fail_timeout=10s;
server app-2:8080 weight=1 max_fails=2 fail_timeout=10s;
keepalive 64;
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🔗 应用实例调优
yaml
# 在docker-compose中调整应用资源
app-1:
deploy:
resources:
limits:
memory: 1G
cpus: '0.5'
reservations:
memory: 512M
cpus: '0.25'
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10