在高并发,大负载压力情况下,对于作为所有服务入口的haproxy,一个简单的reload或者restart都会造成一部分用户连接被中断,造成用户不好的体验。
在haproxy 1.8发布以前,各路大神各显神通,搞了多种所谓的“zero downtime
reload”,但是这些方法都多少有些不良影响。
由于docker和k8s的逐步兴起,haproxy的reload操作变得非常频繁,因此大家非常渴望有一种好方法,能做到真正的0当机。
haproxy的开发者认识到了这个需求的必要性,很快搞出了官方的解决方案,从此再也不需要各种其他方案了。
关于开发者们具体是如何解决这个问题的,思路方法见参考文档,有兴趣可以自行查看。
我理解的大概的原理:
利用3.9版本以后内核中的“SO_REUSEPORT”的sokect选项,即允许同一台主机上的多个socket可以binding到同一个tcp
port
reload的时候,通过stats socket将当前listener的文件描述传递给新起的haproxy进程。
旧的haproxy进程处理完毕当前用户连接后退出,新的haproxy进程处理新的用户连接。
在这个过程中,因为新的haproxy进程也binding到了原有的listener
FD上,在整个过程中不会有连接被关闭。
真正实现了seamless-reload。
haproxy作者willy提到了其实这个方法在bsd上一直有,haproxy的企业版之前也一直支持这个功能,linux之前内核也有,后来消失了,在3.9内核又重新出现了更好的实现。
我这就是说个干的,就是说如何使用这个功能。
前提要求: haproxy的版本高于1.8
配置方法:
1. 修改haproxy的配置文件,给stats socket加入“expose-fd listeners”
# used for newer reload mechanism
stats socket /run/haproxy/admin.sock mode 777 level admin
expose-fd listeners
2. 编辑haproxy的systemd启动文件
]# vi /lib/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
# allows us to do millisecond level restarts without
triggering alert in Systemd
StartLimitInterval=0
StartLimitBurst=0
After=network.target
[Service]
Environment="CONFIG=/etc/haproxy/haproxy.cfg"
"PIDFILE=/run/haproxy.pid"
# EXTRAOPTS and RELOADOPS come from this default file
EnvironmentFile=-/etc/default/haproxy
ExecStartPre=/usr/local/sbin/haproxy -f $CONFIG -c -q
ExecStart=/usr/local/sbin/haproxy -Ws -f $CONFIG -p $PIDFILE
$EXTRAOPTS
# note that the master worker mode obsoletes the old
haproxy-systemd-wrapper
#
# add RELOADOPTS to /etc/default/haproxy if you want seamless
reload
ExecReload=/usr/local/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS
$RELOADOPTS
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
Restart=always
Type=notify
[Install]
WantedBy=multi-user.target
]# echo RELOADOPTS="-x /run/haproxy/admin.sock" >>
/etc/default/haproxy
]# systemctl daemon-reload
]# systemctl enable haproxy.service
关注点一个是“Ws”选项,即master-worker模式
-W : master-worker mode. It is equivalent
to the "master-worker" keyword in
the "global" section of
the configuration. This mode will launch a "master"
which will monitor the
"workers". Using this mode, you can reload HAProxy
directly by sending a
SIGUSR2 signal to the master. The master-worker
mode
is compatible either
with the foreground or daemon mode. It is
recommended to use this
mode with multiprocess and systemd.
另一个关注点“$RELOADOPTS”,即新的reload方法
‘-x’ option is used in the ‘ExecReload’
action of the service file and specifies
the
unix socket used to transfer the listening sockets from the old
process.
This
is the same socket referenced later in the haproxy.cfg ‘expose-fd
listeners’.
就是使用-x选项,通过在haproxy.cfg中定义的stats socket,将listening
socket的FD传递给新的haproxy进程
通过上述两步,参考文档2的作者做了测试,在reload haproxy配置文件,确实做到了0中断。
参考文档:
1.haproxy作者的文章
https://www.haproxy.com/blog/truly-seamless-reloads-with-haproxy-no-more-hacks/
2.其他人的文章
https://fabianlee.org/2017/10/16/haproxy-zero-downtime-reloads-with-haproxy-1-8-on-ubuntu-16-04-with-systemd/
3.haproxy 1.8的发布声明
https://www.mail-archive.com/haproxy@formilux.org/msg28004.html
4.haproxy 1.8关于“expose-fd”
https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#5.1-expose-fd
listeners
5.关于内核”SO_REUSEPORT“
https://lwn.net/Articles/542629/
6.关于内核”SO_REUSEPORT“
http://www.lijiaocn.com/问题/2017/09/19/haproxy-inter-not-found.html
7.systemd的教程:
http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html
8.haproxy的service文件
https://raw.githubusercontent.com/fabianlee/blogcode/master/haproxy/ubuntu1604/haproxy.service