Dubbo 是阿里巴巴公司開源的一個Java高性能優秀的服務框架,使得應用可通過高性能的 RPC 實現服務的輸出和輸入功能,可以和 Spring框架無縫集成。
Motan 是新浪微博開源的一個Java 框架。它誕生的比較晚,起於2013年,2016年5月開源。Motan 在微博平臺中已經廣泛應用,每天為數百個服務完成近千億次的調用。
rpcx 是Go語言生態圈的Dubbo, 比Dubbo更輕量,實現了Dubbo的許多特性,藉助於Go語言優秀的併發特性和簡潔語法,可以使用較少的代碼實現分佈式的RPC服務。
gRPC 是Google開發的高性能、通用的開源RPC框架,其由Google主要面向移動應用開發並基於HTTP/2協議標準而設計,基於ProtoBuf(Protocol Buffers)序列化協議開發,且支持眾多開發語言。本身它不是分佈式的,所以要實現上面的框架的功能需要進一步的開發。
thrift 是Apache的一個跨語言的高性能的服務框架,也得到了廣泛的應用。
以下是它們的功能比較:
對於RPC的考察, 性能是很重要的一點,因為RPC框架經常用在服務的大併發調用的環境中,性能的好壞決定服務的質量以及公司在硬件部署上的花費。
本文通過一個統一的服務,測試這四種框架實現的完整的服務器端和客戶端的性能。
這個服務傳遞的消息體有一個protobuf文件定義:
<code>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];}/<code>
相應的Thrift定義文件為
<code>namespace java com.colobu.thriftstruct 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);}/<code>
事實上這個文件摘自gRPC項目的測試用例,使用反射為每個字段賦值,使用protobuf序列化後的大小為 581 個字節左右。因為Dubbo和Motan缺省不支持Protobuf,所以序列化和反序列化是在代碼中手工實現的。
服務很簡單:
<code>service Hello { // Sends a greeting rpc Say (BenchmarkMessage) returns (BenchmarkMessage) {}}/<code>
接收一個BenchmarkMessage,更改它前兩個字段的值為"OK" 和 100,這樣客戶端得到服務的結果後能夠根據結果判斷服務是否正常的執行。
Dubbo的測試代碼改自:
https://github.com/alibaba/dubbo/tree/master/dubbo-demo
Motan的測試代碼改自:
https://github.com/weibocom/motan/tree/master/motan-demo
rpcx和gRPC的測試代碼在:
https://github.com/smallnest/rpcx/tree/master/_benchmarks
Thrift使用Java進行測試。
正如左耳朵耗子對Dubbo批評一樣,Dubbo官方的測試不正規 (性能測試應該怎麼做?)。
本文測試將用吞吐率、相應時間平均值、響應時間中位數、響應時間最大值進行比較(響應時間最小值都為0,不必比較),當然最好以Top Percentile的指標進行比較,但是我沒有找到Go語言的很好的統計這個庫,所以暫時比較中位數。
另外測試中服務的成功率都是100%。
測試是在兩臺機器上執行的,一臺機器做服務器,一臺機器做客戶端。
兩臺機器的配置都是一樣的,比較老的服務器:
- CPU: Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz, 24 cores
- Memory: 16G
- OS: Linux 2.6.32-358.el6.x86_64, CentOS 6.4
- Go: 1.7
- Java: 1.8
- Dubbo: 2.5.4-SNAPSHOT (2016-09-05)
- Motan: 0.2.2-SNAPSHOT (2016-09-05)
- gRPC: 1.0.0
- rpcx: 2016-09-05
- thrift: 0.9.3 (java)
分別在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框架的測試。
小編每天會更新兩篇文章,喜歡的話可以關注下小編。
閱讀更多 架構師師長 的文章