基于Netty的HTTP客户端的设计与实现
2014-02-08金志国李炜
金志国,李炜
(1 北京邮电大学网络与交换技术国家重点实验室,北京 100876;2 东信北邮信息技术有限公司,北京 100191)
基于Netty的HTTP客户端的设计与实现
金志国1,2,李炜1,2
(1 北京邮电大学网络与交换技术国家重点实验室,北京 100876;2 东信北邮信息技术有限公司,北京 100191)
能力开放平台是一个提供电信能力开放的移动互联网开放平台,向开发者提供丰富的业务能力,包括:短信、彩信、地图、定位等。能力开放平台接入系统需要异步处理客户端的HTTP请求,而平台内部各个系统间的消息传递也需要使用大量的异步HTTP请求。Netty是一款异步的事件驱动的网络应用开源框架,用于快速开发可维护的高性能、高扩展性协议服务器和客户端。本文简述了通过对开源框架Netty的源码封装,提供方便易用可以发送异步HTTP请求的客户端的设计思路和具体实现。
Netty框架;NIO 技术;异步;HTTP客户端
云计算是服务的交付和使用模式,指通过网络以按需、易扩展的方式获得所需服务。在云计算技术发展日新月异的今天,业界开始更多的转向云平台。能力开放平台是基于PaaS(Platform as a Service,平台即服务)提供电信能力开放的移动互联网开放云平台,向开发者提供丰富的业务能力,包括:短信、彩信、地图、定位等。在能力开放平台的接入系统部分,需要处理海量的请求。在用户体验不断提高的要求下,能力开放平台业务处理日益复杂造成交互延迟,传统的Web请求同步模式下业务处理的阻塞造成的延迟已经满足不了高并发需求[1]。
在接入系统内部以及接入系统与其他系统之间,多采用HTTP进行数据传输。由接入系统接受客户传来的请求,进行异步处理,但系统内部的信息传输仍然采用同步模式时,则会造成阻塞,异步的Web服务器也失去了意义。所以,在云平台项目开发过程中急需要一个可以支持大并发高效稳定的异步HTTP客户端[2]。
目前,异步HTTP客户端只有Apache Http Components项目的HttpAsyncClient 4.0-beta4,但仍然是对外测试版。其他的异步框架,如Mina、Netty和Grizzly,均是以Java NIO(Non-Blocking I,非阻塞IO)为基础。本文通过调研,选定采用Netty作为底层源码实现异步HTTP客户端。
1 Netty概述
Netty[3]是一款异步的事件驱动的网络应用框架和工具,用于快速开发可维护的高性能、高扩展性协议服务器和客户端。Netty是一个基于Java NIO[4]客户端/服务器框架,支持快速、简单地开发网络应用,如协议服务器和客户端。
图1 HTTP客户端总体模块图
Netty具有以下优势:
(1)对阻塞和非阻塞的socket提高统一的API;
(2)高度可定制化的线程模型;
(3)基于拦截链模式的事件模型有很高的灵活性和扩展性;
(4)对多种协议的支持,包括HTTP、TCP、UDP、SMTP、FTP以及二进制文本协议,完全支持SSL/TLS,适用于快速开发各种高级组件。
2 总体设计与分析
2.1 总体设计
本文是以Netty框架[3]为底层,将Netty提供的对HTTP协议的支持,编解码等功能封装成异步HTTP客户端,提供简单易懂的API使用,可以很容易的发送HTTP请求,并异步处理HTTP响应。
基于Netty的HTTP客户端总体模块设计[5]见图1所示,设计思路如下:
(1) 提供一个整体的配置类,作为API的入口;
(2) 针对不同的配置类,生成不同的异步客户端启动类;
(3) 由异步客户端负责发送异步和同步的HTTP请求。
2.2 网络模型
Netty基于Java NIO设计并实现,因此它实现异步的方式与Java NIO类似,采用的网络模式是reactor模式。
每个Worker其实表示的是Selector和Thread一种组合,如图2所示。每次创建一个连接,都会选择一个Worker,并且注册到Worker里的Selector,Worker会进行loop,不断地关注通道事件,也就是会说每个Worker(Selector)下会注册多个Channel,并且不断地去Select关注的Channel。Selector在发现感兴趣的事件后,直接调用Channel的Pipeline进行处理。
图2 worker线程模型[3]
2.3 事件驱动模式
消息处理模型采用的是基于事件的Pipeline模式。Pipeline实际上可以理解为对Channel的filter chain,可以通过在Pipeline中定义多个handler来处理各种事件。
Channel表示一个与socket关联的通道。ChannelPipeline是管道,一个Channel拥有一个ChannelPipeline,负责维护两个处理链,即upstream链和downstream链。处理链由多个处理句柄ChannelHandler构成,每个ChannelHandler处理完以后会传递给链中的下一个处理句柄继续处理。ChannelHandler是处理句柄,用户可以定义自己的处理句柄来处理每个请求,或发出请求前进行预处理,典型的处理句柄有编解码器decoder和encoder。ChannelEvent事件是整个模型的处理对象,当产生或触发一个事件时,该事件会沿着ChannelPipeline处理链依次被处理。ChannelFuture表示异步结果,这个是异步事件处理的关键,当一个事件被处理时,可以直接以ChannelFuture的形式直接返回,不用在当前操作中被阻塞。可以通过ChannelFuture得到最终的执行结果,具体的做法是在ChannelFuture添加监听器listener,当操作最终被执行完后,listener会被触发,我们可以在listener的回调函数中预定义我们的业务代码。
ChannelPipeline维持两个处理链:upstream、downstream。Upstream一般处理来自Channel的读事件,而downstream一般处理向Channel的写事件。需要注意的是,这两个处理链是相互独立的,在upstream链中传递到最后一个ChannelHandler处理后,不会再传递到downstream链中继续处理。
在downstream链的末端会有个ChannelSink处理,用户可以自定义这个ChannelSink的实现,系统也有个默认的实现,当downstream链中最后一个ChannelHandler处理完后会被传递给这个ChannelSink进行最后的处理。
2.4 详细设计
2.4.1 配置类
图3定义了总配置的接口,具体的配置实现类通过实现总配置的接口,实现自己的配置信息。
图3 配置类图
Netty的配置类部分内容见表1。
2.4.2 启动类
通过将配置类NettyConfig作为参数传入给异步客户端类[5], 异步客户端类会根据配置类的类型,返回不同的启动类。如果传入NettyConfig,则调用nettyProvider。对应调用Netty底层的bootstrap帮助类,封装成异步客户端启动类返回给用户。用户则可以通过该启动类发送同步或者异步HTTP请求。
由Netty的网络模型(2.2章节)可知,Netty底层采用线程池处理消息的发送和接受,boss线程和worker分别各用一个线程池,即需要两个线程池。如果每次发送一条HTTP请求,都新启动一个Netty客户端类,对应生成新启动两个线程池,开销较大,Netty的性能也完全没有利用起来。由此,设计时采用单例模式,只生成一个AsyncHttpClient异步客户端实例,所有的请求都是通过这个客户端实例进行发送的。
表1 配置项
2.4.3 编解码类
因为Netty消息处理采用事件驱动模式,编解码的工作在Pipeline中进行。Netty已经提供好了多种HTTP[6]的编解码类,如HttpResponseDecoder(对HTTP响应进行解码工作),HttpRequestEncoder(对HTTP请求进行编码工作)。
在Pipeline中除去编解码类,剩下最主要的就是需要我们自己定义的响应处理逻辑类HttpResponse Handler,该类需要继承SimpleChannelUpstream Handler类。经过Decoder解码后的HTTP响应消息会传递到处理逻辑类,方便我们响应进行操作。
这里采用了一种巧妙的设计思路,让 Netty的启动类NettyHttpClient继承SimpleChannelUpstream Handler类,使得响应的处理逻辑也可以通过Netty启动类配置。统一了API的使用。
获取返回消息,定义了两种方式:
(1) 通过默认的handler处理逻辑,获取结果时,通过阻塞的方式,等待默认handler得到结果后,将结果返回。
(2) 通过自定义的回调函数,实现客户端代码的异步。当有消息时,会自动通知客户端。通过实现回调函数接口,可以对响应进行多种操作。
2.4.4 设计模式
本文在设计异步客户端时,参考了很多开源框架[5]的设计原理,采用了工厂模式、Builder模式和单例模式等方法实现[7]。
(1)工厂模式
使用工厂模式构建配置类和启动类,如图4所示,不同的框架实现不同的配置类。异步客户端类根据配置类的类型,产生不同的异步客户端启动类,进行HTTP请求的发送。为以后扩展其他的框架实现方式提供了接口支持。
(2)Builder模式
因为配置类有很多参数需要配置,如果对每一种可能的情况都设置一个构造器,工作量将是非常巨大的,而且可读性很差。采用Builder模式,不直接生成需要的对象,而是让客户端利用所有必要的参数调用构造器(类似于静态工厂的方式),得到一个Builder对象。然后通过对Builder对象上调用类似于setter的方法,来设置每一个相关的可选参数。Builder是配置类的静态成员类,通过调用Build方法来生成不可变的对象。
(3)单例模式
通过单例模式可以保证系统中一个类只有一个异步客户端实例可以被外界访问,从而方便对实例个数的控制并节约系统资源,避免了每次发送请求构建线程池和销毁线程池的开销,高并发量下,功能得到了保障,性能得到了提高。
2.5 分析测试和结果
在完成了基于Netty的HTTP客户端开发工作了,对几种HTTP客户端的性能进行了简单的比较。比较了3种HTTP客户端。2种异步客户端,分别为本文实现的客户端, HttpAsyncClient。1种同步客户端,HttpClient。
图4 工厂模式
通过跑10 000个HTTP的GET请求,得出结果:使用异步的NettyHttpClient共用时间5 972 ms,使用异步的HttpAsyncClient共用时间9 021 ms,使用同步的HttpClient共用时间29 310 ms。从测试结果分析,发现异步客户端比同步客户端效率要高很多,而基于Netty实现的异步HTTP客户端效率要比apache要高。
3 应用
本文所述的基于Netty的异步HTTP客户端已经完成。配置类提供了25个配置项,包括Netty启动的配置项,以及HTTP请求的配置项。同时提供同步和异步HTTP请求,包括GET, POST, DELETE, PUT。还提供发送单向的HTTPS请求的功能。目前,本客户端已经应用在实验室多个项目中。尤其在消息解析引擎中,作为必不可少的一部分。
4 结束语
本文设计并实现的异步HTTP客户端,其设计思路借鉴了很多开源框架的设计原则,始终本着使用简单,低耦合和高内聚的软件设计思路进行的实现。采用的都是通用接口设计,方便以后扩展。
虽然本客户端已经满足了项目中的基本需求,但是还有部分功能没有实现,下一步需要进一步研究的问题是完善本客户端的功能和配置项。同时,考虑到不同的异步框架性能和实现原理的差异性,需要将其他的异步框架也融入进去,使得用户可以选择性使用不同的底层实现,来满足自己不同的功能或者性能需求。
[1] 郑建军. Java在高并发网络编程中的应用[J]. 电脑编程技巧与维护,2013(18):50-52.
[2] Goetz B. Java并发编程实战[M]. 北京:机械工业出版社华章公司,2012.
[3] JBoss. Netty project[CP/OL]. [2012-4-1]. http://netty.io/
[4] Hitchens R. Java NIO[M]. USA: O'Reilly Media, 2002.
[5] Jfarcand. The Async Http Client[CP/OL]. [2012-3-16]. http:// sonatype.github.io/async-http-client/
[6] Gourley D, Totty B. HTTP权威指南[M]. 北京:人民邮电出版社,2012.
[7] 梅特斯克. Java设计模式[M]. 北京:人民邮电出版社,2007.
Design and implementation of HTTP client based on Netty
JIN Zhi-guo1,2, LI Wei1,2
(1 State Key Laboratory of Networking and Switching Technology, Beijing University of Posts and Telecommunications, Beijing 100876, China; 2 EBUPT Information Technology Co., Ltd., Beijing 100191, China)
Open Mobile Platform is an Open Platform providing ability of telecommunication. It provides developers with rich business abilities, including: SMS, MMS, maps, positioning, etc. The access system of Open Mobile Platform requires asynchronous processing HTTP requests for the client, and various systems of the platform also need to use a large number of asynchronous HTTP requests to send message. Netty is an asynchronous event-driven network applications open source framework, which is used for rapid development of maintainable high performance, high scalability protocol servers and clients. This paper briefy describes the design idea and concrete implementation of using open source framework Netty for providing a convenient and easy http client which can send an asynchronous HTTP request.
Netty framework; NIO technology; asynchrony; HTTP client
TN915
A
1008-5599(2014)01-0084-05
2013-12-05
国家973计划项目(No. 2013CB329102);国家自然科学基金资助项目(No. 61372120,61271019, 61101119, 61121001, 61072057, 60902051);长江学者和创新团队发展计划资助(No. IRT1049);北京市支持中央高校共建项目——青年英才计划。