分布式RPC框架性能大比拼
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的插件。
Montan 是新浪微博開源的一個Java 框架。它誕生的比較晚,起于2013年,2016年5月開源。Motan 在微博平臺中已經廣泛應用,每天為數百個服務完成近千億次的調用。
rpcx 是Go語言生態圈的Dubbo, 比Dubbo更輕量,實現了Dubbo的許多特性,借助于Go語言優秀的并發特性和簡潔語法,可以使用較少的代碼實現分布式的RPC服務。
gRPC 是Google開發的高性能、通用的開源RPC框架,其由Google主要面向移動應用開發并基于HTTP/2協議標準而設計,基于ProtoBuf(Protocol Buffers)序列化協議開發,且支持眾多開發語言。本身它不是分布式的,所以要實現上面的框架的功能需要進一步的開發。
以下是它們的功能比較:
Dubbo | Montan | rpcx | gRPC | |
---|---|---|---|---|
開發語言 | Java | Java | Go | 跨語言 |
分布式 | √ | √ | √ | × |
多序列化框架支持 | √ | √ (當前支持Hessian2、Json,可擴展) |
√ | × (只支持protobuf) |
多種注冊中心 | √ | √ | √ | × |
管理中心 | √ | √ | × | × |
跨編程語言 | × | × (支持php client和C server) | × | √ |
對于RPC的考察, 性能是很重要的一點,因為RPC框架經常用在服務的大并發調用的環境中,性能的好壞決定服務的質量以及公司在硬件部署上的花費。
本文通過一個統一的服務,測試這四種框架實現的完整的服務器端和客戶端的性能。
這個服務傳遞的消息體有一個protobuf文件定義:
syntax = "proto2"; packagemain; optionoptimize_for = SPEED; messageBenchmarkMessage{ requiredstringfield1 =1; optionalstringfield9 =9; optionalstringfield18 =18; optionalboolfield80 =80[default=false]; optionalboolfield81 =81[default=true]; requiredint32field2 =2; requiredint32field3 =3; optionalint32field280 =280; optionalint32field6 =6[default=0]; optionalint64field22 =22; optionalstringfield4 =4; repeatedfixed64field5 =5; optionalboolfield59 =59[default=false]; optionalstringfield7 =7; optionalint32field16 =16; optionalint32field130 =130[default=0]; optionalboolfield12 =12[default=true]; optionalboolfield17 =17[default=true]; optionalboolfield13 =13[default=true]; optionalboolfield14 =14[default=true]; optionalint32field104 =104[default=0]; optionalint32field100 =100[default=0]; optionalint32field101 =101[default=0]; optionalstringfield102 =102; optionalstringfield103 =103; optionalint32field29 =29[default=0]; optionalboolfield30 =30[default=false]; optionalint32field60 =60[default=-1]; optionalint32field271 =271[default=-1]; optionalint32field272 =272[default=-1]; optionalint32field150 =150; optionalint32field23 =23[default=0]; optionalboolfield24 =24[default=false]; optionalint32field25 =25[default=0]; optionalboolfield78 =78; optionalint32field67 =67[default=0]; optionalint32field68 =68; optionalint32field128 =128[default=0]; optionalstringfield129 =129[default="xxxxxxxxxxxxxxxxxxxxx"]; optionalint32field131 =131[default=0]; }
事實上這個文件摘自gRPC項目的測試用例,使用反射為每個字段賦值,使用protobuf序列化后的大小為 581 個字節左右。因為Dubbo和Motan缺省不支持Protobuf,所以序列化和反序列化是在代碼中手工實現的。
服務很簡單:
serviceHello{ // Sends a greeting rpcSay (BenchmarkMessage)returns(BenchmarkMessage) {} }
接收一個BenchmarkMessage,更改它前兩個字段的值為"OK" 和 100,這樣客戶端得到服務的結果后能夠根據結果判斷服務是否正常的執行。
Dubbo的測試代碼改自 dubo-demo ,
Motan的測試代碼改自 motan-demo 。
rpcx和gRPC的測試代碼在 rpcx benchmark 。
正如左耳朵耗子對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
分別在client并發數為100、500、1000、2000 和 5000的情況下測試,記錄吞吐率(每秒調用次數, Throughput)、響應時間(Latency) 、成功率。
(更精確的測試還應該記錄CPU使用率、內存使用、網絡帶寬、IO等,本文中未做比較)
首先看在四種并發下各RPC框架的吞吐率:
rpcx的性能遙遙領先,并且其它三種框架在并發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/