基于dubbo框架下的RPC通讯协议性能测试 - lengfo

标签: dubbo 框架 rpc | 发表时间:2015-03-02 20:47 | 作者:lengfo
出处:

一、前言

  Dubbo RPC服务框架支持丰富的传输协议、序列化方式等通讯相关的配置和扩展。dubbo执行一次RPC请求的过程大致如下:消费者(Consumer)向注册中心(Registry)执行RPC请求,注册中心分配服务URL并路由到具体服务提供方(Provider),消费者和服务提供方建立网络连接,服务提供方在本地创建连接池对象并提供远程服务,对于长连接类型协议(如dubbo协议)将保持连接,减少握手认证,调用过程中可以避免频繁建立和断开连接导致的性能开销,保持长连接需要有心跳包的发送,所以对于非频繁调用的服务保持连接同样会有消耗。更多关于dubbo详细介绍请参照官方文档( http://alibaba.github.io/dubbo-doc-static/Home-zh.htm)。

  1、支持常见的传输协议:RMI、Dubbo、Hessain、WebService、Http等,其中Dubbo和RMI协议基于TCP实现,Hessian和WebService基于HTTP实现。

  2、传输框架:Netty、Mina、以及基于servlet等方式。

  3、序列化方式:Hessian2、dubbo、JSON( fastjson 实现)、JAVA、SOAP 等。

  本文主要基于dubbo框架下的通讯协议进行性能测试对比。

 

二、测试方案

  基于dubbo 2.5.3框架,使用zookeeper作为dubbo服务注册中心,分别以单线程和多线程的方式测试以下方案:

  Protocol       Transporter       Serialization     Remark
A  dubbo 协议  netty  hessian2  
B  dubbo 协议  netty  dubbo  
C  dubbo 协议  netty  java  
D  RMI 协议  netty  java  
E  RMI 协议  netty  hessian2  
F  Hessian 协议  servlet  hessian2  Hessian,基于tomcat容器     
G  WebService 协议    servlet  SOAP  CXF,基于tomcat容器  

 

三、传输测试数据

1、单POJO对象,嵌套复杂集合类型

2、POJO集合,包含100个单POJO对象

3、1K字符串

4、100K字符串

5、1M字符串 

 

四、服务接口和实现

  1、服务接口相关代码: 

1 package ibusiness;
2
3 import java.util.List;
4
5 import model.*;
6
7 public interface IBusinessOrder {
8 public String SendStr(String str);
9
10 public List<OrderInfo> LoadOrders(List<OrderInfo> orders);
11
12 public OrderInfo LoadOrder(OrderInfo order);
13 }

  2、服务实现相关代码,测试数据在服务器端不做任何处理原样返回:

1 package business;
2
3 import ibusiness.IBusinessOrder;
4
5 import java.util.List;
6
7 import model.*;
8
9 public class BusinessOrder implements IBusinessOrder {
10 public String SendStr(String str) {
11 return str;
12 }
13
14 public List<OrderInfo> LoadOrders(List<OrderInfo> orders) {
15 return orders;
16 }
17
18 public OrderInfo LoadOrder(OrderInfo order) {
19 return order;
20 }
21 }

 

五、单线程测试

  1、测试仅记录rpc调用时间,测试数据的读取组装以及首次建立连接等相关耗时时间不作统计,循环执行100次取平均值。  

  2、服务消费方测试代码

1 import java.util.List;
2
3 import org.springframework.context.ApplicationContext;
4 import org.springframework.context.support.FileSystemXmlApplicationContext;
5
6 import com.alibaba.dubbo.rpc.service.EchoService;
7 import common.Common;
8
9 import ibusiness.*;
10 import model.*;
11
12 public class Program {
13 public static void main(String[] args) throws Exception {
14
15 ApplicationContext ctx = new FileSystemXmlApplicationContext("src//applicationContext.xml");
16 IBusinessOrder orderBusiness = (IBusinessOrder) ctx.getBean("orderBusiness");
17
18 // EchoService echoService = (EchoService) orderBusiness;
19 // String status = echoService.$echo("OK").toString();
20 // if (!status.equals("OK")) {
21 // System.out.println("orderBusiness out of service!");
22 // return;
23 // } else {
24 // System.out.println("orderBusiness in service !");
25 // }
26
27 long startMili, endMili;
28 int loop = 100;
29
30 // 单个pojo
31 try {
32 OrderInfo order = Common.BuildOrder();
33 orderBusiness.LoadOrder(order); // 防止首次连接的开销
34
35 startMili = System.currentTimeMillis();
36 OrderInfo returnOrder = null;
37 for (int i = 0; i < loop; i++) {
38 returnOrder = orderBusiness.LoadOrder(order);
39 }
40 endMili = System.currentTimeMillis();
41 System.out.println("单个pojo 平均传输耗时为:" + ((endMili - startMili) / (float) loop) + "毫秒 ,返回对象BillNumber:" + returnOrder.getBillNumber());
42 } catch (Exception ex) {
43 System.out.println("单个pojo 测试失败!");
44 //ex.printStackTrace();
45 }
46
47 // pojo集合 (100)
48 try {
49 List<OrderInfo> orderList = Common.BuildOrderList();
50 startMili = System.currentTimeMillis();
51 List<OrderInfo> returnOrderList = null;
52 for (int i = 0; i < loop; i++) {
53 returnOrderList = orderBusiness.LoadOrders(orderList);
54 }
55 endMili = System.currentTimeMillis();
56 System.out.println("pojo集合 (100) 平均传输耗时为:" + ((endMili - startMili) / (float) loop) + "毫秒 ,返回记录数:" + returnOrderList.size());
57 } catch (Exception ex) {
58 System.out.println("pojo集合 (100) 测试失败!");
59 }
60
61 // 1K String
62 try {
63 String str1k = Common.Build1KString();
64 startMili = System.currentTimeMillis();
65 String returnStr1k = null;
66 for (int i = 0; i < loop; i++) {
67 returnStr1k = orderBusiness.SendStr(str1k);
68 }
69 endMili = System.currentTimeMillis();
70 System.out.println("1K String 平均传输耗时为:" + ((endMili - startMili) / (float) loop) + "毫秒,返回字符长度:" + returnStr1k.length());
71 } catch (Exception ex) {
72 System.out.println("1K String 测试失败!");
73 }
74
75 // 100K String
76 try {
77 String str100K = Common.Build100KString();
78 startMili = System.currentTimeMillis();
79 String returnStr100k = null;
80 for (int i = 0; i < loop; i++) {
81 returnStr100k = orderBusiness.SendStr(str100K);
82 }
83 endMili = System.currentTimeMillis();
84 System.out.println("100K String 平均传输耗时为:" + ((endMili - startMili) / (float) loop) + "毫秒,返回字符长度:" + returnStr100k.length());
85 } catch (Exception ex) {
86 System.out.println("100K String 测试失败!");
87 }
88
89 // 1M String
90 try {
91 String str1M = Common.Build1MString();
92 startMili = System.currentTimeMillis();
93 String returnStr1M = null;
94 for (int i = 0; i < loop; i++) {
95 returnStr1M = orderBusiness.SendStr(str1M);
96 }
97 endMili = System.currentTimeMillis();
98 System.out.println("1M String 平均传输耗时为:" + ((endMili - startMili) / (float) loop) + "毫秒,返回字符长度:" + returnStr1M.length());
99 } catch (Exception ex) {
100 System.out.println("1M String 测试失败!");
101 }
102
103 System.out.println("all test done!");
104 }
105 }

  3、测试数据耗时记录

A、dubbo 协议、netty 传输、hessian2 序列化

<dubbo:protocol name="dubbo" server="netty" port="30001" serialization="hessian2"  />

单个POJO 0.958毫秒
POJO集合 (100) 1.438毫秒
1K String 0.68毫秒
100K String 4.262毫秒
1M String 32.473毫秒 
 

B、dubbo 协议、netty 传输、dubbo 序列化

<dubbo:protocol name="dubbo" server="netty" port="30001" serialization="dubbo" /> 
单个POJO 1.45毫秒
POJO集合 (100) 3.42毫秒
1K String 0.94毫秒
100K String 4.35毫秒
1M String 27.92毫秒
 

C、dubbo 协议、netty 传输、java 序列化

<dubbo:protocol name="dubbo" server="netty" port="30001" serialization="java" /> 

单个POJO 1.91毫秒
POJO集合 (100) 4.48毫秒
1K String 1.0毫秒
100K String 3.3毫秒
1M String 18.09毫秒
 

D、RMI 协议、netty 传输、java 序列化 

<dubbo:protocol name="rmi" server="netty" port="1099" serialization="java" />   

单个POJO 1.63毫秒
POJO集合 (100) 5.15毫秒
1K String 0.77毫秒
100K String 2.15毫秒
1M String 15.21毫秒
 

E、RMI 协议、netty 传输、hessian2 序列化 

<dubbo:protocol name="rmi" server="netty" port="1099" serialization="hessian2"  /> 
单个POJO 1.63毫秒
POJO集合 (100) 5.12毫秒
1K String 0.76毫秒
100K String 2.13毫秒
1M String 15.11毫秒
 

F、Hessian协议、servlet(tomcat容器)、hessian2 序列化 

<dubbo:protocol name="hessian" port="8080" server="servlet" serialization="hessian2" /> 
单个POJO 1.6毫秒
POJO集合 (100) 5.98毫秒
1K String 1.88毫秒
100K String 5.52毫秒
1M String 39.87毫秒
 

G、WebService协议、servlet(tomcat容器)、SOAP序列化

<dubbo:protocol name="webservice" port="8080" server="servlet" /> 

单个POJO 7.4毫秒
POJO集合 (100) 34.39毫秒
1K String 6.0毫秒
100K String 7.43毫秒
1M String 34.61毫秒
 

  4、性能对比

 

 

六、多线程测试

  1、由于测试机器配置较低,为了避免达到CPU瓶颈,测试设定服务消费方Consumer并发10个线程,每个线程连续对远程方法执行5次调用,服务提供方设置允许最大连接数100个,同时5个连接并行执行,超时时间设置为5000ms,要求所有事务都能正确返回没有异常,统计包含首次建立连接的消耗时间。

  2、服务消费方测试代码

 

  3、测试数据耗时记录

A、dubbo 协议、netty 传输、hessian2 序列化

<dubbo:protocol name="dubbo" server="netty" port="30001" serialization="hessian2"  /> 
单个POJO 1165毫秒
POJO集合 (100) 1311毫秒
1K String 1149毫秒
100K String 1273毫秒
1M String 2141毫秒
 

B、dubbo 协议、netty 传输、dubbo 序列化

<dubbo:protocol name="dubbo" server="netty" port="30001" serialization="dubbo" /> 

单个POJO 1220毫秒
POJO集合 (100) 1437毫秒
1K String 1145毫秒
100K String 1253毫秒
1M String 2065毫秒
 

C、dubbo 协议、netty 传输、java 序列化

<dubbo:protocol name="dubbo" server="netty" port="30001" serialization="java" /> 

单个POJO 1188毫秒
POJO集合 (100) 1401毫秒
1K String 1123毫秒
100K String 1227毫秒
1M String 1884毫秒
 

D、RMI 协议、netty 传输、java 序列化 

<dubbo:protocol name="rmi" server="netty" port="1099" serialization="java" />   

单个POJO 1751毫秒
POJO集合 (100) 1569毫秒
1K String 1766毫秒
100K String 1356毫秒
1M String 1741毫秒
 

E、RMI 协议、netty 传输、hessian2 序列化 

<dubbo:protocol name="rmi" server="netty" port="1099" serialization="hessian2"  /> 

单个POJO 1759毫秒
POJO集合 (100) 1968毫秒
1K String 1239毫秒
100K String 1339毫秒
1M String 1736毫秒
 

F、Hessian协议、servlet、hessian2 序列化 

<dubbo:protocol name="hessian" port="8080" server="servlet" serialization="hessian2" /> 

单个POJO 1341毫秒
POJO集合 (100) 2223毫秒
1K String 1800毫秒
100K String 1916毫秒
1M String 2445毫秒
 

G、WebService协议、servlet、SOAP序列化

<dubbo:protocol name="webservice" port="8080" server="servlet" /> 

单个POJO 1975毫秒
POJO集合 (100) 2768毫秒
1K String 1894毫秒
100K String 2098毫秒
1M String 2887毫秒
 

  4、性能对比

 
 

七、性能分析

  测试过程中尽管考虑了非常多的影响因素,但仍然有很多局限性,包括连接数限制、并发量、线程池策略、Cache、IO、硬件性能瓶颈等等因素,而且各自的适用场景不同,测试结果 仅供参考

  从单线程测试结果可以看出,dubbo协议采用NIO复用单一长连接更适合满足高并发小数据量的rpc调用,而在大数据量下的传输性能并不好,建议使用rmi协议,多线程测试中dubbo协议对小数据量的rpc调用同样保持优势,在大数据量的传输中由于长连接的原因对比rmi协议传输耗时差距并不明显,这点同样验证了上述观点。关于数据的序列化方式选择需要考虑序列化和反序列化的效率问题,传输内容的大小,以及格式的兼容性约束,其中hessian2作为duobb协议下的默认序列化方式,推荐使用。

  如果有描述错误或者不当的地方欢迎指正。

 


本文链接: 基于dubbo框架下的RPC通讯协议性能测试,转载请注明。

相关 [dubbo 框架 rpc] 推荐:

基于dubbo框架下的RPC通讯协议性能测试 - lengfo

- - 博客园_首页
  Dubbo RPC服务框架支持丰富的传输协议、序列化方式等通讯相关的配置和扩展. 更多关于dubbo详细介绍请参照官方文档( http://alibaba.github.io/dubbo-doc-static/Home-zh.htm).   1、支持常见的传输协议:RMI、Dubbo、Hessain、WebService、Http等,其中Dubbo和RMI协议基于TCP实现,Hessian和WebService基于HTTP实现.

RPC 服务框架 Dubbo 将正式得到官方维护与支持

- - 开源中国社区最新新闻
近日, Dubbo 项目官网更新了一则公告:. dubbo项目将正式得到官方维护与支持,我们期待这款优秀的开源项目在未来持续保持活力,引领开源服务框架  --Alibaba dubbo-team. 在项目 GitHub 主页的 issue 中,也有阿里巴巴的工程师确认了这一消息. 看来,Dubbo 确实重新开始得到官方的维护了.

JAVA RPC 通讯框架

- - 经验沉淀 知识结晶
Bison 是一个JAVA 程间的通信框架,基于apache mina 实现,对mina进行了byteBuffer 缓冲区重用以及半包出处时减少拷贝. 客户端(bison-client) 功能点. 2 支持高用性:高可用的一个基本原则,可以接受快速的失败,但不能接受长时间的等待. Githup地址:https://github.com/gavenpeng/Bison.

【RPC框架HttpInvoker一】HttpInvoker:Spring自带RPC框架

- - 开源软件 - ITeye博客
HttpInvoker是Spring原生的RPC调用框架,HttpInvoker同Burlap和Hessian一样,提供了一致的服务Exporter以及客户端的服务代理工厂Bean,这篇文章主要是复制粘贴了Hessian与Spring集成一文,. 【RPC框架Hessian四】Hessian与Spring集成.

谈Dubbo服务框架

- - 人月神话的BLOG
Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成. 它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合). 从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色.

分布式框架Dubbo

- - Linux - 操作系统 - ITeye博客
互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的. 现在核心业务抽取出来,作为独立的服务,使前端应用能更快速和稳定的响应. 大规模服务化之前,应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡.

zmq-rpc:基于zeromq网络层编写的protobuf RPC框架

- Shengbin - codedump
阅读过zmq的代码之后,感觉这个网络层是我目前见过最高效的–线程之间使用lockfree的消息队列保存消息,可以启动多个I/O线程分担压力等等特性.于是决定基于它写一个protobuf RPC的框架.. 另外,这里使用的protobuf是旧版本2.3.0,新版本2.4.1的生成的RPC service接口跟原来不太一致,暂时还没有去研究它.BTW,升级版本之后导致原来的接口发生变化这是一个很操蛋的事情..

集成libevent,google protobuf的RPC框架

- goodman - C++博客-那谁的技术博客
chenshuo的evproto同样也是集成libevent与google protobuf的RPC框架,不过在对libevent的使用上,这里的做法与他不尽相同:. 1) 他使用了libevent自带的RPC功能, 而这里只使用到libevent对网络I/O进行的封装的最基本的功能.. eventrpc项目目前是avidya下的一个子项目,avidya项目的定位是实现一些分布式的玩具系统(比如google已经公开论文的chubby,mapreduce,GFS等),也许以后不一定能被用上,但是也要实践做一把.由于有一个好用的RPC框架是做分布式的必需品,所有首先实现eventrpc这个子项目了,以后也许还会实现其他语言的版本,如python,java..

NFS-RPC框架优化过程

- EricSheng - BlueDavy之技术blog
NFS-RPC框架从编写之初,到现在为止(应该还会有些提升,不过估计不大),每秒支撑的请求数上升了好几倍,测试结果的演变为:. 以上测试结果为在100并发、100 request byte、100 response byte以及单连接下的背景下得出的,在这篇blog中来分享下这个框架所做的一些优化动作,希望能给编写rpc框架或使用mina/netty/grizzly的同学们一点点帮助,也希望得到高手们更多的指点.

RPC调用框架比较分析

- - 开源软件 - ITeye博客
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议. 简言之,RPC使得程序能够像访问本地系统资源一样,去访问远端系统资源. 比较关键的一些方面包括,通讯协议,序列化,资源(接口)描述,服务框架,性能,语言支持等.