HAProxy 3.4.4
5. 文件描述符限制
HAProxy 3.4 入门、配置与管理三套完整手册的简体中文译本
为确保所有传入连接均能成功处理,HAProxy 在加载时会计算进程生命周期内所需的文件描述符总数。常规 Unix 进程默认被授予 1024 个文件描述符,特权进程可自行提升该限制。这是以 root 身份启动 HAProxy 并由其自行调整限制的原因之一。默认的 1024 个文件描述符大致可支持约 500 个并发连接的处理。该计算基于全局 maxconn 参数,该参数限制每个进程的总连接数,同时考虑监听器数量、启用健康检查的服务器数量、代理检查、对等节点、日志记录器以及可能的其他技术需求。对该数值的粗略估算方法为:将 maxconn 值翻倍,并额外增加数十个,即可得到所需的文件描述符近似数量。
最初,HAProxy 无法自动计算此值,必须通过全局段中的 “ulimit-n” 设置手动指定。这解释了为何至今仍有许多配置中保留该设置。不幸的是,该值常被错误计算,导致在接近 maxconn 限制时出现连接失败,而非在等待所需资源时对新连接进行限流。因此,务必移除任何可能源自极旧版本的残留 “ulimit-n” 设置。
提高文件描述符数量以应对中等负载是必须的,但需进行一些操作系统特定的调整。首先,select() 轮询机制最多只能处理 1024 个文件描述符。实际上,在 Linux 上曾支持更多,但由于某些操作系统附带过于严格的 SELinux 策略,禁止使用 select() 处理超过 1024 个文件描述符,HAProxy 现在在这种情况下拒绝启动,以避免运行时出现任何问题。在所有支持的操作系统上,poll() 均可用,且不受此限制影响。HAProxy 会自动选择该机制,因此无需额外操作即可获得正常配置。但当文件描述符数量增加时,poll() 的性能会显著下降。尽管 HAProxy 尽力降低此性能影响(例如通过内部文件描述符缓存和批量处理),但一个通用的经验是:使用 poll() 处理超过一千个并发连接时,将消耗大量 CPU 资源。
对于基于 2.6 及以上内核的 Linux 系统,将使用 epoll() 系统调用。该机制具有更高的可扩展性,依赖于内核中的回调机制,可保证无论注册监控的文件描述符数量多少,唤醒时间始终恒定。只要检测到该功能,且 HAProxy 已针对某一类 Linux 发行版编译构建,便会自动启用。可通过命令 “HAProxy -vv” 验证其存在与支持情况。
对于支持该功能的 BSD 系统,可使用 kqueue() 作为替代方案。由于其支持批量处理变更,性能远超 poll(),甚至略胜于 epoll()。目前至少 FreeBSD 和 OpenBSD 支持该功能。与 Linux 的 epoll() 类似,其支持情况和可用性会在运行 “HAProxy -vv” 时的输出中报告。
拥有一个优秀的轮询器是一回事,但进程必须能够达到限制才是必须的。HAProxy 启动时,会立即设置新进程的文件描述符限制,并验证设置是否成功。若设置失败,将在进程分叉前报告该问题,以便管理员能够发现。只要进程以 root 身份启动,该设置就应不会失败。然而,若进程由非特权用户启动,则可能失败。如果存在必须不以 root 身份启动 HAProxy 的充分理由(例如:由终端用户或特定应用程序账户启动),则系统管理员可为该特定用户提升文件描述符限制。可通过在用户命令行中执行 “ulimit -n” 验证该设置的有效性。输出结果应反映新的限制值。
请注意:当在用户账户中更改非特权用户的限制时,这些值通常仅在用户登录时被考虑,而在系统启动时运行的某些脚本或 crontab 中则完全不被考虑。这完全取决于操作系统,因此在以这种方式运行 HAProxy 之前,请务必检查 “ulimit -n”。一般建议不要在生产环境中以非特权用户身份启动 HAProxy。另一个重要原因在于,这会阻止 HAProxy 启用某些安全防护功能。
一旦确认系统允许 HAProxy 进程使用请求的文件描述符数量,可能会遇到两个新的系统特定限制。第一个是系统级文件描述符限制,即系统上所有进程打开的文件描述符总数。当达到此限制时,accept() 或 socket() 通常会返回 ENFILE。第二个是每个进程的文件描述符硬限制,它阻止 setrlimit() 设置更高的值。这两项限制均高度依赖于操作系统。在 Linux 上,系统级限制在启动时根据内存总量设定,可通过 “fs.file-max” sysctl 修改。每个进程的默认硬限制为 1048576,但可使用 “fs.nr_open” sysctl 进行更改。
当进程的文件描述符限制设置过低时,可能会在运行过程中观察到文件描述符限制问题。使用 strace 工具时,会报告 accept() 和 socket() 返回 “-1 EMFILE”,表明进程的限制已达到。此时,只需提高 “ulimit-n” 值(或将其移除)即可解决问题。若这些系统调用返回 “-1 ENFILE”,则表示内核的限制已达到,必须调整系统级参数。此类问题必须立即解决,否则会导致高 CPU 使用率(当 accept() 失败时)以及用户可见的连接失败。一种解决方案是降低全局 maxconn 值以强制序列化处理,或禁用 HTTP 持久连接,以促使连接更快释放并重用。
来源与许可
文档取自 pig.center · 上游文档
- 版本
- 3.4.4
- 许可
- GPL-2.0-only
- 来源修订
1dff183d0ca5a430d10324c5bbc64f9853ed77ae5df299827b47b2f54e352f65- 译文修订
1dff183d0ca5a430d10324c5bbc64f9853ed77ae5df299827b47b2f54e352f65