第一阶段:从浏览器到服务器机房(网络传输层)
-
UI/浏览器处理
- 解析:浏览器解析URL协议(HTTP/HTTPS)、Host(域名)、端口和API路径。
- 封装:将上述信息封装成HTTP/HTTPS Request请求。
-
DNS解析:
- 先查本地缓存和hosts文件。
-
若无,向DNS服务器发起请求,获取目标服务器IP。
默认自动获得IP地址和DNS服务器地址,使用DHCP协议由ISP分配
-
路由与NAT:
- 请求经过本地网关和路由器。
- NAT将用户的私有IP转换为公网IP,以便服务器回包时能找到路径。
- 经过ISP的骨干网路由跳转,最终定位到目标服务器所在的机房。
-
机房入口
- 防火墙:根据策略对流量进行拦截(丢弃、拒绝)或放行。
第二阶段:服务器硬件与操作系统层(内核层)
-
网卡接收(NIC)
-
物理层:通过光纤接收物理信号。
-
数据链路层:网卡检查以太网帧中的目标MAC地址,匹配本机MAC则接收。
-
DMA技术(关键点):网卡使用直接内存访问(DMA)技术,不消耗CPU资源,直接将数据写入内存中的环形缓冲区(Ring Buffer/Rx Ring)。
当I/O设备要进行数据传送时,通过DMA控制器 ( 多数外设已内置,PCH或SoC中亦有保留 ) 向CPU提出DMA传送请求, CPU响应之后将让出系统总线,由DMA控制器接管总线进行数据传送。
DMA的流程包括预处理、数据传送和后处理,整个数据块的传送过程都不需要 CPU 参 与 , CPU 只在最初的 DMA控制器初始化和最后的 DMA 结束处理时才介入 。
为保证降低CPU负载同时高速数据流零拷贝、不间断、不丢失,DMA利用硬件上的“循环模式(Circular Mode)”配合内存中的“环形缓冲区”实现永不停歇的数据接收,
-
-
中断处理
- 硬中断:网卡向CPU发送硬中断信号,CPU暂停当前任务。硬中断作用是快速响应,并防止中断风暴。
- 软中断:硬中断触发软中断,异步进行耗时的数据解析工作(从上下文剥离数据、协议栈处理),防止CPU长时间被占用,CPU以轮询(Polling)方式批量处理Ring中有所有权的数据,消费完成后分配新缓冲并回填到Ring中(将所有权交还DMA),最后重新开启中断等待下一轮触发
中断分为外中断或狭义的中断和内中断/异常。
外中断是由外部硬件设备(如键盘、网卡、磁盘控制器)或内部逻辑(如CPU定时器)发出的信号。
内中断由CPU在执行特定指令或遇到特定条件时触发。
外中断又可分为可屏蔽中断(可通过改变屏蔽字实现多重中断)和不可屏蔽中断(通常是严重的硬件故障)。
内中断可分为故障(指令执行异常,可修复后返回到产生故障的指令重新执行),自陷(有意的异常,通常用于调试或系统调用)和终止(使cpu无法继续执行的硬件故障,如存储器校验错误)
外中断和终止属于硬件中断,故障和自陷属于软件中断。
Linux为了提高处理效率,将中断处理过程分为了硬中断/上半部和软中断/下半部。
上半部 (Top Half) = 硬中断:直接响应硬件信号,做最少、最紧急的工作。
下半部 (Bottom Half) = 软中断/Tasklet/工作队列:处理耗时的数据操作,延迟执行。
-
TCP协议栈处理
-
三次握手:
-
客户端发SYN包。
-
服务端回SYN+ACK包,将连接存入半连接队列。
半连接队列提供有状态服务,记录正确的协商信息并避免冗余或历史连接的建立,同时提供安全防护:通过限制队列长度,防止瞬间过多的请求撑爆内存,队列爆满后第二次握手报文需要结合 SYN Cookies,但会导致资源消耗转移到了CPU,为状态信息而舍弃部分高级特性,并使防火墙的一些规则失效。
-
客户端回ACK包,服务端收到后将连接移入全连接队列。
TCP是全双工的可靠通信协议,而在不可靠的网络上要实现可靠通信就需要使用确认机制,使用SYN同步报文和ACK确认报文建立连接,确保通信双方的数据发送和接受能力正常,第一次握手和第二次握手建立客户端到服务器的连接,第二次握手和第三次握手建立服务器和客户端的连接。第二次握手复用了确认报文和同步报文,同时第三次握手也可以携带数据。
-
-
Socket缓冲:TCP层通过请求的Host/Port在内核Socket哈希表中找到对应的
Socket Structure,将Payload(剥离了TCP头部之后的业务数据)放入该Socket对应的接收缓冲区(Receive Buffer)。socket哈希表的key为(源IP地址,源端口,目的IP地址,目的端口,传输层协议)
socket structure记录这个连接的所有状态信息(是否已建立连接、拥塞窗口大小、超时时间等),以及缓冲区指针
-
第三阶段:从Tomcat容器到Java应用(应用层)
-
Tomcat 线程模型
- Poller线程:通过
epoll机制监听Socket缓冲区。一旦发现有数据可读,将Socket封装成SocketProcessor对象。 - 任务队列:Poller将
SocketProcessor提交到任务队列(Task Queue)。 - 工作线程池(Worker Threads):工作线程从Waiting状态被唤醒,从队列中取出Processor并执行
run方法。
tomcat的connector组件负责网络通信、应用层协议解析和Request/Response的转化。
连接器用 ProtocolHandler 接口来封装通信协议和 I/O 模型的差异。ProtocolHandler 内部又分为 EndPoint 和 Processor 模块,EndPoint 负责底层 Socket 通信,默认使用NIO模式,采用Reactor线程模型。
- Poller线程:通过
-
进入JVM
- 数据拷贝:工作线程将数据从内核缓冲区复制到JVM内存(Heap/Direct Memory)。
- 协议解析:解析HTTP报文(头、行、体),封装成标准的
HttpServletRequest和HttpServletResponse对象。
连接器中的Proccesor 负责应用层协议解析,从SocketChannel读取字节流到ByteBuffer并解析为tomcat request对象。然后连接器通过适配器 Adapter 将tomcat request/response对象包装成servlet request/response对象传递给容器(该设计是容器不需要关心具体协议)。
-
Spring MVC / Spring Boot 处理流程
-
Filter Chain:请求经过一系列过滤器(责任链模式)。
一个 Tomcat 实例(Server)可以包含多个 Service,而一个 Service 包含多个 Connector 和一个 Container(Engine)。
Tomcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。
- Engine - Servlet 的顶层容器,包含一 个或多个 Host 子容器;
- Host - 虚拟主机,负责 web 应用的部署和 Context 的创建;
- Context - Web 应用上下文,包含多个 Wrapper,负责 web 配置的解析、管理所有的 Web 资源;
- Wrapper - 最底层的容器,是对 Servlet 的封装,负责 Servlet 实例的创 建、执行和销毁
每个容器层级(Engine, Host, Context, Wrapper)都有自己的 Pipeline。请求像水流一样流过管道,途经一个个 Valve(阀门,用于做拦截、鉴权、日志等),最后到达底层的 Servlet 执行业务逻辑。
- DispatcherServlet:前端控制器入口。
- HandlerMapping:根据URL找到对应的Controller和Method(
@RequestMapping)。 - HandlerInterceptor:执行拦截器的
preHandle方法(权限校验等)。 -
HandlerAdapter:
- 解析参数(
@RequestParam,@PathVariable)。 - 对象转换:处理
@RequestBody,将JSON数据反序列化为Java对象。
- 解析参数(
- 业务执行:调用Controller -> Service -> DAO,执行Java业务逻辑。
-
-
响应返回(Return)
- ReturnValueHandler:处理方法的返回值。
- MessageConverter:处理
@ResponseBody,将Java对象序列化(如转为JSON字节流)。 - 写入响应:将数据写入
HttpServletResponse的输出流。 - 后置处理:执行拦截器的
postHandle。 - 回流:数据沿原路返回(JVM -> 内核Socket发送缓冲区 -> 网卡 -> 网络 -> 客户端)。