深圳建设局网站深业中城绿化项目,ai做的比较好的网站,学生个人网站制作软件,餐厅网站设计模板下载深入RPC#xff0c;更好使用RPC#xff0c;须从RPC框架整体性能考虑问题。得知道如何提升RPC框架的性能、稳定性、安全性、吞吐量及如何在分布式下快速定位问题。RPC框架如何压榨单机吞吐量#xff1f;
1 前言
TPS一直上不去#xff0c;压测时CPU压到40%#xff5e;50%就…深入RPC更好使用RPC须从RPC框架整体性能考虑问题。得知道如何提升RPC框架的性能、稳定性、安全性、吞吐量及如何在分布式下快速定位问题。RPC框架如何压榨单机吞吐量
1 前言
TPS一直上不去压测时CPU压到40%50%就再也压不上去TPS也不提高咋办
看业务逻辑在执行较为耗时的业务逻辑基础上又同步调用了好几个其它服务。由于这几个服务的耗时较长导致服务业务逻辑耗时也长CPU大部分时间都在等待没得到充分利用因此CPU利用率和服务吞吐量上不去。
3 RPC调用吞吐量的影响因素
根本原因由于处理RPC请求较耗时且CPU大部分时间都在等待而没有去计算导致CPU利用率不够。好比一个人干活但他没规划好时间且长时间都闲着当然也就完不成太多工作。
导致RPC请求耗时的原因主要在RPC框架本身吗除非在网络较慢或使用方使用不当否则大多情况刨除业务逻辑处理的耗时时间RPC本身处理请求的效率就算在较差环境也不过ms级。可以说RPC请求耗时大部分是业务耗时如业务逻辑中有访问DB执行慢SQL的操作。所以大多情况影响RPC调用吞吐量原因就是业务逻辑处理慢CPU大部分时间都在等待资源。
找到根因对症下药
3 提升单机吞吐量的方案
响应式开发就是为提升业务处理的吞吐量。提升吞吐量的关键“异步”。我们的RPC框架要做到完全异步化实现全异步RPC。试想一下如果我们每次发送一个异步请求发送请求过后请求即刻就结束了之后业务逻辑全部异步执行结果异步通知这样可以增加多么可观的吞吐量
效果不用我说我想你也清楚了。那RPC框架都有哪些异步策略呢
4 调用端如何异步
最常用方式就是返回Future对象的Future或入参为Callback对象。Future是最简单的一种异步方式。
发起一次异步请求并从请求上下文拿到一个Future之后就可调用Future#get获取结果。
业务逻辑中调用好几个其它服务若同步调用假设调用4个服务每个服务耗时10ms则业务逻辑执行完至少耗时40ms。采用Future连发4次异步请求并拿到4个Future由于异步调用耗时几乎忽略不计之后统一调用这几个Future#get。业务逻辑执行完的时间理想情况10ms耗时整整缩短到原四分之一即吞吐量可能提升4倍。
5 RPC框架Future异步实现
一次RPC调用本质调用端向服务端发一条请求消息服务端收到消息后进行处理处理后响应给调用端一条响应消息调用端收到响应消息后再处理最后将返回值给到动态代理。
对调用端向服务端发送请求消息与接收服务端响应消息是两个完全独立过程大多数情况下都不在一个线程进行。是不是说RPC框架的调用端对RPC调用的处理逻辑内部实现就是异步的是的。
对RPC框架无论同步 or 异步调用调用端内部实现都是异步。
调用端发的每条消息都有个唯一标识调用端向服务端发请求消息前会先创建一个Future并存储消息标识与这Future的映射动态代理所获得返回值最终就是从这Future中获取。当收到服务端响应消息调用端会根据响应消息的唯一标识通过映射找到对应Future将结果注给那个Future再处理最后动态代理从Future得到返回值。
同步调用不过是RPC框架在调用端处理逻辑中主动执行Future#get让动态代理等待返回值异步调用则是RPC框架没有主动执行Future#get用户可以从请求上下文得到这Future自己决定何时执行Future#get
Future示意图 现在你应该很清楚RPC框架是如何实现Future方式的异步了。
6 RPC调用全异步
Future异步是调用端异步的一种方案那服务端是否需异步有何实现方案
RPC服务端接收到请求的二进制消息后据协议拆包解包之后将完整消息解码并反序列化得到入参后再通过反射执行业务逻辑。生产环境中这些操作都在哪个线程执行
当然不在一个线程对二进制消息数据包拆解包的处理是一定在处理网络I/O的线程若网络通信框架使用Netty则对二进制包处理在IO线程而解码与反序列化过程一般也在IO线程处理。
服务端业务逻辑应交给专门业务线程池处理以防止由于业务逻辑处理过慢而影响网络I/O处理。
我们配置的业务线程池的线程数都有限业务线程池的线程数一般只会配置到200因为大多情况下线程数配置到200还不够用说明业务逻辑该优化。但若碰到特殊业务场景让配置的业务线程池打满了。
案例
启动一个服务业务逻辑处理得就是较慢当访问量逐渐变大业务线程池很容易打满吞吐量不理想这时CPU利用率也很低。咋办
调大业务线程池的线程数有更好方案吗服务端业务处理逻辑异步是个好方案。
调大业务线程池的线程数
勉强可解决这问题但对RPC框架往往都有多个服务共用一个线程池情况即使调大业务线程池较耗时服务很可能还会影响其它服务。最佳方案能让业务线程池尽快释放就需RPC框架支持服务端业务逻辑异步处理。
7 服务端业务逻辑异步方案
较难处理因为服务端执行完业务逻辑后要对返回值序列化并编码将消息响应给调用端但若是异步处理业务逻辑触发异步后方法就执行完了来不及将真正结果进行序列化并编码后响应给调用端。
就要RPC框架提供一种回调方式让业务逻辑可异步处理处理完后调用RPC框架回调接口将最终结果通过回调响应给调用端。
可让RPC框架支持CompletableFuture实现RPC调用在调用端与服务端之间完全异步发布一个RPC服务服务接口定义返回值CompletableFuture对象。
调用过程
服务caller发起RPC调用直接拿到返回值CompletableFuture对象之后无需任何额外与RPC框架相关操作如Future方式时需通过请求上下文获取Future的操作直接就可异步处理在服务端业务逻辑创建一个返回值CompletableFuture对象之后服务端真正业务逻辑可在一个线程池中异步处理业务逻辑完成之后再调用这CompletableFuture对象的complete方法完成异步通知调用端在收到服务端发过来的响应后RPC框架再自动调用调用端拿到的那个返回值CompletableFuture对象的complete方法一次异步调用完成
通过CompletableFutureRPC框架可真正做到在调用端与服务端间完全异步同时提升调用端与服务端的两端的单机吞吐量并且CompletableFuture是Java8原生支持业务逻辑中没有任何代码入侵性。
8 总结
影响RPC调用的吞吐量主要原因服务端的业务逻辑比较耗时并且CPU大部分时间都在等待而没有去计算导致CPU利用率不够而提升单机吞吐量的最好办法就是使用异步RPC。
RPC框架的异步策略主要是调用端异步与服务端异步。调用端的异步就是通过Future方式实现异步调用端发起一次异步请求并且从请求上下文中拿到一个Future之后通过Future的get方法获取结果如果业务逻辑中同时调用多个其它的服务则可以通过Future的方式减少业务逻辑的耗时提升吞吐量。服务端异步则需要一种回调方式让业务逻辑可以异步处理之后调用RPC框架提供的回调接口将最终结果异步通知给调用端。
另外我们可以通过对CompletableFuture的支持实现RPC调用在调用端与服务端之间的完全异步同时提升两端的单机吞吐量。
其实RPC框架也可以有其它的异步策略比如集成RxJava再比如gRPC的StreamObserver入参对象但CompletableFuture是Java8原生提供的无代码入侵性并且在使用上更加方便。如果是Java开发让RPC框架支持CompletableFuture可以说是最佳的异步解决方案。
9 FAQ
提升RPC调用吞吐量还有啥解决方案
RPC调用方式
sync
默认方式但这只是『方法』内部同步在RPC框架内部还是异步处理。
future 方式
消费者得到 future自行决定何时获取返回结果。
callback 方式
调用端无需同步处理响应结果可直接返回。最后返回结果在回调线程里异步处理。
oneway 方式
调用端发送请求之后无需接受响应
Dubbo 2.7后使用 CompletableFuture 提升异步处理能力支持以上四种方式。
CPU大部分时间都在等待并未得到充分利用因此CPU利用率和服务吞吐量当然上不去了。对于这段话其实线程处于等待状态时不占用CPU资源。更准确的描述浪费宝贵线程资源大量线程处等待状态可能不是一定导致CPU利用率低。
使用异步的时候返回的速度变快了但是后台所需要的线程数会变少吗线程池我理解还是被打满
异步对于服务提供方来说RPC线程所要处理的事情就变少了。
压榨单机吞吐量的秘诀是异步化针对RPC框架异步化分成
调用端本就是异步化毕竟通过网络发生完请求消息后面就是黑盒此时可选择不让RPC调用端框架拿服务端的响应消息让调用端应用自行选择何时拿。这样调用端就能发送更多的请求消息提高吞吐量服务端异步化核心在于重分利用单机服务端的资源避免CPU闲置业务处理线程处于等待状态
若“业务线程池的线程数配置到200”线程池被打满了若单纯增加线程数量有用吗200个线程都处理不了的话配置到300或500不是只会增加CPU上下文切换时间吗
可能用处不大需提高接口性能或者扩容解决。