前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Tomcat NIO(5)-整体架构

Tomcat NIO(5)-整体架构

作者头像
TA码字
发布2020-08-05 16:40:30
9420
发布2020-08-05 16:40:30
举报
文章被收录于专栏:TA码字TA码字

上一篇文章里我们主要介绍了 tomcat NIO 的数据处理类,即实现读写封装的Request 和 Response,在这里我们主要介绍 NIO 整体架构。

对于 tomcat NIO 来说,是由一系列框架类和数据读写类来组成的,同时这些类运行在不同的线程中,共同维持整个 tomcat NIO 架构。包括原始 socket 监听的acceptor 线程,监测注册在原始 scoket 上的事件是否发生的 poller thread 事件线程,进行数据读写和运行 servlet API 的 tomcat io 线程。当数据需要多次读写的时候,监测注册在原始 scoket 上的读写事件的 block poller 事件线程。这些类和线程共同组成的 tomcat NIO 整体结构如下所示:

上面我们可以发现整体架构运行着4种线程:

  • Acceptor 线程
  • Poller 线程
  • Tomcat IO 线程
  • BlockPoller 线程

Acceptor线程

  • tomcat NIO 架构中会有一个 acceptor 线程,这个线程主要监听端口。当有请求过来的时候,完成 tcp 三次握手,将 accept 过来的 socket 注册OP_REGISTER 事件,并将该事件提交到 Poller 线程的事件队列 PollerEventQueue中 。

Poller线程

  • 在 tomcat NIO 架构中会有 poller 线程,在 tomcat8 及以前的版本之中,可以通过 pollerThreadCount 配置 poller thread 的数目,但是在 tomcat 9.0.21 中 poller thread 数目始终会为 1。
  • poller thread 的核心功能主要由以前文章中介绍的 Poller 类来实现,对于每一个 poller 实例都有一个 NIO selector 实例,同时也有一个事件队列SynchronizedQueue<PollerEvent>。
  • 对于每一个 poller thread 来说,都会去轮询队列 SynchronizedQueue<PollerEvent>,该队列的事件由 acceptor 线程(监听到新连接时)或者 tomcat io 线程(处理完请求之后保持长连接,添加读事件)放入,然后根据不同的事件对原始socket注册相应的读写事件。
  • 每一个poller thread 来说,会调用 java NIO 对象 selector,发起系统调用,来监测原始 scoket 是否有读写事件发生,如果有则将原始 scoket 的封装对象交由 tomcat io 线程处理。

Tomcat IO线程

  • tomcat io 线程是一个线程池,线程池大小可由 tomcat 相关参数配置。
  • tomcat io 线程会接受 poller thread 传入的 scoket 封装对象后,依次调用以前文章介绍的 SocketProcessor/ConnectionHanlder(global instance)/Http11Processor/CoyoteAdapter,最后交由 servlet container 完成servlet API 的调用。
  • 对于request header 的解析,request body 的获取,servlet API 的调用,response 数据的写入发送,这一系列过程都是在 tomcat io 线程中完成的。
  • 对于request header,request body 有时候需要多次读取操作,这个时候 tomcat io 线程会将原始 socket 再次进行读事件的注册,并交由 BlockPoller 线程处理,然后在以前文章中介绍的 readLatch (CountDownLatch) 对象上等待。
  • 对于 response data 有时候不可写,比如原始 scoket 的发送缓冲区满了,这个时候 tomcat io 线程同样会将原始 socket 再次注册写事件,并交由 BlockPoller 线程处理,然后在以前文章介绍的 writeLatch 对象上等待。

BlockPoller线程

  • tomcat NIO 架构中会有 block poller 线程,其核心功能由以前文章中介绍的 BlockPoller 类来实现,BlockPoller 实例会有一个 NIO selector 实例,同时也会拥有一个自己的事件队列实例SynchronizedQueue<Runnable>。
  • 对于BlockPoller thread来说, 会去轮询队列 SynchronizedQueue<Runnable>,该队列的对象(RunnableAdd类型)由 tomcat io 线程放入,然后根据不同的对象对原始 socket 注册相应的读写事件。
  • 对于BlockPoller thread来说, 会调用 java NIO 对象 selector,发起系统调用,来监测原始 scoket 是否有读写事件发生。如果有,则将以前文章介绍的在 readLatch 或者 writeLatch 对象上等待的 tomcat io 线程唤醒,然后 tomcat io 线程继续完成读写操作。

目前先写到这里,下一篇文章里我们继续介绍 tomcat NIO 中的 acceptor 线程。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TA码字 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档