dubbo、motan、rpcx、gRPC、thrift的性能比较php
Dubbo 是阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可经过高性能的 RPC 实现服务的输出和输入功能,能够和 Spring框架无缝集成。不过,略有遗憾的是,听说在淘宝内部,dubbo因为跟淘宝另外一个相似的框架HSF(非开源)有竞争关系,致使dubbo团队已经解散(参见http://www.oschina.net/news/55059/druid-1-0-9 中的评论),反到是当当网的扩展版本仍在持续发展,墙内开花墙外香。其它的一些知名电商如当当、京东、国美维护了本身的分支或者在dubbo的基础开发,可是官方的库缺少维护,相关的依赖类好比Spring,Netty仍是很老的版本(Spring 3.2.16.RELEASE, netty 3.2.5.Final),却是有些网友写了升级Spring和Netty的插件。html
Motan是新浪微博开源的一个Java 框架。它诞生的比较晚,起于2013年,2016年5月开源。Motan 在微博平台中已经普遍应用,天天为数百个服务完成近千亿次的调用。java
rpcx是Go语言生态圈的Dubbo, 比Dubbo更轻量,实现了Dubbo的许多特性,借助于Go语言优秀的并发特性和简洁语法,可使用较少的代码实现分布式的RPC服务。git
gRPC是Google开发的高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。自己它不是分布式的,因此要实现上面的框架的功能须要进一步的开发。github
thrift是Apache的一个跨语言的高性能的服务框架,也获得了普遍的应用。shell
后续还会增长更多的 RPC 框架的比较,敬请收藏本文网址apache
如下是它们的功能比较:编程
Dubbo | Montan | rpcx | gRPC | Thrift | |
---|---|---|---|---|---|
开发语言 | Java | Java | Go | 跨语言 | 跨语言 |
分布式(服务治理) | √ | √ | √ | × | × |
多序列化框架支持 | √ |
√ (当前支持Hessian二、Json,可扩展) |
√ |
× (只支持protobuf) |
× (thrift格式) |
多种注册中心 | √ | √ | √ | × | × |
管理中心 | √ | √ | √ | × | × |
跨编程语言 | × | × (支持php client和C server) | × | √ | √ |
对于RPC的考察, 性能是很重要的一点,由于RPC框架常常用在服务的大并发调用的环境中,性能的好坏决定服务的质量以及公司在硬件部署上的花费。服务器
本文经过一个统一的服务,测试这四种框架实现的完整的服务器端和客户端的性能。
这个服务传递的消息体有一个protobuf文件定义:网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
syntax =
"proto2";
package main;
option optimize_for = SPEED;
message BenchmarkMessage {
required
string field1 =
1;
optional
string field9 =
9;
optional
string field18 =
18;
optional
bool field80 =
80 [default=
false];
optional
bool field81 =
81 [default=
true];
required
int32 field2 =
2;
required
int32 field3 =
3;
optional
int32 field280 =
280;
optional
int32 field6 =
6 [default=
0];
optional
int64 field22 =
22;
optional
string field4 =
4;
repeated
fixed64 field5 =
5;
optional
bool field59 =
59 [default=
false];
optional
string field7 =
7;
optional
int32 field16 =
16;
optional
int32 field130 =
130 [default=
0];
optional
bool field12 =
12 [default=
true];
optional
bool field17 =
17 [default=
true];
optional
bool field13 =
13 [default=
true];
optional
bool field14 =
14 [default=
true];
optional
int32 field104 =
104 [default=
0];
optional
int32 field100 =
100 [default=
0];
optional
int32 field101 =
101 [default=
0];
optional
string field102 =
102;
optional
string field103 =
103;
optional
int32 field29 =
29 [default=
0];
optional
bool field30 =
30 [default=
false];
optional
int32 field60 =
60 [default=-
1];
optional
int32 field271 =
271 [default=-
1];
optional
int32 field272 =
272 [default=-
1];
optional
int32 field150 =
150;
optional
int32 field23 =
23 [default=
0];
optional
bool field24 =
24 [default=
false];
optional
int32 field25 =
25 [default=
0];
optional
bool field78 =
78;
optional
int32 field67 =
67 [default=
0];
optional
int32 field68 =
68;
optional
int32 field128 =
128 [default=
0];
optional
string field129 =
129 [default=
"xxxxxxxxxxxxxxxxxxxxx"];
optional
int32 field131 =
131 [default=
0];
}
|
相应的Thrift定义文件为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
namespace java com.colobu.thrift
struct BenchmarkMessage
{
1:
string field1,
2:
i32 field2,
3:
i32 field3,
4:
string field4,
5:
i64 field5,
6:
i32 field6,
7:
string field7,
9:
string field9,
12:
bool field12,
13:
bool field13,
14:
bool field14,
16:
i32 field16,
17:
bool field17,
18:
string field18,
22:
i64 field22,
23:
i32 field23,
24:
bool field24,
25:
i32 field25,
29:
i32 field29,
30:
bool field30,
59:
bool field59,
60:
i32 field60,
67:
i32 field67,
68:
i32 field68,
78:
bool field78,
80:
bool field80,
81:
bool field81,
100:
i32 field100,
101:
i32 field101,
102:
string field102,
103:
string field103,
104:
i32 field104,
128:
i32 field128,
129:
string field129,
130:
i32 field130,
131:
i32 field131,
150:
i32 field150,
271:
i32 field271,
272:
i32 field272,
280:
i32 field280,
}
service Greeter {
BenchmarkMessage say(
1:BenchmarkMessage name);
}
|
事实上这个文件摘自gRPC项目的测试用例,使用反射为每一个字段赋值,使用protobuf序列化后的大小为 581 个字节左右。由于Dubbo和Motan缺省不支持Protobuf,因此序列化和反序列化是在代码中手工实现的。
服务很简单:
1
2
3
4
|
service Hello {
// Sends a greeting
rpc Say (BenchmarkMessage) returns (BenchmarkMessage) {}
}
|
接收一个BenchmarkMessage,更改它前两个字段的值为"OK" 和 100,这样客户端获得服务的结果后可以根据结果判断服务是否正常的执行。
Dubbo的测试代码改自 dubo-demo,
Motan的测试代码改自 motan-demo。
rpcx和gRPC的测试代码在 rpcx benchmark。
Thrift使用Java进行测试。
正如左耳朵耗子对Dubbo批评同样,Dubbo官方的测试不正规 (性能测试应该怎么作?)。
本文测试将用吞吐率、相应时间平均值、响应时间中位数、响应时间最大值进行比较(响应时间最小值都为0,没必要比较),固然最好以Top Percentile的指标进行比较,可是我没有找到Go语言的很好的统计这个库,因此暂时比较中位数。
另外测试中服务的成功率都是100%。
测试是在两台机器上执行的,一台机器作服务器,一台机器作客户端。
两台机器的配置都是同样的,比较老的服务器:
分别在client并发数为100、500、1000、2000 和 5000的状况下测试,记录吞吐率(每秒调用次数, Throughput)、响应时间(Latency) 、成功率。
(更精确的测试还应该记录CPU使用率、内存使用、网络带宽、IO等,本文中未作比较)
首先看在四种并发下各RPC框架的吞吐率:吞吐率
rpcx的性能遥遥领先,而且其它三种框架在并发client很大的状况下吞吐率会降低。
thrift比rpcx性能差一点,可是还不错,远好于gRPC,dubbo和motan,可是随着client的增多,性能也降低的很厉害,在client较少的状况下吞吐率挺好。
在这四种并发的状况下平均响应:平均响应时间
这个和吞吐率的表现是一致的,仍是rpcx最好,平均响应时间小于30ms, Dubbo在并发client多的状况下响应时间很长。
咱们知道,在微服务流行的今天,一个单一的RPC的服务可能会被不一样系统所调用,这些不一样的系统会建立不一样的client。若是调用的系统不少,就有可能建立不少的client。
这里统计的是这些client总的吞吐率和总的平均时间。
平均响应时间可能掩盖一些真相,尤为是当响应时间的分布不是那么平均,因此咱们还能够关注另一个指标,就是中位数。
这里的中位数指小于这个数值的测试数和大于这个数值的测试数相等。响应时间中位数
gRPC框架的表现最好。
另一个就是比较一下最长的响应时间,看看极端状况下各框架的表现:最大响应时间
rpcx的最大响应时间都小于1秒,Motan的表现也不错,都小于2秒,其它两个框架表现不是太好。
本文以一个相同的测试case测试了四种RPC框架的性能,获得了这四种框架在不一样的并发条件下的性能表现。指望读者能提出宝贵的意见,以便完善这个测试,并能增长更多的RPC框架的测试。
【转自】http://colobu.com/2016/09/05/benchmarks-of-popular-rpc-frameworks/