09 | 比较:Jetty架构特点之Connector组件
该思维导图由 AI 生成,仅供参考
鸟瞰 Jetty 整体架构
- 深入了解
- 翻译
- 解释
- 总结
Jetty的Connector组件是其架构中的关键部分,负责处理I/O模型和应用层协议的封装。与Tomcat相比,Jetty的Connector设计更加灵活,采用了全局线程池和回调函数来模拟异步I/O,使得其在不同场景下具有更广泛的应用前景。Jetty的整体架构由多个Connector、多个Handler和一个线程池组成,其中每个连接器都有自己的线程池,但所有的Connector共享一个全局的线程池。Jetty的设计特点使其成为一个值得选择的Web容器。Jetty的Connector主要完成了三件事件:接收连接、I/O事件查询以及数据读写。为了实现这些功能,Jetty设计了Acceptor、SelectorManager和Connection来分别负责这三件事情。Jetty的Connector设计中的一大特点是使用了回调函数来模拟异步I/O,这使得其在处理请求时更加高效。Jetty的灵活性和定制化特点使其在不同场景下具有更广泛的应用前景。Jetty的Connector设计与Tomcat有所不同,通过对比分析Jetty的整体架构和Connector组件的设计,读者可以加深对Web容器架构设计的理解,同时也能更清楚地了解Jetty与Tomcat的设计区别,从而根据它们的特点来选择适合自己需求的Web容器。Jetty的Connector组件采用了Java NIO通信模型,通过Channel、Buffer和Selector等核心组件实现了高效的I/O处理。Jetty的Connector设计中的一大特点是使用了回调函数来模拟异步I/O,这使得其在处理请求时更加高效。Jetty的整体架构简洁明了,使用了全局线程池和回调函数来模拟异步I/O,使得其在不同场景下具有更广泛的应用前景。
《深入拆解 Tomcat & Jetty 》,新⼈⾸单¥68
全部留言(46)
- 最新
- 精选
- 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-01246 - 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-0221 - 锦使用不同的线程是为了合理的使用全局线程池。 我有两个问题请教老师: 问题一:负责读写的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-3015 - focus源码都是怎么导入,怎么编译,怎么看呢
作者回复: 下载这里的源码,直接IDE打开,设断点就行。 https://github.com/jetty-project/embedded-jetty-jsp
2019-05-3013 - -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-0110 - gameboy120请问注册一堆回调函数的用意是什么?
作者回复: 赶时髦,在应用层面模拟异步编程风格
2019-07-099 - 强哥说了各自的特点。但是感觉缺少关键性的对比,以及背后设计的理念,建议再深入探讨各自的主要差异及场景
作者回复: 随着讲解的深入,会涉及这部分内容。Jetty和Tomcat没有本质区别,一般来说Jetty比较小巧,又可以高度裁剪和定制,因此适合放在嵌入式设备等对内存资源比较紧张的场合。而Tomcat比较成熟稳定,对企业级应用支持比较好。
2019-05-309 - -W.LI-老师好,跑在不同的线程里是为了解耦么?实在想不出,告诉答案吧
作者回复: 反过来想,如果等待连接到达,接收连接、等待数据到达、数据读取和请求处理(等待应用处理完)都在一个线程里,这中间线程可能大部分时间都在”等待“,没有干活,而线程资源是很宝贵的。并且线程阻塞会发生线程上下文切换,浪费CPU资源。
2019-06-028 - kxkq2000分在不同的线程里我认为是这样分工明确好比工厂流水线最大化提升处理能力。 我有个疑问是用全局线程池真的好吗,不是应该根据任务类型分配线程池的吗?用全局的不会互相干扰吗?
作者回复: 全局线程池和多个隔离的线程池各有优缺点。全局的线程池方便控制线程总数,防止过多的线程导致大量线程切换。隔离的线程池可以控制任务优先级,确保低优先级的任务不会去抢高优先级任务的线程。
2019-06-017 - Lrwin感觉jetty就是一个netty模型
作者回复: 说的很对,Tomcat和Jetty相比,Jetty的I/O线程模型更像Netty,后面会讲到Jetty的EatWhatYouKill线程策略,其实就是Netty 4.0中的线程模型。
2019-05-3027