文档贡献者须知:本文档每行格式化为 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 监狱中,此时它完全无法执行任何文件系统访问。它依赖的库(例如: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/haproxyHAProxy 通过在命令行调用 "haproxy" 程序并带有一些参数来启动。实际语法是:$ haproxy [<options>]*
后面跟着一个或多个字母,并且可能跟着一个或多个额外的参数。如果没有指定任何选项,HAProxy 将会显示帮助页面,并提醒支持的选项。可用的选项可能因操作系统而异。这些选项中有相当一部分与“global”部分中的等效选项是重叠的。在这种情况下,命令行始终优先于配置文件,这样就可以使用命令行快速强制执行某些设置,而无需修改配置文件。当前支持的选项列表如下:-- <cfgfile>* :"--" 之后的所有参数都是配置文件/目录的路径,将按声明顺序加载和处理。当依赖 shell 加载许多按数字排序的文件时,这主要很有用。另请参阅 "-f"。 "--" 和 "-f" 之间的区别是,"-f" 必须放在每个文件名之前,而只需要一个 "--" 放在所有文件名之前。这两个选项可以一起使用,命令行顺序仍然适用。当指定多个文件时,每个文件必须以一个节边界开头,因此每个文件的第一个关键字必须是“global”、“defaults”、“peers”、“listen”、“frontend”、“backend”等等中的一个。例如,一个文件不能只包含服务器列表。-f <cfgfile|cfgdir> : 将 <cfgfile> 添加到要加载的配置文件列表中。如果 <cfgdir> 是一个目录,它包含的所有文件(仅文件)将按词法顺序(使用 LC_COLLATE=C)添加到要加载的配置文件列表中;仅添加扩展名为“.cfg”的文件,并且仅添加非隐藏文件(不以“.”开头的文件)。配置文件按其声明顺序加载和处理。此选项可以指定多次以加载多个文件。另请参阅 "--"。 "--" 和 "-f" 之间的区别是,"-f" 必须放在每个文件名之前,而只需要一个 "--" 放在所有文件名之前。这两个选项可以一起使用,命令行顺序仍然适用。当指定多个文件时,每个文件必须以一个节边界开头,因此每个文件的第一个关键字必须是“global”、“defaults”、“peers”、“listen”、“frontend”、“backend”等等中的一个。例如,一个文件不能只包含服务器列表。-C <dir> : 在加载配置文件之前更改到目录 <dir>。在使用相对路径时,这非常有用。注意:在 "--" 后面使用通配符时,它们实际上是在 haproxy 启动之前由 shell 替换的。-D : 以后台模式启动。进程在 fork 后从当前终端分离,并且不再在终端中报告错误。这等同于配置文件“global”部分中的“daemon”关键字。建议在任何 init 脚本中始终强制使用它,以免有问题的配置阻止系统启动。-L <name> : 将本地对等方名称更改为 <name>,默认为本地主机名。这仅与对等复制一起使用。您可以在配置文件中使用 $HAPROXY_LOCALPEER 变量来引用对等方名称。-N <limit> : 将每个代理的默认 maxconn 设置为 <limit>,而不是内置的默认值(通常为 2000)。仅用于调试。-V : 启用详细模式(禁用安静模式)。恢复 "-q" 或 "quiet" 的效果。-W : 主-工作模式。这等同于配置文件“global”部分中的“master-worker”关键字。此模式将启动一个“主进程”,该进程将监视“工作进程”。使用此模式,您可以通过向主进程发送 SIGUSR2 信号直接重新加载 HAProxy。主-工作模式兼容前台模式或后台模式。建议将此模式与多进程和 systemd 一起使用。-Ws : 主-工作模式,支持 systemd 服务中的 `notify` 类型。仅当 HAProxy 是使用 `USE_SYSTEMD` 构建选项编译时,此选项才可用。-c : 仅检查配置文件并在尝试绑定之前退出。如果一切正常,退出状态为零,如果遇到错误,则为非零。如果存在警告,则会报告。默认情况下,此选项不报告成功消息。与 "-V" 结合使用时,将在成功时打印消息“Configuration file is valid”。脚本必须使用退出状态来确定命令的成功。-cc : 评估条件块中使用的条件。如果条件为真,则退出状态为零;如果条件为假,则为 1;如果遇到错误,则为 2。-d : 启用调试模式。这将禁用后台模式,强制进程保持在前台运行,并显示传入和传出的事件。绝不能在 init 脚本中使用。-dC[key] : 转储配置文件。在标记化行之后执行,因此会剥离注释并强制缩进。如果指定了非零密钥,则在敏感/机密字段之前截断行,并使用此密钥对标识符和地址进行哈希处理,算法与 CLI 上的匿名模式相同。这意味着输出可以安全地与需要它来弄清楚匿名转储中发生的事情的开发人员共享。另请参阅 CLI 的 "set anon" 命令。-dD : 启用诊断模式。此模式将输出关于可疑配置语句的额外警告。即使在“zero-warning”模式下,这也不会阻止启动,也不会改变退出状态码。-dF : 禁用数据快速转发。这是一种通过直接在两侧传递数据而不唤醒流来优化数据转发的机制。通过此指令,可以禁用此优化。请注意,它也禁用了任何内核 TCP 拼接。此命令不适用于常规使用,通常只有在复杂的调试会话中,开发人员才会建议使用它。-dG : 禁用使用 getaddrinfo() 将主机名解析为地址。当怀疑 getaddrinfo() 没有按预期工作时,可以使用此选项。此选项的可用性是因为许多系统上存在 getaddrinfo() 的无效实现,导致难以排查的异常。-dI : 启用不安全 fork。这等同于全局部分中的“insecure-fork-wanted”。当使用 ASAN 运行所有 reg-tests 来解析地址时,这可能很有用。-dK<class[,class]*> : 转储每个类中已注册关键字的列表。类列表可通过 "-dKhelp" 获取。可以使用 "-dKall" 转储所有类,否则可以指定逗号分隔的列表,如帮助中所示。输出格式将根据转储的关键字类别而变化(例如,“cfg”将以类似于配置文件格式的格式显示已知的配置关键字,而“smp”将显示以规则集兼容性矩阵为前缀的示例 fetch 函数)。这些很少被人为直接使用,但对于尝试检测新关键字在特定位置出现以自动更新文档、语法高亮文件、配置文件解析器、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()。无论如何,如果使用此选项时出现或消失了错误,则意味着 haproxy 中存在错误,请报告。在字节之后单独或用逗号分隔的其他选项可用。特殊选项 "help" 将列出当前支持的选项及其当前值。每个调试选项都可以强制打开或关闭。通常在构建时根据操作系统选择最佳选项,无需调整,除非开发人员建议。支持的调试选项包括(设置/清除):- fail / no-fail: 结合全局“tune.fail-alloc”设置,此选项会随机使内存分配失败。用于检测代码中缺少错误检查。设置此选项会将失败率预设为 1%。- no-merge / merge: 默认情况下,大小非常相似的池会被合并,从而提高效率,但这会使某些内存转储的分析变得复杂。此选项允许禁用此机制,并且可能会略微增加内存使用量。- cold-first / hot-first: 为了优化 CPU 缓存命中率,默认情况下,最近释放的对象(“热”对象)会被回收用于新分配。但这也会使内存转储的分析复杂化,并可能隐藏使用后释放错误。此选项允许选择最冷的对象,这可能会略微增加 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 等意外值。这类错误很少重现,尤其是在合并池时。这通常通过直接将字节值传递给 -dM 来启用,但使用此选项可以禁用/启用先前设置的值的使用。-dR : 禁用侦听端口上的 SO_REUSEPORT 套接字选项。这等同于全局部分的“noreuseport”关键字。这可以应用于多线程场景,当在 haproxy 线程之间观察到负载分配问题时(可以通过 top 监控)。-dS : 禁用 splice() 系统调用的使用。这等同于全局部分的“nosplice”关键字。当怀疑 splice() 行为不当或导致性能问题时,或者在使用 strace 查看转发数据(使用 splice() 时不显示)时,可以使用此选项。-dV : 禁用服务器端的 SSL 验证。这等同于在全局部分具有“ssl-server-verify none”。当尝试在生产环境之外重现生产问题时,这非常有用。绝不要在 init 脚本中使用它,因为它会降低到服务器的 SSL 安全性。-dW : 如果设置,当在处理配置时发出任何警告时,haproxy 将拒绝启动。这有助于检测细微的错误,并使配置保持干净且跨版本可移植。建议在由人工管理的配置的服务脚本中使用此选项,但建议不要与生成配置一起使用,后者倾向于发出更多警告。它可以与 "-c" 结合使用,以使检查配置中的警告失败。这等同于全局选项“zero-warning”。-dZ : 禁用“零拷贝”模式下的数据转发。这等同于全局部分的“tune.disable-zero-copy-forwarding”关键字。在数据丢失或数据完整性问题的情况下,或者在使用 strace 查看转发数据时,这可能很有用,因为它也禁用了任何内核 TCP 拼接。-db : 禁用后台模式和多进程模式。进程保持在前台。它主要用于开发或小型测试期间,因为 Ctrl-C 足够停止进程。绝不要在 init 脚本中使用它。-de : 禁用“epoll”轮询器的使用。这等同于全局部分的关键字“noepoll”。当怀疑与此轮询器相关的错误时,它非常有用。在支持 epoll 的系统上,通常会回退到“poll”轮询器。-dk : 禁用“kqueue”轮询器的使用。这等同于全局部分的关键字“nokqueue”。当怀疑与此轮询器相关的错误时,它非常有用。在支持 kqueue 的系统上,通常会回退到“poll”轮询器。-dp : 禁用“poll”轮询器的使用。这等同于全局部分的关键字“nopoll”。当怀疑与此轮询器相关的错误时,它非常有用。在支持 poll 的系统上,通常会回退到“select”轮询器,该轮询器无法禁用,并且限制为 1024 个文件描述符。-dr : 忽略服务器地址解析失败。在生产环境之外验证配置时,无法访问相同的解析器并因服务器地址解析失败而导致错误非常普遍,这使得测试配置变得困难。此选项只需将“none”方法附加到所有服务器的地址解析方法列表中,从而确保即使 libc 无法解析地址,启动顺序也不会中断。-dt [<trace_desc>,...] : 在 stderr 上激活跟踪。不带参数,这会在错误级别启用所有跟踪源。这对于检测客户端或服务器的协议违规特别有用。可以使用可选参数使用 ',' 作为分隔符指定各种跟踪配置的列表。每个元素激活一个或所有跟踪源。此外,可以使用 ':' 作为内部分隔符与跟踪名称为每个元素指定级别和详细程度。输入无效的详细程度或级别名称时,将显示可用关键字列表。例如,为每个字段传递 'help' 以首先查看列表可能很方便。-dv : 禁用“evports”轮询器的使用。这等同于全局部分的关键字“noevports”。当怀疑与此轮询器相关的错误时,它非常有用。在支持事件端口(SunOS 源自 Solaris 10 及更高版本)的系统上,通常会回退到“poll”轮询器。-m <limit> : 限制可分配内存,用于将进程数据保留在 <limit> 兆字节。这可能会导致某些连接被拒绝或某些减速,具体取决于正常操作所需的内存量。这主要用于强制 haproxy 进程在资源受限的场景下工作。重要的是要注意,内存不会在 haproxy 进程之间共享,通过 fork() 系统调用创建的子进程会继承其父进程的资源限制。因此,在主-工作模式下,此内存限制分别应用于主进程及其 fork 的工作进程。-n <limit> : 将每个进程的连接限制为 <limit>。这等同于全局部分的关键字 "maxconn"。它优先于此关键字。这可用于快速强制设置较低的限制,以避免在资源限制过低的系统上出现服务中断。-p <file> : 在启动期间将所有进程的 pid 写入 <file>。这等同于全局部分的关键字 "pidfile"。文件在进入 chroot 监狱之前打开,在执行 "-C" 所暗示的 chdir() 之后打开。每个 pid 独占一行。-q : 设置“安静”模式。这将禁用输出消息。它可以与 "-c" 结合使用,仅用于检查配置文件是否有效。-S <bind>[,bind_options...]: 在主-工作模式下,绑定一个主 CLI,该 CLI 可以访问所有正在运行或即将退出的进程。出于安全原因,建议将主 CLI 绑定到本地 UNIX 套接字。绑定选项与配置文件中的 "bind" 关键字相同,单词用逗号而不是空格分隔。注意,此套接字无法用于在无缝重新加载期间从旧进程检索侦听套接字。-sf <pid>* : 在启动完成后向旧进程发送 "finish" 信号 (SIGUSR1),要求它们完成当前工作并退出。<pid> 是要发送信号的 pid 列表(每行一个参数)。列表在任何以 "-" 开头的选项处结束。pid 列表为空也没关系,这样可以根据 "pidof" 或 "pgrep" 命令的结果即时构建。-st <pid>* : 在启动完成后向旧进程发送 "terminate" 信号 (SIGTERM),立即终止它们,而不完成它们正在做的工作。<pid> 是要发送信号的 pid 列表(每行一个参数)。列表在任何以 "-" 开头的选项处结束。pid 列表为空也没关系,这样可以根据 "pidof" 或 "pgrep" 命令的结果即时构建。-v : 报告版本和构建日期。-vv : 显示版本、构建选项、库版本和可用的轮询器。在提交 bug 报告时,系统会要求提供此输出。-x <unix_socket> : 连接到指定的套接字并尝试从旧进程检索任何侦听套接字,并使用它们而不是尝试绑定新的套接字。这有助于在 Linux 上重新加载配置时避免错过任何新连接。在没有主-工作模式的情况下,能力必须在 stats 套接字上使用配置中的 "expose-fd listeners" 来启用。在主-工作模式下,不需要 "expose-fd listeners",主进程在使用 "sockpair@" 语法进行重新加载时会自动使用此选项,这允许主进程直接连接到工作进程而无需使用配置文件中声明的任何 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" 进行验证。其中报告了一些重要信息,例如某些构建选项、目标系统以及所使用的库的版本。当提交 bug 报告时,也会系统地要求提供此信息:$ 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 个开发版本。开发版本不适用于生产环境(除非您确切地知道自己在做什么)。稳定版本将显示为 3 位数字版本,例如 "1.5.14-16f863",表示在 1.5 版本之上进行的第 14 个修复级别。这是一个生产就绪版本。- 发布日期:2015/10/08。以通用的年/月/日格式表示。这里的 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 变量中指示了正确的系统时可用。强烈建议在 Linux 上使用 "epoll" 机制,强烈建议在 BSD 上使用 kqueue 机制。缺少它们将导致使用 poll() 甚至 select(),在处理大量连接时会导致 CPU 使用率过高。
HAProxy 支持优雅停止和强制停止。强制停止很简单,当向 haproxy 进程发送 SIGTERM 信号时,它会立即退出,所有已建立的连接都会关闭。优雅停止由向 haproxy 进程发送 SIGUSR1 信号触发。它仅包括解除侦听端口的绑定,但继续处理现有连接直到它们关闭。一旦最后一个连接关闭,进程就会退出。强制停止方法用于服务管理脚本的 "stop" 或 "restart" 操作。优雅停止用于 "reload" 操作,该操作尝试无缝地在新进程中重新加载新配置。在重新加载或重启期间,新 haproxy 进程本身可能会发送这两种信号,因此它们会在最晚可能的时刻发送,并且仅在绝对必要时发送。这就是分别由 "-st"(强制)和 "-sf"(优雅)选项执行的操作。在主-工作模式下,不需要启动新的 haproxy 进程来重新加载配置。主进程对 SIGUSR2 信号做出响应,通过使用 -sf 参数后跟工作进程的 PID 来重新执行自身。然后主进程将解析配置文件并 fork 新的工作进程。为了更好地理解这些信号的用法,理解整个重启机制很重要。首先,一个现有的 haproxy 进程正在运行。管理员使用特定于系统的命令,如 "/etc/init.d/haproxy reload",来表示他们希望使新配置文件生效。接下来发生的是:首先,服务脚本(/etc/init.d/haproxy 或等效脚本)将使用 "haproxy -c" 验证配置文件是否正确解析。之后,它将尝试使用 "-st" 或 "-sf" 以此配置文件启动 haproxy。然后 HAProxy 尝试绑定到所有侦听端口。如果发生任何致命错误(例如:地址不存在于系统上、权限被拒绝),进程将以错误退出。如果套接字绑定因端口已被使用而失败,那么进程将首先向 "-st" 或 "-sf" pid 列表中的所有 pid 发送 SIGTTOU 信号。这就是所谓的 "pause" 信号。它指示所有现有 haproxy 进程暂时停止侦听端口,以便新进程可以重试绑定。在此期间,旧进程继续处理现有连接。如果绑定仍然失败(例如,因为端口与另一个守护进程共享),那么新进程将向旧进程发送 SIGTTIN 信号,指示它们恢复操作,就像什么都没有发生一样。旧进程将重新开始侦听端口并继续接受连接。请注意,此机制依赖于系统,并且某些操作系统可能不支持多进程模式。如果新进程成功绑定到所有端口,那么它将发送 SIGTERM(在 "-st" 的情况下是强制停止)或 SIGUSR1(在 "-sf" 的情况下是优雅停止)信号到所有进程,通知它们现在由它负责操作,并且旧进程将不得不退出,要么立即退出,要么一旦它们完成工作就退出。重要的是要注意,在此期间,可能会有两个短暂的几毫秒窗口,在此期间,在高负载下可能会注意到一些连接失败。通常观察到的故障率大约是每秒 10000 个新连接的重新加载操作中发生 1 次故障,这意味着一个重度负载的站点以每秒 30000 个新连接运行,在每次重新加载时可能会看到大约 3 个连接失败。发生这种情况的两种情况是:- 如果新进程由于旧进程的存在而绑定失败,它将首先必须经历 SIGTTOU+SIGTTIN 序列,该序列对于几十个前端通常持续约一毫秒,在此期间某些端口将不会绑定到旧进程,也不会绑定到新进程。HAProxy 在支持 SO_REUSEPORT 套接字选项的系统上解决了这个问题,因为它允许新进程在不先要求旧进程取消绑定的情况下进行绑定。大多数 BSD 系统几乎一直支持这一点。Linux 在 2.0 版本中支持它,并在 2.2 版本左右放弃了它,但当时有一些补丁流传。它在内核 3.9 中重新引入,因此如果您观察到的连接失败率高于上述提到的,请确保您的内核是 3.9 或更新版本,或者相关的补丁已向后移植到您的内核(不太可能)。- 当旧进程关闭侦听端口时,内核可能并不总是重新分发套接字积压中剩余的任何待处理连接。在高负载下,SYN 数据包可能发生在套接字关闭之前,并将导致向客户端发送 RST 数据包。在某些关键环境中,即使一个丢包也不能接受,这些情况有时会通过防火墙规则来处理,在重新加载期间阻止 SYN 数据包,迫使客户端重新传输。这完全依赖于系统,因为某些系统可能能够访问其他侦听队列并避免此 RST。第二种情况涉及来自客户端的 ACK,它在一个本地套接字上,该套接字在关闭前处于 SYN_RECV 状态。此 ACK 将导致 RST 数据包,而 haproxy 进程仍未意识到它。这一个更难摆脱,尽管如上所述的防火墙过滤规则在重启进程前一秒钟左右应用时效果很好。对于绝大多数用户来说,此类丢包永远不会发生,因为他们的负载不足以触发竞态条件。对于大多数高流量用户来说,只要他们的系统至少正确支持 SO_REUSEPORT,失败率仍然在噪声范围内。
为了确保所有传入连接都能成功得到服务,HAProxy 在加载时会计算进程生命周期内所需文件描述符的总数。一个普通的 Unix 进程默认通常获得 1024 个文件描述符,而特权进程可以自行提高此限制。这是将 HAProxy 以 root 用户身份启动并允许其调整限制的原因之一。1024 个文件描述符的默认限制大致允许处理约 500 个并发连接。计算基于全局 `maxconn` 参数,该参数限制了每个进程的总连接数、监听器数量、启用了健康检查的服务器数量、代理检查、对等节点、日志记录器以及可能的一些其他技术要求。一个简单的粗略估计是将 `maxconn` 值简单地加倍,再加上几十个,即可获得所需文件描述符的大致数量。最初 HAProxy 不知道如何计算此值,因此必须在全局部分使用“ulimit-n”设置传递该值。这解释了为什么即使在今天,许多配置中仍然存在此设置。不幸的是,它经常被错误计算,导致在接近 `maxconn` 时连接失败,而不是在等待所需资源时限制传入连接。因此,重要的是移除可能从非常旧版本中遗留下来的任何“ulimit-n”设置。提高文件描述符的数量以接受甚至中等负载是强制性的,但这需要一些特定于操作系统的调整。首先,`select()` 轮询系统限制为 1024 个文件描述符。实际上,在 Linux 上,它曾经能够处理更多,但由于某些操作系统附带了过于严格的 SELinux 策略,禁止使用超过 1024 个文件描述符的 `select()`,HAProxy 现在在这种情况下拒绝启动,以避免运行时出现任何问题。在所有支持的操作系统上,`poll()` 都可用,并且不受此限制的影响。它会自动选择,因此无需进行任何操作即可获得有效配置。但是,当文件描述符数量增加时,`poll()` 会变得非常缓慢。虽然 HAProxy 会尽最大努力限制这种性能影响(例如,通过使用内部文件描述符缓存和批量处理),但一个经验法则是,使用 `poll()` 处理超过一千个并发连接会消耗大量 CPU。对于基于内核 2.6 及以上版本的 Linux 系统,将使用 `epoll()` 系统调用。它是一种更具可扩展性的机制,依赖于内核中的回调,保证了唤醒时间恒定,而与注册的被监控文件描述符的数量无关。只要 HAProxy 是为 Linux 版本之一构建的,它就会在检测到时自动使用。可以使用“haproxy -vv”来验证其是否存在和支持。对于支持它的 BSD 系统,`kqueue()` 可用作替代方案。它比 `poll()` 快得多,甚至由于其批量处理更改的能力,比 `epoll()` 略快。至少 FreeBSD 和 OpenBSD 支持它。与 Linux 的 `epoll()` 一样,其支持和可用性会在“haproxy -vv”的输出中报告。拥有一个好的轮询器是一回事,但进程必须能够达到限制。HAProxy 启动时,会立即设置新进程的文件描述符限制并验证是否成功。如果失败,它会在 fork 之前报告,以便管理员可以看到问题。只要进程是以 root 用户身份启动的,就没有理由会失败。但是,如果进程是由非特权用户启动的,则可能失败。如果出于某种令人信服的原因*不*以 root 用户身份启动 haproxy(例如,由最终用户或按应用程序帐户启动),那么系统管理员可以为该特定用户提高文件描述符限制。通过从用户的命令行发出“ulimit -n”可以验证设置的有效性。它应该反映新的限制。警告:当一个非特权用户的限制在其帐户中更改时,相当普遍的是,这些值仅在用户登录时考虑,而在系统启动时运行的某些脚本或 crontab 中根本不考虑。这完全取决于操作系统,请记住在使用这种方式运行 haproxy 时,在启动 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 在单核上可以每秒处理约 80000 次端到端连接的建立和关闭。当一个核心饱和时,典型数据为: - 95% 系统,5% 用户,用于长 TCP 连接或大型 HTTP 对象 - 85% 系统和 15% 用户,用于短 TCP 连接或小型 HTTP 对象(关闭模式) - 70% 系统和 30% 用户,用于小型 HTTP 对象(keep-alive 模式) 规则处理和正则表达式的数量会增加用户空间部分。防火墙规则、连接跟踪、系统中的复杂路由表的出现会增加系统部分。在大多数系统上,在网络传输期间观察到的 CPU 时间可以分为 4 部分: - 中断部分,涉及 I/O 接收时执行的所有处理,甚至在目标进程已知之前。通常 Rx 数据包计入中断。在某些系统(如 Linux)上,中断处理可能会推迟到专用线程,它可能显示为 `softirq`,线程名为 `ksoftirqd/0`(针对 CPU 0)。处理此负载的 CPU 通常由硬件设置定义,尽管在 `softirq` 的情况下,通常可以将处理重新映射到另一个 CPU。此中断部分通常被视为寄生性的,因为它与任何进程无关,但实际上是为了准备进程的工作而进行的一些处理。 - 系统部分,涉及使用从用户空间调用的内核代码执行的所有处理。例如,系统调用被计为系统。所有同步传输的 Tx 数据包将被计为系统时间。如果由于队列填满而必须延迟某些数据包,则它们可能稍后在中断上下文中进行处理(例如,在收到打开 TCP 窗口的 ACK 时)。 - 用户部分,仅在用户空间中运行应用程序代码。HAProxy 仅在此部分运行,尽管它大量使用系统调用。规则处理、正则表达式、压缩、加密都会增加用户部分的 CPU 消耗。 - 空闲部分,这是 CPU 在无事可做时执行的操作。例如,HAProxy 等待传入连接,或等待一些数据离开,这意味着系统正在等待客户端的 ACK 来推送这些数据。在实际的 HAProxy 活动方面,通常(但完全不精确)合理地认为中断/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` 下分配。许多网络接口支持多队列和多中断。通常,将它们分布在少量 CPU 核心上会有帮助,前提是它们都共享相同的 L3 缓存。请务必停止 `irq_balance`,因为它在这种工作负载下总是会产生最坏的结果。对于由大量 SSL 流量或大量压缩组成的用户 CPU 密集型工作负载,可能值得使用多个专用进程来处理特定任务,尽管这里没有通用规则,需要进行实验。为了增加 CPU 容量,可以通过在全局部分使用“nbproc”指令,使 HAProxy 运行多个进程。但这也有一些限制: - 健康检查是按进程运行的,因此目标服务器将接收与运行进程数量相同的检查; - `maxconn` 值和队列是按进程划分的,因此必须设置正确的值以避免服务器过载; - 出站连接应避免使用端口范围以避免冲突; - `stick-tables` 是按进程划分的,并且不同进程之间不共享; - 每个 `peers` 部分一次只能在一个进程上运行; - CLI 操作一次只能作用于一个进程。考虑到这一点,最简单的设置通常包括运行一个在多个进程上运行并负责繁重处理的第一层,然后将流量传递给在单个进程中运行的第二层。此机制适用于 SSL 和压缩,这两种都是 CPU 密集型功能。实例可以通过 UNIX 套接字(比 TCP 套接字便宜且不浪费端口)轻松链接,以及代理协议,该协议可用于将客户端信息传递给下一阶段。这样做时,通常最好将所有单进程任务绑定到进程 1,将额外任务绑定到后续进程,因为这样可以更容易地为不同机器生成相似的配置。在 Linux 版本 3.9 及更高版本中,当每个进程使用同一 IP:port 上的不同监听套接字时,在多进程模式下运行 HAProxy 会更有效;这将使内核在所有进程之间均匀分配负载,而不是同时唤醒它们。有关更多信息,请参阅配置手册中“bind”关键字行的“process”选项。
对于日志记录,HAProxy 始终依赖于 syslog 服务器,因为它不执行任何文件系统访问。使用它的标准方法是通过 UDP 将日志发送到日志服务器(默认端口为 514)。通常配置为 127.0.0.1,本地 syslog 守护程序正在运行,但它也通过网络用于将日志记录到中央服务器。中央服务器提供了额外的优势,尤其是在希望以到达顺序合并日志的主动-主动场景中。HAProxy 也可能使用 UNIX 套接字将日志发送到本地 syslog 守护程序,但不推荐这样做,因为如果 syslog 服务器在 haproxy 运行时重新启动,套接字将被替换,并且新的日志将丢失。由于 HAProxy 将被隔离在 chroot 监狱中,它将无法重新连接到新套接字。在实际使用中也观察到 UNIX 套接字使用的日志缓冲区非常小,即使在非常轻负载下也会导致消息丢失。但这对测试来说可能还可以。建议将以下指令添加到“global”部分,以使 HAProxy 使用“local0”设施记录到本地守护程序: log 127.0.0.1:514 local0 然后将以下指令添加到每个“defaults”部分或每个前端和后端部分: 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()` 发送的日志消息。如果它们没有出现,请使用 strace 启动 haproxy。如果您仍然看不到任何日志,则肯定说明您的配置存在问题。 - 运行 `tcpdump` 来监视端口 514,例如在回环接口上(如果流量是本地发送的):“tcpdump -As0 -ni lo port 514”。如果在那里看到数据包,则证明它们已被发送,然后需要对 `syslogd` 守护程序进行故障排除。虽然流量日志是从前端(接受传入连接的地方)发送的,但后端也需要能够发送日志,以便在健康检查后报告服务器状态更改。有关所有可能的日志设置的更多信息,请查阅 HAProxy 的配置手册。选择一个其他守护程序未使用的设施非常方便。HAProxy 示例通常建议使用“local0”进行流量日志,“local1”进行管理日志,因为它们在实际使用中很少见到。也可以使用单个设施。拥有单独的日志便于日志分析,但也要记住,日志有时可能包含机密信息,因此不能与其他可能意外提供给未经授权人员的日志混合。为了在不严重影响服务器容量的情况下进行现场故障排除,建议使用 HAProxy 提供的“halog”实用程序。这是一种类似 grep 的实用程序,设计用于以非常高的数据速率处理 HAProxy 日志文件。典型速率在每秒 1 到 2 GB 日志之间。它能够仅提取某些日志(例如,搜索特定类别的 HTTP 状态码、连接终止状态、按响应时间范围搜索、仅查找错误),计数行,将输出限制为一定数量的行,并执行一些更高级的统计信息,例如按响应时间或错误计数对服务器进行排序,按时间或计数对 URL 进行排序,按访问计数对客户端地址进行排序,等等。它非常方便,可以快速发现异常,例如一个机器人一直在访问网站,并将其屏蔽。可以查询 HAProxy 的状态。最常用的机制是 HTTP 统计页面。此页面还为监控工具提供了一种备选的 CSV 输出格式。在 Unix 套接字上也提供了相同的格式。统计信息被重新分组为标记为域的类别,对应于 HAProxy 的多个组件。有两个可用的域:proxy 和 resolvers。如果未指定,则选择 proxy 域。请注意,HTTP 页面上只打印代理统计信息。
统计数据既可以从unix套接字读取,也可以从HTTP页面读取。这两种方式都提供CSV格式,其字段如下。第一行以井号('#')开头,每个逗号分隔的字段只有一个单词,表示列的标题。从第二行开始的所有其他行都使用经典的CSV格式,以逗号作为分隔符,以双引号('"')作为可选的文本分隔符,但仅当被包含的文本有歧义时(如果它包含引号或逗号)。文本中的双引号字符('"')会翻倍('""'),这是大多数工具都能识别的格式。为了不破坏使用硬编码列位置的工具,请不要在此之前插入任何列。对于代理统计信息,每个字段名后面都用括号指定该字段可能具有值的类型。类型包括L(监听器)、F(前端)、B(后端)和S(服务器)。有一组固定的静态字段,它们始终以相同的顺序可用。包含字符'-'的列分隔了静态字段的结束,之后字段的存在或顺序不保证。以下是使用代理统计信息域的静态字段列表:0. pxname [LFBS]:代理名称1. svname [LFBS]:服务名称(FRONTEND代表前端,BACKEND代表后端,任何名称代表服务器/监听器)2. qcur [..BS]:当前队列请求。对于后端,这报告了未分配服务器的数量。3. qmax [..BS]:qcur的最大值4. scur [LFBS]:当前会话5. smax [LFBS]:最大会话6. slim [LFBS]:配置的会话限制7. stot [LFBS]:累积会话数8. bin [LFBS]:传入字节9. bout [LFBS]:传出字节10. dreq [LFB.]:因安全问题而拒绝的请求。- 对于tcp,这是因为匹配了tcp-request内容规则。- 对于http,这是因为匹配了http-request或tarpit规则。11. dresp [LFBS]:因安全问题而拒绝的响应。- 对于http,这是因为匹配了http-request规则或“option checkcache”。12. ereq [LF..]:请求错误。可能的原因包括:- 客户端提前终止,在请求发送之前。- 客户端读取错误- 客户端超时- 客户端关闭连接- 客户端的各种无效请求。- 请求被tarpitted。13. econ [..BS]:尝试连接到后端服务器时遇到错误的请求数。后端统计数据是该后端所有服务器统计数据的总和,加上任何未与特定服务器关联的连接错误(例如后端没有活动服务器)。14. eresp [..BS]:响应错误。srv_abrt也将在此处计算。其他一些错误包括:- 客户端套接字写入错误(服务器统计数据不计算此项)- 应用过滤器到响应失败。15. wretr [..BS]:连接到服务器被重试的次数。16. wredis [..BS]:请求被重新调度到另一台服务器的次数。服务器值计算了该服务器被切换离开的次数。17. status [LFBS]:状态(UP/DOWN/NOLB/MAINT/MAINT(via)/MAINT(resolution)...)18. weight [..BS]:总有效权重(后端),有效权重(服务器)19. act [..BS]:活动服务器数量(后端),服务器处于活动状态(服务器)20. bck [..BS]:备份服务器数量(后端),服务器为备份(服务器)21. chkfail [...S]:失败检查次数。(仅计算服务器处于UP状态时失败的检查次数。)22. chkdown [..BS]:UP->DOWN转换次数。后端计数器计算整个后端变为DOWN的转换次数,而不是每个服务器计数器的总和。23. lastchg [..BS]:自上次UP<->DOWN转换以来的秒数24. downtime [..BS]:总停机时间(秒)。后端的值是整个后端的停机时间,而不是服务器停机时间的总和。25. qlimit [...S]:服务器配置的最大队列数,如果值为0(默认,表示无限制)则为空。26. pid [LFBS]:进程ID(0为第一个实例,1为第二个,...)27. iid [LFBS]:唯一代理ID28. sid [L..S]:服务器ID(在代理内部唯一)29. throttle [...S]:服务器当前的节流百分比,当慢启动激活时,如果不在慢启动状态则无值。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层检查有条件通过,例如404并禁用404L7TOUT -> 第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”参数,通常为171. agent_fall [...S]:代理的“fall”参数,通常为172. 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_rate79. conn_tot [.F..]:累积连接数80. intercepted [.FB.]:累积拦截请求数(监控、统计)81. dcon [LF..]:被“tcp-request connection”规则拒绝的请求82. dses [LF..]:被“tcp-request session”规则拒绝的请求83. wrew [LFBS]:累积的无效报头重写警告次数84. connect [..BS]:累积的连接建立尝试次数85. reuse [..BS]:累积的连接重用次数86. cache_lookups [.FB.]:累积的缓存查找次数87. cache_hits [.FB.]:累积的缓存命中次数88. srv_icur [...S]:当前可重用空闲连接数89. src_ilim [...S]:可用空闲连接数的限制90. qtime_max [..BS]:观察到的最大队列时间(毫秒)91. ctime_max [..BS]:观察到的最大连接时间(毫秒)92. rtime_max [..BS]:观察到的最大响应时间(毫秒)(TCP为0)93. ttime_max [..BS]:观察到的最大总会话时间(毫秒)94. eint [LFBS]:累积内部错误数95. idle_conn_cur [...S]:当前不安全的空闲连接数96. safe_conn_cur [...S]:当前安全的空闲连接数97. used_conn_cur [...S]:当前正在使用的连接数98. need_conn_est [...S]:估计需要的连接数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数据。
“show info”和“show stat”都支持一种模式,其中每个输出值都带有其类型以及足够的信息来了解该值应如何在进程之间聚合以及它是如何演变的。在所有情况下,输出都是每行一个值,所有信息都按冒号(':')分隔的字段。第一列指定正在转储的对象或指标。其格式特定于生成此输出的命令,在此部分中不进行描述。通常它将由一系列标识符和字段名组成。第二列包含3个字符,分别表示正在报告的值的来源、性质和范围。第一个字符(来源)指示值是从何处提取的。可能的字符是:M该值是指标。它在一个瞬间有效,并且可能因其性质而变化。S该值是状态。它表示一个离散值,根据定义不能聚合。它可能是服务器的状态(“UP”或“DOWN”)、进程的PID等。K该值是排序键。它表示一个标识符,可用于将某些值分组在一起,因为它是其类别中唯一的。所有内部标识符都是键。某些名称可以列为键,如果它们是唯一的(例如:前端名称是唯一的)。通常键来自配置,尽管其中一些可能是自动分配的。在大多数情况下,键可以被视为等同于配置。C该值来自配置。某些配置值在输出中有意义,例如并发连接限制或cookie名称。根据定义,这些值在从同一配置文件启动的所有进程中都是相同的。P该值来自产品本身。这类值非常少,最常见的用途是报告产品名称、版本和发布日期。这些元素在所有进程之间也是相同的。第二个字符(性质)指示字段所携带信息的性质,以便聚合器可以决定使用什么操作来聚合多个值。可能的字符是:A该值表示自上次事件以来的持续时间。这与持续时间略有不同,因为年龄是根据当前日期自动计算的。一个典型的例子是服务器上次会话发生在多久以前。年龄通常通过取最小值来聚合,并且不需要存储。a该值表示已平均值。平均响应时间和服务器权重属于此类。平均值通常可以在进程之间进行平均。C该值表示累积计数器。此类度量会不断增加,直到回绕。某些监控协议需要区分计数器和仪表以报告不同的类型。通常计数器可以简单地相加,因为它们代表事件或卷。此类指标的示例是连接数或字节数。D该值表示状态的持续时间。这有几种用法,其中大部分包括上次健康检查所花费的时间以及服务器花费的停机时间。持续时间通常不相加,大多数时候会保留最大值来计算SLA。G该值表示仪表。这是一个瞬间的度量。内存使用量或当前活动连接数属于此类。此类指标在聚合时通常相加。L该值表示限制(通常是配置的限制)。根据性质,限制更难聚合,因为它们特定于检索它们的位置。在某些情况下,它们可以相加或单独保留。M该值表示最大值。通常,它适用于一个仪表并保留已知最高值。此类指标的一个示例可能是产品生命周期中遇到的并发连接的最大数量。为了正确聚合最大值,您需要输出一个范围,从所有最大值的最大值到所有值的总和。确实无法知道它们是否同时出现。m该值表示最小值。通常,它适用于一个仪表并保留已知最小值。此类指标的一个示例可能是产品生命周期中遇到的最小可用内存池数量。为了正确聚合最小值,您需要输出一个范围,从所有最小值的最小值到所有值的总和。确实无法知道它们是否同时出现。N该值表示名称,因此它是一个字符串。它用于报告代理名称、服务器名称和cookie名称。名称具有配置或键作为其来源,并且在所有进程中应相同。O该值表示自由文本输出。各种命令的输出、健康检查的返回值、节点描述都属于此类。R该值表示事件速率。这是一个瞬间的度量。它与仪表非常相似,除了接收方知道该度量移动缓慢,并且可以选择不保留所有值。此类指标的一个示例是每秒连接数的测量值。此类指标在聚合时通常相加。T该值表示日期或时间。发出当前日期的字段将属于此类。聚合此类信息的方法留作实现选择。目前没有字段使用此类型。第三个字符(范围)指示值反映的范围。某些元素可以按进程,而其他元素可以按配置或按系统。区分很重要,可以知道单个值是否应在聚合期间保留,还是必须聚合值。目前支持以下字符:C该值对整个节点集群有效,即通过对等协议通信的节点集。例如,可能是存在于与对等节点复制的粘性表中的条目数。目前没有指标使用此范围。P该值仅对报告它的进程有效。大多数指标使用此范围。S该值对整个服务有效,即从同一配置文件启动的进程集。所有来自配置的指标都使用此范围。其他一些指标也可能使用它来表示某些共享资源(例如,共享SSL缓存统计信息)。s该值对整个系统有效,例如系统的名称、当前日期或资源使用情况。目前没有指标使用此范围。消费者将拥有这3个字符的足够信息,以确定如何在多个进程之间准确地报告聚合信息。在此列之后,第三列指示字段的类型,包括“s32”(有符号32位整数)、“s64”(有符号64位整数)、“u32”(无符号32位整数)、“u64”(无符号64位整数)、“str”(字符串)。在解析值之前了解类型很重要,以便正确读取它。例如,包含数字的字符串仍然是字符串而不是整数(例如,由检查提取的错误代码)。然后第四列是值本身,根据其类型进行编码。字符串直接在冒号后面转储,没有前导空格。如果字符串包含冒号,它将正常显示。这意味着不应仅围绕冒号拆分输出,否则某些检查输出或服务器地址可能会被截断。
统计套接字默认未启用。要启用它,有必要在haproxy配置的全局部分添加一行。建议添加第二行以设置更长的超时时间,这在手动发出命令时总是受欢迎的: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库处理,该库支持行编辑和历史记录,这在发出重复命令(例如:watch a counter)时非常方便。套接字支持两种操作模式:- 交互式- 非交互式当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 <-- master,切换到当前工作进程 [0:00:01:03] 11955> @!11942 <-- 当前工作进程,切换到旧工作进程 [0:00:02:17] 11942> @ <-- 旧工作进程,切换回master [0:00:01:10] master>由于可以一次发出多个命令,haproxy使用空行作为分隔符来标记每个命令的输出结束,并确保没有命令会在输出中产生空行。因此,脚本可以轻松地解析输出,即使多个命令在一行上管道传输。某些命令可能需要一个可选的负载。要将其添加到命令中,第一行需要以“<<\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"。
中止并销毁一个临时的 SSL 证书更新事务。另见 "set ssl cert" 和 "commit ssl cert"。
中止并销毁一个临时的 CRL 文件更新事务。另见 "set ssl crl-file" 和 "commit ssl crl-file"。
向 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" 命令。
将条目添加到映射<map>以将值<value>与键<key>关联。此命令不验证条目是否已存在。它主要用于在“clear”或“prepare”操作之后填充映射。条目将添加到ACL的当前版本,除非使用“@<ver>”指定了特定版本。此版本号必须由“prepare acl”预先分配,并且将介于“curr_ver”和“next_ver”之间,这些信息来自“show acl”的输出。使用特定版本号添加的条目在执行“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 >
实例化一个附加到后端<backend>的新服务器。<server>名称不得已在后端使用。对使用动态负载均衡算法的后端施加了特殊限制。可以使用服务器配置文件语句的关键字子集来配置服务器行为。另请注意,不会从同一后端中假设的“default-server”语句中重用任何设置。当前,动态服务器以“none”init-addr方法静态初始化。这意味着,即使服务器创建将被验证,如果指定了FQDN作为地址,也不会进行解析。为了支持重新加载操作,期望通过CLI创建的服务器也应手动插入相关的haproxy配置文件中。不在配置中的动态服务器在重新加载操作后不会恢复。动态服务器可以使用“track”关键字来跟踪配置中另一台服务器的检查状态。但是,不能跟踪另一个动态服务器。这是为了确保即使在动态服务器删除的情况下,跟踪链也能保持一致。使用“check”关键字来启用健康检查支持。请注意,健康检查默认禁用,必须使用“enable health”命令独立于服务器启用。对于代理检查,请使用“agent-check”关键字和“enable agent”命令。请注意,在这种情况下,服务器可以通过代理激活,具体取决于报告的状态,而无需显式的“enable server”命令。这也意味着在删除具有代理检查的动态服务器时需要格外小心。应首先通过“disable agent”禁用代理,以便能够将服务器置于所需的维护模式,然后再删除。使用大量动态服务器时,可能会达到fd限制。在这种情况下,请参考“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 - 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行相似,请参阅其单独的文档以了解详细信息。
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 -
在 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”级别的套接字上发出。
从 ACL <acl> 中删除所有条目。<acl> 是由 "show acl" 返回的 #<id> 或 <name>。请注意,如果引用 <acl> 是一个名称并且与 map 共享,则该 map 也将被清除。默认情况下,只清除 ACL 的当前版本(正在匹配的版本)。但是,可以使用“@”后跟版本号来指定另一个版本。
从 map <map> 中删除所有条目。<map> 是由 "show map" 返回的 #<id> 或 <name>。请注意,如果引用 <map> 是一个名称并且与 acl 共享,则该 acl 也将被清除。默认情况下,只清除 map 的当前版本(正在匹配的版本)。但是,可以使用“@”后跟版本号来指定另一个版本。
从 stick-table <table> 中移除条目。这通常用于解除对某些用户被滥用拒绝访问服务的封锁,但也可用于清除与即将被替换的服务器匹配的一些粘性条目(有关详细信息,请参阅下面的“show table”)。请注意,有时条目的移除会被拒绝,因为它当前正被一个会话跟踪。在会话结束后几秒钟后重试通常足够了。如果没有提供选项参数,则会移除所有条目。当使用“data.”形式时,会移除与使用存储数据应用的过滤器匹配的条目(请参阅<a href="#4.2">第 4.2 节</a>中的“stick-table”)。必须在 <type> 中指定存储的数据类型,并且该数据类型必须存储在表中,否则会报告错误。数据根据 <operator> 与 64 位整数 <value> 进行比较。运算符与 ACL 中的相同:- eq:匹配数据等于此值的所有条目 - ne:匹配数据不等于此值的所有条目 - le:匹配数据小于或等于此值的所有条目 - ge:匹配数据大于或等于此值的所有条目 - lt:匹配数据小于此值的所有条目 - gt:匹配数据大于此值的所有条目当使用 key 形式时,会移除条目 <key>。键必须与表类型相同,目前仅限于 IPv4、IPv6、整数和字符串。当使用 ptr 形式时,会移除条目 <ptr>。<ptr> 以 0xffff 的形式编写,并且必须对应于先前“<a href="#show%20table">show table</a>”命令返回的地址。使用指针匹配条目可能很有用,如果由于键为空或 CLI 上的字符不兼容而无法使用键匹配条目。
$ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a4c: key=127.0.0.1 use=0 exp=3594729 gpc0=0 conn_rate(30000)=1 \ bytes_out_rate(60000)=187 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 >>> 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”命令创建的。替换是原子的。它包括将当前版本原子地更新为指定版本,这将立即导致其他版本中的所有条目不可见,而新版本中的所有条目可见。还可以通过先调用“prepare acl”然后提交而不添加任何条目来使用此命令执行原子删除所有可见 ACL 条目的操作。如果引用的 <acl> 是一个也用作 map 的名称,则无法使用此命令。在这种情况下,必须改用“commit map”命令。commit map @<ver> <map> 提交 map <map> 版本 <ver> 所做的所有更改,并删除所有先前版本。<map> 是“show map”返回的 #<id> 或 <name>。版本号必须在“show map”中报告的“curr_ver”+1 和“next_ver”之间。如果需要,可以使用“show map @<ver> <map>”查看要提交到 map 的内容。指定的版本号通常是通过“prepare map”命令创建的。替换是原子的。它包括将当前版本原子地更新为指定版本,这将立即导致其他版本中的所有条目不可见,而新版本中的所有条目可见。还可以通过先调用“prepare map”然后提交而不添加任何条目来使用此命令执行原子删除所有可见 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”。
提交临时的 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_STRICT,另一些取决于 DEBUG_GLITCHES。该命令接受多个参数的组合,其中一些定义操作,另一些定义过滤器:- bug 启用列出 BUG_ON() 语句的计数器- cnt 启用列出 COUNT_IF() 语句的计数器- chk 启用列出 CHECK_IF() 语句的计数器- glt 启用列出 COUNT_GLITCH() 语句的计数器- all 启用显示从未触发的计数器(值为 0)- reset 操作:重置所有指定的计数器- show 操作:显示所有指定的计数器默认情况下,操作是“show”以显示计数器,并且列出的计数器是所有类型且值为非零的。当没有指定其他操作时,“show”命令是隐式的,仅用于方便从脚本生成命令。输出以一个整数计数器开头,后跟计数器类型(大写),然后是代码中的位置(文件:行号),函数名,以及可选的“: ”后跟描述。请注意,输出格式可能在主版本之间发生变化,并且可能会将新类型和条目反向移植到稳定版本,以改进调试功能。任何对它们的监视都应非常宽容和允许,最好不要这样做。通常,最终用户不会使用此命令,但开发人员在尝试找出问题原因时,寻找 CNT 或 GLT 条目,可能会邀请他们这样做。顺便说一句,非零的“CHK”条目是不应发生的,并且应该报告给开发人员,因为它们可能表明代码中的某些假设不正确。
调用开发者专用的命令。仅在以专家模式(expert mode)运行的 CLI 连接上支持(参见 "expert-mode on")。此类命令极其危险且不可恢复,任何误用都可能导致进程崩溃。它们仅供专家使用,除非得到明确指示,否则绝对不应使用。其中一些命令仅在 haproxy 编译时定义了 DEBUG_DEV 时才可用,因为它们可能存在安全隐患。所有这些命令都需要管理员权限,并且为了避免不熟悉源代码的人员滥用,我们特意没有将它们写入文档。
从 ACL <acl> 中删除所有与键 <key> 对应的 ACL 条目。<acl> 是由 "show acl" 命令返回的 #<id> 或 <name>。如果使用 <ref>,此命令仅删除列出的引用。引用可以通过列出 ACL 的内容来找到。请注意,如果引用 <acl> 是一个名称并且与一个 map 共享,则该条目也将在 map 中被删除。
从 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" 指令直接引用的证书无效。
从 HAProxy 中删除一个证书存储。该证书必须是未使用的,并且已从任何 crt-list 或目录中移除。“show ssl cert”显示证书的状态。此删除操作不适用于在配置中通过“crt”指令直接引用的证书。
从 HAProxy 中删除一个 CRL 文件树条目。该 CRL 文件必须未被使用,并已从任何 crt-list 中移除。"show ssl crl-file" 命令显示 CRL 文件的状态。此删除操作对通过配置中的 "crl-file" 指令直接引用的证书无效。
删除 crt-list 中的一个条目。这将删除前端中用于此条目的所有 SNI。如果一个证书在 crt-list 中被多次使用,您需要提供想要删除的行号。要显示行号,请使用 "show ssl crt-list -n <crtlist>"。
移除附加到后端 <backend> 的一个服务器。所有服务器都有资格,但被其他配置元素引用的服务器除外。服务器在删除前必须置于维护模式。如果服务器仍有活动或空闲连接,或者其连接队列不为空,则操作将被取消。
将辅助代理检查标记为临时停止。在代理检查作为辅助检查运行的情况下(由于服务器指令的 agent-check 参数),只有当代理处于启用状态时才会初始化新的检查。因此,disable agent 将阻止任何新的代理检查被启动,直到使用 enable agent 重新启用代理。当代理被禁用时,对在代理启用时启动的辅助代理检查的处理如下:所有会改变权重的结果,特别是 "drain" 或代理返回的权重,都将被忽略。代理检查的其他处理方式保持不变。此功能的动机是允许暂停代理检查的权重更改效果,以便可以使用 set weight 配置服务器的权重,而不会被代理覆盖。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
为后端 <backend> 禁用动态 cookie 的生成。
将前端标记为临时停止。这对应于软重启期间使用的模式:前端释放端口,但如果需要可以再次启用。应谨慎使用此命令,因为一些非 Linux 操作系统无法重新启用它。这旨在用于那些甚至无法想象停止代理但必须修复配置错误的代理的环境中。这样就有可能释放端口并将其绑定到另一个进程以恢复操作。前端将在统计页面上显示为 "STOP" 状态。前端可以通过其名称或其数字 ID(前缀为井号 '#')指定。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
将主健康检查标记为临时停止。这将禁用发送健康检查,并且最后的健康检查结果将被忽略。服务器将处于未检查状态并被认为是 UP,除非辅助代理检查强制其 down。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
将服务器标记为 DOWN 进行维护。在此模式下,直到服务器离开维护模式,否则不会再对其进行检查。如果该服务器被其他服务器跟踪,那些服务器在维护期间也将被设置为 DOWN。在统计页面上,处于维护状态的服务器将显示 "MAINT" 状态,其跟踪服务器将显示 "MAINT(via)" 状态。后端和服务器都可以通过其名称或其数字 ID(前缀为井号 '#')指定。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
生成一个 stats-file,可用于在启动时预加载 haproxy 计数器值。更多详情请参见 "Stats-file" 部分。
恢复临时停止的辅助代理检查。有关临时启动和停止辅助代理的效果的详细信息,请参见 "disable agent"。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
为后端 <backend> 启用动态 cookie 的生成。还必须提供一个密钥。
恢复一个临时停止的前端。某些监听端口可能无法再次绑定(例如:自'disable frontend'操作以来,另一个进程占用了它们)。如果发生这种情况,将显示错误。某些操作系统可能无法恢复被禁用的前端。前端可以通过其名称或其数字 ID(前缀为井号 '#')指定。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
恢复一个临时停止的主健康检查。这将再次启用发送健康检查。详情请参见 "disable health"。此命令受限,并且只能在配置为 "admin" 级别的套接字上发出。
如果服务器之前被标记为 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 -
此命令类似于 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 -
在 map <map> 或 ACL <acl> 中查找值 <value>。<map> 或 <acl> 是“show map”或“show acl”返回的 #<id> 或 <name>。此命令返回与此 map 相关的所有匹配模式。这对于调试 map 和 ACL 有用。输出格式由每个匹配类型的行组成。每行由空格分隔的单词组成。前两个单词是:<match method>:应用的匹配方法。它可以是“found”、“bool”、“int”、“ip”、“bin”、“len”、“str”、“beg”、“sub”、“dir”、“dom”、“end”或“reg”。<match result>:结果。可以是“match”或“no-match”。只有当模式匹配一个条目时,才会返回后续单词。<index type>:“tree”或“list”。内部查找算法。<case>:“case-insensitive”或“case-sensitive”。对大小写的解释。<entry matched>:match="<entry>"。返回匹配的模式。这在使用正则表达式时很有用。最后两个单词用于显示返回值及其类型。“acl”情况下的模式不存在。return=nothing:没有返回,因为没有“map”。return="<value>":以字符串格式返回的值。return=cannot-display:无法将值转换为字符串。type="<type>":返回的样本的类型。
显示进程范围变量 'name' 的存在、类型和内容。只有进程范围的变量是可读的,所以名称必须以 'proc.' 开头,否则将找不到任何变量。此命令需要 "operator" 或 "admin" 级别。
报告后端 <backend> 中服务器 <server> 的当前权重和初始权重,如果任一不存在则报告错误。初始权重是配置文件中出现的权重。除非当前权重已被更改,否则两者通常相等。后端和服务器都可以通过其名称或其数字 ID(前缀为井号 '#')指定。
打印已知关键字及其基本用法的列表,或与请求的命令匹配的命令。对于未知命令,也会显示相同的帮助屏幕。
发起一个 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" 结合使用。
创建一个新的空 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”命令之前进入交互模式也是一个好主意。
在交互模式下关闭连接。
此命令启用或禁用当前 CLI 会话的“匿名模式”,该模式会将命令输出中某些被视为敏感或机密字段替换为哈希值。这些哈希值保留元素之间足够的连贯性,以帮助开发人员在尝试查找 bug 时识别元素之间的关系,但位数较低(24 位),由于可能匹配的数量很多,因此无法逆转。启用后,如果没有指定密钥,将使用全局密钥(在配置文件中由“anonkey”指定或通过 CLI 命令“set anon global-key”设置)。如果没有设置此类密钥,则会生成一个随机密钥。否则,可以指定用于当前会话的 32 位密钥,例如,重用先前转储中使用的密钥以帮助比较输出。开发人员永远不需要此密钥,并且建议不要共享它,因为它可能允许确认/否定关于某些哈希值可能隐藏的内容的一些猜测。
修改用于生成动态持久性 cookie 的密钥。这将破坏现有会话。
此命令将全局匿名化密钥设置为 <key>,该值必须是 0 到 4294967295 之间的 32 位整数(0 表示禁用全局密钥)。此命令需要管理员权限。
修改 map <map> 中每个键 <key> 对应的值。<map> 是由 "show map" 返回的 #<id> 或 <name>。如果使用 <ref> 代替 <key>,则只更改 <ref> 指向的条目。新值为 <value>。
动态更改指定前端的 maxconn 设置。允许任何正值,包括零,但设置大于全局 maxconn 的值没有太大意义。如果限制增加并且有待处理的连接,它们将立即被接受。如果限制降低到低于当前连接数的水平,新连接的接受将被延迟,直到达到阈值。前端可以通过其名称或其前缀为井号('#')的数字 ID 来指定。
动态更改指定服务器的 maxconn 设置。允许任何正值,包括零,但设置大于全局 maxconn 的值没有太大意义。
在初始全局 maxconn 设置定义的范围内动态更改全局 maxconn 设置。如果它被增加并且有待处理的连接,它们将立即被接受。如果它被降低到低于当前连接数的水平,新连接的接受将被延迟,直到达到阈值。值为零将恢复初始设置。
为指定的子系统启用或禁用 CPU 或内存分析。这相当于在配置文件的 "global" 部分设置或清除 "profiling" 设置。另请参阅 "show profiling"。请注意,手动将任务分析设置为 "on" 会自动重置调度器统计信息,从而允许检查给定时间间隔内的活动。内存分析仅限于某些操作系统(已知在 linux-glibc 目标上有效),并且需要在编译时设置 USE_MEMORY_PROFILING。
更改进程范围的连接速率限制,该限制由全局 'maxconnrate' 设置。值为零表示禁用限制。此限制适用于所有前端,并且更改会立即生效。值以每秒连接数的形式传递。
更改最大输入压缩速率,该速率由全局 'maxcomprate' 设置。值为零表示禁用限制。值以每秒千字节数的形式传递。该值可在 "show info" 的 "CompressBpsRateLim" 行中以字节为单位查看。
更改进程范围的会话速率限制,该限制由全局 'maxsessrate' 设置。值为零表示禁用限制。此限制适用于所有前端,并且更改会立即生效。值以每秒会话数的形式传递。
更改进程范围的 SSL 会话速率限制,该限制由全局 'maxsslrate' 设置。值为零表示禁用限制。此限制适用于所有前端,并且更改会立即生效。值以每秒发送到 SSL 堆栈的会话数的形式传递。它在握手之前应用,以保护堆栈免受握手滥用。
用提供的 IP 地址替换服务器的当前 IP 地址。可选地,可以使用 'port' 参数更改端口。请注意,更改端口也支持从端口映射(表示为 +X 或 -Y)切换或切换到端口映射,前提是为健康检查配置了端口。
强制服务器的代理进入新状态。例如,这对于不考虑某些缓慢的代理检查而立即切换服务器状态非常有用。请注意,如果有跟踪服务器,此更改将传播到它们。
更改服务器代理检查的地址。允许在运行时将代理检查迁移到另一个地址。您可以指定 IP 和主机名,它将被解析。可选地,更改代理端口。
更改用于代理检查的端口。
更改发送到代理检查目标的代理字符串。允许在更改服务器地址时更新字符串以保持两者匹配。
强制服务器的健康状态进入新状态。例如,这对于不考虑某些缓慢的健康检查而立即切换服务器状态非常有用。请注意,如果有跟踪服务器,此更改将传播到它们。
更改用于服务器健康检查的 IP 地址。可选地,更改用于服务器健康检查的端口。
将用于健康检查的端口更改为 <port>
强制服务器的管理状态进入新状态。这对于禁用负载均衡和/或到服务器的任何流量非常有用。将状态设置为 "ready" 会使服务器进入正常模式,该命令等同于 "enable server" 命令。将状态设置为 "maint" 会禁用任何到服务器的流量以及任何健康检查。这等同于 "disable server" 命令。将模式设置为 "drain" 只会从负载均衡中移除服务器,但仍允许其被检查并接受新的持久连接。如果有跟踪服务器,更改将传播到它们。
将服务器的权重更改为参数中传递的值。这与下面的 "set weight" 命令完全等效。
将服务器的 FQDN 更改为参数中传递的值。这要求为该服务器配置并启用了内部运行时 DNS 解析器。
此选项配置到服务器的出向连接的 SSL 加密。关闭时,所有流量都变为明文;健康检查路径不变。此命令已弃用,请改用 "add server" 命令动态创建带或不带 SSL 的新服务器。
更改当前会话期间连接的 stats socket 的严重性输出格式。
此命令是事务系统的一部分,可能需要 "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 -
此命令是事务系统的一部分,可能需要“commit ssl cert”和“abort ssl cert”命令。整个事务系统适用于“show ssl cert”命令显示的任何证书,因此适用于任何前端或后端证书。如果没有正在进行的事务,它将在内存中复制证书 <filename> 到一个临时事务,然后使用负载中的 PEM 文件更新此事务。如果存在具有相同文件名的事务,它将更新此事务。还可以更新与证书链接的文件(.issuer、.sctl、.oscp 等)。修改完成后,您必须使用“commit ssl cert”提交事务。通过 CLI 注入文件时必须小心,因为空行用于通知负载结束。建议注入一个经过清理的 PEM 文件。一种简单的方法是删除所有空行,只保留 PEM 部分中的内容。这可以通过 sed 命令实现。
# 经过一些简单清理 echo -e "set ssl cert localhost.pem <<\n$(sed -n '/^$/d;/-BEGIN/,/-END/p' 127.0.0.1.pem)\n" | \ socat /var/run/haproxy.stat - # 包含提交的完整示例 echo -e "set ssl cert localhost.pem <<\n$(cat 127.0.0.1.pem)\n" | \ socat /var/run/haproxy.stat - echo -e \ "set ssl cert localhost.pem.issuer <<\n $(cat 127.0.0.1.pem.issuer)\n" | \ socat /var/run/haproxy.stat - echo -e \ "set ssl cert localhost.pem.ocsp <<\n$(base64 -w 1000 127.0.0.1.pem.ocsp)\n" | \ socat /var/run/haproxy.stat - echo "commit ssl cert localhost.pem" | socat /var/run/haproxy.stat -
此命令是事务系统的一部分,可能需要 "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 -
此命令用于更新证书的 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
将 <id> 侦听器的下一个 TLS 密钥设置为 <tlskey>。此密钥成为最终密钥,而倒数第二个密钥用于加密(其他密钥仅用于解密)。最旧的 TLS 密钥将被覆盖。<id> 是由 "show tls-keys" 返回的数字 #<id> 或 <file>。<tlskey> 是 base64 编码的 48 位或 80 位 TLS 票证密钥(例如:openssl rand 80 | openssl base64 -A)。
创建或更新表中的 stick-table 条目。如果键不存在,则插入一个条目。请参阅第 4.2 节中的 stick-table,查找 <data_type> 的所有可能值。最常见的用法是动态输入源 IP 地址的条目,并在 gpc0 中设置一个标志以动态阻止 IP 地址或影响其服务质量。可以在单次调用中传递多个 data_types。可以选择使用可选的 ptr 查找而不是键查找现有条目:<ptr> 以 0xffff 的形式编写,并且必须对应于先前“show table”命令返回的地址。使用指针匹配条目可能很有用,如果由于键为空或 CLI 上的不兼容字符而无法使用键匹配条目。
更改当前连接的 CLI 接口超时。这在长时间的调试会话中非常有用,用户需要不断检查一些指标而不会被断开连接。延迟以秒为单位传递。
允许使用表达式 <expression> 或格式字符串 <format> 的结果来设置或覆盖进程范围的变量 'name'。只能使用进程范围的变量,因此名称必须以 'proc.' 开头,否则不会设置任何变量。<expression> 和 <format> 只能涉及“内部”样本获取关键字和转换器,尽管最可能有用的将是 str('something')、int()、简单字符串或其他变量的引用。请注意,命令行解析器不识别引号,因此表达式中的任何空格都必须以反斜杠开头。此命令需要 "operator" 或 "admin" 级别。此命令仅在以实验模式(experimental-mode on)运行的 CLI 连接上受支持。将服务器的权重更改为参数中提供的值。如果值以“%”结尾,则新权重将相对于初始配置的权重。绝对权重允许的范围是 0 到 256。相对权重必须为正数,且生成的绝对权重上限为 256。运行静态负载均衡算法的服务器组中的服务器有更严格的限制,因为权重一旦设置就无法更改。因此,对于这些服务器,唯一接受的值是 0 和 100%(或 0 和初始权重)。更改会立即生效,尽管某些 LB 算法需要一定数量的请求才能考虑更改。此命令的典型用法是通过将服务器的权重设置为零来禁用服务器,然后在更新后将其重新设置为 100% 来重新启用它。此命令受限制,只能在配置为“admin”级别插槽上发出。后端和服务器都可以通过其名称或其数字 ID(以“#”为前缀)来指定。
转储有关 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"。
报告有关内部事件的计数器,这些事件将有助于开发人员,特别是熟悉 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 类型或启动时的 FD 限制。为了避免重复或输出污染,当它们没有增值时(例如,无限值),将省略某些字段。未来可能会出现更多字段,有些字段也可能发生变化。此输出不供脚本解析,不应被视为具有高度可靠性,它主要旨在为能够阅读它的人节省时间。技术上来说,这些信息是从启动时存储它们的内部结构中按原样获取的,因此它们也可以在崩溃后的核心文件中找到。因此,开发人员可能会要求在运行良好的进程上尽早输出,以便与核心转储中找到的信息进行比较,或者在几次重新加载之间进行比较(例如,某些限制可能会发生变化)。如果启用了匿名化,任何可能的敏感值也将被匿名化(例如,节点名称)。输出示例:$ 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
转储进程已知的一个或所有环境变量。不带任何参数时,将转储所有变量。带一个参数时,如果指定的变量存在,则仅转储该变量。否则将输出 "Variable not found"。变量的转储格式与它们存储或由 "env" 实用程序返回的格式相同,即 "<name>=<value>"。这在调试大量使用环境变量的某些配置文件时非常方便,以确保它们包含预期的值。此命令受限,并且只能在配置为 "operator" 或 "admin" 级别的套接字上发出。
转储由前端和后端收集的最后一个已知请求和响应错误。如果指定了 <iid>,则将转储限制为与 ID 为 <iid> 的前端或后端相关的错误。代理 ID“-1”将导致转储所有实例。如果指定了代理名称而不是 ID,则将使用其 ID 作为过滤器。如果在代理名称或 ID 之后添加了“request”或“response”,则仅转储请求或响应错误。此命令受限制,只能在配置为“operator”或“admin”级别的套接字上发出。可能收集的错误是由于协议违规引起的最后一个请求和响应错误,通常是由于标头名称中的无效字符。报告精确地指出了哪个确切字符违反了协议。还报告了其他重要信息,例如检测到错误的精确日期、前端和后端名称、服务器名称(如果已知)、内部事务 ID 以及发起会话的源地址。返回所有字符,并且非打印字符被编码。最常见的字符(\t = 9、\n = 10、\r = 13 和 \e = 27)被编码为一个字母,后跟一个反斜杠。反斜杠本身被编码为 '\\' 以避免混淆。其他非打印字符被编码为 '\xNN',其中 NN 是字符 ASCII 码的两位十六进制表示。行以其第一个字符的位置为前缀,从缓冲区开头开始为 0。每行最多打印一个输入行,并且长行将被分解为多个连续输出行,以便输出宽度永远不会超过 79 个字符。检测一行是否被分解很容易,因为它不会以 '\n' 结尾,并且下一行的偏移量将后跟一个“+”号,表示它是上一行的延续。
$ echo "show errors -1 response" | socat stdio /tmp/sock1 >>> [04/Mar/2009:15:46:56.081] backend http-in (#2) : invalid response src 127.0.0.1, session #54, frontend fe-eth0 (#1), server s2 (#1) response length 213 bytes, error at position 23: 00000 HTTP/1.0 200 OK\r\n 00017 header/bizarre:blah\r\n 00038 Location: blah\r\n 00054 Long-line: this is a very long line which should b 00104+ e broken into multiple lines on the output buffer, 00154+ otherwise it would be too large to print in a ter 00204+ minal\r\n 00211 \r\n 在上面的示例中,我们看到后端“http-in”(内部 ID 为 2)已阻止了其服务器 s2(内部 ID 为 1)的无效响应。请求是在事务 54(此处称为“session”)中,由源 127.0.0.1 发起,并由前端 fe-eth0(ID 为 1)接收。错误检测时总响应长度为 213 字节,错误位于第 23 字节。这是标头名称“header/bizarre”中的斜杠 ('/'),对于标头名称来说,它不是有效的 HTTP 字符。
不带选项时,此命令列出所有已知的事件接收器及其类型。带选项时,如果指定的接收器类型为缓冲区,则会转储该接收器中的所有可用事件。如果在接收器名称后传递“-w”选项,则一旦到达缓冲区末尾,命令将等待新事件并显示它们。可以通过输入任何内容(将被丢弃)或关闭会话来停止操作。最后,“-n”选项用于直接定位到缓冲区的末尾,这通常在与“-w”结合使用时很方便,以便只报告新事件。为方便起见,可以使用“-wn”或“-nw”来同时启用这两个选项。
转储所有打开的文件描述符的列表,如果指定了 <fd>,则仅转储该文件描述符。可以选择传递一组标志来限制转储仅包含某些 FD 类型或省略某些 FD 类型。当遇到“-”或“!”时,选择将对同一参数中的后续字符进行反转。反转会在每个由空格分隔的单词之前重置。可选择的 FD 类型包括“p”表示管道,“l”表示监听器,“c”表示连接(任何类型),“f”表示前端连接,“b”表示后端连接(任何类型),“s”表示到服务器的连接,“d”表示到“dispatch”地址或后端透明地址的连接。其中,“b”是“sd”的快捷方式,“c”是“fb”或“fsd”的快捷方式。“c!f”等同于“b”(“任何连接(除前端连接外)”实际上是后端连接)。这仅面向需要观察内部状态以调试复杂问题(如异常 CPU 使用率)的开发人员。每行报告一个 fd,对于每个 fd,其在 poller 中的状态使用大写字母表示启用标志,小写字母表示禁用标志,使用“P”表示“polled”,“R”表示“ready”,“A”表示“active”,事件状态使用“H”表示“hangup”,“E”表示“error”,“O”表示“output”,“P”表示“priority”,“I”表示“input”,一些其他标志如“N”表示“new”(刚添加到 fd 缓存中),“U”表示“updated”(在 fd 缓存中收到更新),“L”表示“linger_risk”,“C”表示“cloned”,然后是缓存条目位置,指向内部所有者的指针,指向 I/O 回调的指针及其名称(如果已知)。当所有者是连接时,将报告连接标志和目标(前端、代理或服务器)。当所有者是监听器时,将报告监听器的状态及其前端。不了解内部原理的情况下使用此命令没有意义。值得注意的是,输出格式可能会随时间演变,因此此输出不应被设计为持久的工具解析。一些内部结构状态在列出它们的函数看来可能看起来可疑,在这种情况下,输出行将以感叹号('!')作为后缀。这可能有助于在尝试诊断事件时找到起点。
转储当前进程上 haproxy 状态的信息。如果传递了“typed”作为可选参数,则还会发出字段编号、名称和类型,以便外部监控产品可以轻松检索、可能聚合然后报告它们不知道的字段中的信息。每个字段都转储在一行上。如果传递了“json”作为可选参数,则“typed”输出提供的信息将以 JSON 格式作为 JSON 对象列表提供。默认情况下,格式仅包含两个用冒号(':')分隔的列。左列是字段名称,右列是值。非常重要的是要注意,在 typed 输出格式中,单个对象的转储是连续的,因此消费者无需一次存储所有内容。如果传递了“float”作为可选参数,一些通常作为整数发出的字段可能会切换为浮点数以提高精度。故意未指定哪些字段涉及,因为这可能会随时间演变。使用此选项意味着消费者能够处理浮点数。使用的输出格式是 sprintf("%f")。当使用 typed 输出格式时,每行由四个用冒号(':')分隔的列组成。第一列是由三个元素组成的点分隔的序列。第一个元素是字段在列表中的数字位置(从零开始)。此位置应随时间保持不变,但可能出现空洞,具体取决于构建选项或将来是否删除某些字段。第二个元素是字段名称,如默认“show info”输出中所示。第三个元素是相对进程号,从 1 开始。第一列之后的其余行遵循上面部分中描述的“typed output format”。简而言之,第二列(第一个':'之后)指示变量的来源、性质和范围。第三列指示字段的类型,包括“s32”、“s64”、“u32”、“u64”和“str”。然后第四列是值本身,消费者知道如何根据第三列解析,并根据第二列进行处理。因此,typed 模式下的整体行格式为:<field_pos>.<field_name>.<process_num>:<tags>:<type>:<value>当“desc”附加到命令时,会附加一个额外的冒号,后跟一个带引号的字符串,其中包含该指标的描述。撰写本文时,仅支持“typed”和默认输出格式。
> show info Name: HAProxy Version: 1.7-dev1-de52ea-146 Release_date: 2016/03/11 Nbproc: 1 Process_num: 1 Pid: 28105 Uptime: 0d 0h00m04s Uptime_sec: 4 Memmax_MB: 0 PoolAlloc_MB: 0 PoolUsed_MB: 0 PoolFailed: 0 (...) > show info typed 0.Name.1:POS:str:HAProxy 1.Version.1:POS:str:1.7-dev1-de52ea-146 2.Release_date.1:POS:str:2016/03/11 3.Nbproc.1:CGS:u32:1 4.Process_num.1:KGP:u32:1 5.Pid.1:SGP:u32:28105 6.Uptime.1:MDP:str:0d 0h00m08s 7.Uptime_sec.1:MDP:u32:8 8.Memmax_MB.1:CLP:u32:0 9.PoolAlloc_MB.1:MGP:u32:0 10.PoolUsed_MB.1:MGP:u32:0 11.PoolFailed.1:MCP:u32:0 (...)
在类型化格式中,第一列末尾的进程ID使得从多个进程的输出中进行视觉聚合变得非常容易。
$ ( echo show info typed | socat /var/run/haproxy.sock1 ; \ echo show info typed | socat /var/run/haproxy.sock2 ) | \ sort -t . -k 1,1n -k 2,2 -k 3,3n 0.Name.1:POS:str:HAProxy 0.Name.2:POS:str:HAProxy 1.Version.1:POS:str:1.7-dev1-868ab3-148 1.Version.2:POS:str:1.7-dev1-868ab3-148 2.Release_date.1:POS:str:2016/03/11 2.Release_date.2:POS:str:2016/03/11 3.Nbproc.1:CGS:u32:2 3.Nbproc.2:CGS:u32:2 4.Process_num.1:KGP:u32:1 4.Process_num.2:KGP:u32:2 5.Pid.1:SGP:u32:30120 5.Pid.2:SGP:u32:30121 6.Uptime.1:MDP:str:0d 0h01m28s 6.Uptime.2:MDP:str:0d 0h01m28s (...)
JSON 输出的格式在一个 schema 中描述,可以使用“show schema json”输出该 schema。JSON 输出不包含额外的空白字符,以减少输出量。为了方便人类阅读,可以通过一个美化打印器来处理输出。示例:$ echo "show info json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool JSON 输出不包含额外的空白字符,以减少输出量。为了方便人类阅读,可以通过一个美化打印器来处理输出。示例:$ echo "show info json" | socat /var/run/haproxy.sock stdio | \ python -m json.tool
在支持此功能的系统上,转储已加载的共享动态库和对象文件的列表。如果可用,对于每个共享对象,将指示虚拟地址范围、大小和对象路径。这可以用于例如尝试估计哪个库提供了出现在转储中的函数。请注意,在许多系统上,地址会在每次重启时改变(地址空间随机化),因此如果期望使用此列表来分析核心文件,则需要在启动时检索它。此命令只能在配置为“operator”或“admin”级别的套接字上发出。请注意,输出格式可能因操作系统、体系结构甚至 haproxy 版本而异,不应在脚本中依赖它。
转储有关 map 转换器的信息。没有参数时,返回所有可用 map 的列表。如果指定了 <map>,则转储其内容。<map> 是 #<id> 或 <name>。默认情况下,显示 map 的当前版本(当前用于匹配的版本,并在 map 列表中报告为 'curr_ver')。可以通过在 map 标识符前加上“@<ver>”来转储其他版本。版本用作过滤器,不存在的版本将仅报告无结果。“entry_cnt”值代表所有 map 条目的计数,而不仅仅是活动的条目,这意味着它还包括正在添加的条目。在输出中,第一列是唯一的条目标识符,可以用作“del map”和“set map”操作的引用。第二列是模式,第三列是示例(如果可用)。返回的数据不是可用 map 的直接列表,而是组成任何 map 的所有模式的列表。其中许多模式可以与 ACL 共享。
转储有关“peers”部分中配置的对等点的信息。没有参数时,将列出属于所有“peers”部分的所有对等点的列表。如果指定了 <peers section>,则仅转储属于该“peers”部分的对等点的信息。当在 peers 部分名称前指定“dict”时,整个 Tx/Rx 字典缓存也将被转储(非常大)。可能需要传递“-”来转储名为“dict”的 peers 部分。以下是两个示例输出,其中 hostA、hostB 和 hostC 对等点属于“sharedlb” peers 部分。只有 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
转储内部内存池的状态。这对于在怀疑内存泄漏等情况下跟踪内存使用情况非常有用。它执行的操作与前台运行时按下 SIGQUIT 相同,只是它不会刷新内存池。默认情况下,输出不是排序的。如果指定了“byname”,则按内存池名称排序;如果指定了“bysize”,则按项目大小反向排序;如果指定了“byusage”,则按总使用量反向排序,并且仅显示已使用的条目。还可以将输出限制为前 <nb> 个条目(例如,当按使用量排序时)。最后,如果指定了“match”后跟一个前缀,则只显示名称以该前缀开头的内存池。报告的总数仅包括匹配过滤条件的内存池。示例:$ socat - /tmp/haproxy.sock <<< "show pools match quic byusage" Dumping pools usage. Use SIGQUIT to flush them. - Pool quic_conn_r (65560 bytes) : 1337 allocated (87653720 bytes), ... - Pool quic_crypto (1048 bytes) : 6685 allocated (7005880 bytes), ... - Pool quic_conn (4056 bytes) : 1337 allocated (5422872 bytes), ... - Pool quic_rxbuf (262168 bytes) : 8 allocated (2097344 bytes), ... - Pool quic_conne (184 bytes) : 9359 allocated (1722056 bytes), ... - Pool quic_frame (184 bytes) : 7938 allocated (1460592 bytes), ... - Pool quic_tx_pac (152 bytes) : 6454 allocated (981008 bytes), ... - Pool quic_tls_ke (56 bytes) : 12033 allocated (673848 bytes), ... - Pool quic_rx_pac (408 bytes) : 1596 allocated (651168 bytes), ... - Pool quic_tls_se (88 bytes) : 6685 allocated (588280 bytes), ... - Pool quic_cstrea (88 bytes) : 4011 allocated (352968 bytes), ... - Pool quic_tls_iv (24 bytes) : 12033 allocated (288792 bytes), ... - Pool quic_dgram (344 bytes) : 732 allocated (251808 bytes), ... - Pool quic_arng (56 bytes) : 4011 allocated (224616 bytes), ... - Pool quic_conn_c (152 bytes) : 1337 allocated (203224 bytes), ... Total: 15 pools, 109578176 bytes allocated, 109578176 used ...
转储当前的配置文件设置,每行一个,以及更改这些设置所需的命令。当启用任务配置文件时,调度程序收集的一些每个函数的统计信息也会被发出,并提供一个涵盖调用次数、总/平均 CPU 时间和总/平均延迟的摘要。当启用内存配置文件时,将报告一些信息,例如分配/释放的数量及其大小。可以通过指定相应的关键字将转储限制为仅配置文件状态、任务或内存配置文件;默认情况下,所有配置文件信息都会被转储。还可以通过指定数字限制来限制每个类别的输出行数。如果可以请求按地址或按总执行时间而不是按使用情况对输出进行排序,例如,以方便后续调用之间的比较或检查需要优化的地方,并按调用的函数汇总任务活动,而不是查看详细信息。请注意,配置文件本质上是面向开发人员的,因为它提供了有关代码中 CPU 周期或内存浪费位置的线索。那里没有有用的监控内容。
转储给定解析器部分的统计信息,如果未提供部分,则转储所有解析器部分。对于每个名称服务器,报告以下计数器: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:响应到达太晚(在另一个名称服务器之后)
转储所有活动 QUIC 前端连接的信息。此命令受限制,只能在配置为“operator”或“admin”级别的套接字上发出。可以指定一个可选参数来控制详细程度。其值可以以不同的方式解释。第一种可能性是使用预定义值,“oneline”用于默认格式,“full”用于显示所有信息。或者,可以指定一个逗号分隔的字段列表来限制输出。当前支持的值为“tp”、“sock”、“pktns”、“cc”和“mux”。最后一个参数用于限制或扩展连接列表。默认情况下,不显示正在关闭或排队状态的连接。使用“all”的附加参数将它们包含在输出中。还可以通过指定其十六进制地址来限制为单个连接。
转储属于指定后端(如果未指定,则为所有后端)的服务器的当前和空闲连接状态。可以使用后端名称或标识符。输出包括一个显示字段标题的标题行,然后是每个服务器一行,每行包含后端名称和 ID、服务器名称和 ID、地址、端口和一系列值。字段数量根据线程数而变化。鉴于空闲连接的线程特性,重要的是要理解某些值在读取后可能会发生变化,因此,行内的一致性不能保证。此输出主要作为调试工具提供,不适合常规监控或绘图。
转储运行配置中找到的服务器的状态。可以提供后端名称或标识符以仅将输出限制为此后端。转储具有以下格式:- 第一行包含格式版本(本规范中为 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 是从统计套接字设置的。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:服务器健康代理端口。
转储所有已知活动流(以前称为“会话”)。避免在慢速连接上执行此操作,因为它可能会非常大。此命令受限制,只能在配置为“operator”或“admin”级别的套接字上发出。请注意,在连接快速回收的机器上,此输出报告的条目可能少于实际存在的条目,因为它将转储在命令输入之前创建的最后一个流为止的所有现有流;在此期间死亡的流不会出现。
显示有关匹配流的大量内部信息。在第一种形式中,将仅显示与指定流标识符匹配的流。此标识符是“show sess”转储行开头处的第一个字段(它对应于流指针)。在第二种形式中,将仅显示比 <age>(默认以秒为单位)旧的流。改为传递“susp”将仅报告被开发人员认为可疑的条目,这些条目的标准可能会随时间或版本而变化。如果改为使用“all”,则将转储所有流。转储大量流可能会产生巨大的输出,花费大量时间并消耗大量 CPU,因此最好仅转储所需的最小值。这些信息对大多数用户来说是无用的,但可能会被 haproxy 开发人员用于排查复杂错误。输出格式故意不被记录,以便它可以根据需求自由演变。此输出旨在在检查 src/stream.c 中的函数 strm_dump_to_buffer() 时进行解释,以确定某些字段的确切含义。
转储统计信息。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”时,输出格式更适合监控工具,因为它提供了数字位置并指示每个输出字段的类型。每个值都单独占一行,包含进程号、元素号、性质、来源和范围。相同的格式可通过 HTTP 统计信息获得,只需在 URI 后附加“;typed”即可。非常重要的是要注意,在类型化输出格式中,单个对象的转储是连续的,因此消费者无需一次存储所有内容。“up”修改器将只列出据报已启动或未检查的服务器。那些已关闭、未解析或处于维护状态的服务器将不会被列出。这类似于 HTTP 统计信息上的“;up”选项。同样,“no-maint”修改器将像“;no-maint”HTTP 修改器一样工作,并将导致不列出已禁用的服务器。区别在于已启用但已关闭的服务器不会被排除。使用类型化输出格式时,每一行由 4 列组成,用冒号(“:”)分隔。第一列是由点分隔的 5 个元素的序列。第一个元素是一个字母,指示正在描述的对象的类型。目前已知以下对象类型:“F”代表前端,“B”代表后端,“L”代表监听器,“S”代表服务器。第二个元素第二个元素是一个正整数,表示对象所属的代理的唯一标识符。它等同于 CSV 输出的“iid”列,并匹配前端或后端部分中可选的“id”指令前面的值。第三个元素是一个正整数,包含代理内的唯一对象标识符,并对应于 CSV 输出的“sid”列。转储前端或后端时报告 ID 0。对于监听器或服务器,它对应于它们在代理内的相应 ID。第四个元素是字段在列表中的数字位置(从零开始)。此位置应随时间保持不变,但可能会出现空洞,具体取决于构建选项或将来删除某些字段。第五个元素是 CSV 输出中显示的字段名称。第六个元素是一个正整数,是从 1 开始的相对进程号。第一行之后的其余部分遵循上面部分中描述的“类型化输出格式”。简而言之,第二列(第一个“:”之后)指示变量的来源、性质和范围。第三列指示字段类型,包括“s32”、“s64”、“u32”、“u64”、“flt”和“str”。然后第四列是值本身,消费者知道如何根据第三列进行解析,以及如何根据第二列进行处理。当“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
显示加载到进程中的 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 - Filename: /home/tricot/work/haproxy/reg-tests/ssl/set_cafile_ca2.crt Status: Used Certificate #1: Serial: 11A4D2200DC84376E7D233CAFF39DF44BF8D1211 notBefore: Apr 1 07:40:53 2021 GMT notAfter: Aug 17 07:40:53 2048 GMT Subject Alternative Name: Algorithm: RSA4096 SHA1 FingerPrint: A111EF0FEFCDE11D47FE3F33ADCA8435EBEA4864 Subject: /C=FR/ST=Some-State/O=HAProxy Technologies/CN=HAProxy Technologies CA Issuer: /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 - Filename: */home/tricot/work/haproxy/reg-tests/ssl/set_cafile_ca2.crt Status: Unused Certificate #2: Serial: 587A1CE5ED855040A0C82BF255FF300ADB7C8136 [...]
显示加载到进程中的证书列表。在它们的状态变为“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 [...]
显示加载到进程中的 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.
显示 HAProxy 配置中使用的 crt-list 和目录列表。如果指定了文件名,则转储 crt-list 或目录的内容。转储后,输出可用作 crt-list 文件。'-n' 选项可用于显示行号,当条目重复时,与 'del ssl crt-list' 选项结合使用非常有用。带有 '-n' 选项的输出与 crt-list 格式不兼容,无法由 haproxy 加载。
echo "show ssl crt-list -n localhost.crt-list" | socat /tmp/sock1 - # localhost.crt-list common.pem:1 !not.test1.com *.test1.com !localhost common.pem:2 ecdsa.pem:3 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3] localhost !www.test1.com ecdsa.pem:4 [verify none allow-0rtt ssl-min-ver TLSv1.0 ssl-max-ver TLSv1.3]
显示与 HAProxy 中使用的所有 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 - # Certificate IDs Certificate ID key : 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100a Certificate path : /path_to_cert/foo.pem Certificate ID: Issuer Name Hash: 8A83E0060FAFF709CA7E9B95522A2E81635FDA0A Issuer Key Hash: F652B0E435D5EA923851508F0ADBE92D85DE007A Serial Number: 100A $ echo "show ssl ocsp-response 303b300906052b0e03021a050004148a83e0060faff709ca7e9b95522a2e81635fda0a0414f652b0e435d5ea923851508f0adbe92d85de007a0202100a" | socat /var/run/haproxy.master - OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response Version: 1 (0x0) Responder Id: C = FR, O = HAProxy Technologies, CN = ocsp.haproxy.com Produced At: May 27 15:43:38 2021 GMT Responses: Certificate ID: Hash Algorithm: sha1 Issuer Name Hash: 8A83E0060FAFF709CA7E9B95522A2E81635FDA0A Issuer Key Hash: F652B0E435D5EA923851508F0ADBE92D85DE007A Serial Number: 100A Cert Status: good This Update: May 27 15:43:38 2021 GMT Next Update: 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 响应输出一行,并包含响应的预期更新时间、上次成功更新的时间以及成功和失败更新的计数器。它还将以数字和文本形式提供上次更新的状态(成功或不成功)。有关可能错误的完整列表,请参见下文。行将按“Next Update”时间的升序排序。行还将包含使用 OCSP 响应的第一个前端证书的路径。有关 OCSP 自动更新的更多信息,请参阅“show ssl ocsp-response”命令和“ocsp-update”选项。更新错误代码和错误字符串可能如下:+----+-------------------------------------+ | ID | message | +----+-------------------------------------+ | 0 | "Unknown" | | 1 | "Update successful" | | 2 | "HTTP error" | | 3 | "Missing \"ocsp-response\" header" | | 4 | "OCSP response check failure" | | 5 | "Error during insertion" | +----+-------------------------------------+
$ 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
转储 stick-table <name> 的内容。在此模式下,第一行是关于该表的通用信息,与“show table”类似,然后转储所有条目。由于这可能很重,因此可以指定一个过滤器来指定要显示的条目。当使用 data. 形式时,过滤器适用于存储的数据(参见 第 4.2 节中的“stick-table”)。必须在 <type> 中指定存储的数据类型,并且该数据类型必须存储在表中,否则将报告错误。数据将根据 <operator> 与 64 位整数 <value> 进行比较。运算符与 ACL 中的运算符相同:- eq:匹配数据等于此值的所有条目- ne:匹配数据不等于此值的所有条目- le:匹配数据小于或等于此值的所有条目- ge:匹配数据大于或等于此值的所有条目- lt:匹配数据小于此值的所有条目- gt:匹配数据大于此值的所有条目在此形式下,您可以使用多个数据过滤器条目,最多可达构建时定义的数量(默认 4 个)。当使用 key 形式时,将显示条目 <key>。键必须与表相同类型,目前仅限于 IPv4、IPv6、整数和字符串。当使用 ptr 形式时,将显示条目 <ptr>。<ptr> 的格式为 0xffff,并且必须对应于先前“show table”命令返回的地址。使用其指针匹配条目可能相关,如果该条目无法通过键进行匹配,因为键为空或 CLI 上的字符不兼容。
$ echo "show table http_proxy" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a4c: key=127.0.0.1 use=0 exp=3594729 gpc0=0 conn_rate(30000)=1 \ bytes_out_rate(60000)=187 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "show table http_proxy data.gpc0 gt 0" | socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "show table http_proxy data.conn_rate gt 5" | \ socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "show table http_proxy key 127.0.0.2" | \ socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191 $ echo "show table http_proxy ptr 0x80e6a80" | \ socat stdio /tmp/sock1 >>> # table: http_proxy, type: ip, size:204800, used:2 >>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \ bytes_out_rate(60000)=191
当数据标准应用于依赖于时间的动态值(例如字节速率)时,该值在评估条目期间动态计算,以决定是否必须转储它。这意味着这样的过滤器可能会在一段时间内匹配,然后由于时间的推移,平均事件速率下降而不再匹配。可以利用这一点来提取滥用服务的 IP 地址列表,以便监视它们甚至在防火墙中将它们列入黑名单。
$ echo "show table http_proxy data.gpc0 gt 0" \ | socat stdio /tmp/sock1 \ | fgrep 'key=' | cut -d' ' -f2 | cut -d= -f2 > abusers-ip.txt ( 或 | awk '/key/{ print a[split($2,a,"=")]; }' )
当粘性表与支持分片的对等点部分同步时,将为每个键显示分片编号(否则报告“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 重新填充队列的机会较少(除非队列已满)。此命令对进程进行独占访问,在高度负载的进程上发出时可能导致微小但可测量的延迟,因此监控机器人不得滥用此命令。
转储每个线程的一些内部状态和结构,这可能有助于开发人员理解问题。输出会尝试通过显示每个线程一个块来使其可读。当使用 USE_THREAD_DUMP=1 构建 haproxy 时,会使用涉及线程信号的高级转储机制,以便每个线程可以依次转储自己的状态。没有此选项,处理命令的线程会显示其所有详细信息,但其他线程的详细信息较少。星号(“*”)显示在处理命令的线程前面。右尖括号(“>”)也可能显示在自上次调用此命令以来未取得任何进展的线程前面,这表明代码中存在一个必须绝对报告的错误。当这种情况发生在两个线程之间时,通常表示死锁。如果只有一个线程,则表示另一个错误,例如列表损坏。在所有情况下,进程将不再完全可用,需要重新启动。输出格式故意不被记录,以便在确定新需求时可以轻松演变,而无需维护任何形式的向后兼容性,并且就像“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”的输出是否符合该模式。
显示当前跟踪状态。对于每个源,都会显示一行,带有一个单字符状态,指示跟踪是已停止、等待中还是正在运行。会指示跟踪使用的输出接收器(如果未设置,则为 "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”标志报告。
立即终止附加到指定服务器的所有流。例如,这可用于在服务器进入维护模式后终止长时间运行的流。此类终止的流在日志中以“K”标志报告。
单独的“trace”命令会列出跟踪源、它们的当前状态和简要描述。它仅作为进入下一级的菜单,请参见下面的其他“trace”命令。
立即停止所有跟踪。这旨在作为终止调试会话的快速解决方案,或在多个源上启用了复杂的跟踪并影响服务时作为紧急措施使用。
不带参数,这将列出指定源支持的所有事件。它们以“-”为前缀,表示未启用,或以“+”为前缀,表示已启用。重要的是要注意,单个跟踪可能标记有多个事件,只要启用的一个事件与跟踪上标记的一个事件匹配,该事件就会被传递到跟踪子系统。例如,接收类型为 HEADERS 的 HTTP/2 帧可能会触发一个帧事件和一个流事件,因为该帧会创建一个新流。如果为此源启用了帧事件或流事件,则该帧将传递到跟踪框架。使用参数时,可以切换每个事件的状态并单独启用或禁用它们。支持两个特殊关键字,“none”,它不匹配任何事件,用于一次禁用所有事件,以及“any”,它匹配所有事件,用于一次启用所有事件。其他事件特定于事件源。可以通过指定事件名称来启用一个事件,可以选择以“+”为前缀以提高可读性。可以通过指定以“-”或“!”为前缀的事件名称来禁用一个事件。完全禁用跟踪源的一种方法是传递“event none”,此源将立即被完全忽略。
不带参数,这将列出此源的所有跟踪级别,并且当前级别将通过在其前面加上星号(“*”)来指示。使用参数时,这将更改跟踪级别为指定的级别。详细级别是应用于报告事件之前的过滤器的一种形式。这些过滤器用于根据事件的重要性级别有选择地包含或排除事件。例如,开发人员可能需要精确地知道 HTTP 标头在代码的何处被视为无效,而最终用户可能根本不关心此标头的有效性。目前有 5 个不同的跟踪级别:user 将报告适合普通 haproxy 用户观察其流量的信息。通常,一些 HTTP 请求和响应将被报告,但细节不多。大多数源将此设置为默认级别以方便操作。proto 除“user”级别报告的内容外,还会显示协议级别的更新。例如,这可以是帧类型或解码后的 HTTP 标头。state 除“proto”级别报告的内容外,还会显示解析器中发生的(或失败的)状态转换,因此这将显示尝试执行某个操作,而“proto”级别仅显示最终操作。data 除“state”级别报告的内容外,还将包括各个层之间的数据传输。developer 报告所有可用信息,包括仅对尝试理解偶尔发生的错误而相关的“退出此循环”等高级信息。函数名称仅在此级别报告。强烈建议始终仅使用“user”级别,并且仅在开发人员的指示下才切换到其他级别。此外,最好先配置事件,然后再切换到更高的级别,因为这可以避免在未应用任何过滤器时转储大量行。
不带参数,这将列出此源支持的所有用于锁定处理的标准,并用星号(“*”)在其前面显示当前选择。锁定意味着源将聚焦于第一个匹配的事件,并且仅坚持触发此事件的标准,而忽略所有其他标准,直到跟踪停止。例如,这允许在单个连接或单个流上进行跟踪。以下标准由某些跟踪支持,但并非全部,因为其中一些可能对源不可用:backend 锁定启动跟踪的后端connection 锁定启动跟踪的连接frontend 锁定启动跟踪的前端listener 锁定启动跟踪的监听器nothing 不锁定任何内容server 锁定启动跟踪的服务器session 锁定启动跟踪的会话thread 锁定启动跟踪的线程此外,每个源可以提供多达 4 个特定标准,例如内部状态或连接 ID。例如,在 HTTP/2 中,一旦开始跟踪,就可以锁定 H2 流并忽略其他流。当将标准作为参数传递时,将使用该标准而不是其他标准,并且任何现有的跟踪将立即终止,以便它可以使用新标准重新启动。所有源都支持“nothing”特殊关键字,以永久禁用跟踪。
不带参数,这将列出为此源启用以自动暂停、启动或停止跟踪的事件。这些事件特定于每个跟踪源。使用参数时,它将启用事件以执行指定的操作(如果可选地以“+”为前缀),或禁用它(如果以“-”或“!”为前缀)。特殊关键字“now”不是事件,而是请求立即执行操作。关键字“none”和“any”的支持方式与“trace event”相同。支持的 3 个操作分别是“pause”、“start”和“stop”。“pause”操作列举将导致正在运行的跟踪停止并等待新的开始事件以重新启动它的事件。“start”操作列举将跟踪切换到等待模式直到出现其中一个开始事件的事件。“stop”操作列举将永久停止跟踪直到再次手动启用的事件。实际上,手动使用“start now”开始跟踪而不关心事件,并使用“stop now”停止跟踪是有意义的。为了捕获更微妙的事件序列,将“start”设置为正常事件(例如接收 HTTP 请求),并将“stop”设置为非常罕见的事件(例如发出某种错误),将确保最后捕获的事件将匹配所需的条件。并且暂停事件有助于检测序列的结束,禁用锁定并等待另一个机会进行捕获。在这种情况下,启用锁定以仅识别一个特定标准(例如流)可能是有意义的,并将“start”设置为任何启动该标准的操作(例如创建流的所有事件),将“stop”设置为预期的异常,并将“pause”设置为任何结束该标准的操作(例如任何流结束事件)。在这种情况下,跟踪日志将包含完美的干净序列的完整序列,这些序列影响单个对象,直到包含从开始到异常的所有内容的最后一个序列。
不带参数,这将列出此源的所有详细程度级别,并且当前级别将通过在其前面加上星号(“*”)来指示。使用参数时,这将将详细程度级别更改为指定的级别。详细程度级别指示跟踪解码器应执行多远以提供详细信息。它取决于跟踪源,因为某些源甚至不提供特定的解码器。“quiet”级别始终可用,并禁用任何解码。当尝试弄清楚在尝试理解详细信息之前发生了什么时,它可能很有用,因为它对性能和跟踪大小的影响非常小。当源不声明任何详细程度级别时,“default”级别可用,并且将在指定时调用解码器。这是机会主义解码。当源声明某些详细程度级别时,这些级别将与它们对应的描述一起列出。在这种情况下,源提供的跟踪解码器将基于跟踪点处可用信息尽可能准确。高于“quiet”的第一个级别是默认设置的。
为指定的 <certfile> 创建一个 OCSP 请求,并将其发送到其 URI 应在证书的“授权信息访问”部分中指定的 OCSP 响应器。只考虑第一个 URI。然后检查我们应该收到的 OCSP 响应,并将其插入到本地 OCSP 响应树中。此命令仅适用于已经有存储的 OCSP 响应的证书,无论是在初始化期间提供的,还是之前通过“set ssl cert”或“set ssl ocsp-response”命令设置的。如果接收到的 OCSP 响应有效并且已正确插入到本地树中,其内容将显示在标准输出上。格式与“show ssl ocsp-response”中描述的相同。
在其最简单的形式中,没有其他条件,它只会等待请求的延迟时间然后继续。这可以用于收集特定时间间隔内的指标。通过添加条件和可选参数,该命令将等待指定的条件得到满足、不可挽回地失败,或在整个 <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"
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
@<[!]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 - [...]
此命令会为从主 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”命令。
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 -
在此示例中,master 进程已重载 5 次,但其中一个旧的 worker 仍在运行,并经历了 3 次重载。您可以访问此 worker 的 CLI 来了解发生了什么。
HAProxy 需要使用 USE_SHM_OPEN=1 编译才能在 Master CLI 上正确使用,否则并非所有消息都可见。与其在 stats socket 上的对应命令一样,此命令能够显示 HAProxy 的启动消息。但它不转储当前 worker 的启动消息,而是转储最近一次启动或重载的启动消息,这意味着它能够转储失败重载的解析消息。这些消息也会随“reload”命令一起转储。
所谓的 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 相同,变量以美元符号 ('$') 开头,后跟一个开括号 ('{'),然后是变量名,最后是闭括号 ('}')。除了地址之外,环境变量仅在用双引号括起来的参数中进行解释(这是为了不破坏现有使用涉及美元符号的正则表达式的设置)。环境变量也使得编写可在不同站点上运行且只有地址发生变化的配置变得方便。它还可以用于从某些配置中移除密码。下面的示例展示了 init 脚本在启动时如何 source 文件 "site1.env":$ cat site1.env LISTEN=192.168.1.1 CACHE_PFX=192.168.11 SERVER_PFX=192.168.22 LOGGER=192.168.33.1 STATSLP=admin:pa$$w0rd ABUSERS=/etc/haproxy/abuse.lst TIMEOUT=10s $ cat haproxy.cfg global log "${LOGGER}:514" local0 defaults mode http timeout client "${TIMEOUT}" timeout server "${TIMEOUT}" timeout connect 5s frontend public bind "${LISTEN}:80" http-request reject if { src -f "${ABUSERS}" } stats uri /stats stats auth "${STATSLP}" use_backend cache if { path_end .jpg .css .ico } default_backend server backend cache server cache1 "${CACHE_PFX}.1:18080" check server cache2 "${CACHE_PFX}.2:18080" check backend server server cache1 "${SERVER_PFX}.1:8080" check server cache2 "${SERVER_PFX}.2:8080" check有时会有人报告说,系统重启后,haproxy 服务未启动,并且手动启动后就可以工作。大多数情况下,这些人正在使用集群 IP 地址机制,如 keepalived,只将服务 IP 地址分配给主节点。虽然他们之前将 haproxy 绑定到地址 0.0.0.0 时这样做可行,但在绑定到虚拟 IP 地址后就不行了。发生这种情况的原因是,当服务启动时,虚拟 IP 地址尚未被本地节点拥有,因此当 HAProxy 尝试绑定到它时,系统会拒绝,因为它不是本地 IP 地址。修复方法不是延迟 haproxy 服务的启动(因为它不会承受重启),而是正确配置系统以允许绑定到非本地地址。在 Linux 上,这可以通过将 net.ipv4.ip_nonlocal_bind sysctl 设置为 1 来轻松完成。这也对于透明地拦截 HAProxy 经过的特定目标地址的 IP 流量是必需的。涉及源端口范围的多进程配置似乎可以工作,但在高负载下会导致一些随机故障,因为多个进程可能尝试使用相同的源端口连接到同一个服务器,这是不可能的。系统将报告错误,然后会发生重试,选择另一个端口。`retries` 参数中的高值可以在一定程度上隐藏这种效果,但也会增加 CPU 使用率和处理时间。日志也会报告一定数量的重试。因此,在多进程配置中应避免使用端口范围。由于 HAProxy 使用 SO_REUSEPORT 并支持多个独立进程绑定到同一个 IP:port,因此在故障排除时,可能会出现旧进程在新进程启动之前未停止的情况。这会提供荒谬的测试结果,似乎表明对配置的任何更改都被忽略了。原因实际上是,即使新进程以新配置重启,旧进程也会收到一些传入连接并处理它们,从而返回意外结果。如有疑问,只需停止新进程然后重试。如果仍然有效,则很可能意味着一个旧进程仍然存活,需要停止。Linux 的 "netstat -lntp" 在这里很有帮助。当从命令行向 ACL 添加条目时(例如,黑名单源地址),重要的是要记住,这些条目不会同步到文件中,如果有人重新加载配置,这些更新将丢失。虽然这通常是期望的效果(用于黑名单),但当更改是为了解决问题时,可能不一定符合预期。请参阅 CLI 接口的“add acl”操作。
当 HAProxy 使用 "-d" 选项启动时,它将保持在前台运行,并为每个事件打印一行,例如传入连接、连接结束,以及看到的每个请求或响应头行的信息。此调试输出在内容处理之前发出,因此不考虑本地修改。主要用途是显示请求和响应,而无需运行网络嗅探器。当并行处理多个连接时,输出的可读性会降低,尽管 examples/ 目录中的 "debug2ansi" 和 "debug2html" 脚本通过着色输出来提供很大帮助。如果 HAProxy 发现请求或响应格式错误而拒绝,最好的做法是连接到 CLI 并发出“show errors”命令,该命令将报告每个前端和后端捕获的最后一个错误的请求和响应,并提供所有必要的信息来精确指示输入流中被拒绝的第一个字符。这有时需要用来向客户或开发人员证明他们的代码存在 bug。在这种情况下,通常可以通过使用 "option accept-invalid-http-request" 或其服务器端响应的等效命令 "option accept-invalid-http-response" 来放宽检查(但仍保留捕获)。有关更多详细信息,请参阅配置手册。
> show errors Total events captured on [13/Oct/2015:13:43:47.169] : 1 [13/Oct/2015:13:43:40.918] frontend HAProxyLocalStats (#2): invalid request backend <NONE> (#-1), server <NONE> (#-1), event #0 src 127.0.0.1:51981, session #0, session flags 0x00000080 HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000 HTTP chunk len 0 bytes, HTTP body len 0 bytes buffer flags 0x00808002, out 0 bytes, total 31 bytes pending 31 bytes, wrapping at 8040, error at position 13: 00000 GET /invalid request HTTP/1.1\r\n
CLI 上“show info”命令的输出提供了大量有用的信息,包括曾达到的最大连接速率、曾达到的最大 SSL 密钥速率,以及通常有助于解释 CPU 或内存使用量暂时性问题的所有信息。例如:> show info Name: HAProxy Version: 1.6-dev7-e32d18-17 Release_date: 2015/10/12 Nbproc: 1 Process_num: 1 Pid: 7949 Uptime: 0d 0h02m39s Uptime_sec: 159 Memmax_MB: 0 Ulimit-n: 120032 Maxsock: 120032 Maxconn: 60000 Hard_maxconn: 60000 CurrConns: 0 CumConns: 3 CumReq: 3 MaxSslConns: 0 CurrSslConns: 0 CumSslConns: 0 Maxpipes: 0 PipesUsed: 0 PipesFree: 0 ConnRate: 0 ConnRateLimit: 0 MaxConnRate: 1 SessRate: 0 SessRateLimit: 0 MaxSessRate: 1 SslRate: 0 SslRateLimit: 0 MaxSslRate: 0 SslFrontendKeyRate: 0 SslFrontendMaxKeyRate: 0 SslFrontendSessionReuse_pct: 0 SslBackendKeyRate: 0 SslBackendMaxKeyRate: 0 SslCacheLookups: 0 SslCacheMisses: 0 CompressBpsIn: 0 CompressBpsOut: 0 CompressBpsRateLim: 0 ZlibMemUsage: 0 MaxZlibMemUsage: 0 Tasks: 5 Run_queue: 1 Idle_pct: 100 node: wtap description: 当 HAProxy 的新版本中似乎随机出现问题时(例如,每秒一个请求被中止,偶尔崩溃等),尝试启用内存中毒是有价值的,这样每次调用 malloc() 后都会立即用可配置字节填充内存区域。默认情况下,该字节是 0x50('P' 的 ASCII 值),但可以使用任何其他字节,包括零(这将与 calloc() 产生相同效果,并可能使问题消失)。内存中毒是通过命令行选项 "-dM" 启用的。它会稍微影响性能,不建议在生产环境中使用。如果启用内存中毒后问题一直存在,或者当中毒使用零字节时问题从未发生,那显然意味着您找到了一个 bug,并且绝对需要报告它。否则,如果没有明显的改变,问题就无关紧要。在调试某些延迟问题时,重要的是同时使用本地机器上的 strace 和 tcpdump,以及另一台远程系统上的 tcpdump。原因是处理链中存在各种延迟,了解哪个延迟导致了问题,才能知道在哪里采取行动。在实践中,本地 tcpdump 将指示输入数据何时到达。Strace 将指示 haproxy 何时收到这些数据(使用 recv/recvfrom)。警告,openssl 使用 read()/write() 系统调用而不是 recv()/send()。Strace 还将显示 haproxy 何时发送数据,tcpdump 将显示系统何时将这些数据发送到接口。然后,外部 tcpdump 将显示发送的数据何时真正被接收(因为本地 tcpdump 只显示数据包何时排队)。嗅探本地系统的好处是 strace 和 tcpdump 将使用相同的参考时钟。Strace 应与 "-tts200" 一起使用,以获取完整的 timestamps 并报告足够大的数据块以便阅读。Tcpdump 应与 "-nvvttSs0" 一起使用,以报告完整的数据包、实际的序列号和完整的 timestamps。在实践中,接收到的数据几乎总是立即被 haproxy 接收(除非机器 CPU 过载或这些数据无效且未传递)。如果数据已接收但未发送,通常是因为输出缓冲区已满(即:接收方消耗数据的速度不够快)。这可以通过查看轮询在一段时间内未通知输出文件描述符可写来确认(在 strace 输出中,当数据最终离开并回滚到查看何时通知了写事件时,通常更容易发现)。它通常与从接收方收到的 ACK 匹配,并由 tcpdump 检测到。数据发送后,它们可能会在系统中停留一段时间。这里,TCP 拥塞窗口可能受限,不允许数据离开,等待 ACK 来打开窗口。如果流量空闲,并且数据需要 40 毫秒或 200 毫秒才能离开,那么这是一个不同的问题(不是问题),Nagle 算法会阻止空数据包立即离开,希望它们与后续数据合并。HAProxy 在纯 TCP 模式和隧道中自动禁用 Nagle。然而,在转发 HTTP body 时,它绝对仍然启用(这有助于通过减少数据包数量来提高性能)。某些不符合 HTTP 标准的应用程序可能对延迟敏感,当传递不完整的 HTTP 响应消息时。在这种情况下,您必须启用 "option http-no-delay" 来禁用 Nagle 以解决其设计问题,同时要记住链中的任何其他代理也可能受到类似影响。如果 tcpdump 报告数据立即离开,但另一端没有很快看到它们,这可能意味着 WAN 链路拥塞、启用了流控制的 LAN 拥塞导致数据无法离开,或者更常见的是 HAProxy 实际上运行在虚拟机中,并且出于某种原因,虚拟机监控程序决定数据不需要立即发送。在虚拟化环境中,延迟问题几乎总是由虚拟化层引起,因此为了节省时间,值得首先比较 VM 内的 tcpdump 和外部组件的 tcpdump。任何差异都应归因于虚拟机监控程序及其驱动程序。当在 tcpdump 跟踪中看到 TCP SACK 段(使用 -vv)时,这始终意味着发送方有数据包丢失的证据。虽然看不到它们并不意味着没有丢失,但看到它们绝对意味着网络是丢包的。丢失在网络上是正常的,但如果速率过高以至于 SACK 无法被肉眼注意到。如果它们在跟踪中大量出现,就值得调查到底发生了什么以及数据包丢失在哪里。HTTP 无法很好地处理 TCP 丢失,这会导致巨大的延迟。"netstat -i" 命令将报告每个接口的统计信息。接口上 Rx-Ovr 计数器增长表示系统没有足够的资源来接收所有传入的数据包,并且它们在被网络驱动程序处理之前就已丢失。Rx-Drp 表示某些接收到的数据包在网络堆栈中丢失,因为应用程序处理它们的速度不够快。这在某些攻击中也可能发生。Tx-Drp 表示输出队列已满,并且数据包不得不被丢弃。使用 TCP 时,这种情况应该非常罕见,但可能表明出站链接已饱和。
HAProxy 设计为以非常有限的权限运行。标准用法是将其隔离在 chroot 监狱中,并将其权限降至该监狱内没有任何权限的非 root 用户,这样即使将来发现任何漏洞,其被攻破也不会影响系统的其余部分。为了执行 chroot,它首先需要以 root 用户身份启动。为手动构建的 chroot 启动进程是没有意义的,这些 chroot 很难构建,从不被正确维护,并且总是包含比主文件系统多得多的 bug。而且在被攻破的情况下,入侵者可以使用特意构建的文件系统。不幸的是,许多管理员将“以 root 身份启动”和“以 root 身份运行”混淆,导致在启动 haproxy 之前就进行了 uid 更改,从而降低了有效的安全限制。HAProxy 需要以 root 身份启动才能:- 调整文件描述符限制- 绑定到特权端口号- 绑定到特定的网络接口- 透明地监听外来地址- 在 chroot 监狱中隔离自身- 降至另一个非特权 UID HAProxy 可能需要以 root 身份运行才能:- 绑定到出站连接的接口- 为出站连接绑定到特权源端口- 透明地为出站连接绑定到外来地址大多数用户永远不需要“以 root 身份运行”的情况。但“以 root 身份启动”涵盖了大多数用法。安全的配置将具有:- 一个 chroot 声明,指向一个没有任何访问权限的空位置。这可以在 UNIX 命令行上这样准备:# mkdir /var/empty && chmod 0 /var/empty || echo "Failed" 并在 HAProxy 配置的 global 部分中这样引用:chroot /var/empty - global 部分中的 uid/user 和 gid/group 声明:user haproxy group haproxy - 一个 stats socket,其 mode、uid 和 gid 设置为与允许访问 CLI 的用户和/或组匹配,以便没有人可以访问它:stats socket /var/run/haproxy.stat uid hatop gid hatop mode 600
从 v2.9 版本开始,haproxy 支持 Linux capabilities。如果二进制文件是用 USE_LINUX_CAP=1 编译的,那么在从 root 用户切换到非 root 用户时,它能够保留 'setcap' 关键字中给定的 capabilities。从 v3.1 版本开始,haproxy 还会检查 'setcap' 关键字中给定的 capabilities 是否在其二进制文件中的 Permitted set(由管理员设置,capget syscall)中。如果是这种情况,它会在以非 root 用户运行时,将其进程的 Effective set(capset syscall)中的这些 capabilities 进行转换。这样做是为了避免 HAProxy 启动并以 root 身份运行时所有潜在的使用场景:透明代理模式、绑定到特权端口。'setcap' 关键字支持以下网络 capabilities:- cap_net_admin:透明代理、将套接字绑定到特定网络接口、使用 set-mark 操作;- cap_net_raw(cap_net_admin 的子集):透明代理;- cap_net_bind_service:将套接字绑定到特定网络接口;- cap_sys_admin:在特定网络命名空间中创建套接字。Haproxy 绝不会将其 Permitted set 中的 capabilities 转换为 Effective set,除非它们被列为 'setcap' 参数。有关 'setcap' 关键字和支持的 capabilities 的更多信息,请参阅配置指南的第 3.1 章“进程管理和安全”。管理员可以使用以下命令将所需的 capabilities 添加到 haproxy 二进制文件的 Permitted set 中:
# 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()] 一些协议无法启动它们的侦听器!正在退出。