管理指南

版本 2.2.34


文档贡献者须知:本文档每行格式化为 80 列,缩进使用偶数个空格,不使用制表符。请严格遵守这些规则,以便文档能够轻松地在任何地方打印。如果您添加章节,请更新下面的摘要以便于搜索。
1. 前提条件

2.

HAProxy 架构快速回顾

3.

启动 HAProxy

4.

停止和重启 HAProxy

5.

文件描述符限制

6.

内存管理

7.

CPU 使用率

8.

日志

9.

统计信息和监控
9.1.
9.2.
9.3.
9.4.

10.

简化配置管理的技巧

11.

常见陷阱及避免方法

12.

调试和性能问题

13.

安全注意事项
本文档假设读者在类 UNIX 操作系统上拥有足够多的管理技能,日常使用 shell,并且熟悉 strace 和 tcpdump 等故障排除工具。
HAProxy 是一个多线程、事件驱动、非阻塞的守护进程。这意味着它使用事件多路复用机制来调度所有活动,而不是依赖系统在多个活动之间进行调度。大多数情况下,它作为一个单一进程运行,因此在系统上执行 "ps aux" 命令时,通常只会报告一个 "haproxy" 进程,除非正在进行软重载,此时旧进程会与新进程并行完成其工作。因此,使用 strace 工具可以轻松追踪其活动。为了与可用的处理器数量进行扩展,HAProxy 默认会为允许其运行的每个处理器启动一个工作线程。除非显式配置不同,否则传入的流量会在所有这些线程之间分发,所有这些线程都运行相同的事件循环。已采取很大措施来将线程间的依赖性限制在严格的最小值,以尝试实现近乎线性的可扩展性。这带来了一些影响,例如一个给定连接由单个线程提供服务。因此,为了利用所有可用的处理能力,需要拥有至少与线程数相等的连接数,这几乎总是可以保证的。HAProxy 设计成在启动时将自身隔离到 chroot 监狱中,此时它完全无法进行任何文件系统访问。这同样适用于它所依赖的库(例如:libc、libssl 等)。直接的影响是,正在运行的进程将无法重新加载配置文件以应用更改,而是会启动一个使用更新后配置文件的新进程。其他一些不太明显的影响是,libc 在运行时可能尝试访问的某些时区文件或解析器文件将找不到,尽管这通常不会发生,因为它们在启动后不再需要。这一原则的一个优点是,HAProxy 进程是完全无状态的,杀死它后无需进行任何清理,因此任何有效的杀死方法都会做正确的事情。HAProxy 不会写入日志文件,但它依赖于标准的 syslog 协议将日志发送到远程服务器(通常位于同一系统上)。HAProxy 使用其内部时钟来强制执行超时,该时钟源自系统时间,但会纠正意外的漂移。这是通过限制轮询 (poll()) 等待事件的时间,并测量实际花费的时间来实现的。实际上,它从不等待超过一秒钟。这解释了为什么当使用 strace 监控完全空闲的进程时,会注意到周期性的 poll()(或其任何变体)调用,其间被两个 gettimeofday() 调用包围。这些是正常的,完全无害且非常轻量,以至于它们产生的负载在系统级别上是完全无法检测到的,所以那里没有任何异常。示例:16:35:40.002320 gettimeofday({1442759740, 2605}, NULL) = 0 16:35:40.002942 epoll_wait(0, {}, 200, 1000) = 0 16:35:41.007542 gettimeofday({1442759741, 7641}, NULL) = 0 16:35:41.007998 gettimeofday({1442759741, 8114}, NULL) = 0 16:35:41.008391 epoll_wait(0, {}, 200, 1000) = 0 16:35:42.011313 gettimeofday({1442759742, 11411}, NULL) = 0 HAProxy 是一个 TCP 代理,而不是路由器。它处理由内核验证的已建立连接,而不是处理任何形式的数据包或处于其他状态的套接字(例如:没有 SYN_RECV 或 TIME_WAIT),尽管它们的存在可能会阻止它绑定端口。它依赖系统来接受传入连接和发起传出连接。这直接的结果是,转发连接的两端观察到的数据包之间没有关系,它们的大小、数量甚至类型都可能不同。由于连接只能从处于 LISTEN 状态的套接字接受,因此所有它正在监听的套接字都可以使用 "netstat" 工具显示监听套接字。示例:# netstat -ltnp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1629/sshd tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 2847/haproxy tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 2847/haproxy
HAProxy 通过在命令行调用 "haproxy" 程序并带有一些参数来启动。实际语法是:$ haproxy [<options>]*
where [<options>]* 是任意数量的选项。选项始终以 "-" 开头
后面跟着一个或多个字母,并且可能后面跟着一个或多个额外的参数。在没有任何选项的情况下,HAProxy 会显示帮助页面,提醒支持的选项。可用选项可能因操作系统而略有不同。其中许多选项与 "global" 部分中的等效选项重叠。在这种情况下,命令行始终优先于配置文件,以便可以使用命令行快速强制执行某些设置,而无需修改配置文件。当前选项列表为:-- <cfgfile>* : "--" 后面的所有参数都是要加载和按声明顺序处理的配置文件/目录的路径。当依赖 shell 加载许多按数值排序的文件时,这非常有用。另请参阅 "-f"。 "--" 和 "-f" 之间的区别在于,一个 "-f" 必须放在每个文件名之前,而单个 "--" 则在所有文件名之前就足够了。这两个选项都可以一起使用,命令行顺序仍然适用。当指定多个文件时,每个文件都必须从一个节的边界开始,所以每个文件的第一个关键字必须是 "global"、"defaults"、"peers"、"listen"、"frontend"、"backend" 等之一。例如,一个文件不能只包含一个服务器列表。-f <cfgfile|cfgdir> : 将 <cfgfile> 添加到要加载的配置文件列表中。如果 <cfgdir> 是一个目录,则其中所有文件(仅文件)将按词法顺序(使用 LC_COLLATE=C)添加到要加载的配置文件列表中;仅添加扩展名为 ".cfg" 的文件,仅添加非隐藏文件(不以 "." 开头)。配置文件按声明顺序加载和处理。此选项可以指定多次以加载多个文件。另请参阅 "--"。 "--" 和 "-f" 之间的区别在于,一个 "-f" 必须放在每个文件名之前,而单个 "--" 则在所有文件名之前就足够了。这两个选项都可以一起使用,命令行顺序仍然适用。当指定多个文件时,每个文件都必须从一个节的边界开始,所以每个文件的第一个关键字必须是 "global"、"defaults"、"peers"、"listen"、"frontend"、"backend" 等之一。例如,一个文件不能只包含一个服务器列表。-C <dir> : 在加载配置文件之前更改到目录 <dir>。这在使用相对路径时很有用。警告:在使用 "--" 后的通配符时,这些通配符实际上是在 haproxy 启动之前由 shell 替换的。-D : 启动为守护进程。进程在 fork 后从当前终端分离,并且不再在终端中报告错误。它等同于配置文件中 "global" 部分的 "daemon" 关键字。建议在任何 init 脚本中始终强制使用它,以防止有问题的配置阻止系统启动。-L <name> : 将本地对等节点名称更改为 <name>,默认为本地主机名。这仅与对等复制一起使用。您可以在配置文件中使用变量 $HAPROXY_LOCALPEER 来引用对等节点名称。-N <limit> : 将默认的每个代理 maxconn 设置为 <limit>,而不是内置的默认值(通常为 2000)。仅用于调试。-V : 启用详细模式(禁用安静模式)。恢复 "-q" 或 "quiet" 的效果。-W : 主/工作进程模式。它等同于配置文件中 "global" 部分的 "master-worker" 关键字。此模式将启动一个 "master" 来监控 "workers"。使用此模式,您可以直接通过向 master 发送 SIGUSR2 信号来重新加载 HAProxy。主/工作进程模式兼容前台或守护进程模式。建议将此模式与多进程和 systemd 一起使用。-Ws : 支持 `notify` 类型 systemd 服务的 master-worker 模式。仅当 HAProxy 构建时启用了 `USE_SYSTEMD` 构建选项时,此选项才可用。-c : 仅执行配置文件检查,并在尝试绑定之前退出。如果一切正常,退出状态为零,如果遇到错误,则为非零。如果存在警告,则会报告。-d : 启用调试模式。这将禁用守护进程模式,强制进程保持在前台并显示传入和传出的事件。它等同于 "global" 部分的 "debug" 关键字。切勿在 init 脚本中使用它。-dG : 禁用使用 getaddrinfo() 将主机名解析为地址。在怀疑 getaddrinfo() 工作不正常时可以使用此选项。此选项的可用性是由于各种系统上存在许多 getaddrinfo() 的错误实现,并导致难以排查的异常。-dM[<byte>] : 强制内存毒化,这意味着使用 malloc() 或 pool_alloc() 分配的每一个内存区域在传递给调用者之前都会用 <byte> 填充。当未指定 <byte> 时,默认为 0x50 ('P')。虽然这会稍微减慢操作速度,但有助于可靠地触发由于代码中缺少初始化而导致的、会导致随机崩溃的问题。请注意,-dM0 的效果是将任何 malloc() 转换为 calloc()。无论如何,如果在使用此选项时出现或消失一个 bug,则表示 haproxy 中存在 bug,请报告。-dR : 在监听端口上禁用 SO_REUSEPORT 套接字选项。它等同于 "global" 部分的 "noreuseport" 关键字。这可能用于多线程场景,当 HAProxy 线程之间观察到负载分发问题时(可以使用 top 进行监控)。-dS : 禁用使用 splice() 系统调用。它等同于 "global" 部分的 "nosplice" 关键字。当怀疑 splice() 的行为不正确或导致性能问题时,或者在使用 strace 查看转发数据(使用 splice() 时不显示)时,可以使用此选项。-dV : 禁用服务器端的 SSL 验证。它等同于在 "global" 部分具有 "ssl-server-verify none"。当尝试在生产环境之外重现生产环境问题时,这很有用。切勿在 init 脚本中使用此选项,因为它会降低服务器的 SSL 安全性。-dW : 如果设置,haproxy 在处理配置文件时发出任何警告时将拒绝启动。这有助于检测细微的错误,并保持配置的干净和跨版本可移植性。建议在配置文件由人工管理的服务脚本中使用此选项,但不建议与生成配置文件一起使用,后者倾向于发出更多警告。它可以与 "-c" 结合使用,使检查的配置文件中的警告导致失败。这等同于全局选项 "zero-warning"。-db : 禁用后台模式和多进程模式。进程保持在前台。它主要用于开发或小型测试期间,因为 Ctrl-C 足以停止进程。切勿在 init 脚本中使用它。-de : 禁用 "epoll" poller 的使用。它等同于 "global" 部分的关键字 "noepoll"。这在怀疑与此 poller 有关的 bug 时非常有用。在支持 epoll 的系统上,回退通常是 "poll" poller。-dk : 禁用 "kqueue" poller 的使用。它等同于 "global" 部分的关键字 "nokqueue"。这在怀疑与此 poller 有关的 bug 时非常有用。在支持 kqueue 的系统上,回退通常是 "poll" poller。-dp : 禁用 "poll" poller 的使用。它等同于 "global" 部分的关键字 "nopoll"。这在怀疑与此 poller 有关的 bug 时非常有用。在支持 poll 的系统上,回退通常是 "select" poller,它无法禁用,并且仅限于 1024 个文件描述符。-dr : 忽略服务器地址解析失败。在生产环境之外验证配置时,无法访问相同的解析器并导致服务器地址解析失败是很常见的,这使得测试配置变得困难。此选项只需将 "none" 方法附加到所有服务器的地址解析方法列表中,从而确保即使 libc 无法解析地址,启动序列也不会中断。-dv : 禁用 "evports" poller 的使用。它等同于 "global" 部分的关键字 "noevports"。这在怀疑与此 poller 有关的 bug 时非常有用。在支持事件端口(SunOS 源自 Solaris 10 及更高版本)的系统上,回退通常是 "poll" poller。-m <limit> : 将所有进程的总可分配内存限制为 <limit> 兆字节。这可能会导致一些连接被拒绝或一些操作减慢,具体取决于正常操作所需的内存量。这主要用于强制进程在资源受限的使用场景中工作。重要的是要注意,内存不会在进程之间共享,因此在多进程场景中,此值在 fork 之前会先除以 global.nbproc。-n <limit> : 将每个进程的连接限制限制为 <limit>。这等同于 "global" 部分的关键字 "maxconn"。它优先于此关键字。这可用于快速强制较低的限制,以避免在资源限制过低的系统上发生服务中断。-p <file> : 在启动时将所有进程的 PID 写入 <file>。这等同于 "global" 部分的关键字 "pidfile"。文件将在进入 chroot 监狱之前打开,并在执行 "-C" 所隐含的 chdir() 之后打开。每个 PID 独占一行。-q : 设置 "quiet" 模式。这会禁用输出消息。它可以与 "-c" 结合使用,以仅检查配置文件是否有效。-S <bind>[,bind_options...]: 在 master-worker 模式下,绑定一个 master CLI,允许访问所有正在运行或即将离开的进程。出于安全原因,建议将 master CLI 绑定到本地 UNIX 套接字。bind 选项与配置文件中的 "bind" 关键字相同,单词用逗号分隔而不是空格。请注意,在无缝重新加载期间,此套接字不能用于从旧进程检索监听套接字。-sf <pid>* : 在启动完成后向旧进程发送 "finish" 信号 (SIGUSR1),要求它们完成正在做的事情并离开。<pid> 是要信号的 PID 列表(每个参数一个)。列表在任何以 "-" 开头的选项处结束。PID 列表为空也没有问题,因此可以根据 "pidof" 或 "pgrep" 命令的结果动态构建。-st <pid>* : 在启动完成后向旧进程发送 "terminate" 信号 (SIGTERM),要求它们立即终止而不完成正在做的事情。<pid> 是要信号的 PID 列表(每个参数一个)。列表在任何以 "-" 开头的选项处结束。PID 列表为空也没有问题,因此可以根据 "pidof" 或 "pgrep" 命令的结果动态构建。-v : 报告版本和构建日期。-vv : 显示版本、构建选项、库版本和可用的 poller。在提交 bug 报告时,系统会要求提供此输出。-x <unix_socket> : 连接到指定的套接字并尝试从旧进程检索任何监听套接字,并使用它们而不是尝试绑定新的套接字。这对于在 Linux 上重新加载配置时避免在新连接丢失方面非常有用。必须使用配置中的 "expose-fd listeners" 在统计套接字上启用该功能。从 init 文件启动 HAProxy 的安全方法是强制使用守护进程模式,将现有 PID 存储在 pid 文件中,并使用此 pid 文件通知旧进程在退出前完成:haproxy -f /etc/haproxy.cfg \ -D -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid) 当配置拆分为几个特定文件时(例如:tcp vs http),建议使用 "-f" 选项:haproxy -f /etc/haproxy/global.cfg -f /etc/haproxy/stats.cfg \ -f /etc/haproxy/default-tcp.cfg -f /etc/haproxy/tcp.cfg \ -f /etc/haproxy/default-http.cfg -f /etc/haproxy/http.cfg \ -D -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid) 当预期文件数量未知时,例如客户特定的文件,建议为它们分配一个以固定大小的数字序列开头的名称,并使用 "--" 来加载它们,可能是在加载一些默认设置之后:haproxy -f /etc/haproxy/global.cfg -f /etc/haproxy/stats.cfg \ -f /etc/haproxy/default-tcp.cfg -f /etc/haproxy/tcp.cfg \ -f /etc/haproxy/default-http.cfg -f /etc/haproxy/http.cfg \ -D -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid) \ -f /etc/haproxy/default-customers.cfg -- /etc/haproxy/customers/* 有时由于某种原因可能会发生启动失败。那么,验证您正在调用的 HAProxy 版本是否是预期的版本,以及它是否支持您期望的功能(例如:SSL、PCRE、压缩、Lua 等)非常重要。可以使用 "haproxy -vv" 来验证这一点。某些重要信息,例如某些构建选项、目标系统和正在使用的库的版本,会在其中报告。这也是在提交 bug 报告时系统会要求您提供的信息:$ haproxy -vv HA-Proxy version 1.6-dev7-a088d3-4 2015/10/08 Copyright 2000-2015 Willy Tarreau <willy@haproxy.org> Build options : TARGET = linux2628 CPU = generic CC = gcc CFLAGS = -pg -O0 -g -fno-strict-aliasing -Wdeclaration-after-statement \ -DBUFSIZE=8030 -DMAXREWRITE=1030 -DSO_MARK=36 -DTCP_REPAIR=19 OPTIONS = USE_ZLIB=1 USE_DLMALLOC=1 USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1 Default settings : maxconn = 2000, bufsize = 8030, maxrewrite = 1030, maxpollevents = 200 Encrypted password support via crypt(3): yes Built with zlib version : 1.2.6 Compression algorithms supported : identity("identity"), deflate("deflate"), \ raw-deflate("deflate"), gzip("gzip") Built with OpenSSL version : OpenSSL 1.0.1o 12 Jun 2015 Running on OpenSSL version : OpenSSL 1.0.1o 12 Jun 2015 OpenSSL library supports TLS extensions : yes OpenSSL library supports SNI : yes OpenSSL library supports prefer-server-ciphers : yes Built with PCRE version : 8.12 2011-01-15 PCRE library supports JIT : no (USE_PCRE_JIT not set) Built with Lua version : Lua 5.3.1 Built with transparent proxy support using: IP_TRANSPARENT IP_FREEBIND Available polling systems : epoll : pref=300, test result OK poll : pref=200, test result OK select : pref=150, test result OK Total: 3 (3 usable), will use epoll. 许多非开发者用户可以验证的相关信息是:- 版本:上面 1.6-dev7-a088d3-4 表示代码当前处于提交 ID "a088d3",这是官方版本 "1.6-dev7" 之后的第 4 个提交。版本 1.6-dev7 将显示为 "1.6-dev7-8c1ad7"。这里实际重要的是 "1.6-dev7"。这是未来将成为 1.6 版本的第 7 个开发版本。开发版本不适合在生产环境中使用(除非您确切地知道自己在做什么)。稳定版本将显示为 3 位数字版本,例如 "1.5.14-16f863",表示在版本 1.5 之上进行修复的第 14 个级别。这是一个生产就绪版本。- 发布日期:2015/10/08。它以通用的年/月/日格式表示。这里的意思是 2015 年 8 月 8 日。考虑到稳定版本每隔几个月发布一次(早期 1-2 个月,产品非常稳定后有时 6 个月),如果您看到一个旧日期,则意味着您可能受到自那时以来已修复的许多 bug 或安全问题的影响,并且可能值得在官方网站上进行检查。- 构建选项:它们与自己构建软件包的人相关,可以解释为什么事情不像预期的那样工作。例如,上面的开发版本是为 Linux 2.6.28 或更高版本构建的,针对通用 CPU(无 CPU 特定优化),并且没有代码优化 (-O0),因此在性能方面表现不佳。- 库版本:zlib 版本报告为在库本身中找到。通常 zlib 被认为是一个非常稳定的产品,几乎不需要升级。OpenSSL 报告两个版本,构建时使用的版本和正在使用的版本,如系统上找到的。这些版本可能在最后一个字母上有所不同,但数字上绝不会不同。还报告了构建日期,因为大多数 OpenSSL bug 都是安全问题,需要认真对待,因此绝对需要保持此库的最新。看到一个 4 个月大的版本在这里非常可疑,确实错过了更新。PCRE 提供非常快速的正则表达式,强烈推荐。它的某些扩展(如 JIT)并非在所有版本中都可用,并且仍然很新,因此有些人宁愿不使用它们构建,这就是报告构建状态的原因。关于 Lua 脚本语言,HAProxy 需要 5.3 版本,这个版本很新,因为它是在 HAProxy 1.6 发布前不久发布的。检查 Lua 网站是否为该分支提供了一些修复非常重要。- 可用的轮询系统在处理超过约一千个并发连接时会影响进程的可扩展性。这些仅在构建期间在 TARGET 变量中指示了正确的系统时可用。在 Linux 上高度推荐 "epoll" 机制,在 BSD 上高度推荐 kqueue 机制。缺少它们将导致使用 poll() 甚至 select(),在处理大量连接时导致 CPU 使用率高。
HAProxy 支持优雅停止和强制停止。强制停止很简单,当向 haproxy 进程发送 SIGTERM 信号时,它会立即退出,所有已建立的连接都会被关闭。当向 haproxy 进程发送 SIGUSR1 信号时,会触发优雅停止。它包括仅从监听端口解绑,但继续处理现有连接直到它们关闭。一旦最后一个连接关闭,进程退出。强制停止方法用于服务管理脚本的 "stop" 或 "restart" 操作。优雅停止用于 "reload" 操作,该操作尝试在新进程中无缝地重新加载新配置。在重新加载或重启期间,新的 haproxy 进程本身可能会发送这两个信号,以便在尽可能晚的时刻发送,并且仅在绝对需要时发送。这正是 "-st"(强制)和 "-sf"(优雅)选项分别执行的操作。在主/工作进程模式下,无需启动新的 haproxy 进程即可重新加载配置。主进程响应 SIGUSR2 信号,通过以 -sf 参数后跟工作进程的 PID 重新执行自身。然后,主进程将解析配置文件并 fork 新的工作进程。为了更好地理解这些信号的用途,理解整个重启机制很重要。首先,一个现有的 haproxy 进程正在运行。管理员使用系统特定的命令,例如 "/etc/init.d/haproxy reload",指示他希望使新配置文件生效。接下来发生的是。首先,服务脚本(/etc/init.d/haproxy 或等效脚本)将使用 "haproxy -c" 验证配置文件是否正确解析。之后,它将尝试使用该配置文件启动 haproxy,使用 "-st" 或 "-sf"。然后 HAProxy 尝试绑定到所有监听端口。如果发生任何致命错误(例如:地址在系统上不存在、权限被拒绝),进程将以错误退出。如果套接字绑定失败是因为端口已被占用,那么进程将首先向 "-st" 或 "-sf" PID 列表中指定的 PIDs 发送 SIGTTOU 信号。这就是所谓的 "pause" 信号。它指示所有现有的 haproxy 进程暂时停止监听它们的端口,以便新进程可以再次尝试绑定。在此期间,旧进程继续处理现有连接。如果绑定仍然失败(例如,因为端口与其他守护进程共享),那么新进程将向旧进程发送 SIGTTIN 信号,指示它们恢复操作,就好像什么都没发生一样。旧进程将重新开始监听端口并继续接受连接。请注意,此机制是系统依赖的,某些操作系统可能不支持多进程模式下的此机制。如果新进程成功绑定到所有端口,那么它将向所有进程发送 SIGTERM(在 "-st" 的情况下为强制停止)或 SIGUSR1(在 "-sf" 的情况下为优雅停止)信号,通知它们现在由它负责操作,并且旧进程将必须离开,无论是立即离开还是完成工作后离开。需要注意的是,在此期间,可能会有两段几毫秒的时间窗口,在此期间可能会注意到一些连接失败(在高负载下)。通常观察到的失败率约为每秒 10000 个新连接的重新加载操作中发生 1 次失败,这意味着一个高负载的网站以每秒 30000 个新连接的速度运行时,每次重新加载可能会遇到大约 3 次失败的连接。发生这种情况的两种情况是:- 如果新进程由于旧进程的存在而绑定失败,它将不得不首先经历 SIGTTOU+SIGTTIN 序列,该序列通常需要几毫秒才能处理几十个前端,在此期间某些端口将不会绑定到旧进程,也不会绑定到新进程。HAProxy 会在支持 SO_REUSEPORT 套接字选项的系统上解决此问题,因为它允许新进程在不先要求旧进程解绑的情况下进行绑定。大多数 BSD 系统几乎一直支持此功能。Linux 在 2.0 版本中支持此功能,并在 2.2 版本左右弃用,但当时有一些补丁在流传。它在内核 3.9 中重新引入,因此如果您观察到的连接失败率高于上述提到的,请确保您的内核是 3.9 或更新版本,或者相关的补丁已向后移植到您的内核(不太可能)。- 当旧进程关闭监听端口时,内核可能并不总是重新分配套接字积压中剩余的任何待处理连接。在高负载下,SYN 数据包可能发生在套接字关闭之前,并导致向客户端发送 RST 数据包。在某些不允许任何丢弃的关键环境中,有时会使用防火墙规则在重新加载期间阻止 SYN 数据包,迫使客户端重新传输。这完全取决于系统,因为某些系统可能能够访问其他监听队列并避免此 RST。第二种情况是客户端对本地套接字(在关闭前处于 SYN_RECV 状态)的 ACK。此 ACK 将导致 RST 数据包,而 haproxy 进程对此仍不知情。这更难解决,尽管上面提到的防火墙过滤规则在重新启动进程前一秒左右应用效果会很好。对于绝大多数用户来说,这种丢弃永远不会发生,因为他们的负载不足以触发竞态条件。对于大多数高流量用户来说,只要他们的系统至少正确支持 SO_REUSEPORT,失败率仍然相当在噪声范围内。
为了确保所有传入连接都能成功服务,HAProxy 在加载时计算进程生命周期内所需的总文件描述符数量。常规 Unix 进程默认通常获得 1024 个文件描述符,特权进程可以自行提高此限制。这是将 HAProxy 作为 root 启动并让其调整限制的原因之一。1024 个文件描述符的默认限制大致允许处理约 500 个并发连接。计算基于全局 maxconn 参数(限制每个进程的总连接数)、监听器数量、启用了健康检查的服务器数量、代理检查、对等节点、记录器以及可能的一些其他技术要求。一个简单的粗略估计是简单地将 maxconn 值加倍,再加上几十个以获得所需文件描述符的大致数量。最初 HAProxy 不知道如何计算此值,并且有必要通过全局部分的 "ulimit-n" 设置传递该值。这就是为什么即使今天仍能看到许多配置中包含此设置。不幸的是,它经常被错误计算,导致在接近 maxconn 时连接失败,而不是在等待所需资源时限制传入连接。出于这个原因,移除任何可能从非常旧版本遗留下来的 "ulimit-n" 设置非常重要。提高文件描述符数量以接受中等负载是强制性的,但这会带来一些特定于操作系统的调整。首先,select() 轮询系统限制为 1024 个文件描述符。实际上,在 Linux 上,它曾经能够处理更多,但由于某些操作系统带有过度的限制性 SELinux 策略,禁止使用超过 1024 个文件描述符的 select(),HAProxy 现在拒绝在此情况下启动,以避免运行时出现任何问题。在所有支持的操作系统上,poll() 都可用,无需进行任何操作即可获得有效配置。但是,当文件描述符数量增加时,poll() 会变得非常慢。虽然 HAProxy 尽力限制此性能影响(例如:通过使用内部文件描述符缓存和批量处理),一个经验法则是,使用 poll() 处理超过一千个并发连接会消耗大量 CPU。对于基于内核 2.6 及更高版本的 Linux 系统,将使用 epoll() 系统调用。它是一种更具可扩展性的机制,依赖于内核中的回调,保证唤醒时间恒定,与注册的监控文件描述符数量无关。它会在检测到时自动使用,前提是 HAProxy 已为 Linux 之一构建。可以使用 "haproxy -vv" 验证其存在和支持。对于支持它的 BSD 系统,kqueue() 是一个可用的替代方案。它比 poll() 快得多,并且由于其批量处理更改,甚至比 epoll() 略快。至少 FreeBSD 和 OpenBSD 支持它。与 Linux 的 epoll() 一样,其支持和可用性会在 "haproxy -vv" 的输出中报告。拥有一个好的 poller 是一回事,但进程必须能够达到限制。当 HAProxy 启动时,它会立即设置新进程的文件描述符限制并验证其是否成功。如果失败,它会在 fork 之前报告,以便管理员可以看到问题。只要进程以 root 身份启动,就不应该有理由会失败。但是,如果进程由非特权用户启动,它可能会失败。如果出于某种原因 *不* 以 root 身份启动 haproxy(例如:由最终用户或每个应用程序的帐户启动),那么系统管理员可以为该特定用户提高文件描述符限制。可以通过用户命令行发出 "ulimit -n" 来验证设置的有效性。它应该反映新的限制。警告:当在用户帐户中更改非特权用户的限制时,通常只有在用户登录时才会考虑这些值,而在系统启动时运行的某些脚本或 crontab 中则完全不考虑。这完全取决于操作系统,请记住在以这种方式运行时,在启动 haproxy 之前检查 "ulimit -n"。一般的建议是,在生产目的下,永远不要以非特权用户身份启动 haproxy。另一个好处是,它可以防止 haproxy 启用某些安全保护。一旦确定系统将允许 haproxy 进程使用所需数量的文件描述符,可能会遇到两个新的特定于系统的限制。第一个是系统范围的文件描述符限制,即系统上打开的文件描述符总数,涵盖所有进程。当达到此限制时,accept() 或 socket() 通常会返回 ENFILE。第二个是每个进程对文件描述符数量的硬限制,它阻止将 setrlimit() 设置得更高。两者都非常依赖于操作系统。在 Linux 上,系统限制基于内存量在启动时设置。可以使用 "fs.file-max" sysctl 进行更改。并且每个进程的硬限制默认为 1048576,但可以使用 "fs.nr_open" sysctl 进行更改。当系统调用返回 "-1 EMFILE" 时,这意味着进程的限制已达到,并且在系统范围的参数上必须做些什么。这些问题绝对必须解决,因为它们会导致高 CPU 使用率(当 accept() 失败时)和通常对用户可见的连接失败。一个解决方案还包括降低全局 maxconn 值以强制序列化,并可能禁用 HTTP keep-alive 以强制连接释放和更快地重用。
HAProxy 使用一个简单快速的基于池的内存管理。由于它依赖于少量不同类型的对象,因此从一个已经包含适当大小对象的池中获取新对象比为每种不同大小调用 malloc() 要高效得多。池组织成一个堆栈或 LIFO,以便新分配的对象从最近释放的、仍然在 CPU 缓存中的对象中获取。相似大小的池会被合并在一起,以限制内存碎片。默认情况下,由于重点放在性能上,每个释放的对象都会被放回其原始池中,并且分配的对象永远不会被释放,因为预计它们很快就会被重用。在 CLI 上,可以通过 "show pools" 命令检查池中内存的使用情况:> show pools Dumping pools usage. Use SIGQUIT to flush them. - Pool cache_st (16 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9ccc40=03 [SHARED] - Pool pipe (32 bytes) : 5 allocated (160 bytes), 5 used, 0 failures, 2 users, @0x9ccac0=00 [SHARED] - Pool comp_state (48 bytes) : 3 allocated (144 bytes), 3 used, 0 failures, 5 users, @0x9cccc0=04 [SHARED] - Pool filter (64 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 3 users, @0x9ccbc0=02 [SHARED] - Pool vars (80 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9ccb40=01 [SHARED] - Pool uniqueid (128 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9cd240=15 [SHARED] - Pool task (144 bytes) : 55 allocated (7920 bytes), 55 used, 0 failures, 1 users, @0x9cd040=11 [SHARED] - Pool session (160 bytes) : 1 allocated (160 bytes), 1 used, 0 failures, 1 users, @0x9cd140=13 [SHARED] - Pool h2s (208 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9ccec0=08 [SHARED] - Pool h2c (288 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9cce40=07 [SHARED] - Pool spoe_ctx (304 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 2 users, @0x9ccf40=09 [SHARED] - Pool connection (400 bytes) : 2 allocated (800 bytes), 2 used, 0 failures, 1 users, @0x9cd1c0=14 [SHARED] - Pool hdr_idx (416 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9cd340=17 [SHARED] - Pool dns_resolut (480 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9ccdc0=06 [SHARED] - Pool dns_answer_ (576 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9ccd40=05 [SHARED] - Pool stream (960 bytes) : 1 allocated (960 bytes), 1 used, 0 failures, 1 users, @0x9cd0c0=12 [SHARED] - Pool requri (1024 bytes) : 0 allocated (0 bytes), 0 used, 0 failures, 1 users, @0x9cd2c0=16 [SHARED] - Pool buffer (8030 bytes) : 3 allocated (24090 bytes), 2 used, 0 failures, 1 users, @0x9cd3c0=18 [SHARED] - Pool trash (8062 bytes) : 1 allocated (8062 bytes), 1 used, 0 failures, 1 users, @0x9cd440=19 Total: 19 pools, 42296 bytes allocated, 34266 used. 池名称仅具有指示性,它是使用该池的第一个对象类型的名称。括号中的大小是该池中对象的对象大小。对象大小始终向上舍入到最接近的 16 字节倍数。当前分配的对象数量和等效字节数会报告出来,以便轻松了解哪个池导致了最高的内存使用量。"used" 字段还会报告当前使用的对象数量。"allocated" 和 "used" 之间的差值对应于已释放并可供立即使用的对象。行末的地址是池的地址,后面的数字是池的索引(如果存在),或者如果未分配索引则报告为 -1。可以使用命令行选项 "-m",后跟兆字节数,来限制每个进程分配的内存量。它覆盖进程的可寻址空间,因此包括一些库使用的内存以及堆栈,但这是在构建资源受限系统时一个可靠的限制。它的工作方式与具有该功能的系统的 "ulimit -v" 或其他系统的 "ulimit -d" 相同。如果内存分配因内存限制达到或系统没有足够内存而失败,则 haproxy 将首先尝试释放所有池中的可用对象,然后再尝试再次分配内存。通过向 haproxy 进程发送 SIGQUIT 信号可以触发这种释放未使用内存的机制。这样做时,在进程在前台运行时,刷新前的池状态也会报告给 stderr。在重新加载操作期间,切换到优雅停止状态的进程在释放任何连接后还会自动执行一些刷新,以便释放所有可能的内存以供新进程使用。
HAProxy 通常大部分时间花费在系统上,一小部分时间花费在用户空间。一个经过精细调优的 3.5 GHz CPU 在单核上以 100% CPU 负载下,每秒大约可以处理 80000 个端到端的连接建立和关闭。当一个核心饱和时,典型数据为:- 95% 系统,5% 用户(对于长 TCP 连接或大 HTTP 对象)- 85% 系统和 15% 用户(对于短 TCP 连接或小 HTTP 对象,采用 close 模式)- 70% 系统和 30% 用户(对于小 HTTP 对象,采用 keep-alive 模式)规则处理和正则表达式的数量会增加用户空间部分。防火墙规则、连接跟踪、系统中复杂的路由表的存在将增加系统部分。在大多数系统上,在网络传输期间观察到的 CPU 时间可以分为 4 部分:- 中断部分,它涉及 I/O 接收时执行的所有处理,在目标进程已知之前。通常 Rx 数据包计入中断。在某些系统(如 Linux)上,中断处理可能会推迟到专用线程,它可能表现为 softirq,该线程称为 ksoftirqd/0(对于 CPU 0)。处理此负载的 CPU 通常由硬件设置定义,尽管在 softirq 的情况下,可以将其处理重新映射到另一个 CPU。此中断部分通常被视为寄生程序,因为它不与任何进程相关联,但实际上是为进程准备工作的一些处理。- 系统部分,它涉及从用户空间调用的所有内核代码处理。例如,系统调用被计为系统时间。所有同步发送的 Tx 数据包将被计为系统时间。如果由于队列已满而必须推迟某些数据包,它们可能稍后在中断上下文中处理(例如:收到打开 TCP 窗口的 ACK 时)。- 用户部分,它完全在用户空间中运行应用程序代码。HAProxy 完全在此部分运行,尽管它大量使用系统调用。规则处理、正则表达式、压缩、加密都会增加用户部分 CPU 的消耗。- 空闲部分,这是 CPU 在无事可临时执行的操作。例如,HAProxy 等待传入连接,或等待某些数据离开,这意味着系统正在等待来自客户端的 ACK 以推送这些数据。实际上,关于 HAProxy 的活动,通常可以 reasonably accuracy(但完全不精确)地认为中断/softirq 是由内核驱动程序中的 Rx 处理引起的,用户空间是由 HAProxy 中的第 7 层处理引起的,系统时间是由于 Tx 路径上的网络处理引起的。由于 HAProxy 围绕事件循环运行,它使用 poll()(或任何替代方法)等待新事件,并尽快处理所有这些事件,然后再返回 poll() 等待新事件。它测量在 poll() 中花费的时间与处理事件所花费的时间。轮询时间与总时间的比率称为 "idle" 时间,即等待某事发生的空闲时间。此比率显示在 stats 页面的 "idle" 行上,或 CLI 上的 "Idle_pct"。当它接近 100% 时,意味着负载非常低。当它接近 0% 时,意味着总是有活动。虽然在过载系统上可能不非常准确,因为其他进程可能抢占 HAProxy 进程的 CPU,但它仍然提供了 HAProxy 如何认为自己正在工作的良好估计:如果负载低且空闲率也很低,则可能表明 HAProxy 有很多工作要做,可能是由于必须处理的非常昂贵的规则。反之,如果 HAProxy 指示空闲率接近 100%,而事物却很慢,则意味着它无能为力来加快速度,因为它已经在等待传入数据进行处理。在下面的示例中,haproxy 完全空闲:$ echo "show info" | socat - /var/run/haproxy.sock | grep ^Idle Idle_pct: 100 当空闲率开始非常低时,调整系统并将进程和中断正确放置以尽可能节省所有任务的 CPU 资源非常重要。如果存在防火墙,则可能值得尝试禁用它或调整它以确保它不负责大部分性能限制。值得注意的是,卸载有状态防火墙通常会减少中断/softirq 和系统使用量,因为此类防火墙同时作用于 Rx 和 Tx 路径。在 Linux 上,卸载 nf_conntrack 和 ip_conntrack 模块将显示是否有可以改进的地方。如果有,则模块以默认设置运行,您需要找出如何调整它以获得更好的性能。通常,这包括显著增加哈希表大小。在 FreeBSD 上,"pfctl -d" 将同时禁用 "pf" 防火墙及其有状态引擎。如果观察到大量时间花费在中断/softirq 上,则确保它们不在同一个 CPU 上运行很重要。大多数系统倾向于将任务固定在接收网络流量的 CPU 上,因为对于某些工作负载来说,这可以提高性能。但对于高度受网络限制的工作负载,情况恰恰相反,因为 haproxy 进程将不得不与其内核对应物竞争。将 haproxy 固定到一个 CPU 核心,并将中断固定到另一个核心,所有核心共享相同的 L3 缓存,这往往会显著提高网络性能,因为实际上 haproxy 和网络堆栈的工作量非常接近,因此它们几乎可以填满一个 CPU。在 Linux 上,这可以使用 taskset(用于 haproxy)或 cpu-map(从 haproxy 配置)完成,中断在 /proc/irq 下分配。许多网络接口支持多个队列和多个中断。通常,将它们分布在少量 CPU 核心上会有帮助,前提是它们都共享相同的 L3 缓存。请务必停止 irq_balance,它总是会在此类工作负载上产生最坏的结果。对于由大量 SSL 流量或大量压缩组成 CPU 密集型工作负载,可能值得使用多个专用于某些任务的进程,尽管这里没有通用规则,并且需要进行实验。为了增加 CPU 容量,可以通过在全局部分使用 "nbproc" 指令使 HAProxy 运行多个进程。但是有一些限制:- 健康检查是每个进程运行的,因此目标服务器将获得与正在运行的进程数量相同的检查次数;- maxconn 值和队列是每个进程的,因此必须设置正确的值以避免服务器过载;- 出站连接应避免使用端口范围以避免冲突;- 粘性表是每个进程的,并且不会在进程之间共享;- 每个 peers 部分一次只能在一个进程上运行;- CLI 操作一次只能作用于一个进程。考虑到这一点,最简单的设置通常包括有一个运行在多个进程上并负责繁重处理的第一层,将流量传递给在单个进程中运行的第二层。此机制适用于 SSL 和压缩,这两者都是 CPU 密集型功能。实例可以轻松地通过 UNIX 套接字(比 TCP 套接字便宜且不浪费端口)链式连接,以及用于将客户端信息传递到下一阶段的 proxy protocol。这样做时,通常最好将所有单进程任务绑定到进程号 1,并将额外任务绑定到下一个进程,因为这将更容易为不同机器生成类似的配置。在 Linux 3.9 及更高版本上,当每个进程在同一 IP:port 上使用不同的监听套接字运行时,在多进程模式下运行 HAProxy 会更有效;这将使内核在所有进程之间平均分配负载,而不是唤醒所有进程。请查阅配置手册中的 "bind" 关键字行的 "process" 选项以获取更多信息。
对于日志记录,HAProxy 始终依赖于 syslog 服务器,因为它不执行任何文件系统访问。标准用法是通过 UDP 将日志发送到日志服务器(默认端口为 514)。通常配置为 127.0.0.1,本地 syslog 守护进程正在运行,但它也用于通过网络日志记录到中央服务器。中央服务器提供了额外的优势,尤其是在主动-主动场景中,希望将日志按到达顺序合并。HAProxy 也可能使用 UNIX 套接字将日志发送到本地 syslog 守护进程,但这完全不推荐,因为如果 syslog 服务器在 haproxy 运行时重新启动,套接字将被替换,并且新日志将会丢失。由于 HAProxy 将被隔离在 chroot 监狱中,它将无法重新连接到新套接字。在实际应用中也观察到 UNIX 套接字上使用的日志缓冲区非常小,即使在负载很轻的情况下也会导致消息丢失。但这对于测试来说是可以的。建议在 "global" 部分添加以下指令,使 HAProxy 使用 "local0" 设施日志记录到本地守护进程:log 127.0.0.1:514 local0 然后将以下指令添加到每个 "defaults" 部分或每个 "frontend" 和 "backend" 部分:log global 这样,所有日志都将通过全局定义(日志服务器的位置)进行集中。某些 syslog 守护进程默认不监听 UDP 流量,因此根据使用的守护进程,启用此功能的语法会有所不同:- 在 sysklogd 上,您需要在守护进程的命令行上传递 "-r" 参数,以便它监听 UDP 套接字以获取 "remote" 日志;请注意,无法将其限制为地址 127.0.0.1,因此它还会接收来自远程系统的日志;- 在 rsyslogd 上,必须将以下行添加到配置文件中:$ModLoad imudp $UDPServerAddress * $UDPServerRun 514 - 在 syslog-ng 上,可以创建一个新的源,如下所示,然后需要将其添加到 "log" 指令之一中作为有效源:source s_udp { udp(ip(127.0.0.1) port(514)); }; 请参阅您的 syslog 守护进程手册以获取更多信息。如果在系统日志文件中看不到任何日志,请考虑进行以下测试:- 重启 haproxy。每个前端和后端会记录一条指示其启动的日志。如果收到这些日志,则表示日志正在工作。- 运行 "strace -tt -s100 -etrace=sendmsg -p <haproxy's pid>" 并执行一些您期望被记录的操作。您应该会看到使用 sendmsg() 发送的日志消息。如果它们没有出现,则使用 strace 重新启动 haproxy。如果您仍然看不到任何日志,那么肯定您的配置有问题。- 运行 tcpdump 来监视端口 514,例如在回环接口上,如果流量正在本地发送:"tcpdump -As0 -ni lo port 514"。如果在此处看到数据包,则证明它们已被发送,那么就需要对 syslogd 守护进程进行故障排除。虽然流量日志从前端(传入连接被接受的地方)发送,但后端也需要能够发送日志,以便在健康检查之后报告服务器状态更改。请参阅 HAProxy 的配置手册以获取更多关于所有可能的日志设置的信息。选择一个其他守护进程未使用的设施很方便。HAProxy 示例通常建议使用 "local0" 进行流量日志,使用 "local1" 进行管理日志,因为它们在实际应用中从未见过。一个单独的设施也足够了。拥有单独的日志有利于日志分析,但也要记住,日志有时可能包含机密信息,因此不能将其与其他可能意外泄露给未经授权人员的日志混合。为了在不严重影响服务器容量的情况下进行现场故障排除,建议利用 HAProxy 提供的 "halog" 工具。这是一种类似 grep 的实用程序,旨在以非常高的数据速率处理 HAProxy 日志文件。典型数字范围为每秒 1 到 2 GB 的日志。它能够仅提取某些日志(例如:搜索某些类别的 HTTP 状态码、连接终止状态、按响应时间范围搜索、仅查找错误)、计数行、将输出限制为行数,并执行一些更高级的统计信息,例如按响应时间或错误计数对服务器进行排序,按时间或计数对 URL 进行排序,按访问计数对客户端地址进行排序,等等。它非常方便,可以快速发现异常情况,例如机器人循环访问站点,并将其阻止。
可以查询 HAProxy 的状态。最常用的机制是 HTTP 统计页面。该页面还为监控工具提供了一种替代的 CSV 输出格式。在 Unix 套接字上也提供了相同的格式。

9.1. CSV 格式

统计信息可以通过 unix 套接字或 HTTP 页面进行查询。两种方式都提供 CSV 格式,其字段如下。第一行以井号(“#”)开头,每个逗号分隔的字段有一个单词,表示列标题。从第二行开始的所有其他行使用经典的 CSV 格式,以逗号作为分隔符,并以双引号(“"”)作为可选的文本分隔符,但仅当包含的文本含糊不清时(如果它包含引号或逗号)。文本中的双引号字符(“"”)被加倍(“""”),这是大多数工具识别的格式。请不要在此列之前插入任何其他列,以免破坏使用硬编码列位置的工具。每个字段名称后面的括号中是该字段可能具有的值的类型。类型为 L(监听器)、F(前端)、B(后端)和 S(服务器)。0. pxname [LFBS]: 代理名称 1. svname [LFBS]: 服务名称(FRONTEND 代表前端,BACKEND 代表后端,任何名称代表服务器/监听器) 2. qcur [..BS]: 当前排队请求。对于后端,此值报告未分配服务器的排队数量。 3. qmax [..BS]: qcur 的最大值 4. scur [LFBS]: 当前会话 5. smax [LFBS]: 最大会话 6. slim [LFBS]: 配置的会话限制 7. stot [LFBS]: 会话累计数量 8. bin [LFBS]: 输入字节数 9. bout [LFBS]: 输出字节数 10. dreq [LFB.]: 因安全原因而被拒绝的请求。- 对于 TCP,这是因为匹配了 tcp-request 内容规则。- 对于 HTTP,这是因为匹配了 http-request 或 tarpit 规则。 11. dresp [LFBS]: 因安全原因而被拒绝的响应。- 对于 HTTP,这是因为匹配了 http-request 规则,或“option checkcache”。 12. ereq [LF..]: 请求错误。可能的原因包括:- 客户端提前终止,在发送请求之前。- 从客户端读取错误- 客户端超时- 客户端关闭连接- 客户端发送各种无效请求。- 请求被 tarpit。 13. econ [..BS]: 尝试连接到后端服务器时遇到错误的请求数量。后端统计数据是所有服务器统计数据的总和,加上任何未与特定服务器关联的连接错误(例如后端没有活动服务器)。 14. eresp [..BS]: 响应错误。srv_abrt 也将在此处计数。其他一些错误包括:- 客户端套接字写入错误(服务器统计数据不计入)- 应用过滤器到响应失败。 15. wretr [..BS]: 重试连接到服务器的次数。 16. wredis [..BS]: 将请求重新分派到另一台服务器的次数。服务器值计算了该服务器被切换出去的次数。 17. status [LFBS]: 状态(UP/DOWN/NOLB/MAINT/MAINT(via)/MAINT(resolution)...) 18. weight [..BS]: 总权重(后端),服务器权重(服务器) 19. act [..BS]: 活动服务器数量(后端),服务器是否活动(服务器) 20. bck [..BS]: 备份服务器数量(后端),服务器是否备份(服务器) 21. chkfail [...S]: 失败的检查次数。(仅计算服务器处于 UP 状态时失败的检查。) 22. chkdown [..BS]: UP->DOWN 转换次数。后端计数器计算整个后端变为 DOWN 的转换次数,而不是每个服务器计数器的总和。 23. lastchg [..BS]: 自上次 UP<->DOWN 转换以来的秒数 24. downtime [..BS]: 总停机时间(以秒为单位)。后端的值是整个后端的停机时间,而不是服务器停机时间的总和。 25. qlimit [...S]: 服务器的配置的最大队列长度,如果值为 0 则为空(默认,表示无限制) 26. pid [LFBS]: 进程 ID(0 为第一个实例,1 为第二个,...) 27. iid [LFBS]: 唯一代理 ID 28. sid [L..S]: 服务器 ID(在代理内唯一) 29. throttle [...S]: 服务器当前的节流百分比,当 slowstart 激活时,如果不在 slowstart 中则无值。 30. lbtot [..BS]: 服务器被选中的总次数,无论是用于新会话还是重新分派。服务器计数器是该服务器被选中的次数。 31. tracked [...S]: 如果启用了跟踪,则为代理/服务器的 ID。 32. type [LFBS]: (0=frontend, 1=backend, 2=server, 3=socket/listener) 33. rate [.FBS]: 每秒会话数(过去一秒) 34. rate_lim [.F..]: 每秒新会话的配置限制 35. rate_max [.FBS]: 每秒新会话的最大数量 36. check_status [...S]: 上次健康检查的状态,以下之一:UNK -> 未知 INI -> 初始化 SOCKERR -> 套接字错误 L4OK -> 第 4 层检查通过,未启用上层测试 L4TOUT -> 第 1-4 层超时 L4CON -> 第 1-4 层连接问题,例如“连接被拒绝”(tcp rst)或“无法路由到主机”(icmp) L6OK -> 第 6 层检查通过 L6TOUT -> 第 6 层(SSL)超时 L6RSP -> 第 6 层无效响应 - 协议错误 L7OK -> 第 7 层检查通过 L7OKC -> 第 7 层条件通过检查,例如 404 带 disable-on-404 L7TOUT -> 第 7 层(HTTP/SMTP)超时 L7RSP -> 第 7 层无效响应 - 协议错误 L7STS -> 第 7 层响应错误,例如 HTTP 5xx 注意:如果检查正在进行中,将报告上次已知状态,并带有“*”前缀。例如“* L7OK”。 37. check_code [...S]: 第 5-7 层代码,如果可用 38. check_duration [...S]: 完成上次健康检查所需的时间(毫秒) 39. hrsp_1xx [.FBS]: 带有 1xx 代码的 HTTP 响应 40. hrsp_2xx [.FBS]: 带有 2xx 代码的 HTTP 响应 41. hrsp_3xx [.FBS]: 带有 3xx 代码的 HTTP 响应 42. hrsp_4xx [.FBS]: 带有 4xx 代码的 HTTP 响应 43. hrsp_5xx [.FBS]: 带有 5xx 代码的 HTTP 响应 44. hrsp_other [.FBS]: 带有其他代码(协议错误)的 HTTP 响应 45. hanafail [...S]: 失败的健康检查详细信息 46. req_rate [.F..]: 每秒 HTTP 请求数(过去一秒) 47. req_rate_max [.F..]: observed 的最大每秒 HTTP 请求数 48. req_tot [.FB.]: 接收到的 HTTP 请求总数 49. cli_abrt [..BS]: 客户端中止的数据传输次数 50. srv_abrt [..BS]: 服务器中止的数据传输次数(计入 eresp) 51. comp_in [.FB.]: 输入到压缩器的 HTTP 响应字节数 52. comp_out [.FB.]: 由压缩器输出的 HTTP 响应字节数 53. comp_byp [.FB.]: 已绕过 HTTP 压缩器的字节数(CPU/带宽限制) 54. comp_rsp [.FB.]: 被压缩的 HTTP 响应数 55. lastsess [..BS]: 自上次会话分配给服务器/后端以来的秒数 56. last_chk [...S]: 上次健康检查内容或文本错误 57. last_agt [...S]: 上次代理检查内容或文本错误 58. qtime [..BS]: 过去 1024 个请求的平均队列时间(毫秒) 59. ctime [..BS]: 过去 1024 个请求的平均连接时间(毫秒) 60. rtime [..BS]: 过去 1024 个请求的平均响应时间(毫秒)(TCP 为 0) 61. ttime [..BS]: 过去 1024 个请求的平均总会话时间(毫秒) 62. agent_status [...S]: 上次代理检查的状态,以下之一:UNK -> 未知 INI -> 初始化 SOCKERR -> 套接字错误 L4OK -> 第 4 层检查通过,未启用上层测试 L4TOUT -> 第 1-4 层超时 L4CON -> 第 1-4 层连接问题,例如“连接被拒绝”(tcp rst)或“无法路由到主机”(icmp) L7OK -> 代理报告“up” L7STS -> 代理报告“fail”、“stop”或“down” 63. agent_code [...S]: 代理报告的数字代码(如果存在)(目前未使用) 64. agent_duration [...S]: 完成上次检查所需时间(毫秒) 65. check_desc [...S]: check_status 的简短人类可读描述 66. agent_desc [...S]: agent_status 的简短人类可读描述 67. check_rise [...S]: 服务器的“rise”参数,用于检查 68. check_fall [...S]: 服务器的“fall”参数,用于检查 69. check_health [...S]: 服务器的健康检查值,介于 0 和 rise+fall-1 之间 70. agent_rise [...S]: 代理的“rise”参数,通常为 1 71. agent_fall [...S]: 代理的“fall”参数,通常为 1 72. agent_health [...S]: 代理的健康参数,介于 0 和 rise+fall-1 之间 73. addr [L..S]: 地址:端口或“unix”。IPv6 在地址周围使用方括号。 74. cookie [..BS]: 服务器的 cookie 值或后端的 cookie 名称 75. mode [LFBS]: 代理模式(tcp、http、health、unknown) 76. algo [..B.]: 负载均衡算法 77. conn_rate [.F..]: 每秒连接数(过去一秒) 78. conn_rate_max [.F..]: 已知的最高 conn_rate 79. conn_tot [.F..]: 连接总数 80. intercepted [.FB.]: 截获的请求累计数量(监控、统计) 81. dcon [LF..]: 被“tcp-request connection”规则拒绝的请求 82. dses [LF..]: 被“tcp-request session”规则拒绝的请求 83. wrew [LFBS]: 累积的无效头重写警告次数 84. connect [..BS]: 连接建立尝试的累计次数 85. reuse [..BS]: 连接重用的累计次数 86. cache_lookups [.FB.]: 缓存查找的累计次数 87. cache_hits [.FB.]: 缓存命中的累计次数 88. srv_icur [...S]: 当前可用的空闲连接数 89. src_ilim [...S]: 可用空闲连接数的限制 90. qtime_max [..BS]: 观察到的最大队列时间(毫秒) 91. ctime_max [..BS]: 观察到的最大连接时间(毫秒) 92. rtime_max [..BS]: 观察到的最大响应时间(毫秒)(TCP 为 0) 93. ttime_max [..BS]: 观察到的最大总会话时间(毫秒) 94. eint [LFBS]: 内部错误累计数量 95. idle_conn_cur [...S]: 当前不安全的空闲连接数 96. safe_conn_cur [...S]: 当前安全的空闲连接数 97. used_conn_cur [...S]: 使用中的连接数 98. need_conn_est [...S]: 估计需要的连接数

9.2. 类型化输出格式

show info”和“show stat”都支持一种模式,其中每个输出值都附带其类型和足够的信息,以了解该值应如何在进程之间聚合以及它如何演变。在所有情况下,输出由每行一个值组成,所有信息都用冒号(“:”)分隔。第一列指定要转储的对象或度量。其格式特定于生成此输出的命令,在本节中不进行描述。通常,它将由一系列标识符和字段名称组成。第二列包含 3 个字符,分别指示所报告值的来源、性质和范围。第一个字符(来源)指示值是从何处提取的。可能的字符是:M 该值是指标。它在一个瞬间有效,并且可能根据其性质而变化。S 该值是状态。它表示一个离散值,根据定义不能聚合。它可以是服务器的状态(“UP”或“DOWN”)、进程的 PID 等。K 该值是排序键。它表示一个标识符,可用于将某些值分组在一起,因为它在其类中是唯一的。所有内部标识符都是键。有些名称可以列为键,如果它们是唯一的(例如:前端名称是唯一的)。通常键来自配置,尽管其中一些键可能被自动分配。对于大多数用途,键可以被视为等同于配置。C 该值来自配置。某些配置值在输出中有意义,例如并发连接限制或 cookie 名称。根据定义,这些值在从同一配置文件启动的所有进程中都是相同的。P 该值来自产品本身。这类值很少,最常见的用途是报告产品名称、版本和发布日期。这些元素在所有进程之间也相同。第二个字符(性质)指示字段所携带信息的性质,以便聚合器可以决定使用何种操作来聚合多个值。可能的字符是:A 该值表示自上次事件以来的年龄。这与持续时间略有不同,因为年龄是根据当前日期自动计算的。典型示例是服务器上上次会话发生多久之前。年龄通常通过取最小值来聚合,并且不需要存储。a 该值表示已经平均值。响应时间平均值和服务器权重属于此类。平均值通常可以在进程之间平均。C 该值表示累积计数器。这些度量会不断增加,直到回绕。一些监控协议需要区分计数器和仪表,以便报告不同的类型。通常计数器可以简单地求和,因为它们表示事件或数量。此类度量的示例是连接数或字节数。D 该值表示状态的持续时间。对此有几种用法,其中大部分包括上次健康检查所需的时间以及服务器已花费的停机时间。持续时间通常不求和,大多数时候会保留最大值来计算 SLA。G 该值表示仪表。它是在一个瞬间的度量。内存使用情况或当前活动连接数属于此类。此类度量通常在聚合期间求和。L 该值表示限制(通常是已配置的)。根据性质,限制更难聚合,因为它们特定于检索它们的位置。在某些情况下,它们可以求和或保持单独。M 该值表示最大值。通常,它会应用于仪表并保留已知的最高值。此类度量的示例可能是产品生命周期中遇到的最大并发连接数。要正确聚合最大值,您应该输出一个范围,从所有最大值的最小值到所有值的总和。实际上,无法知道它们是否同时出现。m 该值表示最小值。通常,它会应用于仪表并保留已知的最低值。此类度量的示例可能是产品生命周期中遇到的最小可用内存池数。要正确聚合最小值,您应该输出一个范围,从所有最小值的最小值到所有值的总和。实际上,无法知道它们是否同时出现。N 该值表示名称,因此它是字符串。它用于报告代理名称、服务器名称和 cookie 名称。名称具有配置或键作为其来源,并且在所有进程中应该是相同的。O 该值表示自由文本输出。来自各种命令的输出、健康检查的返回、节点描述属于此类。R 该值表示事件速率。它是在一个瞬间的度量。它与仪表非常相似,只是接收者知道该度量变化缓慢,并可能决定不保留所有值。此类度量的示例是每秒连接数的测量值。此类度量通常在聚合期间求和。T 该值表示日期或时间。发出当前日期的字段将属于此类。聚合此类信息的​​方法留给实现选择。目前没有字段使用此类型。第三个字符(范围)指示值反映的范围。某些元素可以按进程,而其他元素可以按配置或按系统。区分这一点很重要,以了解单个值在聚合期间是否应保留,或者值是否必须被聚合。当前支持以下字符:C 该值对整个节点集群有效,该集群是跨对等协议通信的节点集。例如,一个与对等节点复制的 stick table 中的条目数量。目前没有度量使用此范围。P 该值仅对报告它的进程有效。大多数度量使用此范围。S 该值对整个服务有效,即从同一配置文件一起启动的进程集。所有源自配置的度量都使用此范围。其他一些度量也可能使用它用于一些共享资源(例如:共享 SSL 缓存统计信息)。s 该值对整个系统有效,例如系统的名称、当前日期或资源使用情况。目前没有度量使用此范围。使用这些信息进行聚合的消费者通常会有足够的这 3 个字符来确定如何准确地在多个进程中报告聚合信息。在此列之后,第三列指示字段的类型,包括“s32”(有符号 32 位整数)、“s64”(有符号 64 位整数)、“u32”(无符号 32 位整数)、“u64”(无符号 64 位整数)、“str”(字符串)。在解析值以正确读取它之前,了解类型很重要。例如,仅包含数字的字符串仍然是字符串而不是整数(例如:由检查提取的错误代码)。然后第四列是值本身,根据其类型进行编码。字符串直接在冒号之后倾倒,没有前导空格。如果字符串包含冒号,它将正常显示。这意味着输出不应该仅围绕冒号拆分,否则某些检查输出或服务器地址可能会被截断。

9.3. Unix 套接字命令

Stats 套接字默认未启用。为了启用它,有必要在 haproxy 配置的 global 部分添加一行。建议添加第二行以设置更长的超时时间,手动发出命令时总是受欢迎的:global stats socket /var/run/haproxy.sock mode 600 level admin stats timeout 2m 也可以通过重复该行来添加多个 stats 套接字实例,并让它们监听 TCP 端口而不是 UNIX 套接字。这从不默认执行,因为它很危险,但有时可能很有用:global stats socket /var/run/haproxy.sock mode 600 stats socket ipv4@192.168.0.1:9999 level admin stats timeout 2m 要访问套接字,需要使用诸如“socat”之类的外部实用程序。Socat 是一个将任何东西连接到任何东西的瑞士军刀。我们使用它将终端连接到套接字,或将一对 stdin/stdout 管道连接到它以用于脚本。我们将使用的两个主要语法如下:# socat /var/run/haproxy.sock stdio # socat /var/run/haproxy.sock readline 第一个用于脚本。可以将脚本的输出发送到 haproxy,并将 haproxy 的输出传递给另一个脚本。这对于检索计数器或攻击跟踪等非常有用。第二个仅用于手动发出命令。它的好处是终端由 readline 库处理,该库支持行编辑和历史记录,这在发出重复命令(例如:监视计数器)时非常方便。套接字支持两种操作模式:- 交互式- 非交互式当 socat 连接到套接字时,非交互式模式是默认模式。在此模式下,可以发送单行。它被作为一个整体处理,响应被发送回来,并且在响应结束时连接关闭。这是脚本和监控工具使用的模式。在此模式下可以发送多个命令,它们需要用分号(“;”)分隔。例如:# echo "show info;show stat;show table" | socat /var/run/haproxy stdio 如果命令需要使用分号或反斜杠(例如:在值中),则必须用反斜杠(“\”)进行前导。交互式模式显示一个提示符(“>”),并等待在该行输入命令,然后处理它们,并再次显示提示符以等待新命令。该模式通过必须在非交互模式的第一行发送的“prompt”命令进入。该模式是一个切换开关,如果在交互模式下发送“prompt”,它将被禁用,并且连接将在处理同一行的最后一个命令后关闭。因此,手动调试时,通常以“prompt”命令开始:# socat /var/run/haproxy readline prompt > show info ... > 由于一次可以发出多个命令,haproxy 使用空行作为分隔符来标记每个命令的输出结束,并确保任何命令都不能在输出中发出空行。因此,即使在单行上流水线化了多个命令,脚本也可以轻松解析输出。某些命令可能需要可选的负载。要向命令添加负载,第一行需要以“<<\n”模式结束。接下来的行将被视为负载,并且可以包含任意多行。要验证带有负载的命令,需要以空行结束。确实存在限制:传递给 CLI 的整个缓冲区长度不得超过 tune.bfsize,并且模式“<<”不得与行的最后一个单词粘连。在交互模式下输入负载时,提示符将从“> ”变为“+ ”。重要的是要理解,当多个 haproxy 进程在同一套接字上启动时,任何进程都可能接收请求并输出其自己的统计信息。下面提供了当前在 stats 套接字上支持的命令列表。如果发送了未知命令,haproxy 将显示用法消息,提醒所有支持的命令。有些命令支持更复杂的语法,通常会在发生这种情况时解释命令的哪个部分无效。某些命令需要更高级别的权限才能工作。如果您没有足够的权限,您将收到“Permission denied”错误。请查看配置手册中“bind”关键字行的“level”选项以获取更多信息。
abort ssl cert <filename>
中止并销毁一个临时的 SSL 证书更新事务。另见 "set ssl cert" 和 "commit ssl cert"。
add acl <acl> <pattern>
向 ACL <acl> 中添加一个条目。<acl> 是由 "show acl" 返回的 #<id> 或 <file>。此命令不验证条目是否已存在。如果引用的 <acl> 是一个也与 map 一起使用的文件,则不能使用此命令。在这种情况下,您必须使用 "add map" 命令来代替 "add acl"。
add map <map> <key> <value>
add map <map> <payload>
向 map <map> 中添加一个条目,将值 <value> 与键 <key> 关联起来。此命令不验证条目是否已存在。它主要用于在清除操作后填充 map。请注意,如果引用的 <map> 是一个文件并且与一个 map 共享,那么该 map 也将包含一个新的模式条目。使用 payload 语法,可以通过在不同行上输入多个键/值对来添加它们。在每个新行上,第一个单词是键,行的其余部分被认为是值,甚至可以包含空格。
示例
# socat /tmp/sock1 - prompt > add map #-1 << + key1 value1 + key2 value2 with spaces + key3 value3 also with spaces + key4 value4 >
add ssl crt-list <crtlist> <certificate>
add ssl crt-list <crtlist> <payload>
在 crt-list 中添加一个证书。它也可以用于目录,因为现在目录的加载方式与 crt-list 相同。此命令允许您在参数中使用证书名称,要使用 SSL 选项或过滤器,必须将 crt-list 行作为有效负载发送。有效负载中只支持一个 crt-list 行。此命令将为使用 crt-list 的每个 bind 行加载证书。要将新证书推送到 HAProxy,必须使用 "new ssl cert" 和 "set ssl cert" 命令。
示例
$ echo "new ssl cert foobar.pem" | socat /tmp/sock1 - $ echo -e "set ssl cert foobar.pem <<\n$(cat foobar.pem)\n" | socat /tmp/sock1 - $ echo "commit ssl cert foobar.pem" | socat /tmp/sock1 - $ echo "add ssl crt-list certlist1 foobar.pem" | socat /tmp/sock1 - $ echo -e 'add ssl crt-list certlist1 <<\nfoobar.pem [allow-0rtt] foo.bar.com !test1.com\n' | socat /tmp/sock1 -
清除每个代理(前端和后端)和每个服务器中统计计数器的最大值。累积的计数器不受影响。由 "show activity" 报告的内部活动计数器也会被重置。这可用于在事件发生后获得干净的计数器,而无需重新启动或清除流量计数器。此命令受限制,只能在配置为“operator”或“admin”级别的套接字上发出。
清除每个代理(前端和后端)和每个服务器中的所有统计计数器。这与重新启动具有相同的效果。此命令受限制,只能在配置为“admin”级别的套接字上发出。
clear acl <acl>
从 ACL <acl> 中删除所有条目。<acl> 是由 "show acl" 返回的 #<id> 或 <file>。请注意,如果引用的 <acl> 是一个文件并且与一个 map 共享,那么该 map 也将被清除。
clear map <map>
从 map <map> 中删除所有条目。<map> 是由 "show map" 返回的 #<id> 或 <file>。请注意,如果引用的 <map> 是一个文件并且与一个 acl 共享,那么该 acl 也将被清除。
clear table <table> [ data.<type> <operator> <value> ] | [ key <key> ]
从 stick-table <table> 中删除条目。这通常用于解除阻止一些抱怨因滥用而被拒绝访问服务的用户,但也用于清除一些与将要被替换的服务器匹配的 sticky 条目(有关详细信息,请参阅下面的“show table”)。请注意,有时删除条目会被拒绝,因为它当前被某个会话跟踪。通常在会话结束后几秒钟重试通常就足够了。在未提供任何 options 参数的情况下,所有条目都将被删除。当使用“data.”形式时,会删除使用存储数据(请参阅 第 4.2 节中的“stick-table”)应用的过滤器匹配的条目。必须在 <type> 中指定存储的数据类型,并且该数据类型必须存储在表中,否则会报告错误。根据 <operator> 和 64 位整数 <value> 比较数据。运算符与 ACL 中的相同:- eq : 匹配数据等于此值等于此值的条目- ne : 匹配数据不等于此值的条目- le : 匹配数据小于或等于此值的条目- ge : 匹配数据大于或等于此值的条目- lt : 匹配数据小于此值的条目- gt : 匹配数据大于此值的条目当使用 key 形式时,删除条目 <key>。键必须与表相同类型,当前仅限于 IPv4、IPv6、整数和字符串。
示例
$ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a4c: key=127.0.0.1 use=0 exp=3594729 gpc0=0 conn_rate(30000)=1 \ bytes_out_rate(60000)=187 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "clear table http_proxy key 127.0.0.1" | socat stdio /tmp/sock1 $ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:1 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "clear table http_proxy data.gpc0 eq 1" | socat stdio /tmp/sock1 $ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:1
commit ssl cert <filename>
提交一次临时的 SSL 证书更新事务。对于已存在的证书(在“show ssl cert”中状态为“Used”),生成其所需的所有 SSL 上下文和 SNI,插入它们,并删除之前的。在内存中替换配置文件中使用了 <filename> 的所有先前 SSL 证书。失败时,它不会删除或插入任何内容。临时事务一旦提交,就会被销毁。对于新证书(在“new ssl cert”之后,并且在“show ssl cert”中状态为“Unused”),证书将被提交到证书存储中,但不会在 haproxy 的任何地方使用。要使用它并生成其 SNI,您需要将其添加到 crt-list 或使用“add ssl crt-list”的目录中。另请参阅“new ssl cert”、“ssl set cert”、“abort ssl cert”和“add ssl crt-list”。
debug dev <command> [args]*
调用开发者专用的命令。仅在以专家模式(expert mode)运行的 CLI 连接上支持(参见 "expert-mode on")。此类命令极其危险且不可恢复,任何误用都可能导致进程崩溃。它们仅供专家使用,除非得到明确指示,否则绝对不应使用。其中一些命令仅在 haproxy 编译时定义了 DEBUG_DEV 时才可用,因为它们可能存在安全隐患。所有这些命令都需要管理员权限,并且为了避免不熟悉源代码的人员滥用,我们特意没有将它们写入文档。
del acl <acl> [<key>|#<ref>]
从 acl <acl> 中删除所有与键 <key> 对应的 acl 条目。<acl> 是由“show acl”返回的 #<id> 或 <file>。如果使用了 <ref>,此命令仅删除列出的引用。引用可以通过列出 acl 的内容找到。请注意,如果引用的 <acl> 是一个文件并且与 map 共享,该条目也将在 map 中被删除。
del map <map> [<key>|#<ref>]
从 map <map> 中删除所有与键 <key> 对应的 map 条目。<map> 是由“show map”返回的 #<id> 或 <file>。如果使用了 <ref>,此命令仅删除列出的引用。引用可以通过列出 map 的内容找到。请注意,如果引用的 <map> 是一个文件并且与 acl 共享,该条目也将在 acl 中被删除。
del ssl cert <certfile>
从 HAProxy 中删除一个证书存储。该证书必须是未使用的,并且已从任何 crt-list 或目录中移除。“show ssl cert”显示证书的状态。此删除操作不适用于在配置中通过“crt”指令直接引用的证书。
del ssl crt-list <filename> <certfile[:line]>
删除 crt-list 中的一个条目。这将删除前端中用于此条目的所有 SNI。如果一个证书在 crt-list 中被多次使用,您需要提供想要删除的行号。要显示行号,请使用 "show ssl crt-list -n <crtlist>"。
disable agent <backend>/<server>
将辅助代理检查标记为临时停止。在代理检查作为辅助检查运行的情况下(由于服务器指令的 agent-check 参数),只有当代理处于启用状态时才会初始化新的检查。因此,disable agent 将阻止任何新的代理检查被启动,直到使用 enable agent 重新启用代理。当代理被禁用时,对在代理启用时启动的辅助代理检查的处理如下:所有会改变权重的结果,特别是 "drain" 或代理返回的权重,都将被忽略。代理检查的其他处理方式保持不变。此功能的动机是允许暂停代理检查的权重更改效果,以便可以使用 set weight 配置服务器的权重,而不会被代理覆盖。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
为后端 <backend> 禁用动态 cookie 的生成。
disable frontend <frontend>
将前端标记为临时停止。这对应于软重启期间使用的模式:前端释放端口,但如果需要可以再次启用。应谨慎使用此命令,因为一些非 Linux 操作系统无法重新启用它。这旨在用于那些甚至无法想象停止代理但必须修复配置错误的代理的环境中。这样就有可能释放端口并将其绑定到另一个进程以恢复操作。前端将在统计页面上显示为 "STOP" 状态。前端可以通过其名称或其数字 ID(前缀为井号 '#')指定。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
disable health <backend>/<server>
将主健康检查标记为临时停止。这将禁用发送健康检查,并且最后的健康检查结果将被忽略。服务器将处于未检查状态并被认为是 UP,除非辅助代理检查强制其 down。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
disable server <backend>/<server>
将服务器标记为 DOWN 进行维护。在此模式下,直到服务器离开维护模式,否则不会再对其进行检查。如果该服务器被其他服务器跟踪,那些服务器在维护期间也将被设置为 DOWN。在统计页面上,处于维护状态的服务器将显示 "MAINT" 状态,其跟踪服务器将显示 "MAINT(via)" 状态。后端和服务器都可以通过其名称或其数字 ID(前缀为井号 '#')指定。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
enable agent <backend>/<server>
恢复临时停止的辅助代理检查。有关临时启动和停止辅助代理的效果的详细信息,请参见 "disable agent"。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
为后端 <backend> 启用动态 cookie 的生成。还必须提供一个密钥。
enable frontend <frontend>
恢复一个临时停止的前端。某些监听端口可能无法再次绑定(例如:自'disable frontend'操作以来,另一个进程占用了它们)。如果发生这种情况,将显示错误。某些操作系统可能无法恢复被禁用的前端。前端可以通过其名称或其数字 ID(前缀为井号 '#')指定。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
enable health <backend>/<server>
恢复一个临时停止的主健康检查。这将再次启用发送健康检查。详情请参见 "disable health"。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
enable server <backend>/<server>
如果服务器之前被标记为 DOWN 进行维护,此命令将服务器标记为 UP 并重新启用检查。后端和服务器都可以通过其名称或其数字 ID(前缀为井号 '#')指定。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
expert-mode [on|off]
不带选项时,此命令指示当前连接上的专家模式是启用还是禁用。当传递 "on" 时,它仅为当前 CLI 连接打开专家模式。使用 "off" 则将其关闭。专家模式会显示一些专家命令,这些命令对进程可能极其危险,但偶尔可以帮助开发人员收集有关复杂 bug 的重要信息。任何滥用这些功能都可能导致进程崩溃。在没有被邀请的情况下,请勿使用此选项。请注意,此命令故意未在帮助消息中列出。此命令只能在 admin 级别访问。更改到其他级别会自动重置专家模式。
get map <map> <value>
get acl <acl> <value>
查找 map <map> 或 ACL <acl> 中的值 <value>。<map> 或 <acl> 是“show map”或“show acl”返回的 #<id> 或 <file>。此命令返回与此 map 相关的所有匹配的模式。这对于调试 map 和 ACL 非常有用。输出格式由每个匹配类型的一行组成。每行由空格分隔的一系列单词组成。前两个单词是:<match method>: 应用的匹配方法。它可以是“found”、“bool”、“int”、“ip”、“bin”、“len”、“str”、“beg”、“sub”、“dir”、“dom”、“end”或“reg”。<<match result>: 结果。可以是“match”或“no-match”。仅当模式匹配某个条目时,才会返回后面的单词。<index type>: “tree”或“list”。内部查找算法。<case>: “case-insensitive”或“case-sensitive”。大小写的解释。<entry matched>: match="<entry>"。返回匹配的模式。与正则表达式一起使用很有用。最后两个单词用于显示返回值及其类型。在“acl”情况下,模式不存在。return=nothing: 无返回值,因为没有“map”。return="<value>": 以字符串格式返回的值。return=cannot-display: 值无法转换为字符串。type="<type>": 返回的样本的类型。
get weight <backend>/<server>
报告后端 <backend> 中服务器 <server> 的当前权重和初始权重,如果任一不存在则报告错误。初始权重是配置文件中出现的权重。除非当前权重已被更改,否则两者通常相等。后端和服务器都可以通过其名称或其数字 ID(前缀为井号 '#')指定。
打印已知关键字及其基本用法的列表。对于未知命令,也会显示相同的帮助屏幕。
new ssl cert <filename>
创建一个新的空 SSL 证书存储,用于填充证书并添加到目录或 crt-list 中。此命令应与 "set ssl cert" 和 "add ssl crt-list" 结合使用。
切换行首的提示符,并进入或离开交互模式。在交互模式下,命令完成后连接不会关闭。相反,提示符会再次出现,表示解释器正在等待新命令。提示符由一个右尖括号后跟一个空格“> ”组成。当希望定期检查信息(如统计数据或错误)时,此模式特别方便。在发出“help”命令之前进入交互模式也是一个好主意。
在交互模式下关闭连接。
修改用于生成动态持久性 cookie 的密钥。这将破坏现有会话。
set map <map> [<key>|#<ref>] <value>
修改 map <map> 中每个键 <key> 对应的值。<map> 是由“show map”返回的 #<id> 或 <file>。如果使用 <ref> 代替 <key>,则只更改 <ref> 指向的条目。新值为 <value>。
set maxconn frontend <frontend> <value>
动态更改指定前端的 maxconn 设置。允许任何正值,包括零,但设置大于全局 maxconn 的值没有太大意义。如果限制增加并且有待处理的连接,它们将立即被接受。如果限制降低到低于当前连接数的水平,新连接的接受将被延迟,直到达到阈值。前端可以通过其名称或其前缀为井号('#')的数字 ID 来指定。
set maxconn server <backend/server> <value>
动态更改指定服务器的 maxconn 设置。允许任何正值,包括零,但设置大于全局 maxconn 的值没有太大意义。
在初始全局 maxconn 设置定义的范围内动态更改全局 maxconn 设置。如果它被增加并且有待处理的连接,它们将立即被接受。如果它被降低到低于当前连接数的水平,新连接的接受将被延迟,直到达到阈值。值为零将恢复初始设置。
set profiling { tasks } { auto | on | off }
为指定的子系统启用或禁用 CPU 分析。这等同于在配置文件的 "global" 部分中设置或清除 "profiling" 设置。另请参阅 "show profiling"。
更改进程范围的连接速率限制,该限制由全局 'maxconnrate' 设置。值为零表示禁用限制。此限制适用于所有前端,并且更改会立即生效。值以每秒连接数的形式传递。
更改最大输入压缩速率,该速率由全局 'maxcomprate' 设置。值为零表示禁用限制。值以每秒千字节数的形式传递。该值可在 "show info" 的 "CompressBpsRateLim" 行中以字节为单位查看。
更改进程范围的会话速率限制,该限制由全局 'maxsessrate' 设置。值为零表示禁用限制。此限制适用于所有前端,并且更改会立即生效。值以每秒会话数的形式传递。
更改进程范围的 SSL 会话速率限制,该限制由全局 'maxsslrate' 设置。值为零表示禁用限制。此限制适用于所有前端,并且更改会立即生效。值以每秒发送到 SSL 堆栈的会话数的形式传递。它在握手之前应用,以保护堆栈免受握手滥用。
set server <backend>/<server> addr <ip4 or ip6 address> [port <port>]
用提供的 IP 地址替换服务器的当前 IP 地址。可选地,可以使用 'port' 参数更改端口。请注意,更改端口也支持从端口映射(表示为 +X 或 -Y)切换或切换到端口映射,前提是为健康检查配置了端口。
set server <backend>/<server> agent [ up | down ]
强制服务器的代理进入新状态。例如,这对于不考虑某些缓慢的代理检查而立即切换服务器状态非常有用。请注意,如果有跟踪服务器,此更改将传播到它们。
set server <backend>/<server> agent-addr <addr>
更改服务器代理检查的地址。允许在运行时将代理检查迁移到另一个地址。您可以指定 IP 和主机名,它将被解析。
set server <backend>/<server> agent-send <value>
更改发送到代理检查目标的代理字符串。允许在更改服务器地址时更新字符串以保持两者匹配。
set server <backend>/<server> health [ up | stopping | down ]
强制服务器的健康状态进入新状态。例如,这对于不考虑某些缓慢的健康检查而立即切换服务器状态非常有用。请注意,如果有跟踪服务器,此更改将传播到它们。
set server <backend>/<server> check-port <port>
将用于健康检查的端口更改为 <port>
set server <backend>/<server> state [ ready | drain | maint ]
强制服务器的管理状态进入新状态。这对于禁用负载均衡和/或到服务器的任何流量非常有用。将状态设置为 "ready" 会使服务器进入正常模式,该命令等同于 "enable server" 命令。将状态设置为 "maint" 会禁用任何到服务器的流量以及任何健康检查。这等同于 "disable server" 命令。将模式设置为 "drain" 只会从负载均衡中移除服务器,但仍允许其被检查并接受新的持久连接。如果有跟踪服务器,更改将传播到它们。
set server <backend>/<server> weight <weight>[%]
将服务器的权重更改为参数中传递的值。这与下面的 "set weight" 命令完全等效。
set server <backend>/<server> fqdn <FQDN>
将服务器的 FQDN 更改为参数中传递的值。这要求为该服务器配置并启用了内部运行时 DNS 解析器。
set severity-output [ none | number | string ]
更改当前会话期间连接的 stats socket 的严重性输出格式。
set ssl cert <filename> <payload>
此命令是事务系统的一部分,可能需要“commit ssl cert”和“abort ssl cert”命令。整个事务系统适用于“show ssl cert”命令显示的任何证书,目前仅限于前端证书。如果没有正在进行的事务,它将把证书 <filename> 复制到内存中的临时事务,然后使用负载中的 PEM 文件更新此事务。如果存在具有相同文件名的事务,它将更新此事务。也可以更新与证书关联的文件(.issuer、.sctl、.oscp 等)。修改完成后,您必须通过“commit ssl cert”提交事务。通过 CLI 注入文件时必须小心,因为空行用于通知负载结束。建议注入已清理的 PEM 文件。一种简单的方法是删除所有空行,只保留 PEM 部分的内容。这可以通过 sed 命令实现。
示例
# 经过一些简单清理 echo -e "set ssl cert localhost.pem <<\n$(sed -n '/^$/d;/-BEGIN/,/-END/p' 127.0.0.1.pem)\n" | \ socat /var/run/haproxy.stat - # 包含提交的完整示例 echo -e "set ssl cert localhost.pem <<\n$(cat 127.0.0.1.pem)\n" | \ socat /var/run/haproxy.stat - echo -e \ "set ssl cert localhost.pem.issuer <<\n $(cat 127.0.0.1.pem.issuer)\n" | \ socat /var/run/haproxy.stat - echo -e \ "set ssl cert localhost.pem.ocsp <<\n$(base64 -w 1000 127.0.0.1.pem.ocsp)\n" | \ socat /var/run/haproxy.stat - echo "commit ssl cert localhost.pem" | socat /var/run/haproxy.stat -
set ssl ocsp-response <response | payload>
此命令用于更新证书的 OCSP 响应(参见 "bind" 行上的 "crt")。执行的控制与初始加载响应时相同。<response> 必须作为来自 OCSP 服务器的 DER 编码响应的 base64 编码字符串传递。BoringSSL 不支持此命令。
示例
openssl ocsp -issuer issuer.pem -cert server.pem \ -host ocsp.issuer.com:80 -respout resp.der echo "set ssl ocsp-response $(base64 -w 10000 resp.der)" | \ socat stdio /var/run/haproxy.stat 使用 payload 语法:echo -e "set ssl ocsp-response <<\n$(base64 resp.der)\n" | \ socat stdio /var/run/haproxy.stat
set ssl tls-key <id> <tlskey>
将 <id> 侦听器的下一个 TLS 密钥设置为 <tlskey>。此密钥成为最终密钥,而倒数第二个密钥用于加密(其他密钥仅用于解密)。最旧的 TLS 密钥将被覆盖。<id> 是由 "show tls-keys" 返回的数字 #<id> 或 <file>。<tlskey> 是 base64 编码的 48 位或 80 位 TLS 票证密钥(例如:openssl rand 80 | openssl base64 -A)。
set table <table> key <key> [data.<data_type> <value>]*
在 stick-table 中创建或更新一个条目。如果键不存在,则插入一个条目。请参阅 4.2 节 中的 stick-table 以查找 <data_type> 的所有可能值。最常见的用途是动态输入源 IP 地址的条目,并在 gpc0 中设置一个标志来动态阻止 IP 地址或影响其服务质量。可以在单次调用中传递多个 data_type。
更改当前连接的 CLI 接口超时。这在长时间的调试会话中非常有用,用户需要不断检查一些指标而不会被断开连接。延迟以秒为单位传递。
set weight <backend>/<server> <weight>[%]
将服务器的权重更改为参数传递的值。如果值以“%”符号结尾,则新权重将相对于初始配置的权重。绝对权重允许在 0 到 256 之间。相对权重必须为正,结果的绝对权重上限为 256。运行静态负载均衡算法的服务器场中的服务器有更严格的限制,因为一旦设置,权重就不能更改。因此,对于这些服务器,唯一接受的值是 0 和 100%(或 0 和初始权重)。更改立即生效,尽管某些 LB 算法需要一定数量的请求才能考虑更改。此命令的典型用法是在更新期间通过将服务器权重设置为零来禁用服务器,然后在更新后将其设置回 100% 来重新启用它。此命令受限制,只能在配置为 level "admin" 的套接字上发出。后端和服务器都可以通过其名称或其数字 ID(以井号(“#”)为前缀)来指定。
show acl [<acl>]
转储有关 acl 转换器的信息。不带参数时,返回所有可用 acl 的列表。如果指定了 <acl>,则转储其内容。<acl> 是 #<id> 或 <file>。转储格式与 map 相同,甚至对于样本值也是如此。返回的数据不是可用 ACL 的列表,而是构成任何 ACL 的所有模式的列表。这些模式中的许多可以与 map 共享。
转储正在运行的进程中可用的后端列表。
显示当前 CLI 会话的 CLI 级别。结果可能是 'admin'、'operator' 或 'user'。另请参阅 'operator' 和 'user' 命令。
示例
$ socat /tmp/sock1 readline prompt > operator > show cli level operator > user > show cli level user > operator 权限被拒绝
将当前 CLI 会话的 CLI 级别降低到 operator。它不能被提高。它还会放弃专家模式。另请参阅 "show cli level"。
将当前 CLI 会话的 CLI 级别降低到 user。它不能被提高。它还会放弃专家模式。另请参阅 "show cli level"。
报告一些关于内部事件的计数器,这将帮助开发人员以及更广泛的、对 haproxy 足够了解的人员缩小异常行为报告的原因。一个典型的例子是一个正常运行的进程从不休眠并占用 100% 的 CPU。输出字段将由每个指标一行组成,并且同一行上显示每个线程的计数器。这些计数器是 32 位的,并会在进程的生命周期内回绕,这不是问题,因为通常会两次调用此命令。这些字段故意没有文档化,以便在代码中验证其确切含义,即计数器被馈送的地方。这些值也会被 "clear counters" 命令重置。
列出 CLI 套接字。输出格式由 3 个以空格分隔的字段组成。第一个字段是套接字地址,可以是 unix 套接字、ipv4 地址:端口对或 ipv6 地址:端口对。其他类型的套接字不会被转储。第二个字段描述套接字的级别:'admin'、'user' 或 'operator'。最后一个字段列出套接字绑定的进程,用逗号分隔,可以是数字或 'all'。
示例
$ echo 'show cli sockets' | socat stdio /tmp/sock1 # socket lvl processes /tmp/sock1 admin all 127.0.0.1:9999 user 2,3,4 127.0.0.2:9969 user 2 [::1]:9999 operator 2
列出配置的缓存以及存储在每个缓存树中的对象。 $ echo 'show cache' | socat stdio /tmp/sock1 0x7f6ac6c5b03a: foobar (shctx:0x7f6ac6c5b000, available blocks:3918) 1 2 3 4 1. 指向缓存结构的指针 2. 缓存名称 3. 指向 mmap 区域 (shctx) 的指针 4. shctx 中可供重用的块数 0x7f6ac6c5b4cc hash:286881868 size:39114 (39 blocks), refcount:9, expire:237 1 2 3 4 5 6 1. 指向缓存条目的指针 2. 哈希的前 32 位 3. 对象的字节大小 4. 对象使用的块数 5. 使用该条目的事务数 6. 过期时间,如果已过期则可以为负数
show env [<name>]
转储进程已知的一个或所有环境变量。不带任何参数时,将转储所有变量。带一个参数时,如果指定的变量存在,则仅转储该变量。否则将输出 "Variable not found"。变量的转储格式与它们存储或由 "env" 实用程序返回的格式相同,即 "<name>=<value>"。这在调试大量使用环境变量的某些配置文件时非常方便,以确保它们包含预期的值。此命令受限,并且只能在配置为 "operator" 或 "admin" 级别的套接字上发出。
show errors [<iid>|<proxy>] [request|response]
转储前端和后端收集的上次已知的请求和响应错误。如果指定了 <iid>,则将转储限制为仅涉及 ID 为 <iid> 的前端或后端的错误。代理 ID “-1”将导致转储所有实例。如果指定了代理名称而不是 ID,则将使用其 ID 作为过滤器。如果代理名称或 ID 后面添加了“request”或“response”,则仅转储请求或响应错误。此命令受限制,只能在配置为 "operator" 或 "admin" 级别的套接字上发出。可能收集的错误是由于协议违规引起的最后请求和响应错误,通常是由于标头名称中的无效字符。报告精确地指示了哪个确切字符违反了协议。其他重要信息,如检测到错误的確切日期、前端和后端名称、服务器名称(已知时)、内部会话 ID 和发起会话的源地址也会被报告。所有字符都会被返回,并且不可打印字符会被编码。最常见的(\t = 9, \n = 10, \r = 13 和 \e = 27)被编码为反斜杠后面的一个字母。反斜杠本身被编码为“\\”以避免混淆。其他不可打印字符被编码为“\xNN”,其中 NN 是字符 ASCII 码的两位十六进制表示。行以其第一个字符的位置为前缀,从缓冲区的开头开始为 0。最多每行打印一个输入行,并且大行将被分解成多个连续的输出行,以便输出永远不会超过 79 个字符宽。很容易检测一行是否被分解,因为它不会以“\n”结尾,并且下一行的偏移量将带有“+”符号,表示它是前一行的延续。
示例
$ echo "show errors -1 response" | socat stdio /tmp/sock1 >>> [04/Mar/2009:15:46:56.081] backend http-in (#2) : invalid response src 127.0.0.1, session #54, frontend fe-eth0 (#1), server s2 (#1) response length 213 bytes, error at position 23: 00000 HTTP/1.0 200 OK\r\n 00017 header/bizarre:blah\r\n 00038 Location: blah\r\n 00054 Long-line: this is a very long line which should b 00104+ e broken into multiple lines on the output buffer, 00154+ otherwise it would be too large to print in a ter 00204+ minal\r\n 00211 \r\n 上面的示例显示,内部 ID 为 2 的后端“http-in”阻止了其服务器 s2(内部 ID 为 1)的无效响应。请求是源自 127.0.0.1 的会话 54,由 ID 为 1 的前端 fe-eth0 收到。检测到错误时,总响应长度为 213 字节,错误位于第 23 字节。这是标头名称“header/bizarre”中的斜杠(“/”),它不是有效 HTTP 标头名称字符。
show events [<sink>] [-w] [-n]
不带选项时,此命令列出所有已知的事件接收器及其类型。带选项时,如果指定的接收器类型为缓冲区,则会转储该接收器中的所有可用事件。如果在接收器名称后传递“-w”选项,则一旦到达缓冲区末尾,命令将等待新事件并显示它们。可以通过输入任何内容(将被丢弃)或关闭会话来停止操作。最后,“-n”选项用于直接定位到缓冲区的末尾,这通常在与“-w”结合使用时很方便,以便只报告新事件。为方便起见,可以使用“-wn”或“-nw”来同时启用这两个选项。
show fd [<fd>]
转储所有打开的文件描述符的列表,或者仅转储指定数字 <fd> 的文件描述符。这仅针对需要观察内部状态以调试复杂问题(如异常 CPU 使用率)的开发人员。每行报告一个 fd,对于每个 fd,它在 poller 中的状态,使用大写字母表示启用标志,小写字母表示禁用标志,使用“P”表示“polled”(已轮询),“R”表示“ready”(就绪),“A”表示“active”(活动),事件状态使用“H”表示“hangup”(挂断),“E”表示“error”(错误),“O”表示“output”(输出),“P”表示“priority”(优先级)和“I”表示“input”(输入),一些其他标志如“N”表示“new”(刚添加到 fd 缓存中),“U”表示“updated”(在 fd 缓存中收到更新),“L”表示“linger_risk”(延迟风险),“C”表示“cloned”(克隆),然后是缓存条目的位置、指向内部所有者的指针、指向 I/O 回调的指针及其名称(已知时)。当所有者是连接时,将报告连接标志和目标(前端、代理或服务器)。当所有者是监听器时,将报告监听器的状态及其前端。使用此命令没有任何意义,除非对内部原理有深入了解。值得注意的是,输出格式可能会随着时间而演变,因此此输出不能被设计为持久的工具解析。某些内部结构状态可能看起来可疑,在本例中,输出行将以感叹号(“!”)为后缀。这可能有助于在诊断事件时找到一个起点。
show info [typed|json] [desc]
转储当前进程中 haproxy 状态的信息。如果传递了可选参数“typed”,则还会发出字段编号、名称和类型,以便外部监控产品可以轻松检索、可能聚合然后报告它们不知道的字段中的信息。每个字段都在自己的行上转储。如果传递了可选参数“json”,则“typed”输出提供的信息将以 JSON 格式作为 JSON 对象列表提供。默认情况下,格式仅包含两列,用冒号(“:”)分隔。左侧是字段名称,右侧是值。非常重要的是要注意,在 typed 输出格式中,单个对象的转储是连续的,因此消费者无需一次性存储所有内容。使用 typed 输出格式时,每行由 4 列组成,用冒号(“:”)分隔。第一列是点分隔的 3 个元素。第一个元素是列表中字段的数字位置(从零开始)。此位置随时间保持不变,但可能出现空隙,具体取决于构建选项或将来是否删除某些字段。第二个元素是默认“show info”输出中出现的字段名称。第三个元素是相对进程编号,从 1 开始。第一列之后的其余行遵循上面章节中描述的“typed output format”。简而言之,第二列(第一个“:”之后)指示变量的来源、性质和范围。第三列指示字段的类型,包括“s32”、“s64”、“u32”、“u64”和“str”。然后第四列是值本身,消费者可以通过第 3 列知道如何解析,并通过第 2 列知道如何处理。因此,typed 模式下的整体行格式是:<field_pos>.<field_name>.<process_num>:<tags>:<type>:<value> 当向命令附加“desc”时,会附加一个额外的冒号和一个带引号的字符串,其中包含度量的描述。在撰写本文时,这仅支持“typed”和默认输出格式。
示例
> show info Name: HAProxy Version: 1.7-dev1-de52ea-146 Release_date: 2016/03/11 Nbproc: 1 Process_num: 1 Pid: 28105 Uptime: 0d 0h00m04s Uptime_sec: 4 Memmax_MB: 0 PoolAlloc_MB: 0 PoolUsed_MB: 0 PoolFailed: 0 (...) > show info typed 0.Name.1:POS:str:HAProxy 1.Version.1:POS:str:1.7-dev1-de52ea-146 2.Release_date.1:POS:str:2016/03/11 3.Nbproc.1:CGS:u32:1 4.Process_num.1:KGP:u32:1 5.Pid.1:SGP:u32:28105 6.Uptime.1:MDP:str:0d 0h00m08s 7.Uptime_sec.1:MDP:u32:8 8.Memmax_MB.1:CLP:u32:0 9.PoolAlloc_MB.1:MGP:u32:0 10.PoolUsed_MB.1:MGP:u32:0 11.PoolFailed.1:MCP:u32:0 (...)
在类型化格式中,第一列末尾的进程ID使得从多个进程的输出中进行视觉聚合变得非常容易。
示例
$ ( echo show info typed | socat /var/run/haproxy.sock1 ; \ echo show info typed | socat /var/run/haproxy.sock2 ) | \ sort -t . -k 1,1n -k 2,2 -k 3,3n 0.Name.1:POS:str:HAProxy 0.Name.2:POS:str:HAProxy 1.Version.1:POS:str:1.7-dev1-868ab3-148 1.Version.2:POS:str:1.7-dev1-868ab3-148 2.Release_date.1:POS:str:2016/03/11 2.Release_date.2:POS:str:2016/03/11 3.Nbproc.1:CGS:u32:2 3.Nbproc.2:CGS:u32:2 4.Process_num.1:KGP:u32:1 4.Process_num.2:KGP:u32:2 5.Pid.1:SGP:u32:30120 5.Pid.2:SGP:u32:30121 6.Uptime.1:MDP:str:0d 0h01m28s 6.Uptime.2:MDP:str:0d 0h01m28s (...)
JSON 输出的格式在一个 schema 中描述,可以使用“show schema json”输出该 schema。JSON 输出不包含额外的空白字符,以减少输出量。为了方便人类阅读,可以通过一个美化打印器来处理输出。示例:$ echo "show info json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool JSON 输出不包含额外的空白字符,以减少输出量。为了方便人类阅读,可以通过一个美化打印器来处理输出。示例:$ echo "show info json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool
show map [<map>]
转储关于 map 转换器的信息。不带参数时,返回所有可用 map 的列表。如果指定了 <map>,则转储其内容。<map> 是 #<id> 或 <file>。第一列是唯一标识符。它可以作为 "del map" 和 "set map" 操作的参考。第二列是模式,第三列是样本(如果可用)。返回的数据不是直接的可用 map 列表,而是构成任何 map 的所有模式的列表。这些模式中的许多可以与 ACL 共享。
show peers [<peers section>]
转储“peers”部分中配置的对等节点的信息。如果不带参数,将列出所有“peers”部分中的对等节点列表。如果指定了 <peers section>,则仅转储属于该“peers”部分的对等节点信息。以下是两个输出示例,其中 hostA、hostB 和 hostC 对等节点属于“sharedlb”对等节点部分。只有 hostA 和 hostB 已连接。只有 hostA 向 hostB 发送了数据。$ echo "show peers" | socat - /tmp/hostA 0x55deb0224320: [15/Apr/2019:11:28:01] id=sharedlb state=0 flags=0x3 \ resync_timeout=<PAST> task_calls=45122 0x55deb022b540: id=hostC(remote) addr=127.0.0.12:10002 status=CONN \ reconnect=4s confirm=0 flags=0x0 0x55deb022a440: id=hostA(local) addr=127.0.0.10:10000 status=NONE \ reconnect=<NEVER> confirm=0 flags=0x0 0x55deb0227d70: id=hostB(remote) addr=127.0.0.11:10001 status=ESTA reconnect=2s confirm=0 flags=0x20000200 appctx:0x55deb028fba0 st0=7 st1=0 task_calls=14456 \ state=EST xprt=RAW src=127.0.0.1:37257 addr=127.0.0.10:10000 remote_table:0x55deb0224a10 id=stkt local_id=1 remote_id=1 last_local_table:0x55deb0224a10 id=stkt local_id=1 remote_id=1 shared tables: 0x55deb0224a10 local_id=1 remote_id=1 flags=0x0 remote_data=0x65 last_acked=0 last_pushed=3 last_get=0 teaching_origin=0 update=3 table:0x55deb02d6a0 id=stkt update=3 localupdate=3 \ commitupdate=3 syncing=0 $ echo "show peers" | socat - /tmp/hostB 0x55871b5ab320: [15/Apr/2019:11:28:03] id=sharedlb state=0 flags=0x3 \ resync_timeout=<PAST> task_calls=3 0x55871b5b2540: id=hostC(remote) addr=127.0.0.12:10002 status=CONN \ reconnect=3s confirm=0 flags=0x0 0x55871b5b1440: id=hostB(local) addr=127.0.0.11:10001 status=NONE \ reconnect=<NEVER> confirm=0 flags=0x0 0x55871b5aed70: id=hostA(remote) addr=127.0.0.10:10000 status=ESTA \ reconnect=2s confirm=0 flags=0x20000200 appctx:0x7fa46800ee00 st0=7 st1=0 task_calls=62356 \ state=EST remote_table:0x55871b5ab960 id=stkt local_id=1 remote_id=1 last_local_table:0x55871b5ab960 id=stkt local_id=1 remote_id=1 shared tables: 0x55871b5ab960 local_id=1 remote_id=1 flags=0x0 remote_data=0x65 last_acked=3 last_pushed=0 last_get=3 teaching_origin=0 update=0 table:0x55871b5b46a0 id=stkt update=1 localupdate=0 \ commitupdate=0 syncing=0
转储内部内存池的状态。这对于在怀疑有内存泄漏时跟踪内存使用情况很有用。它与在前台运行时发送 SIGQUIT 信号的作用完全相同,只是它不会刷新池。
转储当前的分析设置,每行一个,以及更改它们所需的命令。
show resolvers [<resolvers section id>]
转储给定解析器部分或所有解析器部分(如果未提供部分)的统计信息。对于每个名称服务器,报告以下计数器: sent: 发送到此服务器的 DNS 请求数 valid: 从此服务器收到的有效 DNS 响应数 update: 用于更新服务器 IP 地址的 DNS 响应数 cname: CNAME 响应数 cname_error: 此服务器遇到的 CNAME 错误数 any_err: 空响应数 (即:服务器不支持 ANY 类型) nx: 从此服务器收到的不存在的域响应 timeout: 此服务器未及时应答的次数 refused: 此服务器拒绝的请求数 other: 任何其他 DNS 错误 invalid: 无效的 DNS 响应(从协议角度看) too_big: 响应过大 outdated: 响应到达过晚的次数(在另一个名称服务器之后)
show servers conn [<backend>]
转储属于指定后端(如果未指定,则为所有后端)的服务器的当前和空闲连接状态。可以使用后端名称或标识符。输出包括一个显示字段标题的标题行,然后是每个服务器一行,每行包含后端名称和 ID、服务器名称和 ID、地址、端口和一系列值。字段数量根据线程数而变化。鉴于空闲连接的线程特性,重要的是要理解某些值在读取后可能会发生变化,因此,行内的一致性不能保证。此输出主要作为调试工具提供,不适合常规监控或绘图。
show servers state [<backend>]
转储运行配置中找到的服务器的状态。可以提供后端名称或标识符以将输出限制为此后端。转储格式如下:- 第一行包含格式版本(此规范中为 1);- 第二行包含列标题,以井号(“#”)为前缀;- 第三行及之后的行包含数据;- 以井号(“#”)开头的每一行都被视为注释。由于输出的多个版本可能共存,因此下面是文件格式版本字段及其顺序列表:1:be_id:后端唯一 ID。be_name:后端标签。srv_id:服务器唯一 ID(在后端中)。srv_name:服务器标签。srv_addr:服务器 IP 地址。srv_op_state:服务器运行状态(UP/DOWN/...)。0 = SRV_ST_STOPPED 服务器已关闭。1 = SRV_ST_STARTING 服务器正在预热(已启动但节流)。2 = SRV_ST_RUNNING 服务器已完全启动。3 = SRV_ST_STOPPING 服务器已启动但正在软停止(例如:404)。srv_admin_state:服务器管理状态(MAINT/DRAIN/...)。状态实际上是值的掩码:0x01 = SRV_ADMF_FMAINT 服务器被显式强制进入维护状态。0x02 = SRV_ADMF_IMAINT 服务器继承了跟踪服务器的维护状态。0x04 = SRV_ADMF_CMAINT 服务器因配置而处于维护状态。0x08 = SRV_ADMF_FDRAIN 服务器被显式强制进入排水状态。0x10 = SRV_ADMF_IDRAIN 服务器继承了跟踪服务器的排水状态。0x20 = SRV_ADMF_RMAINT 服务器因 IP 地址解析失败而处于维护状态。0x40 = SRV_ADMF_HMAINT 服务器 FQDN 是从 stats socket 设置的。srv_uweight:用户可见的服务器权重。srv_iweight:服务器的初始权重。srv_time_since_last_change:自上次操作更改以来的时间。srv_check_status:上次健康检查状态。srv_check_result:上次检查结果(FAILED/PASSED/...)。0 = CHK_RES_UNKNOWN 默认初始化为该值。1 = CHK_RES_NEUTRAL 有效检查但无状态信息。2 = CHK_RES_FAILED 检查失败。3 = CHK_RES_PASSED 检查成功,服务器已完全恢复。4 = CHK_RES_CONDPASS 检查报告服务器不想接收新会话。srv_check_health:检查 rise / fall 当前计数器。srv_check_state:检查的状态(ENABLED/PAUSED/...)。状态实际上是值的掩码:0x01 = CHK_ST_INPROGRESS 检查正在运行。0x02 = CHK_ST_CONFIGURED 此检查已配置,可能已启用。0x04 = CHK_ST_ENABLED 此检查当前已启用管理。0x08 = CHK_ST_PAUSED 由于维护(仅健康检查)而暂停检查。srv_agent_state:代理检查的状态(ENABLED/PAUSED/...)。此状态使用与“srv_check_state”相同的掩码值,并添加了此特定值:0x10 = CHK_ST_AGENT 检查是代理检查(否则是健康检查)。bk_f_forced_id:一个标志,用于指示后端 ID 是否由配置强制。srv_f_forced_id:一个标志,用于指示服务器 ID 是否由配置强制。srv_fqdn:服务器 FQDN。srv_port:服务器端口。srvrecord:与此 SRV 关联的 DNS SRV 记录。
转储所有已知会话。避免在慢速连接上执行此操作,因为这可能会产生大量数据。此命令受限制,只能在配置为“operator”或“admin”级别的套接字上发出。请注意,在连接快速回收的机器上,此输出报告的条目数可能少于实际存在的条目数,因为它将转储在输入命令之前创建的所有现有会话直到最后一个;在此期间终止的会话将不会出现。
显示有关指定会话标识符的大量内部信息。此标识符是“show sess”转储中行开头的第一个字段(它对应于会话指针)。这些信息对大多数用户无用,但可能被 haproxy 开发人员用于排查复杂的错误。输出格式有意不作文档说明,以便可以根据需求自由演变。您可以在 src/dumpstats.c 中找到所有返回字段的描述。特殊 id "all" 会转储所有会话的状态,必须尽可能避免使用,因为它非常消耗 CPU 并且可能需要很长时间。
show stat [domain <resolvers|proxy>] [{<iid>|<proxy>} <type> <sid>] \ [typed|json] [desc] [up|no-maint]
使用 CSV 格式转储统计信息;如果 "typed" 在其他参数后传递,则使用上面章节描述的扩展类型化输出格式;或者如果 "json" 在其他参数后传递,则以 JSON 格式转储。通过传递 <id>、<type> 和 <sid>,可以只转储选定的项目:- <iid> 是代理 ID,-1 表示转储所有内容。或者,可以指定代理名称 <proxy>。在这种情况下,此代理的 ID 将用作 ID 选择器。- <type> 选择可转储对象的类型:1 表示前端,2 表示后端,4 表示服务器,-1 表示所有内容。这些值可以进行或运算,例如:1 + 2 = 3 -> 前端 + 后端。1 + 2 + 4 = 7 -> 前端 + 后端 + 服务器。- <sid> 是服务器 ID,-1 表示转储所选代理的所有内容。
示例
$ echo "show info;show stat" | socat stdio unix-connect:/tmp/sock1 >>> Name: HAProxy Version: 1.4-dev2-49 Release_date: 2009/09/23 Nbproc: 1 Process_num: 1 (...) # pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq, (...) stats,FRONTEND,,,0,0,1000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,1,0, (...) stats,BACKEND,0,0,0,0,1000,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,0,250,(...) (...) www1,BACKEND,0,0,0,0,1000,0,0,0,0,0,,0,0,0,0,UP,1,1,0,,0,250, (...) $
在此示例中,一次发出了两个命令。这样,在多进程模式下很容易找到统计数据适用于哪个进程。在 typed 输出格式中不需要这样做,因为进程号会显示在每行中。请注意信息输出后的空行,它标记了第一个块的结束。在第二个块(stats)的末尾会出现一个类似的空行,以便读者知道输出没有被截断。当指定“typed”时,输出格式更适合监控工具,因为它提供了数字位置并指示了每个输出字段的类型。每个值都单独一行,包含进程号、元素号、性质、来源和范围。通过在 URI 后附加“;typed”,可以通过 HTTP 统计信息获得相同的格式。非常重要的是要注意,在 typed 输出格式中,单个对象的转储是连续的,因此消费者无需一次性存储所有内容。使用 typed 输出格式时,每行由 4 列组成,用冒号(“:”)分隔。第一列是点分隔的 5 个元素。第一个元素是表示正在描述的对象类型的字母。目前已知的对象类型如下:“F”表示前端,“B”表示后端,“L”表示监听器,“S”表示服务器。第二个元素是对象所属代理的唯一标识符的正面整数。它等同于 CSV 输出的“iid”列,并匹配前端或后端部分中可选“id”指令前面的值。第三个元素是包含代理内唯一对象标识符的正整数,对应于 CSV 输出的“sid”列。转储前端或后端时报告 ID 0。对于监听器或服务器,这对应于它们在代理内的相应 ID。第四个元素是列表中字段的数字位置(从零开始)。此位置随时间保持不变,但可能出现空隙,具体取决于构建选项或将来是否删除某些字段。第五个元素是 CSV 输出中出现的字段名称。第六个元素是正整数,是相对进程编号,从 1 开始。第一个冒号之后的其余行遵循上面章节中描述的“typed output format”。简而言之,第二列(第一个“:”之后)指示变量的来源、性质和范围。第三列指示字段的类型,包括“s32”、“s64”、“u32”、“u64”和“str”。然后第四列是值本身,消费者可以通过第 3 列知道如何解析,并通过第 2 列知道如何处理。因此,typed 模式下的整体行格式是:<obj>.<px_id>.<id>.<fpos>.<fname>.<process_num>:<tags>:<type>:<value> 以下是 typed 输出格式的示例:$ echo "show stat typed" | socat stdio unix-connect:/tmp/sock1 F.2.0.0.pxname.1:MGP:str:private-frontend F.2.0.1.svname.1:MGP:str:FRONTEND F.2.0.8.bin.1:MGP:u64:0 F.2.0.9.bout.1:MGP:u64:0 F.2.0.40.hrsp_2xx.1:MGP:u64:0 L.2.1.0.pxname.1:MGP:str:private-frontend L.2.1.1.svname.1:MGP:str:sock-1 L.2.1.17.status.1:MGP:str:OPEN L.2.1.73.addr.1:MGP:str:0.0.0.0:8001 S.3.13.60.rtime.1:MCP:u32:0 S.3.13.61.ttime.1:MCP:u32:0 S.3.13.62.agent_status.1:MGP:str:L4TOUT S.3.13.64.agent_duration.1:MGP:u64:2001 S.3.13.65.check_desc.1:MCP:str:Layer4 timeout S.3.13.66.agent_desc.1:MCP:str:Layer4 timeout S.3.13.67.check_rise.1:MCP:u32:2 S.3.13.68.check_fall.1:MCP:u32:3 S.3.13.69.check_health.1:SGP:u32:0 S.3.13.70.agent_rise.1:MaP:u32:1 S.3.13.71.agent_fall.1:SGP:u32:1 S.3.13.72.agent_health.1:SGP:u32:1 S.3.13.73.addr.1:MCP:str:1.255.255.255:8888 S.3.13.75.mode.1:MAP:str:http B.3.0.0.pxname.1:MGP:str:private-backend B.3.0.1.svname.1:MGP:str:BACKEND B.3.0.2.qcur.1:MGP:u32:0 B.3.0.3.qmax.1:MGP:u32:0 B.3.0.4.scur.1:MGP:u32:0 B.3.0.5.smax.1:MGP:u32:0 B.3.0.6.slim.1:MGP:u32:1000 B.3.0.55.lastsess.1:MMP:s32:-1 (...) 在 typed 格式中,第一列末尾的进程 ID 的存在使得从多个进程聚合输出变得非常容易,如下面的示例所示,每行对应一个进程:$ ( echo show stat typed | socat /var/run/haproxy.sock1 - ; \ echo show stat typed | socat /var/run/haproxy.sock2 - ) | \ sort -t . -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5 -k 6,6n B.3.0.0.pxname.1:MGP:str:private-backend B.3.0.0.pxname.2:MGP:str:private-backend B.3.0.1.svname.1:MGP:str:BACKEND B.3.0.1.svname.2:MGP:str:BACKEND B.3.0.2.qcur.1:MGP:u32:0 B.3.0.2.qcur.2:MGP:u32:0 B.3.0.3.qmax.1:MGP:u32:0 B.3.0.3.qmax.2:MGP:u32:0 B.3.0.4.scur.1:MGP:u32:0 B.3.0.4.scur.2:MGP:u32:0 B.3.0.5.smax.1:MGP:u32:0 B.3.0.5.smax.2:MGP:u32:0 B.3.0.6.slim.1:MGP:u32:1000 B.3.0.6.slim.2:MGP:u32:1000 (...) JSON 输出的格式在 schema 中描述,可以通过“show schema json”输出。JSON 输出不包含额外的空格,以减少输出量。为了方便人类阅读,通过 pretty printer 格式化输出可能会有帮助。示例:$ echo "show stat json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool JSON 输出不包含额外的空格,以减少输出量。为了方便人类阅读,通过 pretty printer 格式化输出可能会有帮助。示例:$ echo "show stat json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool
show ssl cert [<filename>]
显示前端使用的证书列表。如果文件名以星号 (*) 为前缀,则表示尚未提交的事务。如果指定了文件名,则显示证书的详细信息。此命令可用于检查证书是否已正确更新。您也可以通过在文件名之前添加星号来显示事务的详细信息。
示例
$ echo "@1 show ssl cert" | socat /var/run/haproxy.master - # 事务 *test.local.pem # 文件名 test.local.pem $ echo "@1 show ssl cert test.local.pem" | socat /var/run/haproxy.master - Filename: test.local.pem Serial: 03ECC19BA54B25E85ABA46EE561B9A10D26F notBefore: Sep 13 21:20:24 2019 GMT notAfter: Dec 12 21:20:24 2019 GMT Issuer: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 Subject: /CN=test.local Subject Alternative Name: DNS:test.local, DNS:imap.test.local Algorithm: RSA2048 SHA1 FingerPrint: 417A11CAE25F607B24F638B4A8AEE51D1E211477 $ echo "@1 show ssl cert *test.local.pem" | socat /var/run/haproxy.master - Filename: *test.local.pem [...]
show ssl crt-list [-n] [<filename>]
显示 HAProxy 配置中使用的 crt-list 和目录列表。如果指定了文件名,则转储 crt-list 或目录的内容。转储后,输出可用作 crt-list 文件。'-n' 选项可用于显示行号,当条目重复时,与 'del ssl crt-list' 选项结合使用非常有用。带有 '-n' 选项的输出与 crt-list 格式不兼容,无法由 haproxy 加载。
示例
echo "show ssl crt-list -n localhost.crt-list" | socat /tmp/sock1 - # localhost.crt-list common.pem:1 !not.test1.com *.test1.com !localhost common.pem:2 ecdsa.pem:3 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com ecdsa.pem:4 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3]
转储当前 haproxy 进程启动期间发出的所有消息,每个启动日志缓冲区对其 haproxy 工作进程都是唯一的。
转储所有已知粘性表的一般信息。返回它们的名称(持有它们的代理的名称)、它们的类型(目前为零,总是 IP)、它们的最大可能条目数大小,以及当前使用的条目数。
示例
$ echo "show table" | socat stdio /tmp/sock1 >>> # table: front_pub, type: ip, size:204800, used:171454 >>> # table: back_rdp, type: ip, size:204800, used:0
show table <name> [ data.<type> <operator> <value> [data.<type> ...]] | [ key <key> ]
转储 stick-table <name> 的内容。在此模式下,第一行是有关表的通用信息,与“show table”一样,然后转储所有条目。由于这可能相当繁重,因此可以指定一个过滤器来指定要显示的条目。当使用“data.”形式时,过滤器应用于存储的数据(请参阅 第 4.2 节中的“stick-table”)。必须在 <type> 中指定存储的数据类型,并且该数据类型必须存储在表中,否则会报告错误。根据 <operator> 和 64 位整数 <value> 比较数据。运算符与 ACL 中的相同:- eq : 匹配数据等于此值等于此值的条目- ne : 匹配数据不等于此值的条目- le : 匹配数据小于或等于此值的条目- ge : 匹配数据大于或等于此值的条目- lt : 匹配数据小于此值的条目- gt : 匹配数据大于此值的条目在此形式下,您可以使用多个数据过滤器条目,最多可达构建时定义的数量(默认为 4)。当使用 key 形式时,显示条目 <key>。键必须与表相同类型,当前仅限于 IPv4、IPv6、整数和字符串。
示例
$ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a4c: key=127.0.0.1 use=0 exp=3594729 gpc0=0 conn_rate(30000)=1 \ bytes_out_rate(60000)=187 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "show table http_proxy data.gpc0 gt 0" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "show table http_proxy data.conn_rate gt 5" | \ socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "show table http_proxy key 127.0.0.2" | \ socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191
当数据标准应用于依赖于时间的动态值(例如字节速率)时,该值在评估条目期间动态计算,以决定是否必须转储它。这意味着这样的过滤器可能会在一段时间内匹配,然后由于时间的推移,平均事件速率下降而不再匹配。可以利用这一点来提取滥用服务的 IP 地址列表,以便监视它们甚至在防火墙中将它们列入黑名单。
示例
$ echo "show table http_proxy data.gpc0 gt 0" \ | socat stdio /tmp/sock1 \ | fgrep 'key=' | cut -d' ' -f2 | cut -d= -f2 > abusers-ip.txt ( 或 | awk '/key/{ print a[split($2,a,"=")]; }' )
转储每个线程的一些内部状态和结构,这有助于开发人员理解问题。输出试图通过显示每个线程一个块来使其可读。当 haproxy 构建时带有 USE_THREAD_DUMP=1,会使用涉及线程信号的高级转储机制,以便每个线程轮流转储自己的状态。没有此选项,处理命令的线程会显示其所有详细信息,但其他线程的详细信息较少。星号(“*”)显示在处理命令的线程前面。右角括号(“>”)也可能显示在自上次调用此命令以来没有取得任何进展的线程前面,这表明代码中存在一个必须绝对报告的错误。当这种情况发生在两个线程之间时,通常表示死锁。如果一个线程是独立的,这是一个不同的错误,例如损坏的列表。在所有情况下,所需的进程不再完全可用,需要重新启动。输出格式故意不公开记录,以便它可以随着新需求的识别而轻松演变,而无需维护任何形式的向后兼容性,并且就像“show activity”一样,如果没有代码在手,这些值就没有意义。
转储所有已加载的 TLS ticket 密钥引用。将显示 TLS ticket 密钥引用 ID 和加载密钥的文件。这两个都可用于使用“set ssl tls-key”更新 TLS 密钥。如果指定了一个 ID 作为参数,它将转储 tickets,使用 * 将转储每个引用的所有密钥。
转储用于“show info json”和“show stat json”输出的模式。为了减少输出量,其中不包含额外的空格。为了方便人类阅读,可以通过一个美化打印器来处理输出。示例:$ echo "show schema json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool 该模式遵循“JSON Schema”(json-schema.org),因此可以使用验证器来验证“show info json”和“show stat json”的输出是否符合该模式。
show trace [<source>]
显示当前跟踪状态。对于每个源,都会显示一行,带有一个单字符状态,指示跟踪是已停止、等待中还是正在运行。会指示跟踪使用的输出接收器(如果未设置,则为 "none"),以及此接收器中丢弃的事件数量,后跟对源的简要描述。如果指定了源名称,则会显示该源支持的所有事件的详细列表,以及它们对每个操作(报告、启动、暂停、停止)的状态,如果启用则用 "+" 表示,否则用 "-" 表示。所有这些事件都是独立的,一个事件可能会触发启动而未被报告,反之亦然。
显示当前 HAProxy 进程的版本。这在 master 和 worker CLI 中都可用。
示例
$ echo "show version" | socat /var/run/haproxy.sock stdio 2.4.9 $ echo "show version" | socat /var/run/haproxy-master.sock stdio 2.5.0
完全删除指定的前端。它所绑定的所有端口都将被释放。此操作后将无法再启用该前端。这旨在用于那些甚至无法想象停止代理但必须修复配置错误的代理的环境中。这样就可以释放端口并将其绑定到另一个进程以恢复操作。一旦终止,该前端将完全不会出现在统计页面上。前端可以通过其名称或以井号('#')为前缀的数字 ID 来指定。此命令受限制,只能在配置为 "admin" 级别的套接字上发出。
立即终止与指定会话标识符匹配的会话。此标识符是“show sess”转储中行开头的第一个字段(它对应于会话指针)。这可用于终止一个长时间运行的会话,而无需等待超时或当正在进行无休止的传输时。此类被终止的会话在日志中以“K”标志报告。
shutdown sessions server <backend>/<server>
立即终止附加到指定服务器的所有会话。例如,这可用于在服务器进入维护模式后终止长时间运行的会话。此类被终止的会话在日志中以“K”标志报告。
单独的“trace”命令会列出跟踪源、它们的当前状态和简要描述。它仅作为进入下一级的菜单,请参见下面的其他“trace”命令。
立即停止所有跟踪。这旨在作为终止调试会话的快速解决方案,或在多个源上启用了复杂的跟踪并影响服务时作为紧急措施使用。
trace <source> event [ [+|-|!]<name> ]
不带参数,这将列出指定源支持的所有事件。如果事件未启用,则以“-”作为前缀;如果已启用,则以“+”作为前缀。重要的是要注意,单个跟踪可能带有多个事件标签,只要启用的事件之一与跟踪上的任何事件标签匹配,事件就会被传递到跟踪子系统。例如,接收 HTTP/2 HEADERS 类型帧可能会触发一个帧事件和一个流事件,因为该帧会创建一个新流。如果此源启用了帧事件或流事件中的任何一个,则帧将传递到跟踪框架。带参数时,可以切换每个事件的状态并单独启用或禁用它们。支持两个特殊关键字,“none”,匹配任何事件,用于一次禁用所有事件;“any”,匹配所有事件,用于一次启用所有事件。其他事件特定于事件源。可以通过指定事件名称来启用一个事件,可以选择以“+”为前缀以提高可读性。可以通过指定带有“-”或“!”前缀的事件名称来禁用一个事件。完全禁用跟踪源的一种方法是传递“event none”,该源将立即被完全忽略。
trace <source> level [<level>]
不带参数,这将列出此源的所有跟踪级别,当前级别将以星号(“*”)为其前面添加前缀。带参数时,这将跟踪级别更改为指定的级别。详细级别是应用于报告事件之前的过滤器的一种形式。这些过滤器用于根据事件的重要性选择性地包含或排除事件。例如,开发人员可能需要精确知道 HTTP 标头在代码中的哪个位置被认为无效,而最终用户可能根本不关心此标头的有效性。当前有 5 个不同的跟踪级别:user 这将报告适合普通 haproxy 用户观察其流量的信息。通常会报告一些 HTTP 请求和响应,但细节不多。大多数源会将此设置为默认级别以简化操作。proto 除了在“user”级别报告的内容外,它还显示协议级别的更新。例如,这可以是帧类型或解码后的 HTTP 标头。state 除了在“proto”级别报告的内容外,它还将显示解析器中发生的转换(或失败的转换),因此这将显示尝试执行操作,而“proto”级别仅显示最终操作。data 除了在“state”级别报告的内容外,它还将包括层之间的数据传输。developer 这报告所有可用信息,可能包括“退出此循环”等高级信息,这些信息仅对试图理解偶尔发生的 bug 的开发人员相关。函数名仅在此级别报告。强烈建议始终仅使用“user”级别,并在开发人员的指示下才切换到其他级别。另外,最好先配置事件再切换到更高级别,因为这可以节省从转储许多行(如果未应用任何过滤器)的情况。
trace <source> lock [criterion]
不带参数,这将列出此源支持的用于锁定处理的所有条件,并以星号(“*”)在其前面指示当前选择。锁定意味着源将关注第一个匹配事件,并且仅坚持触发该事件的条件,忽略所有其他条件,直到跟踪停止。例如,这允许对单个连接或单个流进行跟踪。某些跟踪支持以下条件,但不一定全部支持,因为其中一些可能对源不可用:backend 锁定开始跟踪的后端 connection 锁定开始跟踪的连接 frontend 锁定开始跟踪的前端 listener 锁定开始跟踪的监听器 nothing 不锁定任何东西 server 锁定开始跟踪的服务器 session 锁定开始跟踪的会话 thread 锁定开始跟踪的线程 此外,每个源可能提供多达 4 个特定条件,例如内部状态或连接 ID。例如,在 HTTP/2 中,一旦跟踪开始,就可以锁定 H2 流并忽略其他流。当在参数中传递条件时,将使用该条件代替其他条件,并且现有的所有跟踪将立即终止,以便它可以使用新条件重新启动。所有源都支持“nothing”这个特殊关键字,以永久禁用跟踪。
trace <source> { pause | start | stop } [ [+|-|!]event]
不带参数,这将列出为此源启用的自动暂停、开始或停止跟踪的事件。这些事件特定于每个跟踪源。带参数时,它将为指定的操作启用事件(如果可选地以“+”为前缀)或禁用它(如果以“-”或“!”为前缀)。特殊关键字“now”不是事件,而是要求立即执行操作。关键字“none”和“any”的支持与“trace event”中的相同。支持 3 种操作:“pause”(暂停)、“start”(开始)和“stop”(停止)。“pause”操作枚举将导致正在运行的跟踪停止并等待新的开始事件重新启动的事件。“start”操作枚举将跟踪切换到等待模式直到出现开始事件之一的事件。“stop”操作枚举将永久停止跟踪直到手动重新启用的事件。实际上,通过“start now”手动启动跟踪而不关心事件,并通过“stop”执行操作是有意义的。为了捕获更细微的事件序列,将“start”设置为一个普通事件(例如接收 HTTP 请求),将“stop”设置为一个非常罕见的事件(例如发出某个错误),将确保最后捕获的事件匹配所需的条件。暂停事件有助于检测序列的结束,禁用锁定,并等待另一个机会进行捕获。在这种情况下,启用锁定以仅识别一个特定条件(例如流)可能是有意义的,并将“start”设置为任何启动该条件的内容(例如创建流的所有事件),将“stop”设置为预期的异常,并将“pause”设置为结束该条件的任何内容(例如任何流结束事件)。在这种情况下,跟踪日志将包含影响单个对象的完美干净序列的完整序列,直到包含从开始到异常的所有内容的最后一个序列。
trace <source> sink [<sink>] 不带参数时,将列出此源可用的所有事件接收器,当前配置的接收器前面会有一个星号('*')。接收器“none”始终可用,意味着所有事件都被简单地丢弃,但它们的处理并未被忽略(例如,锁定确实发生)。其他接收器根据配置和构建选项可用,但通常“stdout”和“stderr”在调试模式下可用,内存中的环形缓冲区也应该可用。当指定名称时,指定源的接收器会立即更改。在接收器更改期间,事件不会改变。在最坏的情况下,如果使用无效的接收器(或“none”),可能会丢失一些事件,但操作会继续到不同的目的地。
trace <source> verbosity [<level>]
不带参数,这将列出此源的所有详细程度级别,当前级别将以星号(“*”)为其前面添加前缀。带参数时,这将详细程度级别更改为指定的级别。详细程度级别指示跟踪解码器应执行多远的详细信息。它取决于跟踪源,因为一些源甚至不提供特定的解码器。级别“quiet”始终可用,并且禁用任何解码。当试图在尝试理解细节之前弄清楚发生了什么时,这可能很有用,因为它对性能和跟踪大小的影响非常小。当源未声明任何详细程度级别时,“default”级别可用,并在指定跟踪时调用解码器。这是机会主义解码。当源声明一些详细程度级别时,这些级别将列出,并附有描述它们所对应内容的说明。在这种情况下,跟踪解码器将根据跟踪点处可用信息尽可能准确。默认情况下设置“quiet”之上的第一个级别。

9.4. Master CLI

master CLI 是在 master-worker 模式下绑定到 master 进程的套接字。此 CLI 提供了对每个正在运行或正在退出的进程中的 unix 套接字命令的访问,并允许对这些进程进行基本监控。master CLI 只能通过 haproxy 程序的 -S 选项进行配置。此选项还接受以逗号分隔的绑定选项。
示例
# haproxy -W -S 127.0.0.1:1234 -f test1.cfg # haproxy -Ws -S /tmp/master-socket,uid,1000,gid,1000,mode,600 -f test1.cfg # haproxy -W -S /tmp/master-socket,level,user -f test1.cfg
主 CLI 引入了一个新的 'show proc' 命令来监督进程
示例
$ echo 'show proc' | socat /var/run/haproxy-master.sock - #<PID> <type> <relative PID> <reloads> <uptime> <version> 1162 master 0 5 0d00h02m07s 2.0-dev7-0124c9-7 # workers 1271 worker 1 0 0d00h00m00s 2.0-dev7-0124c9-7 1272 worker 2 0 0d00h00m00s 2.0-dev7-0124c9-7 # old workers 1233 worker [was: 1] 3 0d00h00m43s 2.0-dev3-6019f6-289
在此示例中,主进程已重新加载 5 次,但其中一个旧工作进程仍在运行,并经历了 3 次重新加载。您可以访问该工作进程的 CLI 来了解发生了什么。当启用提示符时(通过“prompt”命令),CLI 正在工作的上下文会显示在提示符中。主进程由“master”字符串标识,其他进程由其 PID 标识。如果上次重新加载失败,主提示符将更改为“master[ReloadFailed]>”,以便可以看到进程仍在运行旧配置,并且新配置不起作用。主 CLI 使用特殊的表示法来访问多个进程。此表示法很容易识别,因为它以 @ 开头。@ 前缀后面可以跟一个相对进程号,或者一个感叹号和一个 PID。(例如 @1 或 @!1271)。单独的 @ 可用于指定主进程。离开的进程只能通过 PID 访问,因为相对进程号只能与当前进程一起使用。
示例
$ socat /var/run/haproxy-master.sock readline prompt master> @1 show info; @2 show info [...] Process_num: 1 Pid: 1271 [...] Process_num: 2 Pid: 1272 [...] master> $ echo '@!1271 show info; @!1272 show info' | socat /var/run/haproxy-master.sock - [...]
前缀可以作为一个命令使用,它将把之后的所有命令发送到指定的进程。
示例
$ socat /var/run/haproxy-master.sock readline prompt master> @1 1271> show info [...] 1271> show stat [...] 1271> @ master> $ echo '@1; show info; show stat; @2; show info; show stat' | socat /var/run/haproxy-master.sock - [...]
您还可以使用“reload”命令重新加载 HAProxy 主进程,该命令与 `kill -USR2` 对主进程执行的操作相同,前提是用户至少具有 "operator" 或 "admin" 权限。
示例
$ echo "reload" | socat /var/run/haproxy-master.sock
请注意,重新加载将关闭与 master CLI 的连接。
两个构成集群的 HAProxy 节点经常拥有除少数地址之外完全相同的配置。不必为每个节点维护一个重复的配置,这不可避免地会导致分歧,而是可以在配置中包含环境变量。因此,多个配置可以共享完全相同的同一个文件,只有少数系统范围的环境变量不同。这始于 1.5 版本,当时只允许地址包含环境变量,而 1.6 版本更进一步,支持在任何地方使用环境变量。语法与 UNIX shell 中的相同,变量以美元符号(“$”)开头,后跟开括号(“{”),然后是变量名,最后是闭括号(“}”)。除了地址之外,环境变量仅在用双引号括起来的参数中解释(这是为了不破坏使用涉及美元符号的正则表达式的现有设置)。环境变量也很方便地编写在各种仅地址发生变化的站点上都能正常工作的配置。它还可以允许从某些配置中删除密码。下面的示例中,“site1.env”文件在启动时由 init 脚本源:$ cat site1.env LISTEN=192.168.1.1 CACHE_PFX=192.168.11 SERVER_PFX=192.168.22 LOGGER=192.168.33.1 STATSLP=admin:pa$$w0rd ABUSERS=/etc/haproxy/abuse.lst TIMEOUT=10s $ cat haproxy.cfg global log "${LOGGER}:514" local0 defaults mode http timeout client "${TIMEOUT}" timeout server "${TIMEOUT}" timeout connect 5s frontend public bind "${LISTEN}:80" http-request reject if { src -f "${ABUSERS}" } stats uri /stats stats auth "${STATSLP}" use_backend cache if { path_end .jpg .css .ico } default_backend server backend cache server cache1 "${CACHE_PFX}.1:18080" check server cache2 "${CACHE_PFX}.2:18080" check backend server server cache1 "${SERVER_PFX}.1:8080" check server cache2 "${SERVER_PFX}.2:8080" check
偶尔会有人报告说,在系统重启后,haproxy 服务没有启动,并且一旦他们手动启动它,它就能工作。大多数情况下,这些人正在运行一个集群 IP 地址机制,如 keepalived,仅将服务 IP 地址分配给主节点,并且虽然以前在绑定 haproxy 到地址 0.0.0.0 时它能工作,但在绑定到虚拟 IP 地址后就停止工作了。这里发生的情况是,当服务启动时,虚拟 IP 地址尚未被本地节点拥有,因此当 HAProxy 想要绑定到它时,系统会拒绝,因为它不是本地 IP 地址。修复方法不是延迟 haproxy 服务启动(因为它不会自动重启),而是正确配置系统以允许绑定到非本地地址。这在 Linux 上通过将 net.ipv4.ip_nonlocal_bind sysctl 设置为 1 来轻松完成。这也适用于透明地拦截通过 HAProxy 的传递给特定目标地址的 IP 流量。涉及源端口范围的多进程配置可能似乎有效,但它们会在高负载下导致一些随机故障,因为一个以上的进程可能尝试使用相同的源端口连接到同一个服务器,这是不可能的。系统将报告一个错误,并发生重试,选择另一个端口。在“retries”参数中设置一个较高的值可以在一定程度上隐藏效果,但这也会带来 CPU 使用率和处理时间的增加。日志也会报告一定数量的重试。因此,在多进程配置中应避免使用端口范围。由于 HAProxy 使用 SO_REUSEPORT 并支持多个独立进程绑定到同一个 IP:port,因此在故障排除过程中,可能会发生一个旧进程在启动新进程之前没有停止的情况。这会产生荒谬的测试结果,似乎表明配置的任何更改都被忽略了。原因是实际上,即使新进程以新配置重新启动,旧进程也会接收一些传入连接并处理它们,从而返回意外的结果。如有疑问,只需停止新进程然后重试。如果仍然有效,很可能意味着一个旧进程仍然处于活动状态,需要停止。Linux 的“netstat -lntp”对此很有帮助。当从命令行向 ACL 添加条目时(例如,当阻止某个源地址时),重要的是要记住,这些条目不会同步到文件,并且如果有人重新加载配置,这些更新将丢失。虽然这通常是期望的效果(用于阻止),但当更改是为了解决问题而进行的修复时,可能不一定符合预期。请参阅 CLI 界面的“add acl”操作。
当 HAProxy 使用 "-d" 选项启动时,它将保持在前台运行,并每处理一个事件打印一行输出,例如:传入连接、连接结束、以及看到的每个请求或响应头行的处理。此调试输出在内容被处理之前发出,因此它不考虑本地修改。它的主要用途是显示请求和响应,而无需运行网络嗅探器。当并行处理多个连接时,输出的可读性会降低,尽管 examples/ 目录中的 "debug2ansi" 和 "debug2html" 脚本通过为输出着色来极大地改善了这一点。如果 HAProxy 检测到请求或响应格式错误而将其拒绝,最好的做法是连接到 CLI 并发出 "show errors",这将报告每个前端和后端捕获到的最后一个有问题的请求和响应,并提供所有必要的信息来精确指出输入流中被拒绝的第一个字符。这有时是向客户或开发人员证明其代码中存在 bug 的必要手段。在这种情况下,通常可以通过使用 "option accept-invalid-http-request" 或其等效的响应选项 "option accept-invalid-http-response" 来放宽检查(但仍保留捕获)。有关更多详细信息,请参阅配置手册。
示例
> show errors Total events captured on [13/Oct/2015:13:43:47.169] : 1 [13/Oct/2015:13:43:40.918] frontend HAProxyLocalStats (#2): invalid request backend <NONE> (#-1), server <NONE> (#-1), event #0 src 127.0.0.1:51981, session #0, session flags 0x00000080 HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000 HTTP chunk len 0 bytes, HTTP body len 0 bytes buffer flags 0x00808002, out 0 bytes, total 31 bytes pending 31 bytes, wrapping at 8040, error at position 13: 00000 GET /invalid request HTTP/1.1\r\n
CLI 中的 "show info" 命令的输出提供了许多有用的信息,例如曾经达到的最大连接速率、曾经达到的最大 SSL 密钥速率,以及通常有助于解释 CPU 或内存使用率临时问题的所有信息。例如:> show info Name: HAProxy Version: 1.6-dev7-e32d18-17 Release_date: 2015/10/12 Nbproc: 1 Process_num: 1 Pid: 7949 Uptime: 0d 0h02m39s Uptime_sec: 159 Memmax_MB: 0 Ulimit-n: 120032 Maxsock: 120032 Maxconn: 60000 Hard_maxconn: 60000 CurrConns: 0 CumConns: 3 CumReq: 3 MaxSslConns: 0 CurrSslConns: 0 CumSslConns: 0 Maxpipes: 0 PipesUsed: 0 PipesFree: 0 ConnRate: 0 ConnRateLimit: 0 MaxConnRate: 1 SessRate: 0 SessRateLimit: 0 MaxSessRate: 1 SslRate: 0 SslRateLimit: 0 MaxSslRate: 0 SslFrontendKeyRate: 0 SslFrontendMaxKeyRate: 0 SslFrontendSessionReuse_pct: 0 SslBackendKeyRate: 0 SslBackendMaxKeyRate: 0 SslCacheLookups: 0 SslCacheMisses: 0 CompressBpsIn: 0 CompressBpsOut: 0 CompressBpsRateLim: 0 ZlibMemUsage: 0 MaxZlibMemUsage: 0 Tasks: 5 Run_queue: 1 Idle_pct: 100 node: wtap description: 当 HAProxy 的新版本中似乎随机出现问题时(例如:每秒请求被中止、偶尔崩溃等),值得尝试启用内存中毒,以便每次调用 malloc() 后立即用可配置的字节填充内存区域。默认情况下,此字节是 0x50(ASCII 码的 'P'),但可以使用任何其他字节,包括零(这将与 calloc() 效果相同,并且可能会消除一些问题)。内存中毒通过命令行选项 "-dM" 启用。它会轻微降低性能,不建议在生产环境中使用。如果使用它时问题一直存在,或者在使用零字节进行中毒时问题消失,那么你肯定找到了一个 bug,需要报告。否则,如果没有明显变化,问题就与此无关。在调试一些延迟问题时,重要的是在本地机器上同时使用 strace 和 tcpdump,并在远程系统上使用另一个 tcpdump。原因是处理链中到处都存在延迟,因此了解是哪个延迟导致了问题对于知道采取何种措施至关重要。实际上,本地 tcpdump 会指示输入数据何时进来。Strace 会指示 haproxy 何时收到这些数据(使用 recv/recvfrom)。注意,openssl 使用 read()/write() 系统调用而不是 recv()/send()。Strace 还会显示 haproxy 何时发送数据,tcpdump 会显示系统何时发送这些数据到接口。然后,外部 tcpdump 将显示发送的数据何时真正收到(因为本地 tcpdump 只显示数据包何时排队)。在本地系统上嗅探的好处是 strace 和 tcpdump 将使用相同的参考时钟。Strace 应该与 "-tts200" 一起使用,以获取完整的时戳并将足够大的数据块报告出来以便阅读。Tcpdump 应该与 "-nvvttSs0" 一起使用,以报告完整的包、真实的序列号和完整的时戳。实际上,接收到的数据几乎总是立即被 haproxy 接收(除非机器 CPU 饱和或这些数据无效而不被传递)。如果数据已接收但未发送,通常是因为输出缓冲区已饱和(即:接收方消耗数据的速度不够快)。这可以通过观察轮询在一段时间内未通知输出文件描述符可写来确认(在 strace 输出中,当数据最终离开并回滚以查看何时通知了写事件时,通常更容易发现)。它通常与接收方收到的 ACK 匹配,并由 tcpdump 检测到。数据发送后,它们可能会在系统中花费一些时间什么都不做。这里,TCP 拥塞窗口可能受限,不允许这些数据离开,需要等待 ACK 来打开窗口。如果流量空闲且数据花费 40 毫秒或 200 毫秒离开,这是另一个问题(不是问题),这是 Nagle 算法阻止空数据包立即离开,希望它们能与后续数据合并。HAProxy 在纯 TCP 模式和隧道中会自动禁用 Nagle。但是,在转发 HTTP 正文时,它肯定仍然启用(这通过减少数据包数量来提高性能)。一些不符合 HTTP 标准的应用程序可能对传递不完整 HTTP 响应消息的延迟敏感。在这种情况下,您将需要启用 "option http-no-delay" 来禁用 Nagle 以解决其设计问题,并请记住链中的任何其他代理也可能受到类似影响。如果 tcpdump 报告数据立即离开但另一端并未迅速看到它们,这可能意味着 WAN 链路拥塞、已启用流量控制且阻止数据离开的 LAN 拥塞,或者更常见的是 HAProxy 实际上运行在虚拟机中,出于某种原因,Hypervisor 决定数据不需要立即发送。在虚拟化环境中,延迟问题几乎总是由虚拟化层引起,因此为了节省时间,值得首先比较 VM 和外部组件中的 tcpdump。任何差异都应归因于 Hypervisor 及其配套驱动程序。当在 tcpdump 跟踪(使用 -vv)中看到 TCP SACK 段时,这始终意味着发送它们的一方已经获得了丢包的证明。虽然没有看到它们并不意味着没有丢包,但看到它们绝对意味着网络是无损的。丢包在网络上是正常的,但当 SACK 无法被肉眼注意到时。如果它们在跟踪中大量出现,那么就值得调查具体发生了什么以及数据包丢失在哪里。HTTP 对 TCP 丢包的容忍度不高,这会导致巨大的延迟。"netstat -i" 命令将按接口报告统计信息。Rx-Ovr 计数器增加的接口表示系统没有足够的资源来接收所有传入的数据包,并且在网络驱动程序处理它们之前它们就丢失了。Rx-Drp 表示一些接收到的数据包在网络堆栈中丢失,因为应用程序处理它们的速度不够快。这在某些攻击中也可能发生。Tx-Drp 意味着输出队列已满,数据包不得不被丢弃。在使用 TCP 时,这种情况应该非常罕见,但可能表明出站链接饱和。
HAProxy 被设计为以非常有限的权限运行。标准用法是将其隔离在一个 chroot 监狱中,并将其权限降级到一个在该监狱中没有任何权限的非 root 用户,这样,如果将来发现任何漏洞,其泄露也不会影响系统的其余部分。为了执行 chroot,它首先需要以 root 用户身份启动。手工构建 chroot 在那里启动进程是徒劳的,这些过程构建起来很麻烦,从未得到妥善维护,而且总会包含比主文件系统更多的 bug。并且在被泄露的情况下,入侵者可以使用故意构建的文件系统。不幸的是,许多管理员混淆了 "以 root 身份启动" 和 "以 root 身份运行",导致在启动 haproxy 之前更改 uid,从而降低了实际的安全限制。HAProxy 需要以 root 身份启动才能: - 调整文件描述符限制 - 绑定到特权端口号 - 绑定到特定的网络接口 - 透明地监听外来地址 - 在 chroot 监狱内隔离自身 - 降级到另一个非特权 UID HAProxy 可能需要以 root 身份运行才能: - 绑定到用于出站连接的接口 - 绑定到用于出站连接的特权源端口 - 透明地绑定到用于出站连接的外来地址 大多数用户永远不需要 "以 root 身份运行" 的情况。但 "以 root 身份启动" 涵盖了大多数用法。安全的配置将包含: - 一个 chroot 语句,指向一个没有任何访问权限的空位置。这可以在 UNIX 命令行上这样准备:# mkdir /var/empty && chmod 0 /var/empty || echo "Failed" 并在 HAProxy 配置的 global 部分这样引用:chroot /var/empty - global 部分中的 uid/user 和 gid/group 语句:user haproxy group haproxy - 一个 stats socket,其模式、uid 和 gid 设置为匹配允许访问 CLI 的用户和/或组,以便没有人可以访问它:stats socket /var/run/haproxy.stat uid hatop gid hatop mode 600


HAProxy 2.2.34 – 管理指南
,