由于最近做微服务化,原有的haproxy通过检测应用的check.jsp来进行应用健康状态检查,
发布版本时,通过mv check.jsp check.jsp.bak,让应用下线。
但是微服务spring-boot工程都是jar包,虽然可以通过7z命令来进行jar包内的文件重命名,或者删除,这样总感觉很low,破坏了jar包的完整性,存在一定的操作风险。虽然spring-boot有优雅停机功能,但是问题是,进行后端的应用优雅停机后,与haproxy的健康检查到应用下线存在一定时间间隔,这一段时间内,有可能会导致请求分发到已经优雅停机的应用上,一般优雅停机后的应用接受到请求后,会引起请求等待,造成应用响应慢的假象。tomcat的connect.pause()方法并没有关闭socket端口,而是引起等待。
既然haproxy作为前端负载,为何不直接改变负载均衡上的应用状态呢?
1.haproxy 配置global nbproc 3。
global
log 127.0.0.1 local0
maxconn 40000
chroot /usr/local/haproxy
user haproxy
group haproxy
daemon
nbproc 3
defaults
log global
option dontlognull
retries 3
option redispatch
maxconn 400000
timeout connect 5000
timeout client 50000
timeout server 50000
listen admin_status
mode http
bind 0.0.0.0:18800
stats enable
stats uri /admin_status
stats auth admin:admin
stats admin if TRUE #开启stats页面的操作应用状态的功能。
option httplog
此时打开haproxy的stats页面,刷新页面可以得到3个不同状态的页面。
其中pid=xxx(process #1,nbproc=3)
其中process #1标示当前页面是第一个haproxy内核进程。每次刷新页面,haproxy根据算法随机返回3个进程中的其中一个进程的stats页面。
此时我们选择应用然后进行下线,set state to MAINT,请求会随机分发到3个进程中的其中一个进程进行应用下线。如果要把3个进程中的应用状态都改掉,就要看运气了。
显然这不是我们想要的。
翻阅相关文档发现有两种可行的方法。
https://www.cnblogs.com/276815076/p/6992557.html
https://blog.youkuaiyun.com/weixin_34007020/article/details/93011764
方法1:通过socat与3个进程进行通信,然每个进程都下线同一个应用。
haproxy的配置
global
log 127.0.0.1 local0
maxconn 400000
chroot /usr/local/haproxy
user haproxy
group haproxy
daemon
nbproc 3
stats socket /var/lib/haproxy/haproxy.sock1 mode 600 level admin process 1
stats socket /var/lib/haproxy/haproxy.sock2 mode 600 level admin process 2
stats socket /var/lib/haproxy/haproxy.sock3 mode 600 level admin process 3
下线操作:
echo "disable server app/staff_200_3" | socat stdio /var/lib/haproxy/haproxy.sock1
echo "disable server app/staff_200_3" | socat stdio /var/lib/haproxy/haproxy.sock2
echo "disable server app/staff_200_3" | socat stdio /var/lib/haproxy/haproxy.sock3
执行命令之后刷新到3个页面发现都下线了。
方法2:定义多个stats端口,每个端口绑定进程。
global
log 127.0.0.1 local0
maxconn 400000
chroot /usr/local/haproxy
user haproxy
group haproxy
daemon
nbproc 3
listen admin_status1
mode http
bind 0.0.0.0:18801
stats enable
stats uri /admin_status
stats auth admin:admin
stats admin if TRUE
option httplog
bind-proccess 1
listen admin_status2
mode http
bind 0.0.0.0:18802
stats enable
stats uri /admin_status
stats auth admin:admin
stats admin if TRUE
option httplog
bind-process 2
listen admin_status3
mode http
bind 0.0.0.0:18803
stats enable
stats uri /admin_status
stats auth admin:admin
stats admin if TRUE
option httplog
登陆3个stats页面进行操作。分别进行下线。
还有一个问题,我们软下线时,已经进入应用的请求能够响应完毕嘛?我们可以在后端应用写一个Thread.sleep(1000)来模拟慢响应,经过测试发现已经进入的应用可以正常响应。