- 1 -
中国科技论文在线
基于 Netty 的 HTTP 客户端的设计与实现#
金志国1,2,李炜1,2**
基金项目:国家 973 计划项目(No. 2013CB329102);国家自然科学基金资助项目(No. 61372120,61271019,
61101119, 61121001, 61072057, 60902051);长江学者和创新团队发展计划资助(No. IRT1049)
作者简介:金志国(1988-),男,硕士研究生,业务网络智能化
通信联系人:李炜(1973-),男,副教授,业务网络智能化
(1. 北京邮电大学网络与交换技术国家重点实验室,北京(100876);
2. 东信北邮信息技术有限公司,北京(100191)) 5
摘要:能力开放平台是一个提供电信能力开放的移动互联网开放平台,向开发者提供丰富的
业务能力,包括:短信、彩信、地图、定位等。能力开放平台接入系统需要异步处理客户
端的 HTTP 请求,而平台内部各个系统间的消息传递也需要使用大量的异步 HTTP 请求。
Netty 是一款异步的事件驱动的网络应用开源框架,用于快速开发可维护的高性能、高扩展10
性协议服务器和客户端。本文简述了通过对开源框架Netty的源码封装,提供方便易用可以
发送异步 HTTP 请求的客户端的设计思路和具体实现。
关键词:Netty 框架;NIO 技术;异步;HTTP 客户端.
中图分类号:
15
The Design and Implementation of HTTP Client Based on
Netty
JI Zhiguo
1,2
, LI Wei
1,2
(1. State Key Lab of Networking and Switching Technology, Beijing University of Posts and
Telecommunications, Beijing 100876, China; 20
2. EBUPT Information Technology Co. Ltd., Beijing 100191, China)
Abstract: 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 25
HTTP requests to send message. Netty is an asynchronous event-driven network applications open
source framework, is used for rapid development of maintainable high performance, high
scalability protocol servers and clients. This paper briefly describes the design idea and concrete
implementation of using open source framework Netty to provide a convenient and easy to use
http client which can send an asynchronous HTTP request. 30
Key words: Netty framework; NIO technology; asynchrony; HTTP Client
0 引言
云计算是服务的交付和使用模式,指通过网络以按需、易扩展的方式获得所需服务。在
云计算技术发展日新月异的今天,业界开始更多的转向云平台[1]。能力开放平台是基于 PaaS35
(platform as a service,平台即服务)提供电信能力开放的移动互联网开放云平台,向开发
者提供丰富的业务能力,包括:短信、彩信、地图、定位等[2]。在能力开放平台的接入系统
部分,需要处理海量的请求。在用户体验不断提高的要求下,能力开放平台业务处理日益复
杂造成交互延迟,传统的 Web 请求同步模式下业务处理的阻塞造成的延迟已经满足不了高
并发需求[3]。 40
在接入系统内部以及接入系统与其他系统之间,多采用 HTTP 进行数据传输。由接入系
统接受客户传来的请求,进行异步处理,但系统内部的信息传输仍然采用同步模式时,则会
- 2 -
中国科技论文在线
造成阻塞,异步的 Web 服务器也失去了意义[4]。所以,在云平台项目开发过程中急需要一
个可以支持大并发高效稳定的异步 HTTP 客户端。
目前,异步HTTP客户端只有Apache HttpComponents 项目的HttpAsyncClient -beta4,45
但仍然是对外测试版。其他的异步框架,如 Mina[5]、Netty 和 Grizzly,均是以 JAVA NIO
(Non-Blocking IO 非阻塞 IO )为基础。本文通过调研,选定采用 Netty 作为底层源码实现
异步 HTTP 客户端。
1 Netty 概述
Netty 是一款异步的事件驱动的网络应用框架和工具,用于快速开发可维护的高性能、50
高扩展性协议服务器和客户端[6]。Netty 是一个基于 Java NIO 客户端/服务器框架,支持快速、
简单地开发网络应用,如协议服务器和客户端[7]。
Netty 具有以下优势[8]:
对阻塞和非阻塞的 socket 提高统一的 API;
高度可定制化的线程模型; 55
基于拦截链模式的事件模型有很高的灵活性和扩展性;
对多种协议的支持,包括 HTTP、TCP、UDP、SMTP、FTP 以及二进制文本协议,
完全支持 SSL/TLS,适用于快速开发各种高级组件。
2 总体设计与分析
总体设计 60
本文是以 Netty 框架为底层,将 Netty 提供的对 HTTP 协议的支持,编解码等功能封装
成异步 HTTP 客户端,提供简单易懂的 API 使用,可以很容易的发送 HTTP 请求,并异步
处理 HTTP 响应[9]。
NettyConfig PipelineFactory NettyResponse
NettyAsyncHttpClient
NettyConnectionPools NettyProtocols HttpDecoder MainHandler HttpEncoder ResponseHeader ResponseBody ResponseStatus
图 1 HTTP 客户端总体模块图 65
基于 Netty 的 HTTP 客户端总体模块设计[10]见图 1,设计思路如下:
(1) 提供一个整体的配置类,作为 API 的入口;
(2) 针对不同的配置类,生成不同的异步客户端启动类;
(3) 由异步客户端负责发送异步和同步的 HTTP 请求。
网络模型 70
Netty 基于 Java NIO 设计并实现,因此它实现异步的方式与 Java NIO 类似,采用的网络
模式是 reactor 模式,如图 2 所示。
- 3 -
中国科技论文在线
MainReactor SubReactor
Client
Client Acceptor
Thread
Pool
Read
Read
Send
Send
queued task
decode compute encode
Worker threads
decode compute encode
decode compute encode
图 2 网络模型
每个 worker 其实表示的是 Selector 和 Thread 一种组合,如图 3 所示。每次创建一个连75
接,都会选择一个 worker,并且注册到 worker 里的 Selector,worker 会进行 loop,不断地关
注通道事件,也就是会说每个 work(selector)下会注册多个 Channel,并且不断地去 Select
关注的 Channel。Selector 在发现感兴趣的事件后,直接调用 channel 的 pipeline 进行处理[11]。
Worker
(Selector Thread)
Worker
(Selector Thread)
Worker
(Selector Thread)
Channel
(Client)
Channel
(Client)
Channel
(Client)
Channel
(Client)
Channel
(Client)
Channel
(Client)
注册 注册 注册
图 3 worker 线程模型 80
事件驱动模式
消息处理模型采用的是基于事件的 Pipeline 模式。pipeline 实际上可以理解为对 channel
的 filter chain,可以通过在 pipeline 中定义多个 handler 来处理各种事件。
Channel 表示一个与 socket 关联的通道。ChannelPipeline 是管道,一个 Channel 拥有一85
个 ChannelPipeline,负责维护两个处理链,即 upstream 链和 downstream 链。处理链由多个
处理句柄 ChannelHandler 构成,每个 ChannelHandler 处理完以后会传递给链中的下一个处
理句柄继续处理。ChannelHandler 是处理句柄,用户可以定义自己的处理句柄来处理每个请
求,或发出请求前进行预处理,典型的处理句柄有编解码器 decoder 和 encoder。ChannelEvent
事件是整个模型的处理对象,当产生或触发一个事件时,该事件会沿着 ChannelPipeline 处90
理链依次被处理。ChannelFuture 表示异步结果,这个是异步事件处理的关键,当一个事件
被处理时,可以直接以 ChannelFuture 的形式直接返回,不用在当前操作中被阻塞。可以通
过 ChannelFuture 得到最终的执行结果,具体的做法是在 ChannelFuture 添加监听器 listener,
当操作最终被执行完后,listener 会被触发,我们可以在 listener 的回调函数中预定义我们的
- 4 -
中国科技论文在线
业务代码[12]。 95
ChannelPipeline 维持两个处理链:upstream、downstream。Upstream 一般处理来自 Channel
的读事件,而 downstream 一般处理向 Channel 的写事件。需要注意的是,这两个处理链是
相互独立的,在 upstream 链中传递到最后一个 ChannelHandler 处理后,不会再传递到
downstream 链中继续处理。
在 downstream 链的末端会有个 ChannelSink 处理,用户可以自定义这个 ChannelSink 的100
实现,系统也有个默认的实现,当 downstream 链中最后一个 ChannelHandler 处理完后会被
传递给这个 ChannelSink 进行最后的处理[13]。
详细设计
配置类
AsyncConfig(配置类)
NettyConfig(netty配置类) MinaConfig(mina配置类) 其他异步框架配置类(扩展类)
105
图 4 配置类图
图 4 定义了总配置的接口,具体的配置实现类通过实现总配置的接口,实现自己的配置
信息。Netty 的配置类部分内容见表 1。
表 1 配置项
方法 默认参数 是 否
需 要
配置
备注
setAsyncConnect True 否 设置是否采用异步连接
setBossExecutorService newCachedThreadPool() 是 设置 BOSS 线程池,可以手
动 配 置 成
newSingleThreadExecutor()
setMaxChunkSize 8192 否 设置最大的 Chunk 大小
setMaxHeaderSize 8192 否 设置请求的头信息的上限
setMaxInitialLineLengt
h
4096 否 设置 HttpClientCodec 长度
上限
setSocketChannelFacto
ry
不配置,会默认初始化
SocketChannelFactory,
其 中 boss 线 程 由
BossExecutorService 值
设 置 ,worker 线 程 由
AsyncConfig 的
executorService 方法设
置,worker 线程数量是
CPU 核数*2
否 此配置项用于在外部直接
配置 SocketChannelFactory
供 httpclient 异步客户端使
用。
setUseBlockingIO False 否 默认采用非阻塞方式
110
- 5 -
中国科技论文在线
启动类
通过将配置类 nettyConfig 作为参数传入给异步客户端类, 异步客户端类会根据配置类
的类型,返回不同的启动类。如果传入 nettyConfig,则调用 nettyProvider。对应调用 netty
底层的 bootstrap 帮助类,封装成异步客户端启动类返回给用户。用户则可以通过该启动类
发送同步或者异步 HTTP 请求[14]。 115
由 Netty 的网络模型可知,Netty 底层采用线程池处理消息的发送和接受,boss 线程和
worker 分别各用一个线程池,即需要两个线程池。如果每次发送一条 HTTP 请求,都新启
动一个 Netty 客户端类,对应生成新启动两个线程池,开销较大,Netty 的性能也完全没有
利用起来。由此,设计时采用单例模式,只生成一个 AsyncHttpClient 异步客户端实例,所
有的请求都是通过这个客户端实例进行发送的。 120
编解码类
因为 Netty 消息处理采用事件驱动模式,编解码的工作在 pipeline 中进行。Netty 已经提
供好了多种 HTTP 的编解码类,如 HttpResponseDecoder(对 HTTP 响应进行解码工作),
HttpRequestEncoder(对 HTTP 请求进行编码工作)。
在 pipeline 中除去编解码类,剩下最主要的就是需要我们自己定义的响应处理逻辑类125
HttpResponseHandler,该类需要继承 SimpleChannelUpstreamHandler 类。经过 Decoder 解码
后的 HTTP 响应消息会传递到处理逻辑类,方便我们响应进行操作。
这里采用了一种巧妙的设计思路,让 Netty 的启动类 NettyHttpClient 继承
SimpleChannelUpstreamHandler 类,使得响应的处理逻辑也可以通过 Netty 启动类配置。统
一了 API 的使用。 130
获取返回消息,定义了两种方式:
1. 通过默认的 handler 处理逻辑,获取结果时,通过阻塞的方式,等待默认 handler 得
到结果后,将结果返回。
2. 通过自定义的回调函数,实现客户端代码的异步。当有消息时,会自动通知客户端。
通过实现回调函数接口,可以对响应进行多种操作。 135
设计模式
本文在设计异步客户端时,参考了很多开源框架的设计原理[15],采用了工厂模式、
Builder 模式和单例模式[16]等方法实现。
- 6 -
中国科技论文在线
(1)工厂模式 140
AsyncConfig
(配置类)
AsyncClientFactory
(工厂)
NettyConfig
(Netty配置类)
其他异步框架配置
类(扩展类)
MinaConfig
(Mina配置类)
Concrete
NettyClient
Concrete
MinaClient
其他异步具体实现类
图 5 工厂模式
使用工厂模式构建配置类和启动类,如图 5 所示,不同的框架实现不同的配置类。异步
客户端类根据配置类的类型,产生不同的异步客户端启动类,进行 HTTP 请求的发送。为以
后扩展其他的框架实现方式提供了接口支持。 145
(2)Builder 模式
因为配置类有很多参数需要配置,如果对每一种可能的情况都设置一个构造器,工作量
将是非常巨大的,而且可读性很差。采用 Builder 模式,不直接生成需要的对象,而是让客
户端利用所有必要的参数调用构造器(类似于静态工厂的方式),得到一个 builder 对象。
然后通过对 builder 对象上调用类似于 setter 的方法,来设置每一个相关的可选参数。Builder150
是配置类的静态成员类,通过调用 build 方法来生成不可变的对象。
(3)单例模式
通过单例模式可以保证系统中一个类只有一个异步客户端实例可以被外界访问,从而方
便对实例个数的控制并节约系统资源,避免了每次发送请求构建线程池和销毁线程池的开
销,高并发量下,功能得到了保障,性能得到了提高。 155
分析测试和结果
在完成了基于 Netty 的 HTTP 客户端开发工作后,对几种 HTTP 客户端的性能进行了简
单的比较。比较了 3 种 HTTP 客户端。2 种异步客户端,分别为本文实现的客户端,
HttpAsyncClient。1 种同步客户端,HttpClient。
通过运行 10000 个 HTTP 的 GET 请求,得出结果使用异步的 NettyHttpClient 共用时间160
5972ms,使用异步的 HttpAsyncClient 共用时间 9021ms,使用同步的 HttpClient 共用时间
29310ms。从结果分析,发现异步客户端比同步客户端效率要高很多,而基于 Netty 实现的
异步 HTTP 客户端效率要比 apache 组织的 HttpAsyncClient 项目效率要高。
- 7 -
中国科技论文在线
3 应用
本文所述的基于 Netty 的异步 HTTP 客户端已经完成。配置类提供了 25 个配置项,包括165
Netty 启动的配置项,以及 HTTP 请求的配置项。同时提供同步和异步 HTTP 请求,包括
GET,POST,DELETE,PUT。还提供发送单向的 HTTPS 请求的功能。目前,本客户端已经应
用在实验室多个项目中。尤其在消息解析引擎中,作为必不可少的一部分。
4 结论
本文设计并实现的异步 HTTP 客户端,其设计思路借鉴了很多开源框架的设计原则,始170
终本着使用简单,低耦合和高内聚的软件设计思路进行的实现。采用的都是通用接口设计,
方便以后扩展。
虽然本客户端已经满足了项目中的基本需求,但是还有部分功能没有实现,下一步需要
进一步研究的问题是完善本客户端的功能和配置项。同时,考虑到不同的异步框架性能和实
现原理的差异性,需要将其他的异步框架也融入进去,使得用户可以选择性使用不同的底层175
实现,来满足自己不同的功能或者性能需求。
[参考文献] (References)
[1] 杜庆灵. 企业信息管理云平台的设计与实现[J]. 通信技术,2012,6(45):110-112.
[2] 姜海建,卢山,徐立臻. 基于事件驱动的 SOA 服务组合技术研究[J]. 计算机与数字工程,2012,40(11):
69-71. 180
[3] 徐茹枝,周凡雅,耿啸风. 企业新一代信息架构及云平台的研究[J]. 中国电子商情:通信市场, 2012,
5(6):112-114.
[4] 黄骁飞,白晓颖,苑丽杰. 异构云平台性能监控与分析研究[J]. 计算机科学,2013,40(11):147-149.
[5] 丛凤侠,杨玉强. 基于 MINA 框架的高性能短信猫服务平台设计[J]. 计算机技术与发展,2013,23(4):
214-216. 185
[6] JBoss. Netty project[OL]. [2012-4-1].
[7] 丁黎明. 使用 NIO 提高 Java 应用输入输出性能[J]. 信息技术,2012,31(4):276-277.
[8] 郑建军. Java 在高并发网络编程中的应用[J]. 电脑编程技巧与维护, 2013,5(18):50-52.
[9] 祝瑞,车敏. 基于 HTTP 协议的服务器程序分析[J]. 现代电子技术,2013,35(4):117-120.
[10] Jfarcand. The Async Http Client[OL]. [2012-3-16]. 190
[11] Hitchens R. Java NIO[M]. USA: O'Reilly Media, 2002.
[12] 钱宇虹. 如何用 Java 回调和线程实现异步调用[J]. 软件工程师,2013,12(10):26-28.
[13] 鲁宾宾. 基于 Java NIO 的通用框架的研究与实现[D]. 北京:北京邮电大学,2012.
[14] Goetz B. Java 并发编程实战[M]. 北京:机械工业出版社华章公司,2012.
[15] 李文锦,王康健. 源代码中设计模式实例的抽取及验证方法研究[J]. 计算机应用研究,2012,29(11):195
4200-4202.
[16] 梅特斯克. Java 设计模式[M]. 北京:人民邮电出版社, 2007.