web容器

 人参与 | 时间:2026-10-17 07:27:01

Tomcat跑着三千个线程,每个线程都在等数据库连接池还一个连接。连接池早就空了,新来的请求只能排队。我盯着监控面板上的红色曲线,心想这破容器又要背锅了——但真凶其实在代码里,有人写了个死循环,把连接全占住了。

Web容器这东西,说穿了就是个调度员。你写的Servlet、Controller,本质上都是些干活的工人。容器负责把HTTP请求分发到对应的工人手上,等工人干完活,再把结果打包成HTTP响应发回去。听起来简单,但魔鬼全在细节里。

我见过最离谱的一次事故,是某个老系统用的容器版本太旧,对HTTP/2协议支持不全。客户端明明发了新的请求格式,容器解析不了,直接返回400错误。用户那边以为是系统崩了,其实只是容器和协议版本不匹配。升级容器版本后,问题立刻消失——就这么简单,但排查花了一整天。

容器的另一个隐藏角色是资源管家。线程池大小、连接池上限、内存分配,全由它说了算。默认配置从来都不适合生产环境,Tomcat默认的线程池是200,但你要是真让200个请求同时进来,每个请求又都去查数据库,数据库那边可能先扛不住。所以调优的时候,得先摸清楚你的业务到底吃哪块资源——是CPU密集还是IO密集,决定你要多开线程还是多给内存。

有个朋友的公司,把容器从Tomcat换成了Undertow,说是性能提升明显。我问他改了什么代码,他说一行没改,就是换了个容器。Undertow的IO模型更激进,同样的硬件条件下,并发处理能力确实强一些。但代价是配置方式完全不同,团队花了两周才适应新容器的调优参数。所以换容器不是银弹,你得先搞清楚瓶颈在哪。

容器最容易被忽视的功能是类加载机制。每个Web应用都有自己独立的类加载器,这意味着你可以在同一个容器里部署两个不同版本的同名库,互不干扰。但这也带来一个经典坑——两个应用用了同一个第三方库的不同版本,如果那个库里有静态变量,就可能出现诡异的串数据问题。排查这种问题比看线程栈还折磨人。

现在流行的Spring Boot内嵌容器,把Tomcat或Jetty直接打包进应用里,省去了单独装容器的麻烦。好处是部署简单,坏处是出了问题你得自己管容器的生命周期。以前容器崩了,重启一下容器就行;现在容器崩了,你得重启整个应用进程,如果应用启动要五分钟,那酸爽,谁试谁知道。

说回开头的死循环。最后我定位到那个问题代码,修掉之后,容器又恢复平静。它还是那个调度员,线程池还是那个大小,但一切顺畅了。容器本身不产生性能,它只是放大你代码的效率——你写得好,它帮你扛住高并发;你写得烂,它替你背锅,然后被运维骂。

顶: 122踩: 63