分布式RPC框架性能大比拼
<p><strong>Dubbo</strong> 是阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。不过,略有遗憾的是,据说在淘宝内部,dubbo由于跟淘宝另一个类似的框架HSF(非开源)有竞争关系,导致dubbo团队已经解散(参见 <a href="/misc/goto?guid=4959714190193191679" rel="nofollow,noindex">http://www.oschina.net/news/55059/druid-1-0-9</a> 中的评论),反到是当当网的扩展版本仍在持续发展,墙内开花墙外香。其它的一些知名电商如当当、京东、国美维护了自己的分支或者在dubbo的基础开发,但是官方的库缺乏维护,相关的依赖类比如Spring,Netty还是很老的版本(Spring 3.2.16.RELEASE, netty 3.2.5.Final),倒是有些网友写了升级Spring和Netty的插件。</p> <p><strong><a href="/misc/goto?guid=4959714190289948945" rel="nofollow,noindex">Montan</a></strong> 是新浪微博开源的一个Java 框架。它诞生的比较晚,起于2013年,2016年5月开源。Motan 在微博平台中已经广泛应用,每天为数百个服务完成近千亿次的调用。</p> <p><strong><a href="/misc/goto?guid=4959714190375689268" rel="nofollow,noindex">rpcx</a> </strong>是Go语言生态圈的Dubbo, 比Dubbo更轻量,实现了Dubbo的许多特性,借助于Go语言优秀的并发特性和简洁语法,可以使用较少的代码实现分布式的RPC服务。</p> <p><strong><a href="/misc/goto?guid=4959002772419022699" rel="nofollow,noindex">gRPC</a></strong> 是Google开发的高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。本身它不是分布式的,所以要实现上面的框架的功能需要进一步的开发。</p> <p>以下是它们的功能比较:</p> <table> <thead> <tr> <th> </th> <th>Dubbo</th> <th>Montan</th> <th>rpcx</th> <th>gRPC</th> </tr> </thead> <tbody> <tr> <td>开发语言</td> <td>Java</td> <td>Java</td> <td>Go</td> <td>跨语言</td> </tr> <tr> <td>分布式</td> <td>√</td> <td>√</td> <td>√</td> <td>×</td> </tr> <tr> <td>多序列化框架支持</td> <td>√</td> <td>√<br> (当前支持Hessian2、Json,可扩展)</td> <td>√</td> <td>×<br> (只支持protobuf)</td> </tr> <tr> <td>多种注册中心</td> <td>√</td> <td>√</td> <td>√</td> <td>×</td> </tr> <tr> <td>管理中心</td> <td>√</td> <td>√</td> <td>×</td> <td>×</td> </tr> <tr> <td>跨编程语言</td> <td>×</td> <td>× (支持php client和C server)</td> <td>×</td> <td>√</td> </tr> </tbody> </table> <p>对于RPC的考察, 性能是很重要的一点,因为RPC框架经常用在服务的大并发调用的环境中,性能的好坏决定服务的质量以及公司在硬件部署上的花费。</p> <p>本文通过一个统一的服务,测试这四种框架实现的完整的服务器端和客户端的性能。</p> <p>这个服务传递的消息体有一个protobuf文件定义:</p> <pre> 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]; } </pre> <p>事实上这个文件摘自gRPC项目的测试用例,使用反射为每个字段赋值,使用protobuf序列化后的大小为 581 个字节左右。因为Dubbo和Motan缺省不支持Protobuf,所以序列化和反序列化是在代码中手工实现的。</p> <p>服务很简单:</p> <pre> serviceHello{ // Sends a greeting rpcSay (BenchmarkMessage)returns(BenchmarkMessage) {} } </pre> <p>接收一个BenchmarkMessage,更改它前两个字段的值为"OK" 和 100,这样客户端得到服务的结果后能够根据结果判断服务是否正常的执行。</p> <p>Dubbo的测试代码改自 <a href="/misc/goto?guid=4959714190489854799" rel="nofollow,noindex">dubo-demo</a> ,</p> <p>Motan的测试代码改自 <a href="/misc/goto?guid=4959714190587721119" rel="nofollow,noindex">motan-demo</a> 。</p> <p>rpcx和gRPC的测试代码在 <a href="/misc/goto?guid=4959714190669385495" rel="nofollow,noindex">rpcx benchmark</a> 。</p> <p>正如左耳朵耗子对Dubbo批评一样,Dubbo官方的测试不正规 ( <a href="/misc/goto?guid=4959714190749676686" rel="nofollow,noindex">性能测试应该怎么做?</a> )。</p> <p>本文测试将用吞吐率、相应时间平均值、响应时间中位数、响应时间最大值进行比较(响应时间最小值都为0,不必比较),当然最好以Top Percentile的指标进行比较,但是我没有找到Go语言的很好的统计这个库,所以暂时比较中位数。</p> <p>另外测试中服务的成功率都是100%。</p> <p>测试是在两台机器上执行的,一台机器做服务器,一台机器做客户端。</p> <p>两台机器的配置都是一样的,比较老的服务器:</p> <ul> <li><strong>CPU</strong> : Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz, 24 cores</li> <li><strong>Memory</strong> : 16G</li> <li><strong>OS</strong> : Linux 2.6.32-358.el6.x86_64, CentOS 6.4</li> <li><strong>Go</strong> : 1.7</li> <li><strong>Java</strong> : 1.8</li> </ul> <p>分别在client并发数为100、500、1000、2000 和 5000的情况下测试,记录吞吐率(每秒调用次数, Throughput)、响应时间(Latency) 、成功率。</p> <p>(更精确的测试还应该记录CPU使用率、内存使用、网络带宽、IO等,本文中未做比较)</p> <p>首先看在四种并发下各RPC框架的吞吐率:</p> <p><img src="https://simg.open-open.com/show/8dae9d1d2a763199e7ab2260b7e1e0b3.png"></p> <p>rpcx的性能遥遥领先,并且其它三种框架在并发client很大的情况下吞吐率会下降。</p> <p>在这四种并发的情况下平均响应:</p> <p><img src="https://simg.open-open.com/show/b33a14bb123225a929189ce9ce7a5e6f.png"></p> <p>这个和吞吐率的表现是一致的,还是rpcx最好,平均响应时间小于30ms, Dubbo在并发client多的情况下响应时间很长。</p> <p>我们知道,在微服务流行的今天,一个单一的RPC的服务可能会被不同系统所调用,这些不同的系统会创建不同的client。如果调用的系统很多,就有可能创建很多的client。</p> <p>这里统计的是这些client总的吞吐率和总的平均时间。</p> <p>平均响应时间可能掩盖一些真相,尤其是当响应时间的分布不是那么平均,所以我们还可以关注另外一个指标,就是中位数。</p> <p>这里的中位数指小于这个数值的测试数和大于这个数值的测试数相等。</p> <p><img src="https://simg.open-open.com/show/2af45790947b0a42b06ac2b775c49d5b.png"></p> <p>gRPC框架的表现最好。</p> <p>另外一个就是比较一下最长的响应时间,看看极端情况下各框架的表现:</p> <p><img src="https://simg.open-open.com/show/24b2e5d0ba9959cc41b2af8deb5465e0.png"></p> <p>rpcx的最大响应时间都小于1秒,Motan的表现也不错,都小于2秒,其它两个框架表现不是太好。</p> <p>本文以一个相同的测试case测试了四种RPC框架的性能,得到了这四种框架在不同的并发条件下的性能表现。期望读者能提出宝贵的意见,以便完善这个测试,并能增加更多的RPC框架的测试。</p> <p> </p> <p>来自:http://colobu.com/2016/09/05/benchmarks-of-popular-rpc-frameworks/</p> <p> </p>
本文由用户 chensh2012 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
转载本站原创文章,请注明出处,并保留原始链接、图片水印。
本站是一个以用户分享为主的开源技术平台,欢迎各类分享!