Tomcat 系统架构(上): 连接器是如何设计的?

Tomcat 系统架构(上): 连接器是如何设计的?

在面试时我们可能经常被问到:你做的 XX 项目的架构是如何设计的,请讲一下实现的思路。对于面试官来说,可以通过你对复杂系统设计的理解,了解你的技术水平以及处理复杂问题的思路。

今天咱们就来一步一步分析 Tomcat 的设计思路,看看 Tomcat 的设计者们当时是怎么回答这个问题的。一方面我们可以学到 Tomcat 的总体架构,学会从宏观上怎么去设计一个复杂系统,怎么设计顶层模块,以及模块之间的关系;另一方面也为我们深入学习 Tomcat 的工作原理打下基础。

 

Tomcat 总体架构


 我们知道如果要设计一个系统,首先是要了解需求。通过专栏前面的文章,我们已经了解了 Tomcat 要实现 2 个核心功能:

  • 处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。
  • 加载和管理 Servlet,以及具体处理 Request 请求。 

因此 Tomcat 设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。连接器负责对外交流,容器负责内部处理。 

所以连接器和容器可以说是 Tomcat 架构里最重要的两部分,需要你花些精力理解清楚。这两部分内容我会分成两期,今天我来分析连接器是如何设计的,下一期我会介绍容器的设计。

在开始讲连接器前,我先铺垫一下 Tomcat 支持的多种 I/O 模型和应用层协议。

Tomcat 支持的 I/O 模型有:

  • NIO:非阻塞 I/O,采用 Java NIO 类库实现。
  • NIO.2:异步 I/O,采用 JDK 7 最新的 NIO.2 类库实现。
  • APR:采用 Apache 可移植运行库实现,是 C/C++ 编写的本地库。 

Tomcat 支持的应用层协议有:

  • HTTP/1.1:这是大部分 Web 应用采用的访问协议。
  • AJP:用于和 Web 服务器集成(如 Apache)。
  • HTTP/2:HTTP 2.0 大幅度的提升了 Web 性能。 

Tomcat 为了实现支持多种 I/O 模型和应用层协议,一个容器可能对接多个连接器,就好比一个房间有多个门。但是单独的连接器或者容器都不能对外提供服务,需要把它们组装起来才能工作,组装后这个整体叫作 Service 组件。这里请你注意,Service 本身没有做什么重要的事情,只是在连接器和容器外面多包了一层,把它们组装在一起。Tomcat 内可能有多个 Service,这样的设计也是出于灵活性的考虑。通过在 Tomcat 中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。 

到此我们得到这样一张关系图:

Tomcat 系统架构(上): 连接器是如何设计的?

从图上你可以看到,最顶层是 Server,这里的 Server 指的就是一个 Tomcat 实例。一个 Server 中有一个或者多个 Service,一个 Service 中有多个连接器和一个容器。连接器与容器之间通过标准的 ServletRequest 和 ServletResponse 通信。