深入拆解Tomcat & Jetty
李号双
eBay技术主管
立即订阅
6067 人已学习
课程目录
已完结 44 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | Java程序员如何快速成长?
免费
模块一 必备基础 (4讲)
01 | Web容器学习路径
02 | HTTP协议必知必会
03 | 你应该知道的Servlet规范和Servlet容器
04 | 实战:纯手工打造和运行一个Servlet
模块二 整体架构 (9讲)
05 | Tomcat系统架构(上): 连接器是如何设计的?
06 | Tomcat系统架构(下):聊聊多层容器的设计
07 | Tomcat如何实现一键式启停?
08 | Tomcat的“高层们”都负责做什么?
09 | 比较:Jetty架构特点之Connector组件
10 | 比较:Jetty架构特点之Handler组件
11 | 总结:从Tomcat和Jetty中提炼组件化设计规范
12 | 实战:优化并提高Tomcat启动速度
13 | 热点问题答疑(1):如何学习源码?
模块三 连接器 (9讲)
14 | NioEndpoint组件:Tomcat如何实现非阻塞I/O?
15 | Nio2Endpoint组件:Tomcat如何实现异步I/O?
16 | AprEndpoint组件:Tomcat APR提高I/O性能的秘密
17 | Executor组件:Tomcat如何扩展Java线程池?
18 | 新特性:Tomcat如何支持WebSocket?
19 | 比较:Jetty的线程策略EatWhatYouKill
20 | 总结:Tomcat和Jetty中的对象池技术
21 | 总结:Tomcat和Jetty的高性能、高并发之道
22 | 热点问题答疑(2):内核如何阻塞与唤醒进程?
模块四 容器 (8讲)
23 | Host容器:Tomcat如何实现热部署和热加载?
24 | Context容器(上):Tomcat如何打破双亲委托机制?
25 | Context容器(中):Tomcat如何隔离Web应用?
26 | Context容器(下):Tomcat如何实现Servlet规范?
27 | 新特性:Tomcat如何支持异步Servlet?
28 | 新特性:Spring Boot如何使用内嵌式的Tomcat和Jetty?
29 | 比较:Jetty如何实现具有上下文信息的责任链?
30 | 热点问题答疑(3):Spring框架中的设计模式
模块五 通用组件 (4讲)
31 | Logger组件:Tomcat的日志框架及实战
32 | Manager组件:Tomcat的Session管理机制解析
33 | Cluster组件:Tomcat的集群通信原理
特别放送 | 如何持续保持对学习的兴趣?
模块六 性能优化 (8讲)
34 | JVM GC原理及调优的基本思路
35 | 如何监控Tomcat的性能?
36 | Tomcat I/O和线程池的并发调优
37 | Tomcat内存溢出的原因分析及调优
38 | Tomcat拒绝连接原因分析及网络优化
39 | Tomcat进程占用CPU过高怎么办?
40 | 谈谈Jetty性能调优的思路
41 | 热点问题答疑(4): Tomcat和Jetty有哪些不同?
结束语 (1讲)
结束语 | 静下心来,品味经典
深入拆解Tomcat & Jetty
登录|注册

09 | 比较:Jetty架构特点之Connector组件

李号双 2019-05-30
经过专栏前面几期的学习,相信你对 Tomcat 的整体架构和工作原理有了基本了解。但是 Servlet 容器并非只有 Tomcat 一家,还有别的架构设计思路吗?今天我们就来看看 Jetty 的设计特点。
Jetty 是 Eclipse 基金会的一个开源项目,和 Tomcat 一样,Jetty 也是一个“HTTP 服务器 + Servlet 容器”,并且 Jetty 和 Tomcat 在架构设计上有不少相似的地方。但同时 Jetty 也有自己的特点,主要是更加小巧,更易于定制化。Jetty 作为一名后起之秀,应用范围也越来越广,比如 Google App Engine 就采用了 Jetty 来作为 Web 容器。Jetty 和 Tomcat 各有特点,所以今天我会和你重点聊聊 Jetty 在哪些地方跟 Tomcat 不同。通过比较它们的差异,一方面希望可以继续加深你对 Web 容器架构设计的理解,另一方面也让你更清楚它们的设计区别,并根据它们的特点来选用这两款 Web 容器。

鸟瞰 Jetty 整体架构

简单来说,Jetty Server 就是由多个 Connector(连接器)、多个 Handler(处理器),以及一个线程池组成。整体结构请看下面这张图。
跟 Tomcat 一样,Jetty 也有 HTTP 服务器和 Servlet 容器的功能,因此 Jetty 中的 Connector 组件和 Handler 组件分别来实现这两个功能,而这两个组件工作时所需要的线程资源都直接从一个全局线程池 ThreadPool 中获取。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Tomcat & Jetty 》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(38)

  • Li Shunduo
    有两个问题请教老师:
    问题一:根据文章看,Jetty中有多个Acceptor组件,请问这些Acceptor背后是共享同一个ServerSocketChannel?还是每个Acceptor有自己的ServerSocketChannel? 如果有多个ServerSocketChannel的话,这些ServerSocketChannel如何做到监听同一个端口?连接到来时如何决定分配到哪一个ServerSocketChannel?
    问题二:Acceptor组件是直接使用ServerSocketChannel.accept()方法来接受连接的,为什么不使用向Selector注册OP_ACCEPT事件的方式来接受连接?直接调用.accept()方法有什么考虑?
    问题三:Jetty中有多个ManagedSelector,这些ManagedSelector背后是共享同一个Selector吗?还是每个ManagedSelector有自己的Selector?如果是多个Selector有什么好处,注册IO事件时如何选择合适的Selector?

    作者回复: 👍不错的问题。
    1)多个Acceptor共享同一个ServerSocketChannel。多个Acceptor线程调用同一个ServerSocketChannel的accept方法,由操作系统保证线程安全
    2)直接调用accept方法,编程上简单一些,否则每个Acceptor又要自己维护一个Selector。
    3)每个ManagedSelector都有自己的Selector,多个Selector可以并行管理大量的channel,提高并发,连接请求到达时采用Round Robin的方式选择ManagedSelector。

    2019-06-01
    10
  • focus
    源码都是怎么导入,怎么编译,怎么看呢

    作者回复: 下载这里的源码,直接IDE打开,设断点就行。
    https://github.com/jetty-project/embedded-jetty-jsp

    2019-05-30
    8
  • 使用不同的线程是为了合理的使用全局线程池。
    我有两个问题请教老师:
    问题一:负责读写的socket与handle线程是什么对应关系呢?多对1,还是1对1?
    问题二:如果有很多tcp建立连接后迟迟没有写入数据导致连接请求堵塞,或者如果有很多handle在处理耗时io操作时,
    同样可能拖慢整个线程池,进而影响到accepters和selectors,那么可能会拖慢整个线程池,jetty是如何考虑的呢?

    作者回复: 1)一个Socket上可以接收多个HTTP请求,每次请求跟一个Hanlder线程是一对一的关系,因为keepalive,一次请求处理完成后Socket不会立即关闭,下一次再来请求,会分配一个新的Hanlder线程。

    2)很好的问题,这就是为什么Servlet3.0中引入了异步Servlet的概念,就是说遇到耗时的IO操作,Tomcat的线程会立即返回,当业务线程处理完后,再调用Tomcat的线程将响应发回给浏览器,异步Servlet的原理后面有专门的一篇来介绍。

    2019-05-30
    5
  • gameboy120
    请问注册一堆回调函数的用意是什么?

    作者回复: 赶时髦,在应用层面模拟异步编程风格

    2019-07-09
    4
  • -W.LI-
    老师好!在线程模型设计上 Tomcat 的 NioEndpoint 跟 Jetty 的 Connector 是相似的,都是用一个 Acceptor 数组监听连接,用一个 Selector 数组侦测 I/O 事件。这句话怎么理解啊?
    问题1:Acceptor 数组监听连接,监听的是一次TCP链接么?

    问题2:Selector 数组侦测 I/O 事件,具体监听的是啥?

    问题3:长链接下,每次http请求会新打开一个channel的,还是复用原有的channel,channel是阻塞还是非阻塞的。

    说的有点乱不晓得老师看的懂不😂。我就是想知道,一次TCP链接,多次http具体是和connector怎么绑定的。

    作者回复: 简单可以这样理解:
    1. Acceptor就是不停的调accept函数,接收新的连接

    2. Selector不停的调select函数,查询某个Channel上是否有数据可读

    3. 同一个浏览器发过来的请求会重用TCP连接,也就是用同一个Channel

    Channel是非阻塞的,连接器里维护了这些Channel实例,过了一段时间超时到了channel还没数据到来,表面用户长时间没有操作浏览器,这时Tomcat才关闭这个channel。

    2019-06-01
    4
  • Geek_28b75e
    老师,麻烦您给说说bio和nio的区别,表面上的差别我看过了,能不能从操作系统角度给讲解一下呢?麻烦您了,实在有点难理解

    作者回复: 第14篇会详细介绍,图文并茂。

    2019-06-04
    2
  • why
    - Jetty 也是 Http 服务器 + Servlet 容器, 更小巧, 更易于定制
    - Jetty 架构: 多个 Connector + 多个 Handler + 一个全局线程池(Connector 和 Handler 共享)
    - 多个 Connector 在不同端口监听请求, 可以根据应用场景选择 Handler : ServletHandler 和 SessionHandler
    - Jetty 用 Server 启动和协调上述组件
    - Jetty 与 Tomcat 的区别
        - Jetty 没有 Service 的概念, Jetty 的 Connector 被 Handler 共享
        - Tomcat 连接器有自己的线程池, Jetty Connector 使用全局线程池
    - Connector 组件, 完成 I/O 模型 + 协议封装
        - 只支持 NIO 模型, 通过 Connection 组件封装协议
        - Java NIO 核心组件为: Channel, Buffer, Selector
            - Channel 即一个 socket 连接
            - Channel 通过 Buffer 间接读写数据
            - Selector 检测 Channel 的 I/O 事件, 可以处理多个 Channel, 减少线程切换开销
        - NIO 完成三个功能: 监听连接, I/O 事件查询, 数据读写, 对应的 Jetty 封装为 Acceptor, SelectorManager, Connection
        - Acceptor 接受请求
            - Jetty 有独立 Acceptor 线程组处理连接请求
            - Connector 的实现类 ServerConnector 中有 _acceptors 数组, 保存固定数目的 Acceptor.
            - Acceptor 是 Connector 内部类, 是 Runnable 的. 通过 getExecutor 得到线程以执行
            - Acceptor 通过阻塞接受连接, 接受连接后, 调用 accepted, 其将 SocketChannel 设为非阻塞, 交给 Selector 处理
        - SelectorManager 管理 Selector
            - 被管理的 Selector 叫 ManagedSelector, 保存于 SelectorManager 的一个数组中
            - SelectorManager 选择一个 Selector, 并创建一个任务 Accept 给 ManagedSelector, ManagerSelector 实现:
                - 调用 register 将 Channel 注册到 Selector, 拿到 SelectionKey
                - 创建 EndPoint 和 Connection, 并与 SelectionKey(Channel) 绑定
            - 当有 I/O 事件时, ManagedSelector 调用 EndPoint 返回一个 Runnable 对象, 并扔给线程池执行
        - Connection
            - 上述 Runnable 对象会调用 Connection 处理请求, 得到 Request 并调用 Handler 容器处理
            - 具体实现类 HttpConnection
                - 请求处理: 在 EndPoint 中注册一系列回调函数, 数据到达时调用. ( 用回调函数模拟异步 I/O ). 在回调方法中读数据, 解析请求并存到 Request
                - 相应处理: Handler 返回 Response, HttpConnection 通过 EndPoint 写到 Channel
    - 留言
        - 每次请求跟一个 Hanlder 线程是一对一的关系, 下一次再来请求,会分配一个新的 Hanlder 线程。
        - 多个 Acceptor 共享同一个 ServerSocketChannel 。多个 Acceptor 线程调用同一个 ServerSocketChannel 的 accept 方法,由操作系统保证线程安全

    作者回复: 👍

    2019-06-02
    2
  • Lrwin
    感觉jetty就是一个netty模型

    作者回复: 说的很对,Tomcat和Jetty相比,Jetty的I/O线程模型更像Netty,后面会讲到Jetty的EatWhatYouKill线程策略,其实就是Netty 4.0中的线程模型。

    2019-05-30
    2
  • 强哥
    说了各自的特点。但是感觉缺少关键性的对比,以及背后设计的理念,建议再深入探讨各自的主要差异及场景

    作者回复: 随着讲解的深入,会涉及这部分内容。Jetty和Tomcat没有本质区别,一般来说Jetty比较小巧,又可以高度裁剪和定制,因此适合放在嵌入式设备等对内存资源比较紧张的场合。而Tomcat比较成熟稳定,对企业级应用支持比较好。

    2019-05-30
    2
  • Monday
    tomcat还没学透,就学jetty,两者还相互比较,生怕自己混淆了

    作者回复: 这个模块还只是架构层面的学习,下一个模块会深入到细节。

    2019-05-30
    2
  • Lc
    Jetty作为后起之秀,跟tomcat相比,它的优势在哪儿?他们的设计思路不同,我们自己在设计的时候应该依据什么来确定使用哪种呢?

    作者回复: Jetty的优势是小巧,代码量小,比如它只支持非阻塞IO,这意味着把它加载到内存后占用内存空间也小,另外还可以把它裁剪的更小,比如不需要Session支持,可以方便的去掉相应的Hanlder。

    2019-05-30
    2
  • 毕延文
    前面几章还好,到这里就有些看不懂了,我还是太菜了。

    作者回复: 补一补相关的基础再来看会好点,22答疑篇希望能帮到你

    2019-06-22
    1
  • 田程杯166
    java处理网络请求的底层都是socket,传统bio是将每个网络连接的socket封装完成后,交给单独的线程去处理,那nio是怎么处理?将每个网络连接封装成的socket,用一个线程去接受 ,然后放到一个数组里面,再用一个线程去轮询这个socket数组?那么实际处理业务的代码是在什么线程呢?业务线程是在哪里创建的呢?

    作者回复:
    感觉这些问题在14篇都会得到解答...

    2019-06-11
    1
  • -W.LI-
    老师好,跑在不同的线程里是为了解耦么?实在想不出,告诉答案吧

    作者回复: 反过来想,如果等待连接到达,接收连接、等待数据到达、数据读取和请求处理(等待应用处理完)都在一个线程里,这中间线程可能大部分时间都在”等待“,没有干活,而线程资源是很宝贵的。并且线程阻塞会发生线程上下文切换,浪费CPU资源。

    2019-06-02
    1
  • 802.11
    老师,在一个类里再写接口或者类,一般是基于什么样的设计思想呢

    作者回复: 内部类,作为一个类的实现细节,外部不需要知道,通过内部类的方式实现显得整洁干净。

    2019-06-02
    1
  • kxkq2000
    分在不同的线程里我认为是这样分工明确好比工厂流水线最大化提升处理能力。
    我有个疑问是用全局线程池真的好吗,不是应该根据任务类型分配线程池的吗?用全局的不会互相干扰吗?

    作者回复: 全局线程池和多个隔离的线程池各有优缺点。全局的线程池方便控制线程总数,防止过多的线程导致大量线程切换。隔离的线程池可以控制任务优先级,确保低优先级的任务不会去抢高优先级任务的线程。

    2019-06-01
    1
  • 非洲铜
    一直没用过jetty当web容器,看的有点懵逼
    2019-05-31
    1
  • 天天向上
    为了分工协作,IO工作,业务处理工作分成两大流程环节,互不干扰,分工明确,
    高效复用IO线程
    2019-05-30
    1
  • Liam
    文中的事例里面,acceptor拿到连接后创建SocketChannel, 为什么又重新去注册Accept事件呢,socketChannel不应该只关心读写事件吗

    作者回复: 这里的Accept事件,只是扔给ManagedSelector一个任务,它拿到这个任务就把Channel注册到自己的Selector上,并不是说ManagedSelector会去accept这个连接,因为连接已经建立了。

    2019-05-30
    1
  • Wiggle Wiggle
    请教一下,在 SelectorManager 在 accept 方法里,向selector中注册channel的事件为什么还是on_accept呢?在上一步的serverchannel不是已经建立连接了吗?

    作者回复: 连接建立之后还要做些处理,这里onaccept应该建立连接的动作

    2019-08-03
收起评论
38
返回
顶部