`
xitong
  • 浏览: 6313699 次
文章分类
社区版块
存档分类
最新评论

jetty http client 实现分析

 
阅读更多

背景


谈到http client,可能大多数想到就是apache的那个http client 或者jdk自带的urlconnection,也许有人会考虑使用netty

无论如何,jetty的高性能实现总归是让人感到好奇,接下来我们一探究竟


样例


我们结合样例代码具体分析


  • 初始化
httpClient = new HttpClient();
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
httpClient.setMaxConnectionsPerAddress(10);
httpClient.setThreadPool(new QueuedThreadPool(20)); // max 20 threads
httpClient.setTimeout(5000); // 5 seconds timeout; if no server reply, the request expire
httpClient.start();


  • 运行
               ContentExchange exchange = new ContentExchange(true) {
			@Override
			protected void onResponseComplete() throws IOException {
				if (getResponseStatus() == 200) {
					String content = getResponseContent();
					System.out.println(content);
				}
			}

			@Override
			protected void onExpire() {
				System.out.println("time out");
			}
		};
		exchange.setMethod("GET");
		exchange.setURL("http://127.0.0.1:8080/simple?id=x");
		httpClient.send(exchange);

代码分为两段

  • 初始化:设置httpclient
  • 运行:实例化ContentExchange,定义callback,本例定义了两个常用的callback:onResponseComplete 和onExpire,更多的callbac可参考官方文档
  • APP在调用httpClient.send(exchange);后不会象往常一样等待返回而是立即返回, 如果有结果或者超时会通过上面的callback通知到APP



httpclient的原理及实现

1 )httpclient的模型



  • SelectConnector: 作为一个connection管理器,封装了selector和connection
  • HttpDestination:一个host的抽象一个HttpClient会连接到多个HttpDestination
  • HttpExchange:一次http请求的封装,一个HttpDestination会有多个HttpExchange以及多个AsyncHttpConnection
  • AsyncHttpConnection:HttpClient对某个HttpDestination的一个网络连接,底层包含一个对应的socket, 可复用来完成多次请求, 如果空闲太久会被废弃
  • SelectChannelEndPoint:socket的封装,AsyncHttpConnection和SelectChannelEndPoint一一对应, 但AsyncHttpConnection承载了更多的东西
  • HttpGenerator:生成http request,在jetty server中负责生成http response
  • HttpParser: 解析http response, 在jetty server中负责解析http request
  • ThreadPool: 线程池,httpclient需要使用线程池配合完成无阻塞IO,这个会在后面的httpclient整体架构分析中详述
  • Timeout:一个已时间排序的链表结构,链表中存储需要过期执行的task,这个会在后面流程分析详述


2)httpclient的整体架构



http client 分为3组线程配合完成


  • selector线程组:数目可设置,默认为1,从_change队列中获取socket注册并扫描操作系统级别的网络事件, 通常是socket可读, 可写的信息,一旦发现有socket可读写,会将相关socket任务丢入_jobs队列供worker线程执行
  • worker线程组:数目根据并发的情况决定,从_jobs队列获取任务,如果任务阻塞会丢入_changes队列异步等待通知再干活
  • tick线程:数目1个,专门用于监控超时的请求以及空闲太久的连接
  • 所有的线程都来自线程池,所以线程池最小为3,否则无法work


3)典型的场景分析
模拟一次请求


3.1 )httpclient初始化


  • 1-2设置两个超时链表,一个是超时请求链表,一个是超时连接链表
  • 3 启动httpbuffer
  • 4 启动线程池
  • 5 启动SelectConnector,此时会启动selector线程任务
  • 6 启动tick线程任务


3.2)jetty http client runtime


3.2.1)httpClient.send(exchange)到底干了什么


  • 1-2正如样例代码所示,APP设置HttpExchange,然后httpclient的send方法
  • 2.1-2.2 httpclient根据httpexchange获取对应http destination,并调用其send方法
  • 2.2.1 将次请求加入请求超时链表
  • 2.2.2 - 2.2.3 获取空闲连接,如果没有,则产生一个新的连接,并调用select进行注册,否则直接使用该连接,并将此连接丢入 _jobs队列让worker线程完成请求
  • 此时客户端就这样无阻塞的完成了


3.2.2)select线程如何参与这个场景




  • 1-3 selector线程从_change队列获取到新的socket, 开始实例化SelectChannelEndPoint
  • 4 通知http desination连接完成,于是http detination将次连接丢入连接超时链表
  • 5-6 将此连接/请求丢入_jobs队列供worker线程使用
  • 其实在selector线程内部还有一个该死的任务来处理空闲太久的socket,这个其实和tick线程有些重复了,我想这主要是因为jetty http client复用jetty server中select的结果

3.2.3)worker线程又如何参与这个场景



  • worker线程从队列中获取任务
  • 1.1 通过此连接发送请求,请求内容http generator产生
  • 1.2 一发完请求立即通过http parser读取响应,如果服务器够快,通常会读到响应
  • 1.3 如果服务器不能及时响应,那么调用SelectChannelEndPoint的updateKey。向select更新此时感兴趣读, 并等待select异步通知
  • 此时worker线程并不会阻塞等待服务返回,而是返回到线程池中去完成别的请求任务

3.2.4)tick线程又干了什么



  • 轮询两个链表_timeoutQ、_idleTimeoutQ,没啥事休眠200ms
  • 请求超时链表_timeoutQ
      • 1 从链表中删除自己
      • 2 执行链表取出的task,一个http exchang中匿名内部类实例
      • 2.1 执行APP 定义的callback: onExpire函数
      • 2.2 http desination专门维护一个exchange list来跟踪进行中的请求,此时调用其exchangeExpired, 删除list中该请求(可能此时list并没有该请求)
      • 2.3 关闭连接
  • 连接超时链表_idleTimeoutQ
      • 1从链表中删除自己
      • 2 关闭连接
      • http desination 维护了两个list:_connections和 _idle,前者跟踪该host的所有连接, 后者跟踪该host的所有空闲连接,此时也会从这两个list删除连接


小结


从jetty http client应该能感知到一个高性能的客户端的某种设计模式


  • worker 线程异步干活,使得app线程无阻塞,app线程通常在web 应用中也是一种服务线程,所以无阻塞特别重要, 想想在jetty server中使用jetty client的场景
  • select 线程通知网络ready事件,使得worker线程无阻塞,如果没有select线程,worker线程也失去了意义, 对于app线程来说无非是压力堆积到了worker线程这边,worker线程迟早是瓶颈
  • tick线程,一种解决超时问题的设计


但这种模式未必适合那种性能很好且稳定的cache server,比如redis,memcache之类,如果后端处理够快, 少量线程甚至单线程+队列都能work,但无论如何比起常规的连接池模式强了不少

分享到:
评论

相关推荐

    eclipse-jetty-plugin-master_源码.rar

    6. **性能优化**:通过阅读源码,开发者可以学习到Jetty是如何实现高效的HTTP处理,如零拷贝、NIO(非阻塞I/O)和EPOLL(Linux下的高性能网络I/O)等技术。 7. **测试框架**:源码通常包含了单元测试和集成测试,这...

    httpcomponents-client.rar

    标签"client"表明这些库主要面向客户端应用,通常与服务器端的HTTP服务器组件(如Apache Tomcat、Jetty等)相对,用于实现客户端应用程序与服务器之间的通信。 在实际开发中,这些库可以方便地集成到Java项目中,...

    jmeter 4.0 websocket plugin 打包

    - **websocket-client-9.4.10.v20180503.jar**:Jetty的WebSocket客户端实现,支持WebSocket协议。 通过以上步骤和依赖库,JMeter能够有效地进行WebSocket的性能测试,包括连接建立时间、消息发送与接收速度、并发...

    jersey 3.12全依赖包

    5. `javassist-3.29.0-GA.jar`:这是一个Java字节码操作和分析框架,Jersey使用它来动态生成类和修改字节码,实现诸如拦截器等功能。 6. `jetty-jakarta-servlet-api-5.0.2.jar`:这是Jetty对Jakarta Servlet API的...

    JMETER WEBSOCKET

    这些库包含了Jetty的各个部分,如jetty-util、jetty-client、jetty-http、jetty-io和jetty-xml,它们分别负责基础工具、客户端连接、HTTP协议处理、I/O操作以及XML解析等。 2. **WebSocket API 和 Common**:...

    jmeterwebsocket_jar包.rar

    websocket-common-9.1.1.v20140108.jar、websocket-api-9.1.1.v20140108.jar和websocket-client-9.1.1.v20140108.jar是Jetty对WebSocket协议的实现,它们包含了WebSocket的API定义、共通逻辑以及客户端实现。...

    JMeterWebSocketSampler插件包

    6. websocket-client-9.1.1.v20140108.jar:Jetty的WebSocket客户端实现,允许程序作为WebSocket客户端发起连接和发送/接收数据。 7. JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar:核心的JMeter WebSocket采样器...

    Jmeter_socket_依赖jar包

    7. **websocket-client-9.1.1.v20140108.jar**:Jetty WebSocket客户端的实现,让开发者可以在应用程序中创建WebSocket客户端连接到服务器。 这些库共同构成了JMeter进行WebSocket测试所需的基础环境。为了在JMeter...

    jmeter websocket 依赖包 免费下载

    6. websocket-client-9.1.1.v20140108.jar:Jetty的Websocket客户端实现,用于建立和维护到Websocket服务器的连接。 7. JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar:这是JMeter的插件,专门用于Websocket测试,它...

    uml.rar_java web server_web server client

    描述中的“WEB SERVER FROM CLIENT OK”可能意味着在实现或测试过程中,客户端已经成功地与Java Web服务器建立了连接,并且能够正常通信。这通常涉及到网络编程的基础,如HTTP协议的理解,以及Servlet或JSP(Java...

    client/server

    在IT行业中,"client/server"模型是一...综上所述,"client/server"模型在Java中涉及到了客户端编程、服务器端开发、HTTP协议交互等多个知识点,每个环节都需要细致的设计和实现,以构建高效、安全、可靠的分布式应用。

    Java健身俱乐部管理系统(Client + Server)

    2. **网络通信**:系统可能使用了Java的Socket编程或HTTP协议实现客户端与服务器间的通信。 3. **多线程**:在服务器端,多线程处理用户请求,保证了并发性能,提升了用户体验。 4. **数据库操作**:可能使用了JDBC...

    jmeter的websocket插件

    6. `websocket-client-9.1.1.v20140108.jar`:Jetty的WebSocket客户端实现,允许程序通过WebSocket协议与远程服务器通信。 7. `JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar`:这是JMeter WebSocket插件的核心组件,...

    使用Jmeter测试WebSocket的接口测试的相关jar包

    6. **websocket-client-9.1.1.v20140108.jar**:WebSocket的客户端实现,允许程序作为WebSocket客户端与WebSocket服务器进行通信,正是我们在JMeter中测试WebSocket接口所需要的组件。 将这些jar包拷贝到Jmeter的\...

    frp_c#_客户端.rar

    5. **源码分析**:"FrpClient-Win-master"源码库的分析,理解客户端程序的架构和工作流程,这对于自定义功能或者解决潜在问题非常有用。 6. **部署与运行**:学习如何在本地计算机上安装和运行FRP客户端,以及如何...

    JMeterWebSocketSampler

    6. **websocket-client-9.4.14.v20181114.jar**:实现了WebSocket客户端的功能,支持与WebSocket服务器建立连接并进行数据交换。 7. **JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar**:这是JMeterWebSocketSampler的...

    WebSocket 在Jmeter测试工具所需jar包

    6. **websocket-client-9.1.1.v20140108.jar**:WebSocket客户端实现,允许创建和管理WebSocket连接,发送和接收数据。 7. **JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar**:这是一个专门为JMeter设计的WebSocket...

    JRebel 插件

    4. **兼容性广泛**:除了IDEA,JRebel 还可与Eclipse、NetBeans等主流Java开发环境无缝集成,并支持Tomcat、Jetty、WebLogic、WebSphere等多种应用服务器。 5. **资源管理**:JRebel 提供了对类加载器的智能管理,...

    apache xmlrpc-3.1.1-sources.zip

    3. **xmlrpc-client-3.1.1-sources.jar.zip**:这是XML-RPC客户端实现,包含了用于发送XML-RPC请求并接收响应的类和接口。开发者可以使用这个模块创建一个XML-RPC客户端,调用远程服务器上注册的XML-RPC服务。它提供...

    基于webservice实现的一个CXF例子

    在CXF项目中,通常会使用一个启动脚本来启动Web服务服务器,例如`cxf-service.xml`这样的Spring配置文件,它会启动一个Jetty或Tomcat服务器并部署Web服务。客户端代码则可以通过执行特定的main方法或者单元测试来...

Global site tag (gtag.js) - Google Analytics