RPC框架性能基本比較測試
21 March 2015
gRPC是Google最近公布的開源軟件,基于最新的HTTP2.0協(xié)議,并支持常見的眾多編程語言。 我們知道HTTP2.0是基于二進(jìn)制的HTTP協(xié)議升級版本,目前各大瀏覽器都在快馬加鞭的加以支持。 我們可以設(shè)想一下,未來瀏覽器支持HTTP2.0,并通過現(xiàn)有開源序列化庫比如protobuf等,可以直接和各種語言的服務(wù)進(jìn)行高效交互,這將是多么“美好”的場景!
gPRC的Java實(shí)現(xiàn)底層網(wǎng)絡(luò)庫是Netty,而且是用到最新的Netty5.0.0.Alpha3的開發(fā)版本,因?yàn)樽钚掳姹踞槍TTP/2做了很多改進(jìn)。 為了跨語言,gPRC也和其他方案一樣,采用了類似古老IDL的接口描述語言,利用自家的Protobuf項(xiàng)目帶的protoc編譯器來生成框架代碼。這和目前最流行的Facebook開源的,現(xiàn)為Apache頂級項(xiàng)目的Thrift原理一致。
我比較好奇,這個(gè)新出世的框架的性能怎么樣,和現(xiàn)有的RPC開源方案比較如何。就花了一些時(shí)間進(jìn)行簡單比較。 我選擇了以下五種開源項(xiàng)目進(jìn)行測試:gRPC, Thrift, Wildfly, Dubbo, JBoss EAP。 為了簡化,測試范例都使用項(xiàng)目自帶的demo或者sample等進(jìn)行簡單修改,使得跨進(jìn)程網(wǎng)絡(luò)調(diào)用次數(shù)一致。
gRPC https://github.com/grpc/grpc
從Github master主干上獲得最新版本,按照說明文件進(jìn)行編譯。如上所述,網(wǎng)絡(luò)框架是Netty5,基于最新的HTTP/2.
測試?yán)訛?RouteGuideClient
IDL為 route_guide.proto
選擇其中g(shù)etFeature方法,去除不用的語句和屏幕輸出,進(jìn)行10,000次同步調(diào)用。
TestClientSync client = new TestClientSync("localhost", 8980);try { final long startTime = System.nanoTime(); for (int i = 0; i < 10000; i++) client.getFeature(409146138, -746188906); final long endTime = System.nanoTime(); info("method 1 : " + (endTime - startTime));}
public void getFeature(int lat, int lon) { try { Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build(); Feature feature = blockingStub.getFeature(request); } catch (RuntimeException e) { logger.log(Level.WARNING, "RPC failed", e); throw e; }}
多次執(zhí)行,記錄需要的時(shí)間。
gRPC還有一種非阻塞的調(diào)用方法,不過因?yàn)闀r(shí)間有限,為了簡化測試,我只用標(biāo)準(zhǔn)的server啟動(dòng)的方式,asyncStub在大并發(fā)訪問時(shí)出錯(cuò),用時(shí)也較長,故這次測試沒有這種方法的結(jié)果數(shù)據(jù)。
Thrift http://thrift.apache.org
從Apache網(wǎng)站獲得最新的0.9.2版本,本機(jī)編譯獲得C的編譯器和Java運(yùn)行環(huán)境。
測試?yán)訛?JavaClient.java
IDL tutorial.thrift
int diff;final long startTime = System.nanoTime();try { for (int i = 0; i < 10000; i++) diff = client.calculate(1, work);} catch (InvalidOperation io) { System.out.println("Invalid operation: " + io.why);}final long endTime = System.nanoTime();System.out.println("method 1 : " + (endTime - startTime));
Thrift采用經(jīng)典的基于網(wǎng)絡(luò)端口的RPC,效率最高,在最后的總結(jié)數(shù)據(jù)可以看到。
Wildfly 8.2.0 http://www.wildfly.org
Wildfly是JBossAS改名后的JBoss應(yīng)用服務(wù)器,實(shí)現(xiàn)了完整的JavaEE規(guī)范。我們知道JavaEE中遠(yuǎn)程RPC調(diào)用是在EJB規(guī)范中定義的。我們這里就是要測試Wildlfy中的遠(yuǎn)程EJB調(diào)用能力,
選用的Wildfly8.2是目前發(fā)布的最新穩(wěn)定版本。這個(gè)版本也支持端口多路服用,也就是EJB遠(yuǎn)程調(diào)用是通過HTTP端口復(fù)用來進(jìn)行的,利用HTTP的Upgrade機(jī)制做到二進(jìn)制運(yùn)行時(shí)刻協(xié)商升級。盡管不是純粹的HTTP/2,但也運(yùn)行機(jī)理也相差無幾。
測試?yán)舆x用jboss-eap-quickstarts項(xiàng)目中的遠(yuǎn)程ejb調(diào)用例子 RemoteEJBClient.java
純Java的RPC方案好處是不需要再有IDL文件定義和編譯生成代碼的過程,只要商議好接口就可以了
public interface RemoteCalculator { int add(int a, int b);}
int sum=0;final long startTime = System.nanoTime();for (int i = 0; i < 10000; i++) { sum = statelessRemoteCalculator.add(a, b);}final long endTime = System.nanoTime();System.out.println("method 1 : " + (endTime - startTime));
調(diào)用無狀態(tài)的SessionBean方法10,000次,對應(yīng)的遠(yuǎn)程EJB服務(wù)是部署在Wildfly應(yīng)用服務(wù)器中的EJB。
Dubbo 2.5.4-SNAPSHOT https://github.com/alibaba/dubbo
Dubbo是阿里集團(tuán)開源的一個(gè)極為成員的RPC框架,在很多互聯(lián)網(wǎng)公司和企業(yè)應(yīng)用中廣泛使用。協(xié)議和序列化框架都可以插拔是及其鮮明的特色。同樣的遠(yuǎn)程接口是基于Java Interface,并且依托于spring框架方便開發(fā)??梢苑奖愕拇虬蓡我晃募?dú)立進(jìn)程運(yùn)行,和現(xiàn)在的微服務(wù)概念一致。
采用github中master主干,目前版本是 2.5.4-SNAPSHOT
測試?yán)舆x用其中的demo進(jìn)行修改 DemoAction.java
public interface DemoService { String sayHello(String name);}
final long startTime = System.nanoTime();for (int i = 0; i < 10000; i ++) { try { String hello = demoService.sayHello("world" + i); } catch (Exception e) { e.printStackTrace(); }}final long endTime = System.nanoTime();System.out.println("method 1 : " + (endTime - startTime));
調(diào)用完畢后查看輸入log文件獲得運(yùn)行時(shí)間。
Redhat JBoss EAP 6.3.2 Link
EAP是JBossAS的商業(yè)版本,實(shí)現(xiàn)了完整的JavaEE規(guī)范。
EAP6基于AS7.2以后的版本構(gòu)建,紅帽提供商業(yè)支持。
AS7在7.2以后,社區(qū)版沒有再發(fā)布,具備能力的企業(yè)可以從源碼進(jìn)行編譯使用,EAP6.3基于AS7.4分支構(gòu)建,很快發(fā)布的EAP6.4基于AS7.5分支構(gòu)建,不出意外這個(gè)會是最后一個(gè)EAP6的minor版本。
AS7還沒有像Wildfly完全采用端口復(fù)用的方式,短程EJB調(diào)用通過獨(dú)立端口完成,基于JBossRemoting3的網(wǎng)絡(luò)連接管理能力。
測試?yán)右廊贿x用jboss-eap-quickstarts項(xiàng)目中的遠(yuǎn)程ejb調(diào)用例子
public interface RemoteCalculator { int add(int a, int b);}
記錄一萬次調(diào)用后的時(shí)長。
數(shù)據(jù)結(jié)果。
最終經(jīng)過4輪測試,不間斷運(yùn)行10,000次遠(yuǎn)程RPC調(diào)用后的結(jié)果如下:

我們可以看到Thrift的效率最高,大概領(lǐng)先一個(gè)數(shù)量級。而其他三個(gè)項(xiàng)目的性能數(shù)據(jù)在同數(shù)量級中,由高到低分別為JBossEAP, dubbo, wildfly和gRPC。
需要說明的有以下幾點(diǎn):
為了簡化測試,我并沒有選擇同樣的調(diào)用接口,而是順手用了項(xiàng)目自帶的,方便修改的示例程序。其中g(shù)RPC和Thrift的接口有對象傳遞,稍微復(fù)雜一些。
不是嚴(yán)格的性能測試流程,比如沒有做預(yù)熱過程,以及測試都運(yùn)行在我的桌面用機(jī)上,沒有完全恢復(fù)成“干凈”的狀態(tài)。
都是簡單的服務(wù)器單一進(jìn)程實(shí)例,標(biāo)準(zhǔn)示范例子,沒有做特別優(yōu)化和設(shè)置多個(gè)線程池之類的。而客戶端調(diào)用也是最簡單的阻塞式多次調(diào)用壓力測試。應(yīng)該是用多個(gè)機(jī)器多連接,多個(gè)線程,以及異步非阻塞的調(diào)用多種環(huán)境進(jìn)行測試更為客觀,有機(jī)會再繼續(xù)完善。
之前沒有看到過基于HTTP/2的RPC調(diào)用性能比較,理論上是應(yīng)該低于經(jīng)典的基于端口的RPC方案的。這個(gè)測試結(jié)果可以簡單印證這個(gè)猜想。Thrift的數(shù)據(jù)遙遙領(lǐng)先.gRPC還在開發(fā)之中,基于的Netty還是alpha版本,而且非阻塞的方式還沒有最后的數(shù)據(jù)。我想耐心一些,給gRPC一些時(shí)間,它會讓我們驚艷的。
Wildfly表現(xiàn)良好,要知道它的服務(wù)端可是完整的JavaEE服務(wù)器啊。不過有時(shí)間的化,我試試看經(jīng)典RMI連接的效率如何,要是能和thrift一個(gè)數(shù)量級就更好了。
dubbo性能也很出色,而且協(xié)議層可以更換的話,應(yīng)該還能有更大提升。
我的測試在一臺過時(shí)的筆記本上,受條件限制,沒有先進(jìn)的G級網(wǎng)絡(luò)和多臺服務(wù)器進(jìn)行標(biāo)準(zhǔn)化性能測試。如果哪位在互聯(lián)網(wǎng)或者企業(yè)工作的朋友有條件,也愿意充分完成這個(gè)測試,請和我聯(lián)系,我會完整介紹我的測試搭建環(huán)境,共享代碼,并幫助完成。我想那個(gè)結(jié)果會更有意義。
補(bǔ)記
最初四個(gè)測試時(shí)間為2015-03-11,03-21加入EAP6.3.2的測試,為基于JBossRemoting的EJB遠(yuǎn)程調(diào)用測試,性能良好。和thrift進(jìn)入一個(gè)數(shù)量級,EJB功能可是很豐富的,帶有事務(wù),安全等高級企業(yè)級組件特性。
Wildfly8經(jīng)過配置后使用和EAP類似的遠(yuǎn)程調(diào)用選項(xiàng),效率和EAP應(yīng)該是一致的。
轉(zhuǎn)載地址:http://www.useopen.net/blog/2015/rpc-performance.html