阿里毕玄:RPC 框架优化之路,从 37k 到 168k

简介: 阿里毕玄:RPC 框架优化之路,从 37k 到 168k


来测试下你的Java编程能力文章里有一些关于Java网络通信的题目,翻出几年前的一篇文章再给大伙看看,这应该算是怎么写一个高性能RPC框架的还不错的实践,感兴趣的其实也可以自己去写个玩玩,这个过程会是学到很多东西的好方法。


下面文章写于2011年。



McQueenRPC(代码在github上)每秒支撑的请求数上升了好几倍,测试结果的演变为:37k–> 56k –> 65k –> 88k –> 93k –> 143k –> 148k –> 153k –> 160k –> 163k –> 168k以上测试结果为在100并发、100 request byte、100 response byte以及单连接下的背景下得出的,在这篇blog中来分享下这个框架所做的一些优化动作,希望能给编写rpc框架或使用netty的同学们一点点帮助,也希望得到高手们更多的指点。

1、37k –> 56k由于目前大部分的NIO框架采用的均为1个socket io线程处理多个连接的io事件,如果io线程时间占用太长的话,就会导致收到的响应处理的比较慢的现象,这步优化就是针对反序列化过程占用io线程而做的,采用的方法即为在读取流时仅根据长度信息把所有的bytes都读好,然后直接作为收到的信息返回给业务线程,业务线程在进行处理前先做反序列化动作,感兴趣的同学可以看看McQueenRPC中:NettyProtocolDecoder,以及NettyServerHandler。

2、56k –> 65k在测试的过程中,发现YGC的耗时比较长,在咨询了sun的人后告诉我主要是由于有旧生代的数据结构引用了大量新生代对象造成的,经过对程序的分析,猜测是benchmark代码本身用于记录请求响应时间信息的ConcurrentLinkedQueue造成的,在某超级大牛的指示下,换成了在每个线程中用数组的方式,按区间来记录响应时间信息等,感兴趣的同学可以看看McQueenRPC中SimpleProcessorBenchmarkClientRunnable

3、65k –> 88k在某超级大牛的分析下,发现目前的情况下io线程的上下文切换还是比较频繁,导致io线程处理效率不够高,默认情况下,NIO框架多数采用的均为接到一个包后,将这个包交由反序列化的处理器进行处理,对于包中有多个请求信息或响应信息的情况,则采用一个一个通知的方式,而rpc框架在接到一个请求或响应对象时的做法通常是唤醒等待的业务线程,因此对于一个包中有多个请求或响应的状况就会导致io线程需要多次唤醒业务线程,这个地方改造的方法是nio框架一次性的将包中所有的请求或响应对象通知给业务线程,然后由业务线程pipeline的去唤醒其他的业务线程,感兴趣的同学可以看看McQueenRPC中:NettyProtocolDecoder,以及NettyClientHandler。

4、88k –> 93k这步没什么可说的,只是多支持了hessian序列化,然后这个结果是用hessian序列化测试得出的,注意的是hessian不要使用3.1.x或3.2.x版本,这两个系列的版本性能极差,建议使用hessian 4.0.x版本

5、93k –> 143k在到达93k时,看到测试的结果中有不少请求的响应时间会超过10ms,于是用btrace一步一步跟踪查找是什么地方会出现这种现象,后来发现是由于之前在确认写入os send buffer时采用的是await的方式,而这会导致需要等待io线程来唤醒,增加了线程上下文切换以及io线程的负担,但这个地方又不能不做处理,后来就改造成仅基于listener的方式进行处理,如写入失败会直接创建一个响应对象,这次改造后效果非常明显,感兴趣的同学可以看看McQueenRPC中:NettyClient。

6、143k –> 148k这步是在@killme2008 的指点下,将tcpNoDelay设置为了false,但这个设置不适用于低压力的情况,在10个线程的情况下tps由3w降到了2k,因此tcpNoDelay这个建议还是设置成true。

7、148k –> 153k这步没什么可说的,只是多支持了protobuf序列化,这个结果是用protobuf序列化测试得出的,之前还测试过下@bnu_chenshuo 写的一个protorpc,是基于protobuf的rpc加上netty实现的,结果也很强悍,测试出来是149k,看来protobuf的rpc也是有不少值得学习的地方的。

8、153k –> 160kserver接到消息的处理过程也修改成类似client的pipeline机制,同时将之前获取协议处理器和序列化/反序列化的处理器的地方由map改成了数组,具体可以参考NettyServerHandler、ProtocolFactory和Codecs。

9、160k –> 163kGrizzly的leader对grizzly部分的代码做了很多的修改,结果创造了目前rpc benchmark的最高纪录:163k。

10、163k –> 168k@minzhou 对McQueenRPC的代码进行了优化,将之前在Decoder中做的构造String对象的部分挪到了业务线程中,于是TPS也有了一定的上升,感谢。

上面就是到目前为止的所有优化动作,其中的很多我估计高手的话是不会犯错的,我走的弯路多了些,总结来说rpc框架的优化动作为:

尽可能减少io线程的占用时间,把能做的事都挪到别的线程里去做;

尽可能减少线程上下文切换;

尽可能使用高效的序列化/反序列化。


本文虽然写于十年前,但对于同类问题处理,其方法仍然有参考意义。


相关文章
|
6月前
|
负载均衡 Dubbo Java
Dubbo 3.x:探索阿里巴巴的开源RPC框架新技术
随着微服务架构的兴起,远程过程调用(RPC)框架成为了关键组件。Dubbo,作为阿里巴巴的开源RPC框架,已经演进到了3.x版本,带来了许多新特性和技术改进。本文将探讨Dubbo 3.x中的一些最新技术,包括服务注册与发现、负载均衡、服务治理等,并通过代码示例展示其使用方式。
338 9
|
6月前
|
JSON 负载均衡 网络协议
Rpc编程系列文章第二篇:RPC框架设计目标
Rpc编程系列文章第二篇:RPC框架设计目标
|
6月前
|
设计模式 负载均衡 网络协议
【分布式技术专题】「分布式技术架构」实践见真知,手把手教你如何实现一个属于自己的RPC框架(架构技术引导篇)
【分布式技术专题】「分布式技术架构」实践见真知,手把手教你如何实现一个属于自己的RPC框架(架构技术引导篇)
242 0
|
3天前
|
自然语言处理 负载均衡 API
gRPC 一种现代、开源、高性能的远程过程调用 (RPC) 可以在任何地方运行的框架
gRPC 是一种现代开源高性能远程过程调用(RPC)框架,支持多种编程语言,可在任何环境中运行。它通过高效的连接方式,支持负载平衡、跟踪、健康检查和身份验证,适用于微服务架构、移动设备和浏览器客户端连接后端服务等场景。gRPC 使用 Protocol Buffers 作为接口定义语言,支持四种服务方法:一元 RPC、服务器流式处理、客户端流式处理和双向流式处理。
|
6月前
|
Dubbo Java 应用服务中间件
Rpc编程系列文章第三篇:Hessian RPC一个老的RPC框架
Rpc编程系列文章第三篇:Hessian RPC一个老的RPC框架
|
3月前
|
Dubbo 网络协议 Java
RPC框架:一文带你搞懂RPC
这篇文章全面介绍了RPC(远程过程调用)的概念、原理和应用场景,解释了RPC如何工作以及为什么在分布式系统中广泛使用,并探讨了几种常用的RPC框架如Thrift、gRPC、Dubbo和Spring Cloud,同时详细阐述了RPC调用流程和实现透明化远程服务调用的关键技术,包括动态代理和消息的编码解码过程。
RPC框架:一文带你搞懂RPC
|
2月前
|
XML 负载均衡 监控
分布式-dubbo-简易版的RPC框架
分布式-dubbo-简易版的RPC框架
|
3月前
|
XML 存储 JSON
(十二)探索高性能通信与RPC框架基石:Json、ProtoBuf、Hessian序列化详解
如今这个分布式风靡的时代,网络通信技术,是每位技术人员必须掌握的技能,因为无论是哪种分布式技术,都离不开心跳、选举、节点感知、数据同步……等机制,而究其根本,这些技术的本质都是网络间的数据交互。正因如此,想要构建一个高性能的分布式组件/系统,不得不思考一个问题:怎么才能让数据传输的速度更快?
|
5月前
|
存储 缓存 Linux
【实战指南】嵌入式RPC框架设计实践:六大核心类构建高效RPC框架
在先前的文章基础上,本文讨论如何通过分层封装提升一个针对嵌入式Linux的RPC框架的易用性。设计包括自动服务注册、高性能通信、泛型序列化和简洁API。框架分为6个关键类:BindingHub、SharedRingBuffer、Parcel、Binder、IBinder和BindInterface。BindingHub负责服务注册,SharedRingBuffer实现高效数据传输,Parcel处理序列化,而Binder和IBinder分别用于服务端和客户端交互。BindInterface提供简单的初始化接口,简化应用集成。测试案例展示了客户端和服务端的交互,验证了RPC功能的有效性。
379 7
|
4月前
|
分布式计算 负载均衡 数据安全/隐私保护
什么是RPC?有哪些RPC框架?
RPC(Remote Procedure Call,远程过程调用)是一种允许运行在一台计算机上的程序调用另一台计算机上子程序的技术。这种技术屏蔽了底层的网络通信细节,使得程序间的远程通信如同本地调用一样简单。RPC机制使得开发者能够构建分布式计算系统,其中不同的组件可以分布在不同的计算机上,但它们之间可以像在同一台机器上一样相互调用。
145 8