HAProxy重启机制详解

目录

haproxy停止进程的方式

一、硬停止

二、软停止

haproxy停止进程的过程分析

haproxy的重启机制

一、发生致命错误

二、绑定端口失败

三、正确绑定端口

reload期间可能出现的连接失败情况分析

一、新进程绑定不了旧进程已绑定的端口

二、旧进程关闭监听的端口时,套接字的backlog中极少数连接无法恢复


本文主要参考了HAProxy英文文档管理指南部分,HAProxy版本为2.4.0。

地址为:HAProxy version 2.4.0 - Management Guide

haproxy停止进程的方式

HAProxy支持优雅停止(graceful stop)和硬停止(hard stop)。

一、硬停止

当向haproxy 进程发送SIGTERM 信号时,haproxy 进程会关闭所有已建立的连接并立即退出。硬停止对应于HAProxy服务的stoprestart动作,也对应于启动命令的-st选项。

二、软停止

当向haproxy 进程发送SIGUSR1信号时,haproxy 进程会解除绑定监听的套接字,但会在现有连接处理完成后才关闭进程。软停止对应于HAProxy服务的reload动作,也对应于启动命令的-sf选项。该操作会尽量在新进程中无损地(不丢失连接)重新加载新配置信息。

haproxy停止进程的过程分析

上面两种信号都可以在重新加载或重新启动期间由新的 haproxy 进程发出。

(1)一般模式下的restart的示意图如下:

 stop与上面的图类似,只是由系统进程发出并关闭旧进程,且不会开启新进程。

(2)一般模式下的reload的示意图如下:

当reload的时候,新进程会开启,同时旧进程会在处理完成原来的连接后再停止,在此期间两个进程并存。 

不过在master-worker 模式下重新加载不会另外启动一个新的 haproxy 进程master进程会自己执行重新加载(通过执行-sf 参数后面跟上worker进程的 PID)对SIGUSR2信号作出响应,然后解析配置文件并 fork 新的worker进程。

(3)master-worker 模式下reload示意图如下:

其中master进程贯穿于haproxy服务启动后的整个生命周期里,由master进程来调度旧进程的退出和新进程的引入。 

为了更好地理解这些信号,需要了解haproxy的重启机制。

haproxy的重启机制

假设有一个正在运行的haproxy 进程。此时若要重新加载新的配置,我们需要使用reload或者restart(如“/etc/init.d/haproxy reload”)。接下来的步骤如下:

首先,服务脚本(/etc/init.d/haproxy或类似脚本)将使用“haproxy -c”验证配置文件是否正确解析。之后,它将尝试使用“-st”或“-sf”选项和该配置文件来启动haproxy。

然后新HAProxy进程会尝试绑定到所有的监听端口。

此时可能出现以下3种情形:

一、发生致命错误

如果发生一些致命错误(如:address not present on the system, permission denied),则该进程会因错误而退出。

二、绑定端口失败

如果套接字绑定失败(端口已被使用),则该进程将首先向“-st”或“-sf”pid列表中指定的所有pid发送一个SIGTTOU信号(也就是“暂停”信号)。它指示所有旧haproxy 进程暂停监听其端口,以便新进程可以再次尝试绑定。在此期间,旧进程继续处理现有连接。

如果绑定仍然失败(因为例如一个端口跟另一个守护进程共享了),那么新进程会向旧进程发送一个SIGTTIN 信号,指示它们恢复操作,旧进程会重新开始监听端口并继续接受连接。注意:这取决于系统,某些系统在多进程模式下并不支持这种机制。

三、正确绑定端口

如果新进程正确绑定到所有端口,会向所有进程发送SIGTERM(“-st”情况下的硬停止)或 SIGUSR1信号(“-sf”情况下的正常停止)通知它们由新进程接管运行,旧进程立即停止或者在完成工作后停止。

reload期间可能出现的连接失败情况分析

需要特别注意,在新进程尝试绑定端口时,会有两个几毫秒的窗口期,在高负载情况下可能会有少许连接失败。在此期间新连接的失败率通常在万分之一左右。也就是说在很高的负载下,比如每秒 30000 个新连接的站点,reload期间可能会出现3个失败的连接。

这两个时间窗口如下:

一、新进程绑定不了旧进程已绑定的端口

如果新进程由于旧进程的存在而无法绑定端口,它会经过 SIGTTOU+SIGTTIN信号序列过程。

当有几十个frontend,该序列通常持续大约一毫秒,在此期间,某些端口既不会绑定到旧进程,又不会绑定到新进程。

HAProxy 在支持SO_REUSEPORT 套接字选项的系统上已经解决了这个问题,因为它允许新进程绑定前旧进程不用先解除绑定。大多数 BSD 系统几乎一直支持这一点。Linux 在 2.0 版中支持此功能,并在 2.2版前后将其删除,不过可以引入一些补丁达到效果。它是在内核 3.9 中重新引入,所以如果观察到的连接失败率高于上述,请确保内核是 3.9 或更新的版本,或者相关补丁已向后移植到内核(可能性不大)。

二、旧进程关闭监听的端口时,套接字的backlog中极少数连接无法恢复

当旧进程关闭监听的端口时,内核并不总是能将套接字的backlog中挂起的连接恢复。这主要是由于服务器收到客户端的SYN后,接下来需要向客户端发送RST对连接进行复位造成连接被关闭。

①在高负载下,套接字在关闭前可能会收到客户端的SYN 包,服务器需要向客户端发送 RST 包。在一些连少许连接失败都不允许出现的关键环境中,有时会使用防火墙规则来在reload期间阻止 SYN 包,从而使客户端重新传输。这完全取决于系统,因为某些系统可能能够访问其他监听队列来避免此 RST。

②在socket关闭前,客户端向处于SYN_RECV 状态的本地套接字发送了ACK。这个 ACK也会导致一个RST 包,而 haproxy 进程也无法感知到。这种情况更难处理,可以通过在重新启动过程的前一秒左右应用防火墙规则进行过滤。

对于绝大多数用户来说,这种连接失败永远不会发生,因为没有足够的负载来触发竞态条件。而对于大部分高流量用户,只要他们的系统正确支持 SO_REUSEPORT ,失败率仍然会在可接受范围内。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值