zoukankan      html  css  js  c++  java
  • 基于dubbo框架下的RPC通讯协议性能测试 转

    一、前言

      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 }
    View Code

    五、单线程测试

      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 }
    View Code

      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协议下的默认序列化方式,推荐使用。

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

  • 相关阅读:
    TCP协议的三次握手、四次挥手
    .NET Framework 3.5 安装
    grep命令总结
    线性回归
    K-Mean聚类算法
    Logistic回归
    朴素贝叶斯
    Decision Tree
    KNN
    GCC for Win32开发环境介绍
  • 原文地址:https://www.cnblogs.com/lishijia/p/5492810.html
Copyright © 2011-2022 走看看