10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图110讲⽹络通信优化之通信协议:如何优化RPC⽹络通信

你好,我是刘超。今天我将带你了解下服务间的⽹络通信优化。

上⼀讲中,我提到了微服务框架,其中SpringCloud和Dubbo的使⽤最为⼴泛,⾏业内也⼀直存在着对两者的⽐较,很多技术
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图2⼈会为这两个框架哪个更好⽽争辩。

我记得我们部⻔在搭建微服务框架时,也在技术选型上纠结良久,还曾⼀度有过激烈的讨论。当前SpringCloud炙⼿可热,具备完整的微服务⽣态,得到了很多同事的票选,但我们最终的选择却是Dubbo,这是为什么呢?

RPC通信是⼤型服务框架的核⼼

我们经常讨论微服务,⾸要应该了解的就是微服务的核⼼到底是什么,这样我们在做技术选型时,才能更准确地把握需求。

就我个⼈理解,我认为微服务的核⼼是远程通信和服务治理。远程通信提供了服务之间通信的桥梁,服务治理则提供了服务的后勤保障。所以,我们在做技术选型时,更多要考虑的是这两个核⼼的需求。

我们知道服务的拆分增加了通信的成本,特别是在⼀些抢购或者促销的业务场景中,如果服务之间存在⽅法调⽤,⽐如,抢购成功之后需要调⽤订单系统、⽀付系统、券包系统等,这种远程通信就很容易成为系统的瓶颈。所以,在满⾜⼀定的服务治理需求的前提下,对远程通信的性能需求就是技术选型的主要影响因素。

⽬前,很多微服务框架中的服务通信是基于RPC通信实现的,在没有进⾏组件扩展的前提下,SpringCloud是基于Feign组件 实现的RPC通信(基于Http+Json序列化实现),Dubbo是基于SPI扩展了很多RPC通信框架,包括RMI、Dubbo、Hessian等
RPC通信框架(默认是Dubbo+Hessian序列化)。不同的业务场景下,RPC通信的选择和优化标准也不同。

例如,开头我提到的我们部⻔在选择微服务框架时,选择了Dubbo。当时的选择标准就是RPC通信可以⽀持抢购类的⾼并发, 在这个业务场景中,请求的特点是瞬时⾼峰、请求量⼤和传⼊、传出参数数据包较⼩。⽽Dubbo中的Dubbo协议就很好地⽀持了这个请求。

以下是基于Dubbo:2.6.4版本进⾏的简单的性能测试。分别测试Dubbo+Protobuf序列化以及Http+Json序列化的通信性能(这
⾥主要模拟单⼀TCP⻓连接+Protobuf序列化和短连接的Http+Json序列化的性能对⽐)。为了验证在数据量不同的情况下⼆者
的性能表现,我分别准备了⼩对象和⼤对象的性能压测,通过这样的⽅式我们也可以间接地了解下⼆者在RPC通信⽅⾯的⽔平。
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图310讲网络通信优化之通信协议:如何优化RPC网络通信 - 图4

这个测试是我之前的积累,基于测试环境⽐较复杂,这⾥我就直接给出结果了,如果你感兴趣的话,可以留⾔和我讨论。

通过以上测试结果可以发现:⽆论从响应时间还是吞吐量上来看,单⼀TCP⻓连接+Protobuf序列化实现的RPC通信框架都有着⾮常明显的优势。

在⾼并发场景下,我们选择后端服务框架或者中间件部⻔⾃⾏设计服务框架时,RPC通信是重点优化的对象。

其实,⽬前成熟的RPC通信框架⾮常多,如果你们公司没有⾃⼰的中间件团队,也可以基于开源的RPC通信框架做扩展。在正式进⾏优化之前,我们不妨简单回顾下RPC。

什么是RPC通信

⼀提到RPC,你是否还想到MVC、SOA这些概念呢?如果你没有经历过这些架构的演变,这些概念就很容易混淆。你可以通过下⾯这张图来了解下这些架构的演变史。
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图5
⽆论是微服务、SOA、还是RPC架构,它们都是分布式服务架构,都需要实现服务之间的互相通信,我们通常把这种通信统称为RPC通信。

RPC(Remote Process Call),即远程服务调⽤,是通过⽹络请求远程计算机程序服务的通信技术。RPC框架封装好了底层
⽹络通信、序列化等技术,我们只需要在项⽬中引⼊各个服务的接⼝包,就可以实现在代码中调⽤RPC服务同调⽤本地⽅法
⼀样。正因为这种⽅便、透明的远程调⽤,RPC被⼴泛应⽤于当下企业级以及互联⽹项⽬中,是实现分布式系统的核⼼。

RMI(Remote Method Invocation)是JDK中最先实现了RPC通信的框架之⼀,RMI的实现对建⽴分布式Java应⽤程序⾄关重
要,是Java体系⾮常重要的底层技术,很多开源的RPC通信框架也是基于RMI实现原理设计出来的,包括Dubbo框架中也接⼊了RMI框架。接下来我们就⼀起了解下RMI的实现原理,看看它存在哪些性能瓶颈有待优化。

RMI:JDK⾃带的RPC通信框架

⽬前RMI已经很成熟地应⽤在了EJB以及Spring框架中,是纯Java⽹络分布式应⽤系统的核⼼解决⽅案。RMI实现了⼀台虚拟机应⽤对远程⽅法的调⽤可以同对本地⽅法的调⽤⼀样,RMI帮我们封装好了其中关于远程通信的内容。

RMI的实现原理

RMI远程代理对象是RMI中最核⼼的组件,除了对象本身所在的虚拟机,其它虚拟机也可以调⽤此对象的⽅法。⽽且这些虚拟机可以不在同⼀个主机上,通过远程代理对象,远程应⽤可以⽤⽹络协议与服务进⾏通信。

我们可以通过⼀张图来详细地了解下整个RMI的通信过程:
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图6

RMI在⾼并发场景下的性能瓶颈

Java默认序列化

RMI的序列化采⽤的是Java默认的序列化⽅式,我在09讲中详细地介绍过Java序列化,我们深知它的性能并不是很好,⽽且其它语⾔框架也暂时不⽀持Java序列化。

TCP短连接

由于RMI是基于TCP短连接实现,在⾼并发情况下,⼤量请求会带来⼤量连接的创建和销毁,这对于系统来说⽆疑是⾮常消耗性能的。

阻塞式⽹络I/O

在08讲中,我提到了⽹络通信存在I/O瓶颈,如果在Socket编程中使⽤传统的I/O模型,在⾼并发场景下基于短连接实现的⽹络通信就很容易产⽣I/O阻塞,性能将会⼤打折扣。

⼀个⾼并发场景下的RPC通信优化路径

SpringCloud的RPC通信和RMI通信的性能瓶颈就⾮常相似。SpringCloud是基于Http通信协议(短连接)和Json序列化实现的,在⾼并发场景下并没有优势。 那么,在瞬时⾼并发的场景下,我们⼜该如何去优化⼀个RPC通信呢?

RPC通信包括了建⽴通信、实现报⽂、传输协议以及传输数据编解码等操作,接下来我们就从每⼀层的优化出发,逐步实现整体的性能优化。

1.选择合适的通信协议

要实现不同机器间的⽹络通信,我们先要了解计算机系统⽹络通信的基本原理。⽹络通信是两台设备之间实现数据流交换的过程,是基于⽹络传输协议和传输数据的编解码来实现的。其中⽹络传输协议有TCP、UDP协议,这两个协议都是基于Socket 编程接⼝之上,为某类应⽤场景⽽扩展出的传输协议。通过以下两张图,我们可以⼤概了解到基于TCP和UDP协议实现的
Socket⽹络通信是怎样的⼀个流程。
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图7
基于TCP协议实现的Socket通信是有连接的,⽽传输数据是要通过三次握⼿来实现数据传输的可靠性,且传输数据是没有边界的,采⽤的是字节流模式。

基于UDP协议实现的Socket通信,客户端不需要建⽴连接,只需要创建⼀个套接字发送数据报给服务端,这样就不能保证数据报⼀定会达到服务端,所以在传输数据⽅⾯,基于UDP协议实现的Socket通信具有不可靠性。UDP发送的数据采⽤的是数据报模式,每个UDP的数据报都有⼀个⻓度,该⻓度将与数据⼀起发送到服务端。

通过对⽐,我们可以得出优化⽅法:为了保证数据传输的可靠性,通常情况下我们会采⽤TCP协议。如果在局域⽹且对数据传

输的可靠性没有要求的情况下,我们也可以考虑使⽤UDP协议,毕竟这种协议的效率要⽐TCP协议⾼。

2.使⽤单⼀⻓连接

如果是基于TCP协议实现Socket通信,我们还能做哪些优化呢?

服务之间的通信不同于客户端与服务端之间的通信。客户端与服务端由于客户端数量多,基于短连接实现请求可以避免⻓时间地占⽤连接,导致系统资源浪费。

但服务之间的通信,连接的消费端不会像客户端那么多,但消费端向服务端请求的数量却⼀样多,我们基于⻓连接实现,就可以省去⼤量的TCP建⽴和关闭连接的操作,从⽽减少系统的性能消耗,节省时间。

3.优化Socket通信

建⽴两台机器的⽹络通信,我们⼀般使⽤Java的Socket编程实现⼀个TCP连接。传统的Socket通信主要存在I/O阻塞、线程模型缺陷以及内存拷⻉等问题。我们可以使⽤⽐较成熟的通信框架,⽐如Netty。Netty4对Socket通信编程做了很多⽅⾯的优
化,具体⻅下⽅。

实现⾮阻塞I/O:在08讲中,我们提到了多路复⽤器Selector实现了⾮阻塞I/O通信。

⾼效的Reactor线程模型:Netty使⽤了主从Reactor多线程模型,服务端接收客户端请求连接是⽤了⼀个主线程,这个主线程
⽤于客户端的连接请求操作,⼀旦连接建⽴成功,将会监听I/O事件,监听到事件后会创建⼀个链路请求。

链路请求将会注册到负责I/O操作的I/O⼯作线程上,由I/O⼯作线程负责后续的I/O操作。利⽤这种线程模型,可以解决在⾼负载、⾼并发的情况下,由于单个NIO线程⽆法监听海量客户端和满⾜⼤量I/O操作造成的问题。

串⾏设计:服务端在接收消息之后,存在着编码、解码、读取和发送等链路操作。如果这些操作都是基于并⾏去实现,⽆疑会导致严重的锁竞争,进⽽导致系统的性能下降。为了提升性能,Netty采⽤了串⾏⽆锁化完成链路操作,Netty提供了Pipeline 实现链路的各个操作在运⾏期间不进⾏线程切换。

零拷⻉:在08讲中,我们提到了⼀个数据从内存发送到⽹络中,存在着两次拷⻉动作,先是从⽤户空间拷⻉到内核空间,再 是从内核空间拷⻉到⽹络I/O中。⽽NIO提供的ByteBuffer可以使⽤Direct Buffers模式,直接开辟⼀个⾮堆物理内存,不需要进
⾏字节缓冲区的⼆次拷⻉,可以直接将数据写⼊到内核空间。

除了以上这些优化,我们还可以针对套接字编程提供的⼀些TCP参数配置项,提⾼⽹络吞吐量,Netty可以基于

ChannelOption来设置这些参数。

TCP_NODELAY:TCP_NODELAY选项是⽤来控制是否开启Nagle算法。Nagle算法通过缓存的⽅式将⼩的数据包组成⼀个⼤的数据包,从⽽避免⼤量的⼩数据包发送阻塞⽹络,提⾼⽹络传输的效率。我们可以关闭该算法,优化对于时延敏感的应⽤场景。

SO_RCVBUF和SO_SNDBUF:可以根据场景调整套接字发送缓冲区和接收缓冲区的⼤⼩。

SO_BACKLOG:backlog参数指定了客户端连接请求缓冲队列的⼤⼩。服务端处理客户端连接请求是按顺序处理的,所以同
⼀时间只能处理⼀个客户端连接,当有多个客户端进来的时候,服务端就会将不能处理的客户端连接请求放在队列中等待处理。

SO_KEEPALIVE:当设置该选项以后,连接会检查⻓时间没有发送数据的客户端的连接状态,检测到客户端断开连接后,服务端将回收该连接。我们可以将该时间设置得短⼀些,来提⾼回收连接的效率。

4.量身定做报⽂格式

接下来就是实现报⽂,我们需要设计⼀套报⽂,⽤于描述具体的校验、操作、传输数据等内容。为了提⾼传输的效率,我们可

以根据⾃⼰的业务和架构来考虑设计,尽量实现报体⼩、满⾜功能、易解析等特性。我们可以参考下⾯的数据格式:
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图810讲网络通信优化之通信协议:如何优化RPC网络通信 - 图9

5.编码、解码

在09讲中,我们分析过序列化编码和解码的过程,对于实现⼀个好的⽹络通信协议来说,兼容优秀的序列化框架是⾮常重要的。如果只是单纯的数据对象传输,我们可以选择性能相对较好的Protobuf序列化,有利于提⾼⽹络通信的性能。

6.调整Linux的TCP参数设置选项

如果RPC是基于TCP短连接实现的,我们可以通过修改Linux TCP配置项来优化⽹络通信。开始TCP配置项的优化之前,我们先来了解下建⽴TCP连接的三次握⼿和关闭TCP连接的四次握⼿,这样有助后⾯内容的理解。

三次握⼿

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图10

四次握⼿

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图11

我们可以通过sysctl -a | grep net.xxx命令运⾏查看Linux系统默认的的TCP参数设置,如果需要修改某项配置,可以通过编辑
vim/etc/sysctl.conf,加⼊需要修改的配置项, 并通过sysctl -p命令运⾏⽣效修改后的配置项设置。通常我们会通过修改以下⼏个配置项来提⾼⽹络吞吐量和降低延时。

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图12

以上就是我们从不同层次对RPC优化的详解,除了最后的Linux系统中TCP的配置项设置调优,其它的调优更多是从代码编程
优化的⻆度出发,最终实现了⼀套RPC通信框架的优化路径。

弄懂了这些,你就可以根据⾃⼰的业务场景去做技术选型了,还能很好地解决过程中出现的⼀些性能问题。

总结

在现在的分布式系统中,特别是系统⾛向微服务化的今天,服务间的通信就显得尤为频繁,掌握服务间的通信原理和通信协议优化,是你的⼀项的必备技能。

在⼀些并发场景⽐较多的系统中,我更偏向使⽤Dubbo实现的这⼀套RPC通信协议。Dubbo协议是建⽴的单⼀⻓连接通信,⽹络I/O为NIO⾮阻塞读写操作,更兼容了Kryo、FST、Protobuf等性能出众的序列化框架,在⾼并发、⼩对象传输的业务场景中
⾮常实⽤。

在企业级系统中,业务往往要⽐普通的互联⽹产品复杂,服务与服务之间可能不仅仅是数据传输,还有图⽚以及⽂件的传输, 所以RPC的通信协议设计考虑更多是功能性需求,在性能⽅⾯不追求极致。其它通信框架在功能性、⽣态以及易⽤、易⼊⻔ 等⽅⾯更具有优势。

思考题

⽬前实现Java RPC通信的框架有很多,实现RPC通信的协议也有很多,除了Dubbo协议以外,你还使⽤过其它RPC通信协议吗?通过这讲的学习,你能对⽐谈谈各⾃的优缺点了吗?

期待在留⾔区看到你的⻅解。也欢迎你点击“请朋友读”,把今天的内容分享给身边的朋友,邀请他⼀起学习。
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图13

  1. 精选留⾔

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图14WL
请教⽼师两个问题:

  1. 在RMI的实现原理示意图中客户端的存根和服务端的⻣架这两个概念是啥意思, 我感觉不太理解.
  2. 在TCP的四次挥⼿中, 客户端最后的TIME_WAIT状态是不是就是CLOSE的状态, 如果不是那TIME_WAIT状态是在啥时候转换成CLOSE状态的.

2019-06-11 07:43
作者回复
我先回答第⼆个问题。

是的,TIME_WAIT状态就是主动断开⽅的最后状态了。主动断开连接⽅之所以是TIME_WAIT状态,是担⼼被断开⽅没有收到最后的ACK,这个TIME_WAIT时间内核默认设置是2MSL(报⽂最⼤⽣存时间),被断开⽅如果超时没有收到ACK,将重新发送F
IN,主动断开⽅收到之后⼜会重新发送ACK通知,重置TIME_WAIT时间。

正常情况下,当主动断开⽅的TIME_WAIT状态到达了定时时间后,内核就会关闭该连接。第⼀个问题,这块⽂章中没有过多的介绍,我在这⾥再叙述下:

Stub是client端的远程对象的代理,负责将远程对象上的⽅法调⽤转发到实际远程对象实现所在的服务器,我们的程序要通过远
程调⽤,底层⼀定是套接字的字节传输,要⼀个对象序列化成为字节码,传输到服务器或者客户端的对端之后,再把该对象反
序列化成为对应的对象,Stub承担着底层序列化、数据组装以及协议封装等⼯作。

Skeleton则是server端的服务对象的代理,负责将接收解析远程调⽤分派到实际远程对象实现调⽤。Stub与Skeleton的关系以及操作是对应的关系,只有实现了java.rmi.Remote接⼝的类或者继承了java.rmi.Remote接⼝的接⼝,才能作为Stub与
Skeleton之间通信的远程对象,Stub与Skeleton之间的通信使⽤Java远程消息交换协议JRMP(Java Remote Messaging Proto
col)进⾏通信,JRMP是专为Java的远程对象制定的协议。Stub和Skeleton之间协作完成客户端与服务器之间的⽅法调⽤时的 通信。

2019-06-11 09:36

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图15Stalary
⽼师,如果业务架构已经选择了SpringCloud,该如何优化远程调⽤呢,⽬前使⽤Feign,底层配置了HttpClient,发现qps⼀直 上不去,暂时是对频繁的请求做了本地cache,但是需要订阅更新事件进⾏刷新
2019-06-11 07:18
作者回复
可以尝试扩展其他RPC框架,例如有同学提到的Google的grpc框架,也是基于Netty通信框架实现,基于protobuf实现的序列化

2019-06-11 09:10

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图16Y⼂z
⽼师好,我想问下已经在线上跑的服务,序列化⽅式是hessian,如果直接换成Protobuf,那么consumer会报错吗?如果报错 的话,如何避免这种情况发⽣呢?
2019-06-11 09:58
作者回复
服务端和消费端重启,会⾛protobuf序列化
2019-06-12 09:17

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图17夏天39度
⽼师,能说⼀下Netty是如何实现串⾏⽆锁化完成链路操作吗,怎么做到⽆锁化的线程切换
2019-06-11 09:15
作者回复
Netty中,分为Reactor主线程和Reactor从线程,主线程主要⽤来监听连接事件,从线程主要⽤来处理监听I/O事件,以及处理 读写I/O操作。

⼀般有其他的业务操作,我们可以在handler中创建线程池来处理。但为了减少上下⽂切换,我们可以在ChannelPipeline上注 册handler事件,例如解码过程。⼀般Reactor从线程监听到读操作,会⽴即调⽤ChannelPipeline的fireChannelRead⽅法完成 读操作,在调⽤完读操作之后,会检查是否有其他handler,如果有,则直接调⽤,不会创建新的线程。

这种⽅式的好处是,不⽤创建新的线程,在从线程中串⾏化完成所有的I/O以及业务操作,减少上下⽂切换;坏处是,给从线程带来了⼀定的阻塞。
2019-06-16 10:34

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图18Joker
⽼师厉害,层层递进啊。。。虽然可能我们⽬前没有⽤到,但是却是个⾮常好的地图啊。
2019-07-09 23:00
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图19张德
还知道JAVA和Python系统之间互相调⽤的thrift
2019-07-07 11:49
作者回复
thrift框架也很优秀
2019-07-08 16:32

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图20nightmare
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图21 能不能讲⼀下netty的串⾏⽆锁化
2019-06-13 12:42
作者回复
Netty中,分为Reactor主线程和Reactor从线程,主线程主要⽤来监听连接事件,从线程主要⽤来处理监听I/O事件,以及处理 读写I/O操作。

⼀般有其他的业务操作,我们可以在handler中创建线程池来处理。但为了减少上下⽂切换,我们可以在ChannelPipeline上注 册handler事件,例如解码过程。⼀般Reactor从线程监听到读操作,会⽴即调⽤ChannelPipeline的fireChannelRead⽅法完成 读操作,在调⽤完读操作之后,会检查是否有其他handler,如果有,则直接调⽤,不会创建新的线程。

这种⽅式的好处是,不⽤创建新的线程,在从线程中串⾏化完成所有的I/O以及业务操作,减少上下⽂切换;坏处是,给从线程带来了⼀定的阻塞。
2019-06-16 10:33

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图22电光⽕⽯

  1. ⽼师线上有⽤过grpc吗,看⽂档说好像现在还不是特别的稳定?
  2. ⽂中的性能测试,http是否有打开keep alive?⾛tcp⽆疑更快,我只想知道⽤http会慢多少,因为毕竟http更简单。有看过其他的benchmark,在打开keep alive的情况下,性能也还⾏,不知道⽼师这个测试是否打开?另外,从测试结果上看,当单次请求数据量很⼤的时候,http⽐tcp好像查不了多少是吗?

谢谢!
2019-06-11 23:36
作者回复
grpc⽬前很多公司在⽤,在Github中有源码阅读https://github.com/grpc。 对的,没有打开keep alive,如果开启效果会好⼀些,减少了⽹络连接。
2019-06-12 10:34

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图23-W.LI-
⽼师好!⽂中提到了⾼效的 Reactor 线程模型。有适合新⼿的资料链接么?还有个pr啥的能⼀起给我个么谢谢了,⽂中讲的看不懂。

2019-06-11 22:36
作者回复
下⼀讲中会讲到Reactor、Proactor线程模型。
2019-06-12 10:00

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图24JackJin
RPC要怎么学,项⽬中也⽤到了dubbo,可跟⽼师说的完全不⼀样,不是添加其他服务接⼝的依赖调⽤⽅法,⽽是发送http请求调⽤其他服务的接⼝。使我们⽤错了吗?
有个疑问依赖其他的服务的接⼝调⽤⽅法,接⼝都没有实现怎么调⽤?
2019-06-11 18:08
作者回复
请问你们⽤的什么协议?dubbo是消费服务类型,服务会注册接⼝到注册中⼼,消费端通过拉取注册中⼼的注册服务接⼝,与服务端通信。所以⼀般都是通过接⼝服务实现消息通信。
2019-06-12 10:03

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图25晓杰
请问⽼师,对于⼤⽂件的传输,⽤哪种协议⽐较好
2019-06-11 16:08
作者回复
建议使⽤hessian协议
2019-06-12 10:10

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图26假装⾃⼰不胖
对于⽹络编程⽐较迷茫,请问有没有⼩⽩⼀些的读物或博客推荐⼀下
2019-06-11 09:17
作者回复
这块知识点⽐较多,建议可以看⼀些基础书籍,例如Unix⽹络编程、TCP/IP⽹络编程,再看看netty实战,就可以进阶Java⽹络编程了。
2019-06-13 09:28

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图27Liam
能否讲讲不同情况下,tcp各个调优参数的值应该怎么设和通常设置为多少
2019-06-11 08:53
10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图28⿊崽
断开连接是四次挥⼿吧
2019-06-11 08:20
作者回复
是的,⽂中提到了。
2019-06-11 09:37

10讲网络通信优化之通信协议:如何优化RPC网络通信 - 图29进阶的码农
我们是⽤spring-cloud 继承google的grpc
2019-06-11 07:32
作者回复
优秀
2019-06-11 09:11