1. 程式人生 > >分散式RPC框架效能大比拼

分散式RPC框架效能大比拼

來源:http://colobu.com/2016/09/05/benchmarks-of-popular-rpc-frameworks/

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的外掛。

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檔案定義:

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定義檔案為

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,所以序列化和反序列化是在程式碼中手工實現的。

服務很簡單:

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%。

測試是在兩臺機器上執行的,一臺機器做伺服器,一臺機器做客戶端。

兩臺機器的配置都是一樣的,比較老的伺服器:

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框架的測試。

版權申明:內容來源網路,版權歸原創者所有。除非無法確認,我們都會標明作者及出處,如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝。

-END-