管理指南

版本 3.1.10-18


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

2.

HAProxy 架构快速回顾

3.

启动 HAProxy

4.

停止和重启 HAProxy

5.

文件描述符限制

6.

内存管理

7.

CPU 使用率

8.

日志

9.

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

10.

简化配置管理的技巧

11.

常见陷阱及避免方法

12.

调试和性能问题

13.

安全注意事项
13.1.
本文档假设读者在类 UNIX 操作系统上拥有足够多的管理技能,日常使用 shell,并且熟悉 strace 和 tcpdump 等故障排除工具。
HAProxy 是一个多线程、事件驱动、非阻塞的守护进程。这意味着它使用事件多路复用技术来调度其所有活动,而不是依赖系统在多个活动之间进行调度。大多数时候,它作为单个进程运行,因此在系统上执行 "ps aux" 的输出将只报告一个 "haproxy" 进程,除非正在进行软重载,并且一个旧进程正在与新进程并行地完成其工作。因此,使用 strace 工具总是很容易跟踪其活动。为了随着可用处理器数量的增加而扩展,HAProxy 默认会为它被允许运行的每个处理器启动一个工作线程。除非明确配置不同,否则传入的流量会分散到所有这些线程上,所有线程都运行相同的事件循环。为了将线程间的依赖性限制到最低,以实现接近线性的可扩展性,我们付出了巨大的努力。这带来了一些影响,例如一个给定的连接由单个线程服务。因此,为了使用所有可用的处理能力,需要有至少与线程数一样多的连接,这几乎总是能够得到满足。HAProxy 被设计为在启动期间将自己隔离到一个 chroot jail 中,在那里它根本无法执行任何文件系统访问。这也适用于它所依赖的库(例如: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 : 作为守护进程启动。进程在派生后与当前终端分离,错误不再在终端中报告。它等同于配置中 "global" 部分的 "daemon" 关键字。建议在任何 init 脚本中始终强制使用它,这样有问题的配置就不会阻止系统启动。 -L <name> : 将本地对等点名称更改为 <name>,默认为本地主机名。这仅在对等点复制中使用。您可以在配置文件中使用变量 $HAPROXY_LOCALPEER 来引用对等点名称。 -N <limit> : 将每个代理的默认 maxconn 设置为 <limit>,而不是内置的默认值(通常是 2000)。仅用于调试。 -V : 启用详细模式(禁用安静模式)。撤销 "-q" 或 "quiet" 的效果。 -W : master-worker 模式。它等同于配置中 "global" 部分的 "master-worker" 关键字。此模式将启动一个 "master",它将监控 "worker"。使用此模式,您可以通过向 master 发送 SIGUSR2 信号来直接重新加载 HAProxy。master-worker 模式与前台或守护进程模式兼容。建议在多进程和 systemd 环境下使用此模式。 -Ws : 支持 systemd 服务的 `notify` 类型的 master-worker 模式。 -c : 仅执行配置文件检查,并在尝试绑定之前退出。如果一切正常,退出状态为零;如果遇到错误,则为非零。如果存在任何警告,将报告它们。默认情况下,此选项不报告成功消息。与 "-V" 结合使用时,成功时将打印消息 "Configuration file is valid"。脚本必须使用退出状态来确定命令的成功。 -cc : 评估配置中条件块内使用的条件。如果条件为真,退出状态为零;如果条件为假,则为 1;如果遇到错误,则为 2。 -d : 启用调试模式。这会禁用守护进程模式,强制进程保持在前台并显示传入和传出的事件。绝不能在 init 脚本中使用它。 -dC[key] : 转储配置文件。这是在行被标记化之后执行的,因此注释被剥离并且强制缩进。如果指定了非零密钥,则行在敏感/机密字段之前被截断,并且标识符和地址使用与 CLI 上的匿名化模式相同的算法和此密钥进行哈希处理后发出。这意味着输出可以安全地与需要它的开发人员共享,以找出在使用相同密钥进行匿名化的转储中发生了什么。另请参阅 CLI 的 "set anon" 命令。 -dD : 启用诊断模式。此模式将输出有关可疑配置语句的额外警告。即使在 "zero-warning" 模式下,这也绝不会阻止启动,也不会改变退出状态码。 -dF : 禁用数据快速转发。这是一种通过将数据直接从一侧传递到另一侧而无需唤醒流来优化数据转发的机制。通过此指令,可以禁用此优化。请注意,它还禁用了任何内核 tcp splicing。此命令不适用于常规使用,通常仅由开发人员在复杂的调试会话中建议使用。 -dG : 禁用使用 getaddrinfo() 将主机名解析为地址。当怀疑 getaddrinfo() 工作不正常时可以使用它。提供此选项是因为许多系统上存在 getaddrinfo() 的伪劣实现,并导致难以排查的异常。 -dI : 启用不安全的 fork。这等同于 global 部分中的 "insecure-fork-wanted"。当使用 ASAN 运行所有需要 fork addr2line 来解析地址的回归测试时,这可能很有用。 -dK<class[,class]*> : 转储每个类中注册的关键字列表。类列表可通过 "-dKhelp" 获取。可以使用 "-dKall" 转储所有类,否则可以在帮助中显示的选择中指定一个逗号分隔的列表。输出格式将根据要转储的关键字类而有所不同(例如,"cfg" 将以类似于配置文件格式的格式显示已知的配置关键字,而 "smp" 将显示带有每个规则集的兼容性矩阵前缀的示例获取函数)。这些可能很少被人类直接使用,但对于试图检测在某些位置出现新关键字以自动更新某些文档、语法高亮文件、配置解析器、API 等的外部工具非常有帮助。输出格式可能会随着时间的推移而有所变化,因此强烈建议主要使用此输出来检测与以前存档的差异。请注意,并非所有关键字都列出,因为许多关键字在不同的关键字注册子系统创建之前就已经存在很长时间了,并且它们没有出现在那里。然而,由于新关键字仅通过现代机制添加,因此可以合理地假设此输出可用于以良好准确性检测语言的增加。关键字仅在配置完全解析后才被转储,因此即使是动态创建的关键字也可以被转储。转储并退出的一个好方法是在现有配置上运行静默配置检查:./haproxy -dKall -q -c -f foo.cfg 如果没有可用的配置文件,使用 "-f /dev/null" 也可以转储所有默认关键字,但由于没有侦听器,返回状态将不为零,必须忽略。 -dL : 转储在配置处理结束时加载的动态共享库列表。这通常还包括深层依赖项,例如从 Lua 代码加载的任何内容,以及可执行文件本身。该列表以一种应该足够容易清理以直接生成所有依赖项的 tarball 的格式打印。由于它不会停止程序的启动,建议仅与 "-c" 和 "-q" 结合使用,其中仅显示已加载对象的列表(或在出错的情况下不显示任何内容)。此外,请记住,当提供这样的包以帮助进行核心文件分析时,大多数库实际上是符号链接,在创建存档时需要取消引用:./haproxy -W -q -c -dL -f foo.cfg | tar -T - -hzcf archive.tgz 在详细模式 (-V) 下启动时,除非使用安静模式 (-q),否则还会枚举共享库的地址范围。 -dM[<byte>[,]][help|options,...] : 强制内存投毒,和/或更改内存其他调试选项。内存投毒意味着每个用 malloc() 或 pool_alloc() 分配的内存区域在传递给调用者之前都将填充 <byte>。当未指定 <byte> 时,默认为 0x50 ('P')。虽然这会稍微减慢操作,但它对于可靠地触发由代码中缺少初始化而导致随机崩溃的问题非常有用。请注意 -dM0 的效果是将任何 malloc() 转换为 calloc()。在任何情况下,如果使用此选项时出现或消失了 bug,则意味着 haproxy 中存在 bug,请报告它。许多其他选项可以单独使用,也可以在字节后的逗号后使用。特殊选项 "help" 将列出当前支持的选项及其当前值。每个调试选项可以强制打开或关闭。通常在构建时根据操作系统选择最优化的选项,不需要调整,除非开发人员建议。支持的调试选项包括 (set/clear): - fail / no-fail: 这会启用随机失败的内存分配,与全局 "tune.fail-alloc" 设置结合使用。这用于检测代码中缺少的错误检查。设置此选项会将失败率预设为 1%。 - no-merge / merge: 默认情况下,大小非常相似的池会合并,从而提高效率,但这会使某些内存转储的分析变得复杂。此选项允许禁用此机制,并可能略微增加内存使用。 - cold-first / hot-first: 为了优化 CPU 缓存命中率,默认情况下,最近释放的对象(“热”对象)会用于新的分配。但这样做也使内存转储的分析变得复杂,并可能隐藏 use-after-free 的 bug。此选项允许优先选择最冷的对象,这可能会导致 CPU 使用率略微增加。 - integrity / no-integrity: 启用此选项后,将在分配的区域上启用内存完整性检查,以验证自上次释放以来它是否未被修改。这与 "no-merge"、"cold-first" 和 "tag" 配合使用效果最佳。启用此选项会稍微增加 CPU 使用率。 - no-global / global: 根据操作系统,如果估计标准分配器对于线程来说太慢或效率低下,则可能会启用进程范围的全局内存缓存。此选项允许强制禁用或启用它。禁用它可能会导致低效分配器的 CPU 使用率增加。启用它可能会导致高效分配器的内存使用率更高。 - no-cache / cache: 每个线程都使用一个非常快的本地对象缓存进行分配,默认情况下始终启用。此选项允许禁用它。由于全局缓存也通过本地缓存,这实际上将导致禁用所有缓存并直接从默认分配器分配。这可能会导致 CPU 使用率显著增加,但也可能在微型系统上节省少量内存。 - caller / no-caller: 启用此选项会在每个分配的对象中保留一些额外空间,以存储分配或释放它的最后一个调用者的地址。这有助于开发人员在分析内存转储时追溯时间,并猜测意外事件是如何发生的。 - tag / no-tag: 启用此选项会在每个分配的对象中保留一些额外空间,以存储一个标签,该标签可以检测诸如双重释放、释放无效对象和缓冲区溢出等错误。它以每个分配增加 4 或 8 个字节为代价,提供了更强的可靠性保证。这通常是检测内存损坏的第一步。 - poison / no-poison: 启用此选项将用固定的模式填充分配的对象,以确保如果在新添加的字段中错误地忘记了初始化例程,则不会出现某些意外值(例如 0)。这种 bug 往往很少重现,尤其是在池未合并时。通常通过直接将字节值传递给 -dM 来启用此选项,但使用此选项可以禁用/启用先前设置的值的使用。 -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"。 -dZ : 禁用 "零拷贝" 模式下的数据转发。它等同于 "global" 部分的 "tune.disable-zero-copy-forwarding" 关键字。在数据丢失或数据完整性问题的情况下,或者在使用 strace 查看转发数据时,这可能会有所帮助,因为它还禁用了任何内核 tcp splicing。 -db : 禁用后台模式和多进程模式。进程保持在前台。它主要在开发或小型测试期间使用,因为 Ctrl-C 足以停止进程。切勿在 init 脚本中使用它。 -de : 禁用 "epoll" 轮询器。它等同于 "global" 部分的关键字 "noepoll"。当怀疑与此轮询器相关的 bug 时,这非常有用。在支持 epoll 的系统上,后备通常是 "poll" 轮询器。 -dk : 禁用 "kqueue" 轮询器。它等同于 "global" 部分的关键字 "nokqueue"。当怀疑与此轮询器相关的 bug 时,这非常有用。在支持 kqueue 的系统上,后备通常是 "poll" 轮询器。 -dp : 禁用 "poll" 轮询器。它等同于 "global" 部分的关键字 "nopoll"。当怀疑与此轮询器相关的 bug 时,这非常有用。在支持 poll 的系统上,后备通常是 "select" 轮询器,它不能被禁用且限制为 1024 个文件描述符。 -dr : 忽略服务器地址解析失败。在生产环境之外验证配置时,通常无法访问相同的解析器,导致服务器地址解析失败,从而难以测试配置。此选项简单地将 "none" 方法附加到所有服务器的地址解析方法列表中,确保即使 libc 无法解析地址,启动序列也不会中断。 -dt [<trace_desc>,...] : 激活 stderr 上的跟踪。不带参数时,它会在错误级别上启用所有跟踪源。这尤其有助于检测客户端或服务器的协议违规。可选参数可用于指定使用','作为分隔符的各种跟踪配置列表。每个元素激活一个或所有跟踪源。此外,可以在每个元素上使用':'作为内部分隔符和跟踪名称来选择性地指定级别和详细程度。当输入无效的详细程度或级别名称时,将显示可用关键字的列表。例如,可以方便地为每个字段传递'help'以首先查阅列表。 -dv : 禁用 "evports" 轮询器。它等同于 "global" 部分的关键字 "noevports"。当怀疑与此轮询器相关的 bug 时,这非常有用。在支持事件端口的系统(源自 Solaris 10 及更高版本的 SunOS)上,后备通常是 "poll" 轮询器。 -m <limit> : 将可分配内存(用于保存进程数据)限制为 <limit> 兆字节。这可能会导致一些连接拒绝或根据正常操作所需的内存量而导致一些减速。这主要用于强制 haproxy 进程在受限的资源消耗场景中工作。重要的是要注意,内存不在 haproxy 进程之间共享,通过 fork() 系统调用创建的子进程继承其父进程的资源限制。因此,在 master-worker 模式下,此内存限制分别应用于 master 及其派生的 worker 进程。 -n <limit> : 将每个进程的连接限制限制为 <limit>。这等同于全局部分的关键字 "maxconn"。它优先于此关键字。这可用于快速强制降低限制,以避免在资源限制过低的系统上出现服务中断。 -p <file> : 在启动期间将所有进程的 pid 写入 <file>。这等同于 "global" 部分的关键字 "pidfile"。该文件在进入 chroot jail 之前和执行 "-C" 所隐含的 chdir() 之后打开。每个 pid 出现在单独的一行上。 -q : 设置“安静”模式。这会禁用输出消息。它可以与 "-c" 结合使用,仅检查配置文件是否有效。 -S <bind>[,bind_options...]: 在 master-worker 模式下,绑定一个 master CLI,允许访问每个进程,无论是正在运行的还是正在退出的。出于安全原因,建议将 master CLI 绑定到本地 UNIX 套接字。绑定选项与配置文件中的 "bind" 关键字相同,但单词之间用逗号而不是空格分隔。请注意,此套接字不能用于在无缝重载期间从旧进程中检索侦听套接字。 -sf <pid>* : 在启动完成后向旧进程发送 "finish" 信号 (SIGUSR1),要求它们完成正在做的事情并退出。<pid> 是要发送信号的 pid 列表(每个参数一个)。列表在任何以 "-" 开头的选项处结束。如果 pid 列表为空也没问题,因此可以根据 "pidof" 或 "pgrep" 等命令的结果动态构建它。 -st <pid>* : 在启动完成后向旧进程发送 "terminate" 信号 (SIGTERM),以立即终止它们,而无需完成它们正在做的事情。<pid> 是要发送信号的 pid 列表(每个参数一个)。列表在任何以 "-" 开头的选项处结束。如果 pid 列表为空也没问题,因此可以根据 "pidof" 或 "pgrep" 等命令的结果动态构建它。 -v : 报告版本和构建日期。 -vv : 显示版本、构建选项、库版本和可用的轮询器。在提交错误报告时,系统会要求提供此输出。 -x <unix_socket> : 连接到指定的套接字,并尝试从旧进程中检索任何侦听套接字,并使用它们而不是尝试绑定新的套接字。这对于在 Linux 上重新加载配置时避免丢失任何新连接很有用。在没有 master-worker 模式的情况下,必须在您的配置中使用 "expose-fd listeners" 在 stats 套接字上启用此功能。在 master-worker 模式下,它不需要 "expose-fd listeners",master 将在重载时使用 "sockpair@" 语法自动使用此选项,这允许 master 直接连接到 worker,而无需使用配置中声明的任何 stats 套接字。如果要禁用此功能,可以传递 -x /dev/null。从 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" 来验证。一些重要信息,例如某些构建选项、目标系统和正在使用的库的版本都会在那里报告。在发布错误报告时,这也是您会被系统地要求提供的信息: $ haproxy -vv HAProxy 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 个开发版本。开发版本不适合在生产中使用(除非您确切知道自己在做什么)。稳定版本将显示为三位数版本,例如 "1.5.14-16f863",表示在版本 1.5 之上的第 14 个修复级别。这是一个生产就绪的版本。 - 发布日期:2015/10/08。它以通用的年/月/日格式表示。这里表示 2015 年 10 月 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 变量中指定了正确的系统时才可用。"epoll" 机制在 Linux 上强烈推荐,而 kqueue 机制在 BSD 上强烈推荐。缺少它们将导致使用 poll() 甚至 select(),在处理大量连接时会导致高 CPU 使用率。
HAProxy 支持平滑停止和硬停止。硬停止很简单,当向 haproxy 进程发送 SIGTERM 信号时,它会立即退出,所有已建立的连接都会被关闭。平滑停止是在向 haproxy 进程发送 SIGUSR1 信号时触发的。它只包括从监听端口解绑,但继续处理现有连接直到它们关闭。一旦最后一个连接关闭,进程就会退出。硬停止方法用于服务管理脚本的 "stop" 或 "restart" 操作。平滑停止用于 "reload" 操作,该操作尝试在新进程中无缝地重新加载新配置。这两个信号都可能在重载或重启期间由新的 haproxy 进程本身发送,以便它们在尽可能晚的时刻发送,并且仅在绝对需要时发送。这就是分别由 "-st" (硬停止) 和 "-sf" (平滑停止) 选项执行的操作。在 master-worker 模式下,不需要启动新的 haproxy 进程来重新加载配置。主进程对 SIGUSR2 信号的反应是,使用 -sf 参数后跟 worker 的 PID 来重新执行自己。然后主进程将解析配置文件并 fork 新的 worker。为了更好地理解这些信号是如何使用的,了解整个重启机制非常重要。首先,一个现有的 haproxy 进程正在运行。管理员使用系统特定的命令,如 "/etc/init.d/haproxy reload",来表明他们希望使新的配置文件生效。接下来发生的是以下情况。首先,服务脚本(/etc/init.d/haproxy 或等效脚本)将使用 "haproxy -c" 验证配置文件是否能正确解析。之后,它将尝试使用此配置文件启动 haproxy,使用 "-st" 或 "-sf"。然后 HAProxy 尝试绑定到所有监听端口。如果发生一些致命错误(例如:系统上不存在地址,权限被拒绝),进程将以错误退出。如果套接字绑定失败是因为端口已被使用,那么新进程将首先向 "-st" 或 "-sf" pid 列表中指定的所有 pid 发送一个 SIGTTOU 信号。这就是所谓的“暂停”信号。它指示所有现有的 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 个文件描述符,而一个特权进程可以自己提高这个限制。这就是为什么以 root 身份启动 HAProxy 并让它调整限制的原因之一。默认的 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" 的输出中报告。拥有一个好的轮询器是一回事,但进程能够达到这些限制是强制性的。当 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 来更改它。当文件描述符限制设置得太低时,可能会在正在运行的进程上观察到。strace 工具将报告当进程的限制达到时,accept() 和 socket() 返回 "-1 EMFILE"。在这种情况下,简单地提高 "ulimit-n" 的值(或删除它)将解决问题。如果这些系统调用返回 "-1 ENFILE",则意味着内核的限制已达到,必须在系统范围的参数上做些什么。这些问题必须绝对解决,因为它们会导致高 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 次端到端的连接建立和关闭。当一个核心饱和时,典型的数据是: - 长 TCP 连接或大型 HTTP 对象:95% 系统态,5% 用户态 - 短 TCP 连接或关闭模式下的小型 HTTP 对象:85% 系统态,15% 用户态 - 保持连接模式下的小型 HTTP 对象:70% 系统态,30% 用户态 规则处理和正则表达式的数量会增加用户态部分。系统中防火墙规则、连接跟踪、复杂路由表的存在则会增加系统态部分。在大多数系统上,网络传输期间观察到的 CPU 时间可以分为 4 个部分: - 中断部分,涉及 I/O 接收时执行的所有处理,甚至在目标进程被知晓之前。通常 Rx 数据包计入中断。在某些系统上,如 Linux,中断处理可能会被推迟到一个专用线程,这时它可能显示为 softirq,该线程名为 ksoftirqd/0(对于 CPU 0)。负责此负载的 CPU 通常由硬件设置定义,尽管在 softirq 的情况下,通常可以将处理重新映射到另一个 CPU。这个中断部分通常被认为是寄生的,因为它与任何进程无关,但实际上它是为进程准备工作而进行的一些处理。 - 系统部分,涉及从用户态调用的所有使用内核代码的处理。例如,系统调用计为系统时间。所有同步传递的 Tx 数据包都将计为系统时间。如果某些数据包由于队列填满而必须推迟,它们可能会在稍后的中断上下文中处理(例如:在收到打开 TCP 窗口的 ACK 时)。 - 用户部分,专门在用户态运行应用程序代码。HAProxy 完全在这一部分运行,尽管它大量使用系统调用。规则处理、正则表达式、压缩、加密都会增加 CPU 消耗的用户部分。 - 空闲部分,是 CPU 在无事可做时所做的事情。例如,HAProxy 等待传入连接,或等待一些数据离开,这意味着系统正在等待客户端的 ACK 来推送这些数据。在实践中,关于 HAProxy 的活动,通常可以合理准确地(但完全不精确)认为中断/softirq 是由内核驱动程序中的 Rx 处理引起的,用户态是由 HAProxy 中的第 7 层处理引起的,而系统时间是由 Tx 路径上的网络处理引起的。由于 HAProxy 围绕事件循环运行,它使用 poll()(或任何替代方案)等待新事件,并尽快处理所有这些事件,然后返回 poll() 等待新事件。它测量在 poll() 中等待的时间与处理事件所花费的时间。轮询时间与总时间的比率称为“空闲”时间,它是等待某事发生所花费的时间量。这个比率在统计页面的 "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 下分配。许多网络接口支持多个队列和多个中断。通常,将它们分散到少数共享相同 L3 缓存的 CPU 核心上会有所帮助。请务必停止 irq_balance,因为它在这种工作负载下总是做出最糟糕的事情。对于由大量 SSL 流量或大量压缩组成的 CPU 密集型工作负载,可能值得使用多个专门用于某些任务的进程,尽管这里没有通用规则,需要进行实验。为了增加 CPU 容量,可以使用全局部分中的 "nbproc" 指令使 HAProxy 作为多个进程运行。但有一些限制: - 健康检查是按进程运行的,因此目标服务器将获得与运行进程数一样多的检查; - maxconn 值和队列是按进程的,因此必须设置正确的值以避免服务器过载; - 出站连接应避免使用端口范围以避免冲突 - 粘滞表是按进程的,并且在进程之间不共享; - 每个 peers 部分一次只能在一个进程上运行; - CLI 操作一次只会作用于单个进程。考虑到这一点,最简单的设置通常是有一个运行在多个进程上的第一层,负责繁重的处理,将流量传递给运行在单个进程中的第二层。这种机制适用于 SSL 和压缩这两个 CPU 密集型功能。实例可以很容易地通过 UNIX 套接字(比 TCP 套接字更便宜且不浪费端口)链接,并且代理协议对于将客户端信息传递到下一阶段很有用。这样做时,通常最好将所有单进程任务绑定到进程号 1,并将额外任务绑定到后续进程,因为这将使为不同机器生成相似配置更容易。在 Linux 3.9 及以上版本中,当每个进程在同一 IP:端口上使用不同的侦听套接字时,以多进程模式运行 HAProxy 效率更高;这将使内核在所有进程之间均匀分配负载,而不是唤醒所有进程。请查阅配置手册中 "bind" 关键字行的 "process" 选项以获取更多信息。
在日志记录方面,HAProxy 始终依赖 syslog 服务器,因为它不执行任何文件系统访问。标准的使用方式是通过 UDP 将日志发送到日志服务器(默认为 514 端口)。通常情况下,这被配置为 127.0.0.1,即本地 syslog 守护进程正在运行的地方,但也可以通过网络将日志记录到中央服务器。中央服务器提供了额外的好处,特别是在主-主(active-active)场景中,希望按到达顺序合并日志。HAProxy 也可以使用 UNIX 套接字将其日志发送到本地 syslog 守护进程,但完全不推荐这样做,因为如果在 haproxy 运行时重启 syslog 服务器,套接字将被替换,新的日志将会丢失。由于 HAProxy 将被隔离在 chroot jail 中,它将无法重新连接到新的套接字。现场也观察到,UNIX 套接字上使用的日志缓冲区非常小,即使在负载很轻的情况下也会导致消息丢失。不过,这对于测试来说是可以的。建议在 "global" 部分添加以下指令,使 HAProxy 使用 "local0" facility 记录到本地守护进程:log 127.0.0.1:514 local0,然后在每个 "defaults" 部分或每个前端和后端部分添加以下指令:log global 这样,所有日志都将通过日志服务器所在的全局定义进行集中化。有些 syslog 守护进程默认不监听 UDP 流量,因此根据所使用的守护进程,启用此功能的语法会有所不同: - 在 sysklogd 上,你需要在守护进程的命令行上传递 "-r" 参数,以便它监听一个 UDP 套接字以接收“远程”日志;请注意,无法将其限制为地址 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() 发送出去。如果它们没有出现,请在 haproxy 之上使用 strace 重新启动。如果您仍然看不到任何日志,这绝对意味着您的配置有问题。 - 运行 tcpdump 来监视端口 514,例如在环回接口上(如果流量是本地发送的):“tcpdump -As0 -ni lo port 514”。如果在那里看到了数据包,就证明它们被发送出去了,那么就需要对 syslogd 守护进程进行故障排查。虽然流量日志是从前端(接受传入连接的地方)发送的,但后端也需要能够发送日志,以便报告因健康检查而导致的服务状态变化。请查阅 HAProxy 的配置手册以获取有关所有可能日志设置的更多信息。选择一个未被其他守护进程使用的 facility 是很方便的。HAProxy 的示例通常建议对流量日志使用 "local0",对管理日志使用 "local1",因为它们在实践中从未见过。使用单一 facility 也是可以的。拥有独立的日志对于日志分析很方便,但同样重要的是要记住,日志有时可能包含机密信息,因此它们不能与其他可能意外泄露给未经授权人员的日志混合在一起。对于在不影响服务器容量的情况下进行现场故障排查,建议使用 HAProxy 附带的 "halog" 实用程序。这是一种类似 grep 的工具,旨在以非常快的数据速率处理 HAProxy 日志文件。典型的处理速度在每秒 1 到 2 GB 日志之间。它能够仅提取某些日志(例如:搜索某些类别的 HTTP 状态码、连接终止状态、按响应时间范围搜索、仅查找错误),计算行数,限制输出行数,并执行一些更高级的统计,例如按响应时间或错误计数对服务器进行排序,按时间或计数对 URL 进行排序,按访问计数对客户端地址进行排序等等。这对于快速发现异常情况(例如网站上的机器人循环访问)并阻止它们非常方便。
可以查询 HAProxy 的状态。最常用的机制是 HTTP 统计页面。此页面还为监控工具提供了一种备选的 CSV 输出格式。在 Unix 套接字上也提供了相同的格式。统计信息被重新分组为标记为域的类别,对应于 HAProxy 的多个组件。有两个可用的域:proxy 和 resolvers。如果未指定,则选择 proxy 域。请注意,HTTP 页面上只打印代理统计信息。

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 content 规则。 - 对于 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]:为服务器配置的 maxqueue,如果值为 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=前端, 1=后端, 2=服务器, 3=套接字/监听器) 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 层有条件地通过检查,例如带有 disable-on-404 的 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]:http 响应代码为 1xx 的数量 40. hrsp_2xx [.FBS]:http 响应代码为 2xx 的数量 41. hrsp_3xx [.FBS]:http 响应代码为 3xx 的数量 42. hrsp_4xx [.FBS]:http 响应代码为 4xx 的数量 43. hrsp_5xx [.FBS]:http 响应代码为 5xx 的数量 44. hrsp_other [.FBS]:http 响应为其他代码(协议错误)的数量 45. hanafail [...S]:失败的健康检查详情 46. req_rate [.F..]:在最后经过的一秒内的每秒 HTTP 请求数 47. req_rate_max [.F..]:观察到的每秒最大 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.]:累计被拦截的请求数 (monitor, stats) 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]:估计需要的连接数 99. uweight [..BS]:总用户权重(后端),服务器用户权重(服务器) 100. agg_server_status [..B.]:后端服务器状态的聚合仪表值 101. agg_server_status_check [..B.]:(已弃用) 102. agg_check_status [..B.]:后端服务器状态检查状态的聚合仪表值 103. srid [...S]:服务器 ID 修订版 104. sess_other [.F..]:自进程启动以来除 HTTP 外的会话总数 105. h1_sess [.F..]:自进程启动以来的 HTTP/1 会话总数 106. h2_sess [.F..]:自进程启动以来的 HTTP/2 会话总数 107. h3_sess [.F..]:自进程启动以来的 HTTP/3 会话总数 108. req_other [.F..]:自工作进程启动以来,此对象处理的除 HTTP 外的会话总数 109. h1req [.F..]:自工作进程启动以来,此对象处理的 HTTP/1 会话总数 110. h2req [.F..]:自工作进程启动以来,此对象处理的 hTTP/2 会话总数 111. h3req [.F..]:自工作进程启动以来,此对象处理的 HTTP/3 会话总数 112. proto [L...]:协议对于所有其他统计域,不保证字段的存在或顺序。在这种情况下,应始终使用标题行来解析 CSV 数据。

9.2. 类型化输出格式

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

9.3. Unix 套接字命令

默认情况下,统计套接字(stats socket)未启用。为了启用它,必须在 haproxy 配置的 global 部分添加一行。建议添加第二行以设置更长的超时时间,这在手动发出命令时总是很有用的: global stats socket /var/run/haproxy.sock mode 600 level admin stats timeout 2m 也可以通过重复该行来添加多个统计套接字实例,并让它们监听 TCP 端口而不是 UNIX 套接字。默认情况下从不这样做,因为这很危险,但在某些情况下可能很方便: global stats socket /var/run/haproxy.sock mode 600 level admin 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 ... > (可选)进程的运行时间可以显示在提示符中。要启用此功能,“prompt timed”命令将启用提示符并切换时间的显示。运行时间以“d:hh:mm:ss”格式显示,其中“d”是天数,“hh”、“mm”、“ss”分别是小时、分钟和秒,各占两位数: # socat /var/run/haproxy readline prompt timed [23:03:34:39]> show version 2.8-dev9-e5e622-18 [23:03:34:41]> quit 当在主 CLI 上设置了带时间的提示符时,提示符将显示当前选定进程的运行时间,因此这将适用于主进程、当前工作进程或旧的工作进程: master> prompt timed [0:00:00:50] master> show proc (...) [0:00:00:58] master> @!11955 <-- 主进程,切换到当前工作进程 [0:00:01:03] 11955> @!11942 <-- 当前工作进程,切换到旧的工作进程 [0:00:02:17] 11942> @ <-- 旧的工作进程,切换回主进程 [0:00:01:10] master> 由于可以一次发出多个命令,haproxy 使用空行作为分隔符来标记每个命令的输出结束,并确保没有命令可以在输出中发出空行。因此,即使多个命令在单行上被管道化,脚本也可以轻松解析输出。有些命令可能带有可选的有效负载(payload)。要向命令添加一个,第一行需要以“<<\n”模式结束。接下来的行将被视为有效负载,可以包含任意多行。要验证带有有效负载的命令,它需要以空行结束。可以自定义有效负载模式,以更改有效负载结束的方式。为了使用除空行之外的其他内容结束有效负载,可以在'<<'和'\n'之间设置自定义模式。除了'<<'之外,只能使用7个字符,否则将不被视为有效负载。例如,要使用包含空行和注释的 PEM 文件: # echo -e "set ssl cert common.pem <<%EOF%\n$(cat common.pem)\n%EOF%\n" | \ socat /var/run/haproxy.stat - 存在限制:传递给 CLI 的整个缓冲区的长度不得大于 tune.bfsize,并且模式“<<”不能与该行的最后一个单词粘在一起。在交互模式下输入有效负载时,提示符将从“> ”变为“+ ”。重要的是要理解,当多个 haproxy 进程在同一个套接字上启动时,任何进程都可能接收请求并输出其自己的统计信息。下面提供了统计套接字当前支持的命令列表。如果发送了一个未知的命令,haproxy 会显示用法消息,提醒所有支持的命令。有些命令支持更复杂的语法,通常当发生这种情况时,它会解释命令的哪一部分是无效的。有些命令需要更高的权限才能工作。如果您没有足够的权限,您将收到一个错误“Permission denied”。请查看配置手册中“bind”关键字行的“level”选项以获取更多信息。
中止并销毁一个临时的 CA 文件更新事务。另见 "set ssl ca-file" 和 "commit ssl ca-file"。
abort ssl cert <filename>
中止并销毁一个临时的 SSL 证书更新事务。另见 "set ssl cert" 和 "commit ssl cert"。
中止并销毁一个临时的 CRL 文件更新事务。另见 "set ssl crl-file" 和 "commit ssl crl-file"。
add acl [@<ver>] <acl> <pattern>
向 ACL <acl> 中添加一个条目。<acl> 是由 "show acl" 返回的 #<id> 或 <name>。此命令不验证该条目是否已存在。条目被添加到 ACL 的当前版本,除非用 "@<ver>" 指定了特定版本。此版本号必须事先由 "prepare acl" 分配,并且它将介于 "show acl" 输出中报告的 "curr_ver" 和 "next_ver" 版本之间。使用特定版本号添加的条目在对它们执行 "commit acl" 操作之前将不会匹配。但是,可以使用 "show acl @<ver>" 命令查询它们,并使用 "clear acl @<ver>" 命令清除它们。如果引用 <acl> 是一个也与 map 一起使用的名称,则不能使用此命令。在这种情况下,必须改用 "add map" 命令。
add map [@<ver>] <map> <key> <value>
add map [@<ver>] <map> <payload>
在映射表 <map> 中添加一个条目,将值 <value> 与键 <key> 关联起来。此命令不验证条目是否已存在。它主要用于在执行 "clear" 或 "prepare" 操作后填充映射表。条目会添加到 ACL 的当前版本中,除非使用 "@<ver>" 指定了特定版本。此版本号必须事先由 "prepare acl" 分配,并且它将介于 "show acl" 输出中报告的 "curr_ver" 和 "next_ver" 版本之间。使用特定版本号添加的条目在对它们执行 "commit map" 操作之前不会匹配。但是,可以使用 "show map @<ver>" 命令查询它们,并使用 "clear acl @<ver>" 命令清除它们。如果指定的映射表也用作 ACL,则 ACL 将只匹配 <key> 部分而忽略 <value> 部分。使用有效负载语法,可以通过在不同行上输入多个键/值对来添加它们。在每个新行上,第一个词是键,该行的其余部分被视为值,甚至可以包含空格。
示例
# socat /tmp/sock1 - prompt > add map #-1 << + key1 value1 + key2 value2 with spaces + key3 value3 also with spaces + key4 value4 >
add server <backend>/<server> [args]*
实例化一个附加到后端 <backend> 的新服务器。<server> 名称在后端中必须尚未使用。对后端有一个特殊限制,即它必须使用动态负载均衡算法。可以使用服务器配置文件语句中的一部分关键字来配置服务器行为。另请注意,不会从同一后端中假设存在的 'default-server' 语句中重用任何设置。目前,动态服务器使用 "none" init-addr 方法进行静态初始化。这意味着如果指定了 FQDN 作为地址,将不会进行任何解析,即使服务器创建会被验证。为了支持重载操作,期望通过 CLI 创建的服务器也手动插入到相关的 haproxy 配置文件中。配置中不存在的动态服务器在重载操作后不会被恢复。动态服务器可以使用 "track" 关键字来跟踪配置中另一个服务器的检查状态。但是,无法跟踪另一个动态服务器。这是为了确保即使在删除动态服务器的情况下,跟踪链也能保持一致。使用 "check" 关键字启用健康检查支持。请注意,健康检查默认是禁用的,必须使用 "enable health" 命令独立于服务器启用。对于代理检查,请使用 "agent-check" 关键字和 "enable agent" 命令。请注意,在这种情况下,服务器可能会根据报告的状态通过代理被激活,而无需显式的 "enable server" 命令。这也意味着在移除带有代理检查的动态服务器时需要格外小心。应首先通过 "disable agent" 停用代理,以便能够在移除前将服务器置于所需的维护模式。当使用大量动态服务器时,可能会达到文件描述符限制。在这种情况下,请参考 "u-limit" 全局关键字文档。以下是当前支持的关键字列表: - agent-addr - agent-check - agent-inter - agent-port - agent-send - allow-0rtt - alpn - addr - backup - ca-file - check - check-alpn - check-proto - check-send-proxy - check-sni - check-ssl - check-via-socks4 - ciphers - ciphersuites - cookie - crl-file - crt - disabled - downinter - error-limit - fall - fastinter - force-sslv3/tlsv10/tlsv11/tlsv12/tlsv13 - id - init-state - inter - maxconn - maxqueue - minconn - no-ssl-reuse - no-sslv3/tlsv10/tlsv11/tlsv12/tlsv13 - no-tls-tickets - npn - observe - on-error - on-marked-down - on-marked-up - pool-low-conn - pool-max-conn - pool-purge-delay - port - proto - proxy-v2-options - rise - send-proxy - send-proxy-v2 - send-proxy-v2-ssl - send-proxy-v2-ssl-cn - slowstart - sni - source - ssl - ssl-max-ver - ssl-min-ver - tfo - tls-tickets - track - usesrc - verify - verifyhost - weight - ws 它们的语法类似于配置文件中的 server 行,请参考它们各自的文档以获取详细信息。
add ssl ca-file <cafile> <payload> 向 ca-file 添加新证书。当您达到 CLI 上的缓冲区大小限制并希望添加多个证书时,此命令很有用。您能够单独添加每个证书,而不是用所有证书执行 "set" 操作。一个 "set ssl ca-file" 将重置 ca-file。
示例
echo -e "set ssl ca-file cafile.pem <<\n$(cat rootCA.crt)\n" | \ socat /var/run/haproxy.stat - echo -e "add ssl ca-file cafile.pem <<\n$(cat intermediate1.crt)\n" | \ socat /var/run/haproxy.stat - echo -e "add ssl ca-file cafile.pem <<\n$(cat intermediate2.crt)\n" | \ socat /var/run/haproxy.stat - echo "commit ssl ca-file cafile.pem" | socat /var/run/haproxy.stat -
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 [@<ver>] <acl>
从 ACL <acl> 中删除所有条目。<acl> 是由 "show acl" 返回的 #<id> 或 <name>。请注意,如果引用 <acl> 是一个名称并且与 map 共享,则该 map 也将被清除。默认情况下,只清除 ACL 的当前版本(正在匹配的版本)。但是,可以使用“@”后跟版本号来指定另一个版本。
clear map [@<ver>] <map>
从 map <map> 中删除所有条目。<map> 是由 "show map" 返回的 #<id> 或 <name>。请注意,如果引用 <map> 是一个名称并且与 acl 共享,则该 acl 也将被清除。默认情况下,只清除 map 的当前版本(正在匹配的版本)。但是,可以使用“@”后跟版本号来指定另一个版本。
clear table <table> [ data.<type> <operator> <value> ] | [ key <key> ] | [ ptr <ptr> ]
从粘性表 <table> 中删除条目。这通常用于解锁一些抱怨他们被滥用拒绝访问服务的用户,但也可用于清除与即将被替换的服务器匹配的一些粘性条目(详见下面的“show table”)。请注意,有时删除条目会被拒绝,因为它当前正被会话跟踪。通常在会话结束后几秒钟重试就足够了。在没有提供选项参数的情况下,所有条目都将被删除。当使用 "data." 形式时,将删除与使用存储数据应用的过滤器匹配的条目(参见第 4.2 节中的“stick-table”)。必须在 <type> 中指定存储的数据类型,并且此数据类型必须存储在表中,否则会报告错误。数据根据 <operator> 与 64 位整数 <value> 进行比较。操作符与 ACL 相同: - eq:匹配其数据等于此值的条目 - ne:匹配其数据不等于此值的条目 - le:匹配其数据小于或等于此值的条目 - ge:匹配其数据大于或等于此值的条目 - lt:匹配其数据小于此值的条目 - gt:匹配其数据大于此值的条目当使用 key 形式时,条目 <key> 被删除。键的类型必须与表的类型相同,目前仅限于 IPv4、IPv6、整数和字符串。当使用 ptr 形式时,条目 <ptr> 被删除。<ptr> 以 0xffff 的形式写入,并且必须对应于先前“show table”命令返回的地址。由于空键或 cli 上的不兼容字符,当无法使用键匹配条目时,使用其指针匹配条目可能是相关的。
示例
$ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:20480_0, 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 >>> 0x80e6b40: key=127.0.0.3 use=0 exp=3594743 gpc0=2 conn_rate(30000)=10 \ bytes_out_rate(60000)=200 $ 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 \ >>> 0x80e6b40: key=127.0.0.3 use=0 exp=3594743 gpc0=2 conn_rate(30000)=10 \ bytes_out_rate(60000)=200 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 >>> 0x80e6b40: key=127.0.0.3 use=0 exp=3594743 gpc0=2 conn_rate(30000)=10 \ bytes_out_rate(60000)=200 $ echo "clear table http_proxy ptr 0x80e6b40" | socat stdio /tmp/sock1 $ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:0
commit acl @<ver> <acl> 提交对 ACL <acl> 版本 <ver> 所做的所有更改,并删除所有过去的版本。<acl> 是由“show acl”返回的 #<id> 或 <name>。版本号必须介于“show acl”报告的 "curr_ver"+1 和 "next_ver" 之间。如果需要,可以使用“show acl @<ver> <acl>”来查阅要提交到 ACL 的内容。指定的版本号通常是通过“prepare acl”命令创建的。替换是原子性的。它包括原子地将当前版本更新为指定版本,这将立即导致其他版本中的所有条目变得不可见,而新版本中的所有条目变得可见。也可以使用此命令来执行对 ACL 所有可见条目的原子性删除,方法是先调用“prepare acl”,然后在不添加任何条目的情况下进行提交。如果引用 <acl> 是一个也用作映射表的名称,则不能使用此命令。在这种情况下,必须改用“commit map”命令。 commit map @<ver> <map> 提交对映射表 <map> 版本 <ver> 所做的所有更改,并删除所有过去的版本。<map> 是由“show map”返回的 #<id> 或 <name>。版本号必须介于“show map”报告的 "curr_ver"+1 和 "next_ver" 之间。如果需要,可以使用“show map @<ver> <map>”来查阅要提交到映射表的内容。指定的版本号通常是通过“prepare map”命令创建的。替换是原子性的。它包括原子地将当前版本更新为指定版本,这将立即导致其他版本中的所有条目变得不可见,而新版本中的所有条目变得可见。也可以使用此命令来执行对映射表所有可见条目的原子性删除,方法是先调用“prepare map”,然后在不添加任何条目的情况下进行提交。
提交一个临时的 SSL CA 文件更新事务。对于一个已存在的 CA 文件(在“show ssl ca-file”中处于“Used”状态),新的 CA 文件树条目将被插入到 CA 文件树中,并且每个使用该 CA 文件条目的实例都将被重建,同时重建其所需的 SSL 上下文。所有先前由重建实例使用的上下文都将被移除。成功后,先前的 CA 文件条目将从树中移除。失败时,不会移除或删除任何内容,并且所有原始的 SSL 上下文都将被保留和使用。一旦临时事务被提交,它就会被销毁。对于一个新的 CA 文件(在“new ssl ca-file”之后,并且在“show ssl ca-file”中处于“Unused”状态),该 CA 文件将被插入到 CA 文件树中,但它不会在 HAProxy 的任何地方被使用。要使用它并生成使用它的 SSL 上下文,您需要使用“add ssl crt-list”将其添加到一个 crt-list 中。另请参阅“new ssl ca-file”、“set ssl ca-file”、“add ssl ca-file”、“abort ssl ca-file”和“add ssl crt-list”。
commit ssl cert <filename>
提交一个临时的 SSL 证书更新事务。对于一个现有的证书(在 "show ssl cert" 中处于 "Used" 状态),生成它需要的所有 SSL 上下文和 SNI,插入它们,并移除之前的。在内存中替换所有使用 <filename> 的地方的旧 SSL 证书。如果失败,它不会移除或插入任何东西。一旦临时事务被提交,它就会被销毁。对于一个新证书(在 "new ssl cert" 之后,并且在 "show ssl cert" 中处于 "Unused" 状态),该证书将被提交到一个证书存储区,但它不会在 haproxy 的任何地方被使用。要使用它并生成其 SNI,您需要使用 "add ssl crt-list" 将其添加到一个 crt-list 或目录中。另请参阅 "new ssl cert"、"set ssl cert"、"abort ssl cert" 和 "add ssl crt-list"。
提交一个临时的 SSL CRL 文件更新事务。对于一个已存在的 CRL 文件(在 "show ssl crl-file" 中处于 "Used" 状态),新的 CRL 文件条目将被插入到 CA 文件树(它同时保存 CA 文件和 CRL 文件)中,并且每个使用该 CRL 文件条目的实例都将被重建,同时重建其所需的 SSL 上下文。所有先前由重建实例使用的上下文都将被移除。成功后,先前的 CRL 文件条目将从树中移除。失败时,不会移除或删除任何内容,并且所有原始的 SSL 上下文都将被保留和使用。一旦临时事务被提交,它就会被销毁。对于一个新的 CRL 文件(在 "new ssl crl-file" 之后,并且在 "show ssl crl-file" 中处于 "Unused" 状态),该 CRL 文件将被插入到 CRL 文件树中,但它不会在 HAProxy 的任何地方被使用。要使用它并生成使用它的 SSL 上下文,您需要使用 "add ssl crt-list" 将其添加到一个 crt-list 中。另请参阅 "new ssl crl-file"、"set ssl crl-file"、"abort ssl crl-file" 和 "add ssl crt-list"。
debug counters [reset|show|all|bug|chk|cnt|glt|?]*
列出代码中放置的内部计数器,这些计数器可能因某些构建选项而异。其中一些依赖于 DEBUG_STRICT,其他则依赖于 DEBUG_GLITCHES。该命令接受多个参数的组合,一些定义操作,另一些定义过滤器: - bug 启用列出 BUG_ON() 语句的计数器 - cnt 启用列出 COUNT_IF() 语句的计数器 - chk 启用列出 CHECK_IF() 语句的计数器 - glt 启用列出 COUNT_GLITCH() 语句的计数器 - all 启用显示从未触发的计数器(值为 0) - reset 操作:重置所有指定的计数器 - show 操作:显示所有指定的计数器 默认情况下,操作是 "show" 以显示计数器,并且列出的计数器是所有非零值类型。当没有指定其他操作时,"show" 命令是隐式的,仅为方便脚本生成命令而存在。输出以一个整数计数器开始,后跟大写的计数器类型,然后是其在代码中的位置(文件:行),函数名,以及可选的 ": " 后跟描述。请注意,输出格式可能在主版本之间发生变化,并且新的类型和条目可能会为了提高调试能力而被反向移植到稳定版本。对它们进行的任何监控都应以非常宽松和宽容的方式进行,最好不要进行。通常,最终用户不会使用此命令,但开发人员可能会邀请他们这样做,以试图找出问题的原因,寻找 CNT 或 GLT 条目。顺便说一下,非零的 "CHK" 条目是不应该出现的,应该报告给开发人员,因为它们可能表示代码中存在一些不正确的假设。
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> 或 <name>。如果使用 <ref>,此命令仅删除列出的引用。引用可以通过列出 ACL 的内容来找到。请注意,如果引用 <acl> 是一个名称并且与一个 map 共享,则该条目也将在 map 中被删除。
del map <map> [<key>|#<ref>]
从 map <map> 中删除所有与键 <key> 对应的 map 条目。<map> 是由 "show map" 命令返回的 #<id> 或 <name>。如果使用 <ref>,此命令仅删除列出的引用。引用可以通过列出 map 的内容来找到。请注意,如果引用 <map> 是一个名称并且与一个 ACL 共享,则该条目也将在 map 中被删除。
从 HAProxy 中删除一个 CA 文件树条目。该 CA 文件必须未被使用,并已从任何 crt-list 中移除。"show ssl ca-file" 命令显示 CA 文件的状态。此删除操作对通过配置中的 "ca-file" 或 "ca-verify-file" 指令直接引用的证书无效。
del ssl cert <certfile>
从 HAProxy 中删除一个证书存储。该证书必须是未使用的,并且已从任何 crt-list 或目录中移除。“show ssl cert”显示证书的状态。此删除操作不适用于在配置中通过“crt”指令直接引用的证书。
从 HAProxy 中删除一个 CRL 文件树条目。该 CRL 文件必须未被使用,并已从任何 crt-list 中移除。"show ssl crl-file" 命令显示 CRL 文件的状态。此删除操作对通过配置中的 "crl-file" 指令直接引用的证书无效。
del ssl crt-list <filename> <certfile[:line]>
删除 crt-list 中的一个条目。这将删除前端中用于此条目的所有 SNI。如果一个证书在 crt-list 中被多次使用,您需要提供想要删除的行号。要显示行号,请使用 "show ssl crt-list -n <crtlist>"。
del server <backend>/<server>
移除附加到后端 <backend> 的一个服务器。所有服务器都有资格,但被其他配置元素引用的服务器除外。服务器在删除前必须置于维护模式。如果服务器仍有活动或空闲连接,或者其连接队列不为空,则操作将被取消。
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" 级别的套接字上发出。
dump ssl cert <certfile>
转储加载到 HAProxy 内存中的证书。这将以 PEM 格式转储证书,先是私钥,然后是叶证书,最后是证书链。您也可以通过在文件名前加上星号来转储一个事务。这对于在 CLI 上更新了证书但文件系统上未更新时,将证书保存到文件系统非常有用。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
示例
$ echo "dump ssl cert cert1.pem" | socat /tmp/sock1 -
$ echo "dump ssl cert cert1.pem" | socat /tmp/sock1 - | openssl storeutl -noout -text /dev/stdin
生成一个 stats-file,可用于在启动时预加载 haproxy 计数器值。更多详情请参见 "Stats-file" 部分。
echo <text>
通过 CLI 打印一些文本。在转储多个命令的结果时,可用于在命令之间编写注释。
示例
echo "expert-mode on; echo FDs from fdtab; show fd; echo wild FDs; debug dev fd" | socat /var/run/haproxy.sock -
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" 级别的套接字上发出。
不带选项时,此命令指示当前连接的实验模式是启用还是禁用。当传递 "on" 时,它仅为当前 CLI 连接打开实验模式。使用 "off" 则关闭它。实验模式用于访问仍在开发中的额外功能。这些功能目前不稳定,应谨慎使用。它们可能会在不同版本之间发生重大变更。当从主 CLI 使用此命令时,不应带有前缀,因为它将在连接到任何工作进程的 CLI 时为其设置模式。
示例
echo "@1; experimental-mode on; <experimental_cmd>..." | socat /var/run/haproxy.master - echo "experimental-mode on; @1 <experimental_cmd>..." | socat /var/run/haproxy.master -
expert-mode [on|off]
此命令类似于 experimental-mode,但用于切换专家模式。专家模式启用显示专家命令,这些命令对进程可能极其危险,但偶尔可以帮助开发人员收集有关复杂错误的重要信息。任何滥用这些功能都可能导致进程崩溃。除非被邀请,否则不要使用此选项。请注意,此命令特意未在帮助信息中列出。此命令仅在 admin 级别下可用。切换到其他级别会自动重置专家模式。当从主 CLI 使用此命令时,不应带有前缀,因为它将在连接到任何工作进程的 CLI 时为其设置模式。
示例
echo "@1; expert-mode on; debug dev exit 1" | socat /var/run/haproxy.master - echo "expert-mode on; @1 debug dev exit 1" | socat /var/run/haproxy.master -
get map <map> <value>
get acl <acl> <value>
在映射表 <map> 或 ACL <acl> 中查找值 <value>。<map> 或 <acl> 是由 "show map" 或 "show acl" 返回的 #<id> 或 <name>。此命令返回与此映射关联的所有匹配模式。这对于调试映射和 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 var <name>
显示进程范围变量 'name' 的存在、类型和内容。只有进程范围的变量是可读的,所以名称必须以 'proc.' 开头,否则将找不到任何变量。此命令需要 "operator" 或 "admin" 级别。
get weight <backend>/<server>
报告后端 <backend> 中服务器 <server> 的当前权重和初始权重,如果任一不存在则报告错误。初始权重是配置文件中出现的权重。除非当前权重已被更改,否则两者通常相等。后端和服务器都可以通过其名称或其数字 ID(前缀为井号 '#')指定。
help [<command>]
打印已知关键字及其基本用法的列表,或与请求的命令匹配的命令。对于未知命令,也会显示相同的帮助屏幕。
httpclient <method> <URI>
发起一个 HTTP 客户端请求并在 CLI 上打印响应。仅在专家模式下运行的 CLI 连接上支持(参见 "expert-mode on")。这仅用于调试。httpclient 能够使用 "default" 解析器部分解析 URL 中的服务器名称,该部分默认填充了您 /etc/resolv.conf 中的 DNS 服务器。但是,如果您不使用可以解析这些主机的本地 dns 守护程序,它将无法解析 /etc/hosts 中的主机。
创建一个新的空 CA 文件树条目,用于填充一组 CA 证书并添加到 crt-list 中。此命令应与 "set ssl ca-file"、"add ssl ca-file" 和 "add ssl crt-list" 结合使用。
new ssl cert <filename>
创建一个新的空 SSL 证书存储,用于填充证书并添加到目录或 crt-list 中。此命令应与 "set ssl cert" 和 "add ssl crt-list" 结合使用。
创建一个新的空 CRL 文件树条目,用于填充一组 CRL 并添加到 crt-list 中。此命令应与 "set ssl crl-file" 和 "add ssl crt-list" 结合使用。
在 ACL <acl> 中分配一个新的版本号以进行原子替换。<acl> 是由 "show acl" 返回的 #<id> 或 <name>。新的版本号在响应中以 "New version created:" 之后显示。然后,此编号可用于准备向 ACL 中添加新条目,这些条目将在提交后原子地替换当前条目。它在 "show acl" 中报告为 "next_ver"。分配新版本没有影响,因为一旦提交了更新的版本,未使用的版本将自动被移除。版本号是无符号的 32 位值,在末尾会回绕,因此在外部程序中比较它们时必须小心。如果引用 <acl> 是一个也用作 map 的名称,则不能使用此命令。在这种情况下,必须改用 "prepare map" 命令。
在 map <map> 中分配一个新的版本号以进行原子替换。<map> 是由 "show map" 返回的 #<id> 或 <name>。新的版本号在响应中以 "New version created:" 之后显示。然后,此编号可用于准备向 map 中添加新条目,这些条目将在提交后原子地替换当前条目。它在 "show map" 中报告为 "next_ver"。分配新版本没有影响,因为一旦提交了更新的版本,未使用的版本将自动被移除。版本号是无符号的 32 位值,在末尾会回绕,因此在外部程序中比较它们时必须小心。
切换行首的提示符,并进入或离开交互模式。在交互模式下,命令完成后连接不会关闭。相反,提示符会再次出现,表示解释器正在等待新命令。提示符由一个右尖括号后跟一个空格“> ”组成。当希望定期检查信息(如统计数据或错误)时,此模式特别方便。在发出“help”命令之前进入交互模式也是一个好主意。
在交互模式下关闭连接。
set anon [on|off] [<key>]
该命令为当前的 CLI 会话启用或禁用“匿名化模式”,该模式会将命令输出中被认为是敏感或机密的某些字段替换为哈希值。这些哈希值在元素之间保留了足够的一致性,以帮助开发人员在尝试发现错误时识别元素之间的关系,但比特数较低(24位),使其由于可能匹配的数量众多而不可逆。开启时,如果未指定密钥,将使用全局密钥(在配置文件中由 "anonkey" 指定,或通过 CLI 命令 "set anon global-key" 设置)。如果未设置此类密钥,将生成一个随机密钥。否则,可以指定当前会话要使用的 32 位密钥,例如,重用之前转储中使用的密钥以帮助比较输出。开发人员永远不需要此密钥,建议永远不要共享它,因为它可能允许确认/否认关于某些哈希值可能隐藏内容的某些猜测。
修改用于生成动态持久性 cookie 的密钥。这将破坏现有会话。
此命令将全局匿名化密钥设置为 <key>,该值必须是 0 到 4294967295 之间的 32 位整数(0 表示禁用全局密钥)。此命令需要管理员权限。
set map <map> [<key>|#<ref>] <value>
修改 map <map> 中每个键 <key> 对应的值。<map> 是由 "show map" 返回的 #<id> 或 <name>。如果使用 <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 | memory } { auto | on | off }
为指定的子系统启用或禁用 CPU 或内存分析。这相当于在配置文件的 "global" 部分设置或清除 "profiling" 设置。另请参阅 "show profiling"。请注意,手动将任务分析设置为 "on" 会自动重置调度器统计信息,从而允许检查给定时间间隔内的活动。内存分析仅限于某些操作系统(已知在 linux-glibc 目标上有效),并且需要在编译时设置 USE_MEMORY_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> [port <port>]
更改服务器代理检查的地址。允许在运行时将代理检查迁移到另一个地址。您可以指定 IP 和主机名,它将被解析。可选地,更改代理端口。
set server <backend>/<server> agent-port <port>
更改用于代理检查的端口。
set server <backend>/<server> agent-send <value>
更改发送到代理检查目标的代理字符串。允许在更改服务器地址时更新字符串以保持两者匹配。
set server <backend>/<server> health [ up | stopping | down ]
强制服务器的健康状态进入新状态。例如,这对于不考虑某些缓慢的健康检查而立即切换服务器状态非常有用。请注意,如果有跟踪服务器,此更改将传播到它们。
set server <backend>/<server> check-addr <ip4 | ip6> [port <port>]
更改用于服务器健康检查的 IP 地址。可选地,更改用于服务器健康检查的端口。
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 server <backend>/<server> ssl [ on | off ] (已弃用)
此选项配置到服务器的出向连接的 SSL 加密。关闭时,所有流量都变为明文;健康检查路径不变。此命令已弃用,请改用 "add server" 命令动态创建带或不带 SSL 的新服务器。
set severity-output [ none | number | string ]
更改当前会话期间连接的 stats socket 的严重性输出格式。
set ssl ca-file <cafile> <payload>
此命令是事务系统的一部分,可能需要 "commit ssl ca-file" 和 "abort ssl ca-file" 命令。如果没有正在进行的事务,它将创建一个 CA 文件树条目,其中将存储 payload 中包含的证书。该 CA 文件条目不会存储在 CA 文件树中,只会保存在一个临时事务中。如果已存在同名文件的事务,则前一个 CA 文件条目将被删除并由新的替换。完成修改后,您必须通过调用 "commit ssl ca-file" 来提交事务。如果您想分别添加多个证书,可以使用 "add ssl ca-file" 命令。
示例
echo -e "set ssl ca-file cafile.pem <<\n$(cat rootCA.crt)\n" | \ socat /var/run/haproxy.stat - echo "commit ssl ca-file cafile.pem" | socat /var/run/haproxy.stat -
set ssl cert <filename> <payload>
此命令是事务系统的一部分,可能需要 "commit ssl cert" 和 "abort ssl cert" 命令。整个事务系统适用于 "show ssl cert" 命令显示的任何证书,因此适用于任何前端或后端证书。如果没有正在进行的事务,它将在内存中将证书 <filename> 复制到一个临时事务中,然后使用有效负载中的 PEM 文件更新此事务。如果存在具有相同文件名的事务,它将更新此事务。也可以更新与证书关联的文件(.issuer、.sctl、.ocsp 等)。修改完成后,您必须 "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 crl-file <crlfile> <payload>
此命令是事务系统的一部分,可能需要 "commit ssl crl-file" 和 "abort ssl crl-file" 命令。如果没有正在进行的事务,它将创建一个 CRL 文件树条目,其中将存储 payload 中包含的撤销列表。CRL 文件条目不会存储在 CRL 文件树中,只会保存在一个临时事务中。如果已存在同名文件的事务,则前一个 CRL 文件条目将被删除并由新的替换。完成修改后,您必须通过调用 "commit ssl crl-file" 来提交事务。
示例
echo -e "set ssl crl-file crlfile.pem <<\n$(cat rootCRL.pem)\n" | \ socat /var/run/haproxy.stat - echo "commit ssl crl-file crlfile.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>]*
set table <table> ptr <ptr> [data.<data_type> <value>]*
在表中创建或更新一个粘性表条目。如果键不存在,则会插入一个条目。请参阅 第 4.2 节 中的 stick-table 以查找 <data_type> 的所有可能值。最可能的用途包括动态输入源 IP 地址的条目,并在 gpc0 中设置一个标志来动态阻止 IP 地址或影响其服务质量。可以在单次调用中传递多个 data_types。可选的 ptr 查找可用于替代现有条目的 key 查找:<ptr> 以 0xffff 的形式写入,并且必须对应于先前“show table”命令返回的地址。如果由于空键或 cli 上的不兼容字符而无法使用键匹配条目,则使用其指针匹配条目可能是相关的。
更改当前连接的 CLI 接口超时。这在长时间的调试会话中非常有用,用户需要不断检查一些指标而不会被断开连接。延迟以秒为单位传递。
set var <name> <expression>
set var <name> expr <expression>
set var <name> fmt <format>
允许使用表达式 <expression> 或格式字符串 <format> 的结果来设置或覆盖进程范围的变量 'name'。只能使用进程范围的变量,因此名称必须以 'proc.' 开头,否则不会设置任何变量。<expression> 和 <format> 只能涉及“内部”样本获取关键字和转换器,尽管最可能有用的将是 str('something')、int()、简单字符串或其他变量的引用。请注意,命令行解析器不识别引号,因此表达式中的任何空格都必须以反斜杠开头。此命令需要 "operator" 或 "admin" 级别。此命令仅在以实验模式(experimental-mode on)运行的 CLI 连接上受支持。
set weight <backend>/<server> <weight>[%]
将服务器的权重更改为参数中传递的值。如果值以“%”符号结尾,则新权重将相对于初始配置的权重。绝对权重允许在 0 到 256 之间。相对权重必须为正,且产生的绝对权重上限为 256。属于运行静态负载均衡算法的服务器组的服务器有更严格的限制,因为权重一旦设置就不能更改。因此,对于这些服务器,唯一接受的值是 0 和 100%(或 0 和初始权重)。更改会立即生效,尽管某些 LB 算法需要一定数量的请求才能考虑更改。此命令的典型用法是在更新期间通过将其权重设置为零来禁用服务器,然后在更新后通过将其设置回 100% 来重新启用它。此命令受限制,只能在配置为“admin”级别的套接字上发出。后端和服务器都可以通过其名称或其数字 ID(以井号“#”为前缀)来指定。
show acl [[@<ver>] <acl>]
转储有关 acl 转换器的信息。不带参数时,返回所有可用 acl 的列表。如果指定了 <acl>,则转储其内容。<acl> 是 #<id> 或 <name>。默认情况下,显示 ACL 的当前版本(当前正在匹配的版本,在 ACL 列表中报告为 'curr_ver')。可以通过在 ACL 标识符前加上 '@<ver>' 来转储其他版本。版本用作过滤器,不存在的版本将简单地报告无结果。转储格式与 map 相同,甚至对于样本值也是如此。返回的数据不是可用 ACL 的列表,而是组成任何 ACL 的所有模式的列表。许多这些模式可以与 map 共享。'entry_cnt' 值表示所有 ACL 条目的计数,而不仅仅是活动条目,这意味着它还包括当前正在添加的条目。
显示匿名模式的当前状态(启用或禁用)和当前会话的密钥。
转储正在运行的进程中可用的后端列表。
显示当前 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"。
show activity [-1 | 0 | thread_num]
报告有关内部事件的一些计数器,这将帮助开发人员以及更广泛地了解 haproxy 的人缩小异常行为报告的原因。一个典型的例子是一个正常运行的进程从不休眠并占用 100% 的 CPU。输出字段将由每度量一行组成,并且同一行上显示每个线程的计数器。这些计数器是 32 位的,并且在进程的生命周期内会回绕,这不是问题,因为通常会对该命令进行两次调用。这些字段有意未作文档说明,以便在提供计数器的代码中验证其确切含义。这些值也由“clear counters”命令重置。在多线程部署中,第一列将指示所有线程的总和(或根据度量性质的平均值),并且所有线程值的列表将以线程顺序在方括号中表示。可选地,可以在参数中指定要转储的线程号。特殊值“0”将报告聚合值(第一列),而“-1”(这是默认值)将显示所有列。请注意,就像在单线程模式下一样,当请求单个列时将没有方括号。
列出 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 vary:0x0011223344556677 size:39114 (39 blocks), refcount:9, expire:237 1 2 3 4 5 6 7 1. 指向缓存条目的指针 2. 哈希的前 32 位 3. 在 vary 的情况下条目的次要哈希 4. 对象的字节大小 5. 对象使用的块数 6. 使用该条目的事务数 7. 过期时间,如果已过期则可能为负数
此命令旨在集中一些 HAProxy 开发人员可能需要的信息,以更好地理解特定问题的原因。它通常不为用户提供有用的信息,但这些信息使开发人员能够排除某些假设。格式大致是一系列包含缩进行的部分,每行一个元素,例如操作系统类型和版本、CPU 类型或启动时的文件描述符限制。当某些字段不增加价值时(例如,无限制的值),为了避免重复或输出污染,它们将被省略。将来可能会出现更多字段,并且某些字段可能会更改。此输出不适合由脚本解析,并且不应被认为具有高度的可靠性,它主要是为了节省能够阅读它的人的时间。从技术上讲,这些信息是按原样从一个内部结构中获取的,该结构在启动时将它们存储在一起,以便在崩溃后的核心文件中也能找到它们。因此,开发人员可能会要求在一个行为良好的进程上提供早期输出,以便与核心转储中的内容进行比较,或者在几次重载之间进行比较(例如,某些限制可能会更改)。如果启用了匿名化,任何可能敏感的值也将被匿名化(例如,节点名称)。输出示例: $ socat stdio /tmp/sock1 <<< "show dev" Platform info machine vendor: To be filled by O.E.M machine family: Altra cpu model: Impl 0x41 Arch 8 Part 0xd0c r3p1 virtual machine: no container: no OS name: Linux OS release: 6.2.0-36-generic OS version: #37~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon Oct 9 18:01:07 UTC 2 OS architecture: aarch64 node name: 489aaf Process info pid: 1735846 boot uid: 509 boot gid: 1002 fd limit (soft): 1024 fd limit (hard): 1048576
show env [<name>]
转储进程已知的一个或所有环境变量。不带任何参数时,将转储所有变量。带一个参数时,如果指定的变量存在,则仅转储该变量。否则将输出 "Variable not found"。变量的转储格式与它们存储或由 "env" 实用程序返回的格式相同,即 "<name>=<value>"。这在调试大量使用环境变量的某些配置文件时非常方便,以确保它们包含预期的值。此命令受限,并且只能在配置为 "operator" 或 "admin" 级别的套接字上发出。
show errors [<iid>|<proxy>] [request|response]
转储前端和后端收集的最后已知的 HTTP/1.x 请求和响应错误。如果指定了 <iid>,则将转储限制为与 ID 为 <iid> 的前端或后端相关的错误。代理 ID "-1" 将导致所有实例被转储。如果指定了代理名称,其 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" 阻止了来自其内部 ID 为 1 的服务器 s2 的一个无效响应。该请求是在事务 54(此处称为“会话”)上,由源 127.0.0.1 发起,并由 ID 为 1 的前端 fe-eth0 接收。当检测到错误时,总响应长度为 213 字节,错误位于字节 23。这是头名称 "header/bizarre" 中的斜杠('/'),它不是一个有效的 HTTP 头名称字符。
show events [<sink>] [-w] [-n]
不带选项时,此命令列出所有已知的事件接收器及其类型。带选项时,如果指定的接收器类型为缓冲区,则会转储该接收器中的所有可用事件。如果在接收器名称后传递“-w”选项,则一旦到达缓冲区末尾,命令将等待新事件并显示它们。可以通过输入任何内容(将被丢弃)或关闭会话来停止操作。最后,“-n”选项用于直接定位到缓冲区的末尾,这通常在与“-w”结合使用时很方便,以便只报告新事件。为方便起见,可以使用“-wn”或“-nw”来同时启用这两个选项。
show fd [-!plcfbsd]* [<fd>]
转储所有打开的文件描述符列表,或者如果指定了,则仅转储编号为 <fd> 的那个。可以选择性地传递一组标志,以仅将转储限制为某些 FD 类型或省略某些 FD 类型。当遇到 '-' 或 '!' 时,选择将对同一参数中后面的字符进行反转。在每个由空格分隔的参数词之前,反转都会被重置。可选的 FD 类型包括 'p' 代表管道,'l' 代表监听器,'c' 代表连接(任何类型),'f' 代表前端连接,'b' 代表后端连接(任何类型),'s' 代表到服务器的连接,'d' 代表到 "dispatch" 地址或后端透明地址的连接。这样,'b' 是 'sd' 的快捷方式,'c' 是 'fb' 或 'fsd' 的快捷方式。'c!f' 等同于 'b'(“除前端连接外的任何连接”实际上就是后端连接)。这仅针对需要观察内部状态以调试复杂问题(如异常 CPU 使用率)的开发人员。每个 fd 报告一行,对于每个 fd,它在轮询器中的状态使用大写字母表示启用的标志,小写字母表示禁用的标志,使用 "P" 代表 "轮询","R" 代表 "就绪","A" 代表 "活动",事件状态使用 "H" 代表 "挂起","E" 代表 "错误","O" 代表 "输出","P" 代表 "优先","I" 代表 "输入",还有一些其他标志,如 "N" 代表 "new"(刚添加到 fd 缓存中),"U" 代表 "updated"(在 fd 缓存中接收到更新),"L" 代表 "linger_risk","C" 代表 "cloned",然后是缓存的条目位置,指向内部所有者的指针,指向 I/O 回调的指针及其名称(如果已知)。当所有者是连接时,会报告连接标志和目标(前端、代理或服务器)。当所有者是监听器时,会报告监听器的状态及其前端。在不熟悉内部机制的情况下使用此命令没有意义。值得注意的是,输出格式可能会随着时间的推移而演变,因此不应由设计为持久的工具来解析此输出。某些内部结构状态可能对列出它们的函数来说看起来可疑,在这种情况下,输出行将以后缀感叹号('!')结尾。这可能有助于在尝试诊断事件时找到一个起点。
show info [typed|json] [desc] [float]
转储当前进程上 haproxy 的状态信息。如果传递了 "typed" 作为可选参数,字段编号、名称和类型也会被发出,以便外部监控产品可以轻松检索、可能聚合,然后报告在它们不知道的字段中找到的信息。每个字段都在自己的一行上转储。如果传递了 "json" 作为可选参数,则 "typed" 输出提供的信息将以 JSON 格式作为 JSON 对象列表提供。默认情况下,格式只包含由冒号(':')分隔的两列。左边是字段名,右边是值。非常重要的一点是,在类型化输出格式中,单个对象的转储是连续的,因此消费者不需要一次存储所有内容。如果传递了 "float" 作为可选参数,一些通常作为整数发出的字段可能会切换到浮点数以获得更高的精度。哪些字段会受影响是特意未指定的,因为这可能会随着时间的推移而演变。使用此选项意味着消费者能够处理浮点数。使用的输出格式是 sprintf("%f")。当使用类型化输出格式时,每行由4列组成,由冒号(':')分隔。第一列是一个由点分隔的3个元素的系列。第一个元素是字段在列表中的数字位置(从零开始)。这个位置不应随时间改变,但预计会出现空洞,这取决于构建选项或将来是否删除某些字段。第二个元素是字段名,就像它在默认的 "show info" 输出中出现的那样。第三个元素是相对进程号,从1开始。从第一个冒号开始的该行其余部分遵循上面“类型化输出格式”一节中描述的格式。简而言之,第二列(在第一个':'之后)指示变量的来源、性质和范围。第三列指示字段的类型,包括 "s32"、"s64"、"u32"、"u64" 和 "str"。然后第四列是值本身,消费者知道如何根据第3列解析它,并根据第2列处理它。因此,类型化模式下的整体行格式是: <字段位置>.<字段名>.<进程号>:<标签>:<类型>:<值> 当 "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
在支持此功能的系统上,转储已加载的共享动态库和对象文件的列表。如果可用,对于每个共享对象,将指示虚拟地址范围、大小和对象路径。这可以用于例如尝试估计哪个库提供了出现在转储中的函数。请注意,在许多系统上,地址会在每次重启时改变(地址空间随机化),因此如果期望使用此列表来分析核心文件,则需要在启动时检索它。此命令只能在配置为“operator”或“admin”级别的套接字上发出。请注意,输出格式可能因操作系统、体系结构甚至 haproxy 版本而异,不应在脚本中依赖它。
show map [[@<ver>] <map>]
转储有关映射转换器的信息。不带参数时,返回所有可用映射的列表。如果指定了 <map>,则转储其内容。<map> 是 #<id> 或 <name>。默认情况下,显示映射的当前版本(当前正在匹配并报告为 'curr_ver' 的版本)。可以通过在映射标识符前加上 '@<ver>' 来转储其他版本。版本作为一个过滤器,不存在的版本将简单地报告没有结果。'entry_cnt' 值表示所有映射条目的计数,而不仅仅是活动条目,这意味着它也包括当前正在添加的条目。在输出中,第一列是唯一的条目标识符,可用作操作 "del map" 和 "set map" 的参考。第二列是模式,第三列是可用的示例。返回的数据不直接是可用映射的列表,而是构成任何映射的所有模式的列表。这些模式中的许多可以与 ACL 共享。
show peers [dict|-] [<peers section>]
转储在 "peers" 部分中配置的对等体信息。不带参数时,将列出属于所有 "peers" 部分的对等体列表。如果指定了 <peers section>,则只转储属于此 "peers" 部分的对等体信息。如果在对等体部分名称前指定了 "dict",则整个 Tx/Rx 字典缓存也将被转储(非常大)。可能需要传递 "-" 来转储名为 "dict" 的对等体部分。以下是两个输出示例,其中 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:0x55deb022d6a0 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
show pools [byname|bysize|byusage] [match <pfx>] [<nb>]
转储内部内存池的状态。例如,当怀疑存在内存泄漏时,这对于跟踪内存使用情况很有用。除了不清空池外,其作用与在前台运行时按 SIGQUIT 完全相同。默认情况下,输出不排序。如果指定了 "byname",则按池名称排序;如果指定了 "bysize",则按项目大小降序排序;如果指定了 "byusage",则按总使用量降序排序,并且只显示已使用的条目。还可以将输出限制为前 <nb> 个条目(例如,按使用情况排序时)。最后,如果指定了 "match" 后跟一个前缀,则只显示名称以此前缀开头的池。报告的总数仅涉及符合过滤条件的池。示例:$ socat - /tmp/haproxysock <<< "show pools match quic byusage" 正在转储池使用情况。使用 SIGQUIT 来清空它们。 - Pool quic_conn_r (65560 字节): 已分配 1337 (87653720 字节), ... - Pool quic_crypto (1048 字节): 已分配 6685 (7005880 字节), ... - Pool quic_conn (4056 字节): 已分配 1337 (5422872 字节), ... - Pool quic_rxbuf (262168 字节): 已分配 8 (2097344 字节), ... - Pool quic_conne (184 字节): 已分配 9359 (1722056 字节), ... - Pool quic_frame (184 字节): 已分配 7938 (1460592 字节), ... - Pool quic_tx_pac (152 字节): 已分配 6454 (981008 字节), ... - Pool quic_tls_ke (56 字节): 已分配 12033 (673848 字节), ... - Pool quic_rx_pac (408 字节): 已分配 1596 (651168 字节), ... - Pool quic_tls_se (88 字节): 已分配 6685 (588280 字节), ... - Pool quic_cstrea (88 字节): 已分配 4011 (352968 字节), ... - Pool quic_tls_iv (24 字节): 已分配 12033 (288792 字节), ... - Pool quic_dgram (344 字节): 已分配 732 (251808 字节), ... - Pool quic_arng (56 字节): 已分配 4011 (224616 字节), ... - Pool quic_conn_c (152 字节): 已分配 1337 (203224 字节), ... 总计: 15 个池, 已分配 109578176 字节, 已使用 109578176 ...
show profiling [{all | status | tasks | memory}] [byaddr|bytime|aggr|<max_lines>]*
转储当前的分析设置,每行一个,以及更改它们所需的命令。当启用任务分析时,调度器收集的一些每个函数的统计信息也将被输出,并附有一个摘要,涵盖调用次数、总/平均 CPU 时间和总/平均延迟。当启用内存分析时,将报告一些信息,如分配/释放的次数及其大小。可以通过指定相应的关键字将转储限制为仅分析状态、任务或内存分析;默认情况下,将转储所有分析信息。还可以通过指定数字限制来限制每个类别的输出行数。可以请求按地址或总执行时间而不是按使用情况对输出进行排序,例如,为了方便后续调用之间的比较或检查需要优化的地方,并且可以按被调用函数聚合任务活动,而不是查看详细信息。请注意,分析本质上是针对开发人员的,因为它提供了关于代码中 CPU 周期或内存浪费在何处的线索。这里没有任何可用于监控的有用信息。
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 quic [<format>] [<filter>]
转储所有活动的 QUIC 前端连接的信息。此命令受限制,只能在配置为“operator”或“admin”级别的套接字上发出。可以指定一个可选参数来控制详细程度。其值可以有多种解释方式。第一种可能性是使用预定义的值,“oneline”表示默认格式,“full”表示显示所有信息。或者,可以指定一个逗号分隔的字段列表来限制输出。当前支持的值是“tp”、“sock”、“pktns”、“cc”和“mux”。最后,格式中的“help”将显示更详细的帮助信息。最后一个参数用于限制或扩展连接列表。默认情况下,不显示处于关闭或排空状态的连接。使用额外的参数“all”将它们包含在输出中。也可以通过指定其十六进制地址来限制为单个连接。
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 套接字设置的。 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: 检查的上升/下降当前计数器。 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 记录。 srv_use_ssl: 服务器连接使用 SSL。 srv_check_port: 服务器健康检查端口。 srv_check_addr: 服务器健康检查地址。 srv_agent_addr: 服务器健康代理地址。 srv_agent_port: 服务器健康代理端口。
show sess [<options>*]
转储所有已知的活动流(以前称为“会话”)。避免在慢速连接上执行此操作,因为输出可能非常庞大。此命令受限制,只能在配置为“operator”或“admin”级别的套接字上发出。请注意,在连接回收速度快的机器上,此输出报告的条目数可能少于实际存在的条目数,因为它将转储在输入命令之前创建的所有现有流;在此期间终止的流将不会出现。有关支持的选项,请参见下文。
show sess [<id> | all | help] [<options>*]
显示有关匹配流的大量内部信息。该命令有两种输出格式:一种是简短格式,在不请求特定流标识符时是默认格式;另一种是扩展格式,在列出指定流时使用。简短格式,默认与“show sess”一起使用,每行只转储一个流和少量信息,并在行首以十六进制显示流标识符(它对应于指向流的指针)。在扩展格式中,由“show sess <id>”或“show sess all”使用,流会以大量的调试细节在多行中转储(每个大约 20 行),并且仍然以其标识符开头。此处流之间的分隔符是行首的标识符;属于同一流的额外行以一个或多个空格开头(流以缩进方式转储)。转储许多流可能会产生巨大的输出,花费大量时间并且占用大量 CPU,因此最好只转储所需的最小量。这些信息对大多数用户来说是无用的,但 HAProxy 开发人员可能会使用它们来解决复杂的错误。确切的输出格式有意未作文档说明,以便它可以根据需求自由演变,包括在稳定分支中。此输出旨在与 src/stream.c 中的 strm_dump_to_buffer() 函数一起解读,以弄清某些字段的确切含义。“help”参数将显示命令的详细用法,而不是转储流。可以设置一些选项来自定义转储或应用一些过滤器。以下是支持的选项: - backend <b> 仅显示附加到此后端的流 - frontend <f> 仅显示附加到此前端的流 - older <age> 仅显示比 <age> 秒更旧的流 - server <b/s> 仅显示附加到此后端+服务器的流 - show-uri 转储事务 URI,在请求分析期间捕获。仅在捕获时显示。 - susp 仅显示开发人员根据可能随时间或版本变化的条件认为可疑的流。
show stat [domain <resolvers|proxy>] [{<iid>|<proxy>} <type> <sid>] \ [typed|json] [desc] [up|no-maint]
转储统计信息。domain 用于选择要打印的统计信息;目前可用的是 resolvers 和 proxy。默认情况下,使用 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" 时,输出格式更适合监控工具,因为它提供数字位置并指示每个输出字段的类型。每个值都单独占一行,包含进程号、元素号、性质、来源和范围。通过在 URI 后传递 ";typed",也可以通过 HTTP 统计信息获得相同的格式。非常重要的一点是,在类型化输出格式中,单个对象的转储是连续的,因此消费者无需一次性存储所有内容。"up" 修饰符将导致仅列出报告为 up 或未检查的服务器。那些 down、unresolved 或 in maintenance 的服务器将不会被列出。这类似于 HTTP 统计信息上的 ";up" 选项。同样,"no-maint" 修饰符将像 ";no-maint" HTTP 修饰符一样工作,并导致禁用的服务器不被列出。区别在于那些已启用但 down 的服务器不会被排除。当使用类型化输出格式时,每行由 4 个由冒号(':')分隔的列组成。第一列是由点分隔的 5 个元素组成的系列。第一个元素是表示所描述对象类型的字母。目前已知的对象类型如下:'F' 代表前端,'B' 代表后端,'L' 代表侦听器,'S' 代表服务器。第二个元素是代表对象所属代理的唯一标识符的正整数。它等同于 CSV 输出的 "iid" 列,并与前端或后端部分中可选 "id" 指令前面的值匹配。第三个元素是包含代理内部唯一对象标识符的正整数,并对应于 CSV 输出的 "sid" 列。转储前端或后端时报告 ID 0。对于侦听器或服务器,这对应于它们在代理内部各自的 ID。第四个元素是列表中字段的数字位置(从零开始)。此位置不应随时间变化,但可能会有空缺,具体取决于构建选项或将来是否删除某些字段。第五个元素是它在 CSV 输出中出现的字段名称。第六个元素是正整数,是从 1 开始的相对进程号。从第一个冒号开始的行余下部分遵循上面部分描述的“类型化输出格式”。简而言之,第二列(第一个':'之后)表示变量的来源、性质和范围。第三列表示字段类型,包括 "s32"、"s64"、"u32"、"u64"、"flt" 和 "str"。然后第四列是值本身,消费者知道如何根据第 3 列解析它,以及如何根据第 2 列处理它。当命令后附加 "desc" 时,会附加一个额外的冒号,后跟一个带引号的字符串,其中包含该指标的描述。在撰写本文时,这仅支持 "typed" 输出格式。因此,类型化模式下的整体行格式为:<obj>.<px_id>.<id>.<fpos>.<fname>.<process_num>:<tags>:<type>:<value> 以下是类型化输出格式的示例:$ 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 (...) 在类型化格式中,第一列末尾的进程 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 输出的格式在一个模式中描述,可以使用 "show schema json" 输出。JSON 输出不包含额外的空格,以减少输出量。为了方便人类阅读,将输出通过一个美化打印器可能会有帮助。示例:$ echo "show stat json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool JSON 输出不包含额外的空格,以减少输出量。为了方便人类阅读,将输出通过一个美化打印器可能会有帮助。示例:$ echo "show stat json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool
show ssl ca-file [<cafile>[:<index>]]
显示加载到进程中的 CA 文件列表及其各自的证书数量。在状态变为“Used”之前,证书不会被任何前端或后端使用。列表中可能会出现一个“@system-ca”条目,它由 httpclient 默认加载。它包含由 OpenSSL 返回的您系统的受信任 CA 列表。如果文件名前缀为星号,则表示它是一个尚未提交的事务。如果指定了 <cafile> 而没有 <index>,它将显示 CA 文件的状态(“Used”/“Unused”),然后是 CA 文件中包含的所有证书的详细信息。每个证书显示的详细信息与“show ssl cert”命令显示的详细信息相同。如果指定了 <cafile> 后跟 <index>,它将只显示具有指定索引的证书的详细信息。索引从 1 开始。如果索引无效(例如太大),则不会显示任何内容。此命令可用于检查 CA 文件是否已正确更新。您还可以通过在文件名前加上星号来显示正在进行的事务的详细信息。
示例
$ echo "show ssl ca-file" | socat /var/run/haproxy.master - # 事务 *cafile.crt - 2 个证书 # 文件名 cafile.crt - 1 个证书 $ echo "show ssl ca-file cafile.crt" | socat /var/run/haproxy.master - 文件名: /home/tricot/work/haproxy/reg-tests/ssl/set_cafile_ca2.crt 状态: 已使用 证书 #1: 序列号: 11A4D2200DC84376E7D233CAFF39DF44BF8D1211 生效时间: Apr 1 07:40:53 2021 GMT 失效时间: Aug 17 07:40:53 2048 GMT 主体备用名称: 算法: RSA4096 SHA1 指纹: A111EF0FEFCDE11D47FE3F33ADCA8435EBEA4864 主体: /C=FR/ST=Some-State/O=HAProxy Technologies/CN=HAProxy Technologies CA 颁发者: /C=FR/ST=Some-State/O=HAProxy Technologies/CN=HAProxy Technologies CA $ echo "show ssl ca-file *cafile.crt:2" | socat /var/run/haproxy.master - 文件名: */home/tricot/work/haproxy/reg-tests/ssl/set_cafile_ca2.crt 状态: 未使用 证书 #2: 序列号: 587A1CE5ED855040A0C82BF255FF300ADB7C8136 [...]
show ssl cert [<filename>]
显示加载到进程中的证书列表。在它们的状态变为“Used”之前,它们不会被任何前端或后端使用。如果文件名以星号为前缀,则表示它是一个尚未提交的事务。如果指定了文件名,它将显示有关该证书的详细信息。此命令可用于检查证书是否已正确更新。您还可以通过在文件名前加上星号来显示事务的详细信息。此命令还可用于显示证书的 OCSP 响应的详细信息,方法是在文件名后加上“.ocsp”扩展名。它适用于已提交的证书以及正在进行的事务。对于已提交的证书,此命令等同于使用证书对应的 OCSP 响应 ID 调用“show ssl ocsp-response”。
示例
$ 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 Status: Used 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 Status: Unused [...]
show ssl crl-file [<crlfile>[:<index>]]
显示加载到进程中的 CRL 文件列表。在它们的状态变为“Used”之前,它们不会被任何前端或后端使用。如果文件名以星号为前缀,则表示它是一个尚未提交的事务。如果指定了不带 <index> 的 <crlfile>,它将显示 CRL 文件的状态(“Used”/“Unused”),后跟 CRL 文件中包含的所有吊销列表的详细信息。每个列表显示的详细信息基于“openssl crl -text -noout -in <file>”的输出。如果指定了 <crlfile> 后跟一个 <index>,它将只显示具有指定索引的列表的详细信息。索引从 1 开始。如果索引无效(例如太大),则不会显示任何内容。此命令可用于检查 CRL 文件是否已正确更新。您还可以通过在文件名前加上星号来显示正在进行的事务的详细信息。
示例
$ echo "show ssl crl-file" | socat /var/run/haproxy.master - # transaction *crlfile.pem # filename crlfile.pem $ echo "show ssl crl-file crlfile.pem" | socat /var/run/haproxy.master - Filename: /home/tricot/work/haproxy/reg-tests/ssl/crlfile.pem Status: Used Certificate Revocation List #1: Version 1 Signature Algorithm: sha256WithRSAEncryption Issuer: /C=FR/O=HAProxy Technologies/CN=Intermediate CA2 Last Update: Apr 23 14:45:39 2021 GMT Next Update: Sep 8 14:45:39 2048 GMT Revoked Certificates: Serial Number: 1008 Revocation Date: Apr 23 14:45:36 2021 GMT Certificate Revocation List #2: Version 1 Signature Algorithm: sha256WithRSAEncryption Issuer: /C=FR/O=HAProxy Technologies/CN=Root CA Last Update: Apr 23 14:30:44 2021 GMT Next Update: Sep 8 14:30:44 2048 GMT No Revoked Certificates.
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]
show ssl ocsp-response [[text|base64] <id|path>]
显示与 HAProxy 中使用的所有 OCSP 响应对应的 OCSP 树条目的 ID,以及相应的前端证书路径、颁发者名称和密钥哈希,以及构建 OCSP 响应的证书序列号。如果提供了有效的 <id> 或有效前端证书的 <path>,则显示相应 OCSP 响应的内容。当提供 <id> 时,可以定义转储数据的格式。'text' 选项是默认选项,它允许以与 "openssl ocsp -respin <ocsp-response> -text" 调用相同的方式显示有关 OCSP 响应的详细信息。'base64' 格式允许以 base64 格式转储 OCSP 响应的内容。
示例
$ echo "show ssl ocsp-response" | socat /var/run/haproxy.master - # 证书 ID 证书 ID 密钥 : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100a 证书路径 : /path_to_cert/foo.pem 证书 ID: 颁发者名称哈希: 8A83E0060FAFF709CA7E9B95522A2E81635FDA0A 颁发者密钥哈希: F652B0E435D5EA923851508F0ADBE92D85DE007A 序列号: 100A $ echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100a" | socat /var/run/haproxy.master - OCSP 响应数据: OCSP 响应状态: 成功 (0x0) 响应类型: 基本 OCSP 响应 版本: 1 (0x0) 响应者 ID: C = FR, O = HAProxy Technologies, CN = ocsp.haproxy.com 生成时间: May 27 15:43:38 2021 GMT 响应: 证书 ID: 哈希算法: sha1 颁发者名称哈希: 8A83E0060FAFF709CA7E9B95522A2E81635FDA0A 颁发者密钥哈希: F652B0E435D5EA923851508F0ADBE92D85DE007A 序列号: 100A 证书状态: 良好 本次更新时间: May 27 15:43:38 2021 GMT 下次更新时间: Oct 12 15:43:38 2048 GMT [...] $ echo "show ssl ocsp-response base64 /path_to_cert/foo.pem" | socat /var/run/haproxy.sock - MIIB8woBAKCCAewwggHoBgkrBgEFBQcwAQEEggHZMIIB1TCBvqE[...]
显示有关受 OCSP 更新机制影响的条目的信息。该命令将为每个 OCSP 响应输出一行,并包含响应的预期更新时间以及上次成功更新的时间,以及成功和失败更新的计数器。它还将以数字和文本形式给出上次更新的状态(成功或不成功)。有关可能错误的完整列表,请参见下文。这些行将按“下次更新”时间的升序排序。这些行还将包含使用该 OCSP 响应的第一个前端证书的路径。有关 OCSP 自动更新的更多信息,请参见“show ssl ocsp-response”命令和“ocsp-update”选项。更新错误代码和错误字符串可以如下:+----+-------------------------------------+ | ID | 消息 | +----+-------------------------------------+ | 0 | “未知” | | 1 | “更新成功” | | 2 | “HTTP 错误” | | 3 | “缺少 \"ocsp-response\" 标头” | | 4 | “OCSP 响应检查失败” | | 5 | “插入期间出错” | +----+-------------------------------------+
示例
$ echo "show ssl ocsp-updates" | socat /tmp/haproxy.sock - OCSP Certid | Path | Next Update | Last Update | Successes | Failures | Last Update Status | Last Update Status (str) 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a02021015 | /path_to_cert/cert.pem | 30/Jan/2023:00:08:09 +0000 | - | 0 | 1 | 2 | HTTP error 304b300906052b0e03021a0500041448dac9a0fb2bd32d4ff0de68d2f567b735f9b3c40414142eb317b75856cbae500940e61faf9d8b14c2c6021203e16a7aa01542f291237b454a627fdea9c1 | /path_to_cert/other_cert.pem | 30/Jan/2023:01:07:09 +0000 | 30/Jan/2023:00:07:09 +0000 | 1 | 0 | 1 | Update successful
显示 OpenSSL 在初始化期间加载的提供程序的名称。提供程序的加载确实可以通过 OpenSSL 配置文件进行配置,此选项允许检查是否加载了正确的提供程序。此命令仅适用于 OpenSSL v3。
示例
$ echo "show ssl providers" | socat /var/run/haproxy.master - Loaded providers : - fips - base
转储当前 haproxy 进程启动期间发出的所有消息,每个 startup-logs 缓冲区对其 haproxy 工作进程都是唯一的。此关键字也存在于 master CLI 上,它显示最新的启动或重新加载尝试。
转储所有已知粘性表的一般信息。返回它们的名称(持有它们的代理的名称)、它们的类型(目前为零,总是 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> ] | [ ptr <ptr> ]
转储粘滞表 <name> 的内容。在此模式下,首先报告有关表的通用信息的第一行,与“show table”一样,然后转储所有条目。由于这可能相当繁重,因此可以指定一个过滤器以指定要显示的条目。当使用“data.”形式时,过滤器适用于存储的数据(请参见第 4.2 节中的“stick-table”)。必须在 <type> 中指定存储的数据类型,并且此数据类型必须存储在表中,否则将报告错误。数据根据 <operator> 与 64 位整数 <value> 进行比较。运算符与 ACL 的运算符相同: - eq:匹配其数据等于此值的条目 - ne:匹配其数据不等于此值的条目 - le:匹配其数据小于或等于此值的条目 - ge:匹配其数据大于或等于此值的条目 - lt:匹配其数据小于此值的条目 - gt:匹配其数据大于此值的条目 在此形式中,您可以使用多个数据过滤器条目,最多可达到构建时定义的最大值(默认为 4)。当使用 key 形式时,显示条目 <key>。key 的类型必须与表的类型相同,目前仅限于 IPv4、IPv6、整数和字符串。当使用 ptr 形式时,显示条目 <ptr>。<ptr> 以 0xffff 的形式写入,并且必须与先前“show table”命令返回的地址相对应。如果由于空键或 cli 上的不兼容字符而无法使用键匹配条目,则使用其指针匹配条目可能相关。
示例
$ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # 表: http_proxy, 类型: ip, 大小:204800, 已用: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 >>> # 表: http_proxy, 类型: ip, 大小:204800, 已用: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 >>> # 表: http_proxy, 类型: ip, 大小:204800, 已用: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 >>> # 表: http_proxy, 类型: ip, 大小:204800, 已用: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 ptr 0x80e6a80" | \ socat stdio /tmp/sock1 >>> # 表: http_proxy, 类型: ip, 大小:204800, 已用: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,"=")]; }' )
当粘性表与支持分片的对等点部分同步时,将为每个键显示分片编号(否则报告“0”)。这允许知道哪些对等点将接收此键。
示例
$ echo "show table http_proxy" | socat stdio /tmp/sock1 | fgrep shard= 0x7f23b0c822a8: key=10.0.0.2 use=0 exp=296398 shard=9 gpc0=0 0x7f23a063f948: key=10.0.0.6 use=0 exp=296075 shard=12 gpc0=0 0x7f23b03920b8: key=10.0.0.8 use=0 exp=296766 shard=1 gpc0=0 0x7f23a43c09e8: key=10.0.0.12 use=0 exp=295368 shard=8 gpc0=0
转储当前运行队列中的任务数,以及每个函数的出现次数,以及已知时的平均延迟(对于启用了任务分析的纯任务)。转储是完成时的快照,根据当时队列中剩余的任务可能会有变化,尤其是在单线程模式下,因为 I/O 重新填充队列的机会较少(除非队列已满)。此命令对进程进行独占访问,在高度负载的进程上发出时可能导致微小但可测量的延迟,因此监控机器人不得滥用此命令。
转储每个线程的一些内部状态和结构,这可能有助于开发人员理解问题。输出尝试通过为每个线程显示一个块来使其可读。当 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> [<args...>]
为源 <source> 配置跟踪。不带参数时,将列出给定源支持的所有子命令。可以链接多个子命令。支持以下子命令: event [ [+|-|!]<name> ] 不带参数时,将列出指定源支持的所有事件。如果未启用,则前缀为“-”,如果已启用,则前缀为“+”。需要注意的是,单个跟踪可以标记多个事件,只要任何启用的事件与跟踪上标记的事件之一匹配,该事件就会传递给跟踪子系统。例如,接收一个类型为 HEADERS 的 HTTP/2 帧可能会触发一个帧事件和一个流事件,因为该帧创建了一个新流。如果该源的帧事件或流事件被启用,该帧将被传递给跟踪框架。带参数时,可以切换每个事件的状态并单独启用或禁用它们。支持两个特殊关键字,“none”匹配任何事件,用于一次性禁用所有事件;“any”匹配所有事件,用于一次性启用所有事件。其他事件特定于事件源。可以通过指定其名称来启用一个事件,可选地前缀为“+”以提高可读性。可以通过指定其名称并前缀为“-”或“!”来禁用一个事件。完全禁用跟踪源的一种方法是传递“event none”,该源将立即被完全忽略。 follow <other_source> 这允许源 <source> 在另一个源 <other_source> 锁定一个标准并且相同的标准也匹配当前源时,也发出跟踪。例如,如果一个源锁定在一个会话上,从另一个源跟随该源将使该另一个源发出与此会话相关的所有事件的跟踪。这可以在某种程度上用于跟踪后端请求以及相关的前端连接。“session”源通过提供一个可用于锁定处理的“new”和“end”事件使这更容易。请注意,在这种情况下,源 <source> 不需要启用其跟踪,其跟踪状态也不会受到影响。但是,如果它们不包含允许将它们与被跟踪元素相关联的信息,则某些事件可能会丢失。元源“all”也可以与此命令一起使用:在这种情况下,所有源都将跟随 <other_source>。
示例
trace h1 lock session start sess_new pause sess_end follow session
level [<level>] 不带参数时,将列出此源的所有跟踪级别,当前级别将在其前面加上星号('*')表示。带参数时,将跟踪级别更改为指定级别。详细级别是一种在报告事件之前应用的过滤器。这些过滤器用于根据其重要性级别选择性地包含或排除事件。例如,开发人员可能需要精确地知道代码中 HTTP 标头在何处被视为无效,而最终用户可能根本不关心此标头的有效性。跟踪目前有 5 个不同的级别: user 这将报告适合普通 haproxy 用户观察其流量的信息。通常会报告一些 HTTP 请求和响应,但没有太多细节。大多数源会将其设置为默认级别以方便操作。 proto 除了在“user”级别报告的内容外,它还显示协议级别的更新。这可以是例如解码后的帧类型或 HTTP 标头。 state 除了在“proto”级别报告的内容外,它还将显示解析器中发生的状态转换(或失败的转换),因此这将显示执行操作的尝试,而“proto”级别仅显示最终操作。 data 除了在“state”级别报告的内容外,它还将包括各个层之间的数据传输。 developer 它报告所有可用的信息,其中可能包括高级信息,例如“跳出此循环”,这些信息仅对试图理解偶尔在现场发生的错误的开发人员有用。函数名仅在此级别报告。强烈建议始终仅使用“user”级别,并且仅在开发人员指示时才切换到其他级别。此外,在切换到更高级别之前,最好先配置事件,因为如果没有应用过滤器,这可能会避免转储许多行。元源“all”也可以与此命令一起使用:在这种情况下,该级别将一次性应用于所有现有源。 lock [criterion] 不带参数时,将列出此源支持的所有锁定处理标准,并通过在其前面加上星号('*')来显示当前选择。锁定意味着源将专注于第一个匹配的事件,并只坚持触发此事件的标准,并忽略所有其他事件,直到跟踪停止。这允许例如对单个连接或单个流进行跟踪。某些跟踪支持以下标准,但不一定全部支持,因为其中一些可能对源不可用: backend 锁定在启动跟踪的后端上 connection 锁定在启动跟踪的连接上 frontend 锁定在启动跟踪的前端上 listener 锁定在启动跟踪的侦听器上 nothing 不锁定任何东西 server 锁定在启动跟踪的服务器上 session 锁定在启动跟踪的会话上 thread 锁定在启动跟踪的线程上 除此之外,每个源最多可以提供 4 个特定标准,例如内部状态或连接 ID。例如,在 HTTP/2 中,可以锁定 H2 流并在跟踪开始后忽略其他流。当在参数中传递标准时,将使用此标准而不是其他标准,并且任何现有的跟踪将立即终止,以便可以使用新标准重新启动。所有源都支持特殊关键字“nothing”以永久禁用跟踪。 { pause | start | stop } [ [+|-|!]event] 不带参数时,将列出为此源自动暂停、启动或停止跟踪的已启用事件。这些事件特定于每个跟踪源。带参数时,将为指定操作启用事件(如果可选地前缀为“+”)或禁用它(如果前缀为“-”或“!”)。特殊关键字“now”不是事件,并请求立即执行操作。支持关键字“none”和“any”,就像在“trace event”中一样。支持的 3 个操作分别是“pause”、“start”和“stop”。“pause”操作枚举将导致正在运行的跟踪停止并等待新的启动事件重新启动它的事件。“start”操作枚举将跟踪切换到等待模式的事件,直到出现其中一个启动事件。“stop”操作枚举将明确停止跟踪的事件,直到再次手动启用它。实际上,手动使用“start now”启动跟踪而无需关心事件,并使用“stop now”停止它是有意义的。为了捕获更微妙的事件序列,将“start”设置为正常事件(如接收 HTTP 请求),将“stop”设置为非常罕见的事件(如发出某个错误),将确保最后捕获的事件将匹配所需的标准。而暂停事件对于检测序列的结束、禁用锁定并等待另一个捕获机会很有用。在这种情况下,启用锁定以仅发现一个特定标准(例如,一个流),并将“start”设置为启动该标准的任何事件(例如,所有创建流的事件),将“stop”设置为预期的异常,将“pause”设置为结束该标准的任何事件(例如,任何流结束事件)是有意义的。在这种情况下,跟踪日志将包含影响单个对象的完全干净的序列,直到最后一个序列包含从开始到异常的所有内容。 sink [<sink>] 不带参数时,将列出此源可用的所有事件接收器,当前配置的接收器将在其前面加上星号('*')。接收器“none”始终可用,表示所有事件都被简单地丢弃,尽管它们的处理不会被忽略(例如,锁定确实会发生)。其他接收器根据配置和构建选项可用,但通常“stdout”和“stderr”在调试模式下可用,内存中的环形缓冲区也应该可用。当指定名称时,指定源的接收器会立即更改。在接收器更改期间,事件不会更改。在最坏的情况下,如果使用无效的接收器(或“none”),某些事件可能会丢失,但操作会继续到不同的目的地。元源“all”也可以与此命令一起使用:在这种情况下,接收器将应用于所有现有源。 verbosity [<level>] 不带参数时,将列出此源的所有详细级别,当前级别将在其前面加上星号('*')表示。带参数时,将详细级别更改为指定的级别。详细级别指示跟踪解码器应在多大程度上提供详细信息。它取决于跟踪源,因为某些源甚至不会提供特定的解码器。级别“quiet”始终可用,并禁用任何解码。在尝试了解细节之前,它可以用于弄清楚正在发生什么,因为它对性能和跟踪大小的影响非常小。当源未声明详细级别时,级别“default”可用,并在跟踪中指定时导致调用解码器。这是一种机会性解码。当源声明某些详细级别时,这些级别会与它们对应的描述一起列出。在这种情况下,源提供的跟踪解码器将根据跟踪点可用的信息尽可能准确。默认情况下设置“quiet”以上的第一个级别。
为指定的 <certfile> 创建一个 OCSP 请求,并将其发送到其 URI 应在证书的“授权信息访问”部分中指定的 OCSP 响应器。只考虑第一个 URI。然后检查我们应该收到的 OCSP 响应,并将其插入到本地 OCSP 响应树中。此命令仅适用于已经有存储的 OCSP 响应的证书,无论是在初始化期间提供的,还是之前通过“set ssl cert”或“set ssl ocsp-response”命令设置的。如果接收到的 OCSP 响应有效并且已正确插入到本地树中,其内容将显示在标准输出上。格式与“show ssl ocsp-response”中描述的相同。
wait { -h | <delay> } [<condition> [<args>...]]
在其最简单的形式中,没有任何条件,它只是在继续之前等待请求的延迟。这可用于收集特定时间间隔周围的指标。带有条件和可选参数,该命令将等待指定的条件得到满足、不可恢复地失败,或者在整个 <delay> 持续时间内保持不满足。支持的条件有: - srv-removable <proxy>/<server>:这将等待指定的服务器可被移除,即处于维护状态并且其上不再有任何连接。某些条件将永远不会被接受(例如,不在维护状态),并将导致报告指示未满足哪个条件的特定错误消息。服务器甚至可能已并行移除并且不再存在。如果在延迟之前一切正常,则返回成功并终止操作。延迟的默认单位是毫秒,但如果后缀有通常的计时器单位(us, ms, s, m, h, d),则也接受其他单位。当与 'socat' 实用程序一起使用时,不要忘记扩展 socat 的关闭超时以覆盖等待时间。将 "-h" 作为第一个或第二个参数传递会提供该命令的用法。
示例
$ socat -t20 /path/to/socket - <<< "show activity; wait 10s; show activity" $ socat -t5 /path/to/socket - <<< " disable server px/srv1 shutdown sessions server px/srv1 wait 2s srv-removable px/srv1 del server px/srv1"

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

9.4.1. Master CLI 命令

@<[!]pid> Master CLI 使用一种特殊的前缀表示法来访问多个进程。这种表示法很容易识别,因为它以 @ 开头。@ 前缀后面可以跟一个相对进程号,或者一个感叹号和一个 PID(例如 @1 或 @!1271)。单独的 @ 可以用来指定 master 进程。正在退出的进程只能通过 PID 访问,因为相对进程号只适用于当前进程。 错误(Bugs):已知用于实现 master 和 worker 之间通信的 sockpair@ 协议在 macOS 上并不可靠,这是由于 macOS 的 sendmsg(2) 实现中存在问题。因此,一个命令可能会最终没有响应。
示例
$ 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 - [...]
expert-mode [on|off]
此命令为从主 CLI 访问的每个工作进程激活“expert-mode”。与“mcli-debug-mode”结合使用时,它还会在主进程上激活该命令。在主 CLI 提示符中显示标志“e”。另请参见第 9.3 节中的“expert-mode”和 9.4.1 中的“mcli-debug-mode”。
此命令为从主 CLI 访问的每个工作进程激活“experimental-mode”。与“mcli-debug-mode”结合使用时,它还会在主进程上激活该命令。在主 CLI 提示符中显示标志“x”。另请参见第 9.3 节中的“experimental-mode”和 9.4.1 中的“mcli-debug-mode”。
此命令与主 CLI 上的“reload”命令作用相同,但它执行的是硬停止 (-st) 而不是软停止 (-sf) 上一个进程。这意味着上一个进程在退出前不会等待完成任何操作,因此所有连接都将被关闭。另请参见“reload”命令。
此关键字在主 CLI 中启用一种特殊模式,该模式在主 CLI 上启用了所有原本用于工作进程 CLI 的关键字,从而允许调试主进程。激活后,您可以使用“help”列出新的可用关键字。与“experimental-mode”或“expert-mode”结合使用时,它会启用更多关键字。在主 CLI 提示符中显示标志“d”。
当提示符启用时(通过“prompt”命令),CLI 正在工作的上下文会显示在提示符中。master 进程由字符串 "master" 标识,其他进程则由其 PID 标识。如果最后一次重载失败,master 提示符将变为 "master[ReloadFailed]>",这样就可以清楚地看到该进程仍在旧配置上运行,而新配置并未生效。Master CLI 的提示符能够显示几个标志,代表启用的模式:“d”表示 mcli-debug-mode,“e”表示 expert-mode,“x”表示 experimental-mode。
示例
$ socat /var/run/haproxy-master.sock - prompt master> expert-mode on master(e)> experimental-mode on master(xe)> mcli-debug-mode on master(xed)> @1 95191(xed)>
您还可以使用“reload”命令重新加载 HAProxy 主进程,其作用与在主进程上执行 `kill -USR2` 相同,前提是用户至少具有“operator”或“admin”权限。此命令允许您执行同步重新加载,该命令将在重新加载执行后返回一个重新加载状态。如果使用工具来解析它,请小心超时,它只有在配置被解析并且新的工作进程被派生后才会返回。“socat”命令默认使用 0.5 秒的超时,因此如果重新加载时间过长,它将在显示消息之前退出。“ncat”默认没有超时。当使用 USE_SHM_OPEN=1 编译时,reload 命令也能够转储主进程的启动日志。
示例
$ echo "reload" | socat -t300 /var/run/haproxy-master.sock stdin Success=1 -- [NOTICE] (482713) : haproxy version is 2.7-dev7-4827fb-69 [NOTICE] (482713) : path to executable is ./haproxy [WARNING] (482713) : config : 'http-request' rules ignored for proxy 'frt1' as they require HTTP mode. [NOTICE] (482713) : New worker (482720) forked [NOTICE] (482713) : Loading success. $ echo "reload" | socat -t300 /var/run/haproxy-master.sock stdin Success=0 -- [NOTICE] (482886) : haproxy version is 2.7-dev7-4827fb-69 [NOTICE] (482886) : path to executable is ./haproxy [ALERT] (482886) : config : parsing [test3.cfg:1]: unknown keyword 'Aglobal' out of section. [ALERT] (482886) : config : Fatal errors found in configuration. [WARNING] (482886) : Loading failure! $
reload 命令是在主 CLI 上执行的最后一个命令,其后的所有其他命令都将被忽略。一旦 reload 命令返回其状态,它将关闭与 CLI 的连接。请注意,重新加载将关闭与主 CLI 的所有连接。另请参见“hard-reload”命令。
show proc [debug]
Master CLI 引入了一个 'show proc' 命令来监控进程。
示例
$ echo 'show proc' | socat /var/run/haproxy-master.sock - #<PID> <type> <reloads> <uptime> <version> 1162 master 5 [failed: 0] 0d00h02m07s 2.5-dev13 # workers 1271 worker 1 0d00h00m00s 2.5-dev13 # old workers 1233 worker 3 0d00h00m43s 2.0-dev3-6019f6-289 # programs 1244 foo 0 0d00h00m00s - 1255 bar 0 0d00h00m00s -
在此示例中,主进程已重新加载 5 次,但其中一个旧的工作进程仍在运行,并经历了 3 次重新加载。您可以访问此工作进程的 CLI 来了解发生了什么。'debug' 参数可用于显示调试细节,它当前显示用于 IPC 通信的 FD。请注意,不保证调试输出在 haproxy 版本之间保持稳定。
HAProxy 需要使用 USE_SHM_OPEN=1 编译才能在 Master CLI 上正确使用,否则并非所有消息都可见。与其在 stats socket 上的对应命令一样,此命令能够显示 HAProxy 的启动消息。但它不转储当前 worker 的启动消息,而是转储最近一次启动或重载的启动消息,这意味着它能够转储失败重载的解析消息。这些消息也会随“reload”命令一起转储。

9.5. Stats 文件

所谓的 stats-file 可用于在进程启动时使用非空值预加载内部 haproxy 计数器。其主要目的是在重新加载期间保留工作进程的统计信息。stats-file 中只包含所有暴露的 haproxy 统计信息的一部分,因为它只对预加载指标类型的值有意义。目前,stats-file 中仅支持代理计数器。这允许为前端、后端、服务器和侦听器预加载值。但是,只有具有非空 GUID 的对象实例才会存储在 stats-file 中。这保证了即使其他参数不同,值也会为具有匹配类型和 GUID 的对象预加载。CLI 命令“dump stats-file”的目的是生成一个 stats-file。stats-file 的格式是内部定义的,并且可以自由地进行未来的更改和扩展。它被设计为至少在相邻的 haproxy 稳定分支版本之间兼容,但在将 stats-file 加载到在较旧版本上运行的进程时可能需要可选的额外配置。
很常见的情况是,构成集群的两个 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:端口,在故障排除期间,可能会发生旧进程在启动新进程之前没有被停止的情况。这会提供荒谬的测试结果,倾向于表明对配置的任何更改都被忽略了。原因实际上是,即使新进程以新配置重新启动,旧进程也会获得一些传入连接并处理它们,返回意外的结果。如有疑问,只需停止新进程再试一次。如果它仍然有效,很可能意味着一个旧进程仍然存在,必须被停止。Linux 的“netstat -lntp”在这里很有帮助。当从命令行向 ACL 添加条目时(例如,当将源地址列入黑名单时),重要的是要记住这些条目不会同步到文件,如果有人重新加载配置,这些更新将会丢失。虽然这通常是期望的效果(对于黑名单),但当更改是作为问题修复时,它可能不一定符合预期。请参见 CLI 接口的“add acl”操作。
当 HAProxy 以“-d”选项启动时,它将保持在前台,并为每个事件打印一行,例如传入连接、连接结束,以及看到的每个请求或响应头行。此调试输出在内容处理之前发出,因此它们不考虑本地修改。主要用途是显示请求和响应,而无需运行网络嗅探器。当并行处理多个连接时,输出的可读性较差,尽管 examples/ 目录中的“debug2ansi”和“debug2html”脚本通过为输出着色肯定会有所帮助。如果 HAProxy 发现 HTTP/1.x 请求或响应格式不正确而拒绝它,最好的做法是连接到 CLI 并发出“show errors”,它将报告每个前端和后端最后捕获到的有问题的 HTTP/1.x 请求和响应,以及所有必要的信息,以精确指出被拒绝的输入流的第一个字符。这有时需要向客户或开发人员证明他们的代码中存在错误。在这种情况下,通常可以使用“option accept-unsafe-violations-in-http-request”或其等效的服务器响应“option accept-unsafe-violations-in-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 名称: HAProxy 版本: 1.6-dev7-e32d18-17 发布日期: 2015/10/12 进程数: 1 进程号: 1 Pid: 7949 运行时间: 0d 0h02m39s 运行时间_秒: 159 最大内存_MB: 0 Ulimit-n: 120032 最大套接字数: 120032 最大连接数: 60000 硬性_最大连接数: 60000 当前连接数: 0 累计连接数: 3 累计请求数: 3 最大Ssl连接数: 0 当前Ssl连接数: 0 累计Ssl连接数: 0 最大管道数: 0 已用管道数: 0 空闲管道数: 0 连接速率: 0 连接速率限制: 0 最大连接速率: 1 会话速率: 0 会话速率限制: 0 最大会话速率: 1 Ssl速率: 0 Ssl速率限制: 0 最大Ssl速率: 0 Ssl前端密钥速率: 0 Ssl前端最大密钥速率: 0 Ssl前端会话重用_百分比: 0 Ssl后端密钥速率: 0 Ssl后端最大密钥速率: 0 Ssl缓存查找次数: 0 Ssl缓存未命中次数: 0 压缩输入Bps: 0 压缩输出Bps: 0 压缩Bps速率限制: 0 Zlib内存使用量: 0 最大Zlib内存使用量: 0 任务数: 5 运行队列: 1 空闲百分比: 100 节点: wtap 描述: 当一个问题似乎在新版本的 HAProxy 上随机出现时(例如:每隔一个请求被中止,偶尔崩溃等),值得尝试启用内存投毒,以便每次调用 malloc() 后立即用可配置的字节填充内存区域。默认情况下,此字节为 0x50(ASCII 'P'),但可以使用任何其他字节,包括零(其效果与 calloc() 相同,可能会使问题消失)。内存投毒在命令行上使用“-dM”选项启用。它会稍微影响性能,不建议在生产环境中使用。如果问题在使用它时一直发生,或者在使用零字节投毒时从不发生,这清楚地意味着您发现了一个错误,并且您肯定需要报告它。否则,如果没有明显变化,则问题与此无关。在调试某些延迟问题时,重要的是在本地机器上同时使用 strace 和 tcpdump,并在远程系统上使用另一个 tcpdump。这样做的原因是,处理链的每个环节都有延迟,重要的是要知道是哪个环节导致了延迟,以便知道在哪里采取行动。实际上,本地 tcpdump 将指示输入数据何时到达。Strace 将指示 haproxy 何时接收到这些数据(使用 recv/recvfrom)。警告,openssl 使用 read()/write() 系统调用而不是 recv()/send()。Strace 还将显示 haproxy 何时发送数据,而 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 实际上在虚拟机中运行,并且由于某种原因,虚拟机管理程序决定数据不需要立即发送。在虚拟化环境中,延迟问题几乎总是由虚拟化层引起的,因此为了节省时间,值得首先比较虚拟机和外部组件上的 tcpdump。任何差异都必须归功于虚拟机管理程序及其附带的驱动程序。当在 tcpdump 跟踪中看到一些 TCP SACK 段时(使用 -vv),这总是意味着发送方已获得数据包丢失的证据。虽然看不到它们并不意味着没有丢失,但看到它们肯定意味着网络是有损的。网络上的丢失是正常的,但其速率不应让 SACK 用肉眼就能注意到。如果它们在跟踪中大量出现,值得调查到底发生了什么以及数据包在哪里丢失。HTTP 不太适应 TCP 丢失,这会引入巨大的延迟。“netstat -i”命令将报告每个接口的统计信息。Rx-Ovr 计数器增长的接口表明系统没有足够的资源来接收所有传入的数据包,并且它们在被网络驱动程序处理之前就丢失了。Rx-Drp 表明一些接收到的数据包在网络堆栈中丢失,因为应用程序处理它们的速度不够快。这在某些攻击期间也可能发生。Tx-Drp 意味着输出队列已满,数据包必须被丢弃。使用 TCP 时,这应该非常罕见,但可能表明传出链路饱和。
HAProxy 设计为以非常有限的权限运行。使用它的标准方法是将其隔离到一个 chroot jail 中,并将其权限降低到一个在该 jail 内没有任何权限的非 root 用户,这样,如果未来发现任何漏洞,其被利用也不会影响系统的其余部分。为了执行 chroot,它首先需要以 root 用户身份启动。构建手工制作的 chroot 来启动该进程是没有意义的,这些 chroot 构建起来很痛苦,从未得到适当的维护,并且总是包含比主文件系统多得多的错误。并且在被利用的情况下,入侵者可以使用特意构建的文件系统。不幸的是,许多管理员混淆了“以 root 身份启动”和“以 root 身份运行”,导致在启动 haproxy 之前更改 uid,从而降低了有效的安全限制。HAProxy 需要以 root 身份启动才能: - 调整文件描述符限制 - 绑定到特权端口号 - 绑定到特定的网络接口 - 透明地侦听外部地址 - 将自身隔离在 chroot jail 内 - 降级到另一个非特权的 UID HAProxy 可能需要以 root 身份运行才能: - 绑定到用于传出连接的接口 - 绑定到用于传出连接的特权源端口 - 透明地绑定到用于传出连接的外部地址 大多数用户永远不需要“以 root 身份运行”的情况。但“以 root 身份启动”涵盖了大多数用法。一个安全的配置将具有: - 一个指向没有任何访问权限的空位置的 chroot 语句。这可以在 UNIX 命令行上这样准备: # mkdir /var/empty && chmod 0 /var/empty || echo "失败" 并在 HAProxy 配置的全局部分这样引用: chroot /var/empty - 在全局部分同时有 uid/user 和 gid/group 语句: user haproxy group haproxy - 一个 stats 套接字,其模式、uid 和 gid 设置为匹配允许访问 CLI 的用户和/或组,以便任何人都无法访问它: stats socket /var/run/haproxy.stat uid hatop gid hatop mode 600

13.1. Linux capabilities 支持

从 v2.9 版本开始,haproxy 支持 Linux capabilities。如果二进制文件使用 USE_LINUX_CAP=1 编译,它能够在从 root 用户切换到非 root 用户期间保留 'setcap' 关键字中给定的 capabilities。从 v3.1 版本开始,haproxy 还会检查 'setcap' 关键字中给定的 capabilities 是否已在其二进制文件的 Permitted 集中由管理员设置 (capget syscall)。如果是这种情况,它会在以非 root 用户运行时,将这些 capabilities 转换到其进程的 Effective 集中 (capset syscall)。这样做是为了避免 haproxy 以 root 身份启动和运行的所有潜在用例:透明代理模式、绑定到特权端口。'setcap' 关键字支持以下网络 capabilities: - cap_net_admin: 透明代理、将套接字绑定到特定网络接口、使用 set-mark 操作; - cap_net_raw (cap_net_admin 的子集): 透明代理; - cap_net_bind_service: 将套接字绑定到特定网络接口; - cap_sys_admin: 在特定网络命名空间中创建套接字。如果这些 capabilities 没有被列为 'setcap' 的参数,Haproxy 绝不会将它们从其 Permitted 集转换到 Effective 集。有关 'setcap' 关键字和支持的 capabilities 的更多信息,请参见《配置指南》第 3.1 章“进程管理和安全”。管理员可以使用以下命令在 haproxy 二进制文件的 Permitted 集中添加所需的 capabilities
示例
# setcap cap_net_admin,cap_net_bind_service=p /usr/local/sbin/haproxy
添加的 capabilities 将在其启动后在进程的 Permitted 集中看到。如果相同的 capabilities 是 'setcap' 关键字的参数,它们也可以在进程的 Effective 集中看到。这可以通过以下命令检查
示例
# grep Cap /proc/<haproxy PID>/status CapInh: 0000000000000000 CapPrm: 0000000000001400 CapEff: 0000000000001400 CapBnd: 000001ffffffffff CapAmb: 0000000000000000
有关 setcap 和 capabilities 集的更多详细信息,请参见 Linux 手册页 (capabilities(7))。在某些用例中,如透明代理或在特定网络命名空间中创建套接字,配置文件解析器会检测到需要 cap_net_raw 或 cap_sys_admin 或其他一些支持的 capabilities。然后,在初始化阶段,haproxy 进程会检查是否可以将这些 capabilities 放入其 Effective 集中。如果由于 capget 或 capset syscall 失败(由 SELinux、Seccomp 等安全模块对 syscall 设置的限制)而无法实现,进程会发出诊断警告(以 -dD 启动)。由于支持许多具有不同系统设置的不同平台,解析器无法从配置文件中推断出是否会绑定到特权端口。因此,在权限不足的情况下(以非 root 用户运行),进程将仅以如下警报消息终止。用户需要重新检查其配置和 haproxy 二进制文件的 capabilities 集。
示例
$ haproxy -dD -f haproxy.cfg ... [ALERT] (96797) : 绑定 [haproxy.cfg:36] 用于前端 fe: 无法绑定套接字 (权限被拒绝) 用于 [0.0.0.0:80] [ALERT] (96797) : [haproxy.main()] 一些协议无法启动它们的侦听器!正在退出。


HAProxy 3.1.10-18 – 管理指南
,