会话保持时长设置过长,直接后果是连接资源被空闲连接长期占压,极端配置下单个后端节点可能堆积上万个半开连接,导致新建请求无连接可用,负载均衡器内存和内核连接跟踪表双双告急,最终引发大面积超时或服务雪崩。
每个会话连接背后藏着哪些资源开销
会话保持本质上是让来自同一用户的请求固定打到同一台后端服务器,这个“保持”动作本身不产生太多成本,真正吃掉资源的是那些被保持住却不干活的空闲连接,业内专家指出,一个TCP长连接在后端服务器上至少占用三块资源:文件描述符、内核socket缓冲区内存、以及连接跟踪表项。
文件描述符不是无限的,Linux系统默认的ulimit -n通常是1024,生产环境调到65535甚至更高很常见,但每个进程能打开的文件描述符总数有硬上限,假设一台后端服务器部署了Nginx,worker_connections设置为10240,意味着最多同时维持1万个连接,如果会话保持超时时间设成1小时,而这1小时内实际只有几百个活跃用户,其余全是超时等待中的空闲连接,那么这1万个连接槽位很快就被占满。
连接跟踪表更隐蔽,使用iptables或firewalld的场景下,Linux内核的nf_conntrack模块会为每个连接建立一条跟踪记录,每条记录大约占300字节内存,听起来不多,但nf_conntrack_max默认值在多数发行版上是65536条,当空闲连接把这张表塞满之后,新连接根本进不来,连SSH都会卡住。
内存开销虽然单条不大,架不住数量多,一条空闲TCP连接的内核socket缓冲区默认读写各16KB到64KB,一万条空闲连接就是几百MB的内存被“挂名占用”,这些内存不会写数据,但谁也不能动它,跟被锁死的座位一样。
超时设置过长如何引发连锁故障
把会话保持超时从默认的60秒调成3600秒,表面上用户不用频繁重新登录了,但为此付出的代价是连接资源的闲置率急剧攀升,以电商大促场景为例,网关层配置了IP哈希会话保持,超时时间设成4小时,活动期间涌入大量用户,每个用户在前几分钟完成浏览、加购、下单操作后就不再产生请求,但网关依然死死攥着这些连接不放手。
后端Tomcat的maxConnections默认只有8192,一旦空闲连接把线程池和连接池耗光,新用户请求只能排队等待,延迟从几十毫秒飙升到数秒,最终表现为页面白屏、接口超时,这时候运维查监控大概率看到流量没涨,TCP连接数涨得吓人,Active Connections掉得很低。
连接跟踪表被塞满时的故障更绝,服务器CPU占用不高,内存也没爆,但所有新连接建立失败,旧连接收发数据也异常。dmesg里刷出nf_conntrack: table full, dropping packet,负载均衡器的健康检查请求也被丢包,导致后端节点被误摘除,流量全挤到剩余节点,分分钟压垮。
会话保持时长和健康检查超时混在一起踩坑很常见,某业务把会话保持设为30分钟,健康检查间隔设为5秒,超时设为2秒,后端节点发生慢查询时,健康检查连续失败,负载均衡器将节点标记为不健康,但会话保持表里还留着指向该节点的会话记录,后续请求依然被转发到故障节点,直到会话表项过期,中间这段时间用户请求全部报错,行业共识是,会话保持超时时间必须小于等于健康检查超时时间乘以最大重试次数,否则故障节点无法被及时摘除。
连接资源数学模型讲清楚占用逻辑
连接资源的占用不是一个线性关系,它跟“每秒新建连接数”和“平均请求处理时间”直接挂钩,用通俗的话说,服务器维持的连接数约等于每秒新建连接数乘以每个连接的平均存活时间,这个公式看起来简单,但很多人配置会话保持时根本没算过账。
假设一台网关每秒接收500个新请求,每个请求处理时间是200毫秒,处理后连接立即释放,那么瞬时的连接占用大约500乘以0.2,等于100条,非常轻松,但如果会话保持超时设为300秒,而这500个用户处理完请求后不再发起新请求,连接依然保持打开,瞬时连接数变成500乘以300,等于15万条,再大的服务器也扛不住。
这个模型可以套用到负载均衡器的四层转发场景,使用LVS或者Nginx Stream模块做TCP转发时,keepalive_timeout同样遵循这个逻辑,连接保持时间越长,需要的内存和文件描述符越多,两者几乎是等比关系,把超时缩短一半,连接占用就少一半,简单粗暴地有效。
云厂商的负载均衡产品对会话保持超时各有上限,简米云SLB的会话保持超时支持1秒到86400秒的配置,酷番云CLB支持1秒到3600秒,华为云ELB支持1秒到14400秒,默认值一般在15分钟到30分钟之间,选多大超时合适,得看业务的实际请求间隔,用户操作频繁的应用,超时设成5到10分钟足够;用户操作稀疏的管理后台,设成30分钟也能理解,非要设成24小时,那就要做好连接资源被大量占用的心理准备。
教你一套实用的会话保持配置检查法
检查当前负载均衡器的会话保持超时设置,别只看控制台上的数值,要结合实际流量特征来验证,收集三个数据:业务高峰期的活跃在线用户数、用户两次连续请求的最大间隔时间、后端服务器的连接数和内存余量。
常用后端Web容器(Nginx、Apache、Tomcat)的默认连接超时、最大连接数、空闲连接回收时间对比:
| 组件 | 默认连接超时 | 最大连接数 | 空闲连接回收机制 |
|---|---|---|---|
| Nginx | keepalive_timeout 75s | worker_connections 1024 | 超时直接关闭 |
| Apache | KeepAliveTimeout 5s | MaxRequestWorkers 256 | 超时直接关闭 |
| Tomcat | connectionTimeout 60s | maxConnections 8192 | 超时直接关闭 |
| Redis | timeout 0(永不过期) | 无硬性上限 | 需手动配置 |
从表格可以看出,默认超时普遍设置得比较克制,Nginx的75秒和Tomcat的60秒都是经过多年实践沉淀的合理值,直接改用这些默认值通常不会出大问题,真正需要警惕的是那些被调成“看起来更稳”的超大值,比如半小时起步的HTTP长连接配置。
检查Linux内核连接跟踪表的当前占用情况,执行sysctl net.netfilter.nf_conntrack_count和sysctl net.netfilter.nf_conntrack_max对比看余量,如果当前计数已经超过上限的八成,要么调高上限,要么缩短会话保持时间,调高上限只是给系统扩容,不解决资源浪费的问题,缩短会话保持时间才是治本。
对于负载均衡层,建议会话保持超时设为5到15分钟的区间,这个时长足够覆盖绝大多数业务的真实用户操作间隔,特别重的文件上传下载场景可以放宽到30分钟,但超过30分钟的会话保持就应该考虑用应用层的token刷新机制替代,而不是靠传输层硬扛。
排查完超时设置后,顺手检查一下后端服务的keepalive配置是否匹配,后端Nginx的keepalive_timeout如果小于负载均衡器的会话保持超时,后端连接会被提前关闭,负载均衡器还傻傻保持着到客户端的连接,数据转发时才发现后端连接已经断了,产生大量502错误,两层超时时间要遵循“负载均衡器不小于后端服务”的原则,差值尽量控制在1分钟以内。
会话保持时长设置过长的典型问题速查
会话保持时长设置过长会占用多少连接资源?
每个空闲会话连接在后端服务器上占用1个文件描述符、数十KB内核内存和约300字节连接跟踪表空间,以1万个空闲连接为例,至少占用200MB内存和1万文件描述符,同时消耗连接跟踪表约3MB空间,多数情况下,这些连接完全空闲却无法被回收。
为什么缩短会话保持超时后故障率反而下降了?
缩短超时使空闲连接被及时回收,释放出文件描述符和内存用于新建连接,连接跟踪表的表项周转加快,哈希冲突概率下降,丢包率随之降低,本质上不是“缩短超时治好了故障”,而是“连接资源重新够用了”。
如何判断当前会话保持时长是否合理?
查看后端服务器的ss -s输出,观察total连接数中timewait和established的比例,若established中空闲连接占比超过70%,且活跃请求量不大,说明会话保持时间过长,利用ss -lnt配合awk统计各状态连接数,定期对比即可量化评估,调优思路是用最小的超时时间满足用户连续操作的需求,每缩短一分钟都是在回收连接资源。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/634980.html





