作者介绍:简历上没有一个精通的运维工程师,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。
我们上一大章介绍了Kubernetes的知识,本章节我们进入中间件的讲解,这里会包含很多不同的类型组件,中间件的第一个大类我这里定义的是Web服务器。由于目前使用最广泛的Web服务器是Nginx,所以我们这里的讲解主要以Nginx服务器为主。
上2个小节,我们介绍了Nginx的核心功能反向代理。但是他的一个规则只能对应一个后端,如果后端有多个同样服务跑在多个服务器上,我们Nginx这里应该如何来配置,让他支持多个后端,并实现负载均衡功能呢?
负载均衡实现
我们这里用一台后端服务器启动2个同样的服务,采用不同的端口来代替2台服务器,然后前端使用Nginx来代理这2个服务。
server {
listen 80;
server_name 192.168.31.120;
location / {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
upstream backend_servers {
server 192.168.31.121:8080;
server 192.168.31.121:9090;
}
这里我们把代理的后端地址从一个具体的地址换成了我们定义的一个名字,然后在server同级的upstream模块里面定义后端的地址,这里只定义2个,实际可多个。默认情况下他他会把请求轮流转发到后端的2个服务。
负载均衡算法
如果不做任何配置的情况下就是轮询(轮流),依次向后端配置的服务转发请求。当然除了默认的轮询还有多种算法。
upstream backend {
server 192.168.1.101 weight=5; # 50% 流量
server 192.168.1.102 weight=3; # 30% 流量
server 192.168.1.103 weight=2; # 20% 流量
}
2. 最少连接数 (Least Connections)
upstream backend {
least_conn;
server 192.168.1.101;
server 192.168.1.102;
}
upstream backend {
ip_hash;
server 192.168.1.101;
server 192.168.1.102;
}
ngx_http_upstream_hash_module
):upstream backend {
hash $request_uri consistent; # consistent 表示一致性哈希
server 192.168.1.101;
server 192.168.1.102;
}
健康检查逻辑
前面我们介绍他通过多种负载均衡算法转发到后端,但是后端的服务也可能出现异常,如果后端服务异常以后,Nginx还会把流量转发过去吗?默认我们只要配置负载均衡,他就会自动给我们添加健康检查,剔除不健康的节点。
#默认值
max_fails 1
fail_timeout=10s
upstream backend {
server 192.168.1.101:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 max_fails=3 fail_timeout=30s;
}
正常状态
两个后端服务器 101
和 102
均处于健康状态。Nginx 使用默认的轮询策略分发请求到这两个服务器。每个请求会交替发送到101 和 102所有请求均返回
2xx
或 3xx
等正常状态码。失败计数器(max_fails
)保持为 0
。
故障状态
假设 192.168.1.101 发生故障,触发条件:当请求发送到 101 时,Nginx 检测到以下情况之一:连接超时(如 TCP 握手失败)。服务器返回 5xx 错误码(如 500、502)。主动拒绝连接(如服务崩溃)。
计数器递增
每次失败(如超时或错误响应),101 的失败计数器 +1。关键规则:计数器仅在 fail_timeout=30s 时间窗口内累计。(例如:30 秒内连续失败 3 次,或 30 秒内累计失败 3 次)。
标记为不可用
如果 30秒 内累计失败达到 3次,Nginx 将 101 标记为 unavailable。标记后,Nginx 停止 向 101 发送新请求,持续 30秒(fail_timeout 的第二个作用)。
流量切换
所有请求会被转发到剩余的健康节点 102。用户可能观察到部分请求失败,但服务整体仍可用(因 102 仍正常)。
故障恢复阶段
30秒后:Nginx 尝试恢复 101自动探测:当 fail_timeout=30s 超时后,Nginx 会重新将 101 加入负载均衡池。隐式检查:Nginx 不会主动发送健康检查请求,而是在下一个客户端请求触发时尝试 101。恢复逻辑:下一个请求到达时,Nginx 会尝试将请求发送到 101。如果请求成功:101 的失败计数器 重置为 0。101 重新成为健康节点,参与后续的负载均衡。
如果请求再次失败
失败计数器 +1,重新进入故障判断流程。若在 30秒 内再次累计 3次 失败,101 会再次被标记为不可用 30秒。
以上流程是我以前的理解,但是经过我测试发现目前的版本(v1.20.1), 如果把其中一个服务关闭,则请求转发会失败,但是他会把请求重新转发到另外一个正常的节点,这样前端请求就感知不到后端异常。
==> access.log <==
192.168.31.120 - - [03/Apr/2025:22:30:02 +0800] "GET / HTTP/1.1" 200 42 "-" "curl/7.29.0" "-"
192.168.31.120 - - [03/Apr/2025:22:30:04 +0800] "GET / HTTP/1.1" 200 42 "-" "curl/7.29.0" "-"
==> error.log <==
2025/04/03 22:30:06 [error] 2809#2809: *1005 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.31.120, server: 192.168.31.120, request: "GET / HTTP/1.1", upstream: "http://192.168.31.121:9090/", host: "192.168.31.120"
==> access.log <==
192.168.31.120 - - [03/Apr/2025:22:30:06 +0800] "GET / HTTP/1.1" 200 42 "-" "curl/7.29.0" "-"
192.168.31.120 - - [03/Apr/2025:22:30:08 +0800] "GET / HTTP/1.1" 200 42 "-" "curl/7.29.0" "-"
正常请求是每2秒,然后轮流转发给后端2台服务器,但是我们看到06秒的时候失败,然后06秒还有一次成功的记录(这次请求是重新转发刚刚失败的请求),这样前面的请求就感知不到后端失败。
如果你想要浮现上面的逻辑,可以显示添加参数。
location / {
proxy_pass http://backend_servers;
proxy_next_upstream error timeout; # 禁用重试
}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有