Tomcat架构解析之BIO和ARP

一、前言

    自Tomcat8.5版本开始,Tocat移除了对BIO的支持,这篇博客内容只适用于8.0以及之前的版本。

二、BIO

    BIO即阻塞式I/O,是Java提供的最基本的I/O方式。在网络通信(此处主要讨论TCP/IP协议)中,需要通过Socket在客户端与服务端建立双向链接以实现通信,其主要步骤如下:

  1. 服务端监听某个端口是否有链接请求。
  2. 客户端向服务端发出链接请求。
  3. 服务端向客户端返回Accept(接受)消息,此时链接成功。
  4. 客户端和服务端通过Send()、Write()等方法与对方通信。
  5. 关闭链接。

    Java分别提供了两个类Socket和ServerSocker,用来表示双向链接的客户端和服务端。现实情况往往是多个客户端链接同一个服务器。在Web应用部署场景下,来自不同客户端浏览器的请求均通过服务器进行分发处理。每种服务器对于客户端请求的并发处理机制不同,接下来看一下Tomcat服务器的实现。

    Tomcat的I/O监听由Endpoint完成,具体到BIO是JIoEndpoin。尽管Endpoint并未继承自Lifecycle,但他同样有相应的生命周期方法,并在Connector状态变化时调用。

    JIoEndpoint启动过程如下:

  1. 根据IP地质(多IP的情况)以及款创建ServerSocket实例。
  2. 如果Connector没有配置共享线程池,创建请求处理线程池。
  3. 根据acceptorThreadCount配置的数量,创建并且启动org.apache.tomcat.util.net.JIoEndpoint.Acceptor线程。Acceptor实现了Runnable接口,负责轮询接收客户端请求(Socket.accept() )。这些线程是单独启动的,并未放到线程池中,因此不会影响请求并发处理。Acceptor还会检测Endpoint状态(如果状态是暂停状态,则等待)以及最大连接数。
  4. 当接收到客户端请求后,创建SocketProcessor对象(同样也实现了Runnable接口),并提交到线程池处理。
  5. SocketProcessor并未直接处理Socket,而是将其交由具体的协议处理类,如org.apache.coyote.http11.Http11Processor用于处理BIo方式下的HTTP协议。在Http11Processor中根据Socket构造具体的输入输出对象。
  6. 此外,JIoEndpoint还构造了一个单独线程用于检测超时请求。

    可见,Tomcat对于接收请求(Acceptor)和处理请求(Processor)均采用异步处理。异步接收可以保证服务器同时接收来自多个客户端的请求,而异步处理请求则可以避免请求处理过程阻塞服务器接收新请求。通过这种机制,Tomcat可以做到尽快接收请求并将其放入处理线程池。同时对于持续的链接(如文件上传)会放到一个单独“等待请求集合”(线程安全)以实现超时检测。

三、ARP

    APR(Apache Portable Runtime),即Apache 可移植运行库。APR的使命是创建和维护一套软件库,以便在不同操作系统底层实现的基础上提供统一的API。通过APR的API,出开发者可以再开发阶段不必考虑平台的差异性,也不必关心程序的最终构建环境。减少程序开发中编写特殊代码区分不同操作系统以避免系统缺陷或者利用系统特性的工作。

    APR为应用程序开发提供统一的API,对于某些操作系统不支持的功能,APR则进行模拟实现,因此采用APR可以真正做到扩平台应用开发。

    APR最早是Apache HTTP Server的一部分,后来Apache基金会考虑到其通用性,将其作为独立的项目进行维护。

    APR提供的主要功能模块包括L内存分配及内存池、原子操作、文件I/O、锁、内存映射、哈希表、网络I/O、轮询、进程以及线程操作等等。

    通过采用APR,Tomcat可以获得高度可扩展性以及优越的性能,并且可以更好的与本地服务器技术集成,从而可以使Tomcat作为一款通用的Web服务器使用,而不仅仅作为轻量级应用服务器。这种情况下,Java将不再是一门侧重于后端的编程语言,也可以更多的用于成熟的Web服务器平台。

    Tomcat启动时,会自动检测系统是否安装了APR,如果已经安装,则自动采用APR进行I/O处理(除非已指定Connector的protocol属性为具体的协议类)。

    在Tomcat中使用APR需要安装以下三个本地组件:

  • APR库。
  • APR JNI封装包(Tomcat使用)。
  • OpenSSL。

AprEndpoint

    Tomcat中APR的实现可以参见AprEndpoint。首先,他与其他Endpoint实现遵循了一致的接口定义,其次,他与NioEndpoint类似,采用轮询的方式处理请求(正确的说是NioEndpoint模仿了Apr的轮询方式)。

    AprEndpoint的处理过程如下图所示:
在这里插入图片描述
    与其他Endpoint相比,AprEndpoint在启动时除了参见Socket、绑定地址已经端口、创建SSL上下文环境,还会进行操作系统层级设置。如创建内存池、对于Unix和Windows系统设置Socket重用标识(SO_REUSEADDR)、设置延迟接收Socket的标识(TCP_DEFER_ACCEPT)。而且除了接收请求的线程池和异步超时线程之外,还要创建轮询线程和Sendfile线程。

    AprEndpoint的Acceptor线程以阻塞形式监听请求链接,当有新的请求链接时,他会构造一个SocketWithOptionProcessor对象并且提交到请求处理线程池。该对象会判断是否设置了TCP_DEFER_ACCEPT表示。如果是,直接调用Handler(负责构造具体的协议处理类)处理请求;否则,将当前Socket添加到Poller线程的轮询队列,Poller线程轮询检测Socket的状态,并且根据检测结果构造SocketProcessor对象并且提交到请求处理线程池。SocketProcessor对象直接调用Handler进行请求处理。

    之所以如此设计,是因为如果设置了TCP_DEFER_ACCEPT标识,只有数据到达后,服务单才会Accept请求,此时在SocketWithOptionProcessor中可以直接处理请求,而不必再轮询检测状态。如果没有设置该标识,则需要轮询检测数据是否到达,此时需要将准备好的请求提交到线程池处理,以避免阻塞轮询线程。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值