当前位置: 首页 > news >正文

从 Server.xml 到字节码:Tomcat 内核全景与请求旅程 10 000 字深剖

(零)为什么要重读 Tomcat
· 面试最爱问:HTTP 请求在 Tomcat 里到底拐了多少弯?
· 生产最怕出:CPU 100 %、线程池打满、类加载泄漏、Session 爆炸。
· 云原生最尴尬:镜像个头 200 MB,启动 30 s,HPA 还来不及扩容。
本文不贴源码,用伪代码、示意图与运维日志,带你走完一次请求的“一生”。


(一)俯瞰:Tomcat 的 4 大版图

  1. Server ‑> Service ‑> Engine ‑> Host ‑> Context ‑> Wrapper
    一条 Server.xml 就是一颗树,节点各司其职,请勿随意增删。

  2. Connector:把“字节流”封装成“Request/Response 对象”。
    BIO/NIO/NIO2/APR 四种实现,分别对应 Java 同步、Java NIO、Java AIO、OpenSSL。

  3. Container:Pipeline + Valve 责任链,像极了 Servlet Filter。

  4. 顶层组件:Jasper(JSP 编译器)、Catalina(Servlet 容器)、Coyote(HTTP 协议处理器)。

(二)一次 HTTP 请求的 12 站地

  1. Acceptor 线程:监听 8080,accept() 得到 SocketChannel。

  2. Poller 线程:NIO 模式下,把 Channel 注册到 Selector,等待 READ 事件。

  3. Processor:解析 HTTP 报文,生成 Request Coyote → Request Catalina → HttpServletRequest。

  4. Mapper:根据 URI 映射到 Host、Context、Wrapper,匹配原则“最长前缀”。

  5. Pipeline.invoke():StandardEngineValve → StandardHostValve → StandardContextValve → StandardWrapperValve。

  6. FilterChain:执行 web.xml 中配置的 Filters(顺序 = 声明顺序)。

  7. Servlet.service():业务代码开始跑。

  8. JSP 编译:如果请求 *.jsp,Jasper 把 JSP 转译成 .java,再编译成 .class,默认放在 $CATALINA_BASE/work。

  9. 响应阶段:WrapperValve → FilterChain → Connector → Poller → Socket 写回。

  10. AsyncContext:若业务开启异步,Processor 归还线程给 Poller,等待业务线程回调。

  11. keep-alive:Tomcat 10 默认 maxKeepAliveRequests=100,超出即关闭连接,防止“空轮询”。

  12. 日志:AccessLogValve 按 %h %l %u %t "%r" %s %b 格式刷盘。

(三)线程模型:Acceptor / Poller / Worker
· Acceptor:数量由 acceptorThreadCount 决定,默认 1。
· Poller:selectorPool.size = min(2, CPU 核数)。
· Worker:Executor 线程池,maxThreads 200 是“总阀门”,minSpareThreads 25 保证低峰期不反复创建。
CPU 100 % 排查模板:

  1. top -H 找 nid 十六进制 → jstack 转线程名 → 定位哪个 Servlet 卡在 SQL。

  2. jstat ‑gc 观察是否频繁 Full GC,导致线程长时间阻塞。

(四)类加载:打破双亲委派的三次场景

  1. WebappClassLoader:每个 Context 一个实例,先自己加载 /WEB-INF/classes 与 /WEB-INF/lib,再向上委派。

  2. Common ClassLoader:$CATALINA_BASE/lib 下的 JAR,被所有 Webapp 共享。

  3. Shared ClassLoader:可选配置,解决多 Webapp 共用大体积 SDK(如 Hadoop)。
    内存泄漏根因:ThreadLocal 引用 WebappClassLoader → 线程未销毁 → 元空间 OOM。
    解决方案:

  • 在 Context 的 stop() 中执行 ThreadLocal.remove()。

  • 使用 Guava 的 FinalizableReferenceQueue 清理。

(五)Session 管理:内存、Redis、JDBC、JWT
· StandardManager:内存 Map,重启即失效,仅适合单体。
· PersistentManager + FileStore:序列化到 SESSIONS.ser,优雅停机时 dump。
· RedisSessionManager:通过 Valve 拦截 request,把 Session 序列化为 JSON,存在 Redis TTL=1800 s。
坑:Tomcat 10 以后包名从 org.apache.catalina.session.RedisSessionManager 换成非官方维护,注意兼容性。
· JWT:无状态会话,Tomcat 侧只负责 Filter 解析,不存储。

(六)JSP & Jasper:编译、热替换、预编译
· JspC:Maven 插件把 JSP 预编译为 Servlet,启动提速 50 %。
· development=true 时,Jasper 监听 .jsp 文件变更,重新生成源码。
· mappedfile=false 可关闭静态文本合并,调试时行号对应准确。

(七)HTTPS & APR:OpenSSL 的零拷贝
· NIO + JSSE:Java 层握手,堆内内存拷贝两次。
· APR + OpenSSL:Tomcat Native 库,使用 DirectBuffer,CPU 降低 30 %。
· HTTP/2:通过 upgrade 或 h2c direct,依赖 ALPN 与 openssl 1.0.2+。

(八)监控与诊断

  1. JMX:Catalina MBean 暴露 Connector、ThreadPool、Session 指标。

  2. psi-probe:老牌 Web UI,支持在线查看线程栈、数据源连接。

  3. AccessLogValve:%{X-Forwarded-For}i 记录真实 IP。

  4. GC Log:-Xlog:gc*:file=/tmp/gc.log:time,uptime,pid 观察 GC 与线程阻塞关联。

(九)云原生改造 6 步曲

  1. 镜像:alpine-jre + tomcat:10-jre17,剔除 examples、docs,瘦身至 80 MB。

  2. 启动脚本:catalina.sh 里 JAVA_OPTS 外置到 ConfigMap,热更新无需重建镜像。

  3. 优雅停机:

    • server.xml 开启 <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>

    • k8s preStop exec sleep 15 让正在处理的请求完成。

  4. 探针:

    • livenessProbe 200 /healthz

    • readinessProbe 200 /ready

  5. 水平扩缩:

    • HPA 用 CPU 50 % + Tomcat 线程池利用率自定义指标。

  6. Sidecar:

    • Envoy 做 mTLS、熔断、灰度。

(十)彩蛋:Tomcat 的“隐藏功能”
· JreMemoryLeakPreventionListener:GC 触发后显式调用 sun.misc.GC.requestLatency(),减少 RMI 带来的 full GC。
· ParallelWebappClassLoader:JDK9+ 模块化后,可并行加载类,启动提速 15 %。
· StuckThreadDetectionValve:监控超过 threshold 秒的线程,发邮件报警。

http://www.dtcms.com/a/287698.html

相关文章:

  • 泛型机制详解
  • 2.4 组件间通信Props(父传子)
  • Java SE 讨论String类
  • GATE:基于移动嵌入式设备的实时边缘构建图注意力神经网络用于鲁棒室内定位
  • C++命名空间深度解析:避免命名冲突的终极解决方案
  • HTTPHTTPSTLSDNSRSA
  • LVS四种工作模式深度解析
  • ENSP路由综合实验 + 思科(cisco)/华为(ensp)链路聚合实验
  • Vite的优缺点(精简版)
  • Java大视界:Java大数据在智能医疗电子健康档案数据挖掘与健康服务创新>
  • lvs笔记
  • RabbitMQ面试精讲 Day 3:Exchange类型与路由策略详解
  • Arc虚拟细胞挑战入门指南
  • OpenCV 官翻5 - 机器学习
  • 实战AI关键词SEO核心技巧高效应用
  • python学智能算法(二十五)|SVM-拉格朗日乘数法理解
  • 7.19 Java基础 | 异常
  • OpenCV 官翻 4 - 相机标定与三维重建
  • [spring6: AspectJAdvisorFactory AspectJProxyFactory]-源码解析
  • 基于 OpenCV 的 Haar 级联人脸检测模型对比研究 —— 以典型应用场景验证为例 毕业论文——仙盟创梦IDE
  • 智能光电检测:YOLO+OpenCV联合算法工程实践
  • Spring Boot入门
  • NJU 凸优化导论(9) 对偶(II)KKT条件+变形重构
  • 从Prompt到结构建模:如何以数据驱动重构日本语言学校体系?以国际日本语学院为例
  • Java行为型模式---访问者模式
  • 自动驾驶仿真领域常见开源工具
  • Linux 内存管理(2):了解内存回收机制
  • Linux 技术概述与学习指南
  • 微信小程序——世界天气小助手
  • AWS Partner: Sales Accreditation (Business)