
在高并发的Web服务环境中,TCP连接队列、文件句柄限制以及交换分区策略是保证系统稳定的三大要素之一,任何一个环节出现错误都会导致连接被拒绝、请求响应时间变长或者进程假死的情况发生。
TCP连接队列由SYN队列和Accept队列组成两层结构,其中net.ipv4.tcp_max_syn_backlog用来控制半连接队列的大小来应对突发的SYN洪水攻击,而somaxconn则决定了整个连接队列的最大值,对应用层的accept()函数速度有直接影响。当Nginx或者应用服务器瞬时处理能力不够的时候,如果Accept队列太短的话就会导致内核直接把已经完成了三次握手但是还没有被接受的连接给丢弃掉,客户端就会看到连接超时。因此要调整这两个参数的时候要一起考虑应用程序的backlog设置,不能出现内核队列和应用层队列长度不一致的情况。
文件句柄限制分为系统级的fs.file-max和进程级的ulimit两种类型,每一个TCP连接、日志文件或管道都会占用一个句柄。当高流量网站的连接数超过了默认的1024个进程限制的时候,worker进程就不能再创建新的socket了,在错误日志中会经常出现“Too many open files”的信息。因此要把进程级的限制提高到几万级别,并且要保证系统级的上限有足够的空间来应对这种情况的发生,避免出现句柄用尽导致的连锁反应。
swappiness参数用来控制交换分区的行为,取值范围是0到100之间。传统的默认值60会使内存在受到压力的时候就进行页换出操作,从而产生不可预测的I/O延迟。对于对延迟比较敏感的Web服务来说,把它的值降到10以下可以抑制不必要的交换行为,在物理内存真的用光之后才启动swap。另外合理设置vm.overcommit_memory可以避免因为内存分配失败而导致的OOM Killer误杀重要进程的情况发生。
三者之间存在隐性的关系:句柄用尽会加快连接堆积的速度,队列满了会使内存更加紧张,内存不足会导致swap抖动,最后造成性能雪崩。
内核参数的优化不是单独调整某个值,而是要建立起TCP连接管理、资源限制和内存回收之间的动态平衡关系,根据实际的流量特征以及硬件配置来进行有针对性的调节,并且用监测数据来不断验证自己的效果,从而把网站稳定性的基准设定在一个可以预见的范围内。