12.11. 调整内核限制

12.11.1. 文件/进程限制

12.11.1.1. kern.maxfiles

可根据系统的要求来提高或降低 sysctl(8)变量kern.maxfiles。这个变量表示系统中文件描述符的最大数量。当文件描述符表已满时,file: table is full会在系统消息缓冲区中反复显示,可以用 dmesg(8) 查看。

每个打开的文件、套接字或 fifo 使用一个文件描述符。一个大规模的生产型服务器可能很容易需要成千上万的文件描述符,这取决于同时运行的服务的种类和数量。

在较早的 FreeBSD 版本中,kern.maxfiles 的默认值来自于内核配置文件中的 maxuserskern.maxfiles 的增长与 maxusers 的值成比例。当编译一个自定义的内核时,考虑根据系统的使用情况来设置这个内核配置选项。从这个数字来看,内核被赋予了大部分的预定义限制。即使一台生产机器可能没有256个并发用户,但所需要的资源可能与一个高规模的网络服务器相似。

只读的 sysctl(8) 变量 kern.maxusers 在启动时根据系统中可用的内存量自动确定大小,也可以在运行时通过检查 kern.maxusers 的值来确定。有些系统需要更大或更小的 kern.maxusers 值,64、128 和 256 的值并不少见。除非需要大量的文件描述符,否则不建议超过 256。许多被 kern.maxusers 设置为默认值的可调整值可以在启动时或运行时在 /boot/loader.conf 中被单独覆盖。请参考 loader.conf(5)/boot/defaults/loader.conf 以了解更多细节和一些提示。

在较早的版本中,如果 maxusers 被设置为 0,系统会自动进行调整(自动调整算法将 maxusers 设定为等于系统中的内存量,最小为32,最大为384)。在设置这个选项时,至少要把 maxusers 设置为 4,特别是在系统运行 Xorg 或用来编译软件的情况下。maxusers 设置的最重要的表是最大进程数,它被设置为20 + 16 * maxusers 。如果 maxusers 被设置为 1,则只能有 36 个同时进行的进程,包括系统在启动时启动的18个左右的进程和 Xorg 使用的 15 个左右的进程。即使是一个简单的任务,比如阅读一个手册页面,也会启动9个进程来过滤、解压和查看它。将 maxusers 设置为 64,最多允许 1044 个同时进行的进程,这应该足以满足几乎所有的用途。但是,如果在试图启动另一个程序时显示错误,或者服务器在运行时有大量的并发用户,请增加数量并重新构建。

注意

maxusers 并不限制可以登录机器的用户数量。相反,考虑到系统中的最大用户数和每个用户将运行的进程数,它将各种表的大小设置为合理值。

12.11.1.2. kern.ipc.soacceptqueue

sysctl(8)的kern.ipc.soacceptqueue变量限制了用于接受新 TCP 连接的监听队列的大小。默认值 128 通常太低,不利于稳健地处理高负荷的 web 服务器上的新连接。对于这样的环境,建议将这个值增加到1024或更高。像 sendmail(8) 或 Apache 这样的服务可能本身就限制了监听队列的大小,但通常在其配置文件中会有一个指令来调整队列大小。大的监听队列在避免拒绝服务(DoS)攻击方面做得更好。

12.11.2. 网络限制

NMBCLUSTERS 内核配置选项决定了系统可用的网络 Mbufs 的数量。一个大量使用的服务器,如果 Mbufs 的数量很低,会妨碍性能。每个簇代表大约 2K 的内存,所以 1024 的值代表 2 兆字节的内核内存保留给网络缓冲区。可以做一个简单的计算来计算出需要多少个。一个网络服务器的最大同时连接数为 1000,每个连接使用 6K 的接收和 16K 的发送缓冲区,需要大约 32MB 的网络缓冲区来覆盖网络服务器。一个好的经验法则是乘以 2,所以 2 x 32 MB / 2 KB = 64 MB / 2 kB = 32768。对于拥有更大内存的机器,建议使用 4096 和 32768 之间的值。千万不要为这个参数指定一个任意的高值,因为它可能导致启动时崩溃。要观察网络集群的使用情况,可以使用 netstat(1)-m

应该使用 kern.ipc.nmbclusters loader 可调参数来在启动时进行调整。只有老版本的 FreeBSD 需要使用 NMBCLUSTERS 内核 config(8) 选项。

对于大量使用 sendfile(2) 系统调用的繁忙服务器,可能需要通过 NSFBUFS 内核配置选项或在 /boot/loader.conf 中设置其值来增加 sendfile(2) 缓冲区的数量 (详见 loader(8)的手册)。这个参数需要调整的一个常见指标是当进程被看到处于sfbufa状态时。sysctl(8) 变量 kern.ipc.nsfbufs 是只读的。这个参数在名义上与 kern.maxusers 呈比例关系,但可能需要进行相应的调整。

重要:

即使一个套接字被标记为非阻塞,在非阻塞套接字上调用 sendfile(2) 可能会导致 sendfile(2) 的调用阻塞,直到有足够的 struct sf_buf 可用。

12.11.2.1. net.inet.ip.portrange.*

net.inet.ip.portrange.* sysctl(8) 变量控制自动绑定到 TCP 和 UDP 套接字的端口号范围,其中有三个范围:一个低范围,一个默认范围和一个高范围。大多数网络程序使用默认范围,它由 net.inet.ip.portrange.firstnet.inet.ip.portrange.last 控制,它们的默认值分别为 1024 和 5000。绑定的端口范围用于出站连接,在某些情况下,系统有可能运行到端口之外。这种情况最常发生在运行一个高负荷的网络代理时。当运行一个主要处理传入连接的服务器,如 Web 服务器,或有有限数量的传出连接,如邮件中转时,端口范围不是问题。对于端口不足的情况,建议适度增加 net.inet.ip.portrange.last。10000、20000 或 30000 的值可能是合理的。在改变端口范围时要考虑到防火墙的影响。一些防火墙可能会阻止大范围的端口,通常是低编号的端口,并希望系统使用较高范围的端口进行外发连接。出于这个原因,不建议降低 net.inet.ip.portrange.first 的值。

12.11.2.2. TCP 带宽延迟产品

TCP 带宽延迟乘积限制可以通过将 net.inet.tcp.inflight.enable sysctl(8)变量设置为 1 来启用。这指示系统尝试计算每个连接的带宽延迟乘积,并将排入网络的数据量限制在维持最佳吞吐量所需的数量。

当通过调制解调器、千兆以太网、高速广域网链路或任何其他具有高带宽延迟积的链路提供数据时,这一功能非常有用,特别是当同时使用窗口缩放或配置了大的发送窗口时。当启用这个选项时,还要将 net.inet.tcp.inflight.debug 设置为 0,以禁用调试。对于生产使用,将 net.inet.tcp.inflight.min 设置为至少 6144 可能是有益的。设置高的最小值可能会有效地禁用带宽限制,这取决于链路的情况。限制功能减少了中间路由和交换机数据包队列中积累的数据量,并减少了本地主机接口队列中积累的数据量。由于排队的数据量较少,交互式连接,特别是通过慢速调制解调器,将以较低的往返时间运行。这个功能只影响服务器端的数据传输,如上传。它对数据接收或下载没有影响。

不建议调整 net.inet.tcp.inflight.stab。这个参数的默认值是 20,代表在计算带宽延迟乘积窗口时增加 2 个最大的数据包。额外的窗口是稳定算法和提高对变化条件的反应能力所必需的,但它也可能导致在慢速链路上更高的 ping(8) 时间,尽管仍然比没有 inflight 算法时低得多。在这种情况下,可以尝试把这个参数减少到15、10或5,并把 net.inet.tcp.inflight.min 减少到3500这样一个值,以获得理想的效果。减少这些参数应该只作为最后的手段来做。

12.11.3. 虚拟内存

12.11.3.1. kern.maxvnodes

一个虚拟节点(vnode)是一个文件或目录的内部代表。增加操作系统可用的虚拟节点的数量可以减少磁盘 I/O。通常情况下,这是由操作系统处理的,不需要改变。在某些情况下,磁盘 I/O 是一个瓶颈,系统正在耗尽 vnodes,这个设置需要增加。不活动的和空闲的 RAM 的数量将需要被考虑在内。

要查看当前正在使用的虚拟节点的数量:

  1. # sysctl vfs.numvnodes
  2. vfs.numvnodes: 91349

查看虚拟节点的最大数量:

  1. # sysctl kern.maxvnodes
  2. kern.maxvnodes: 100000

如果当前的 vnode 使用量接近最大值,可以尝试将 kern.maxvnodes 增加到 1000 的数值。密切关注 vfs.numvnodes 的数量。如果它再次攀升到最大值,kern.maxvnodes 将需要进一步增加。否则,top(1) 报告的内存使用的转变应该是可见的,更多的内存应该被需要。