关注 “Java艺术” 我们一起成长!
试下这篇能不能把去年写的Dubbo源码分析系列文章重新激活
Dubbo RPC使用dubbo协议只需要一个长连接就可以收发所有请求,为什么使用http协议的Spring Cloud即便使用长连接也需要连接池呢?
http协议是一种同步应答的交互模式的应用层协议。就是客户端向服务端建立连接后,向服务端发起请求时,客户端必须要阻塞当前连接等到服务端响应,即便使用NIO。
如果你用一个Chanel向服务端发送一个http请求,没等服务端响应,你又用Chanel向服务端发送另一个请求,那服务端响应的结果客户端就没办法知道对应是哪个请求的响应。因此客户端必须同步阻塞等待,除非客户端不需要响应结果。
但dubbo协议、以及我们自定义的协议为什么可以只用一个长连接处理接收和发送所有请求?原因很简单,dubbo协议会为每个请求数据包设置一个不会重复的id,并且用一个Map存储id对应的Future,让发起调用的线程阻塞等待结果。服务端在响应数据包时,将请求id回写到数据包,客户端的单一长连接在接收到响应数据包时,根据请求id从Map中获取Future并写入值、将阻塞等待的发请调用的线程唤醒。
http协议可以实现吗?可以是可以,但一个巴掌拍不响,你得要服务端配合才行。就是客户端在发送请求时,在请求头加一个标志请求id,服务端响应时将此id也写到响应头。如果服务端漏掉将这个请求id回写到响应头,那么客户端就永远也拿不到服务端的响应。不在协议约定之内的就不好去实现。
dubbo客户端只配一个长连接为什么可以处理这么多的请求,除上述原因外,长连接只负责发送和接收消息,如果使用netty,那么这个长连接绑定的线程还负责处理编码和解码,dubbo协议(Dubbo源码,详解dubbo协议数据包及解包过程)的固定长度的请求头,解码方面自然效率比解码http协议(Netty源码,详解Http协议的数据包解码过程)要高。如果数据包很小,编码解密所花费的时间几乎可以忽略不计。理论上,只要网络带宽足够,一个长连接可以并发处理发送和接收大量的请求。
dubbo适用于小数据量(数据包小)大并发(高并发)的服务调用,以及服务消费者机器数远大于服务提供者机器数量的场景,特别是接口响应耗时短的场景,但不适用于传输大数据的服务调用。
阿里众多开源项目中,也是使用Netty自定义通信协议实现交互,如RocketMQ、Sentinel。
▼
往期原创精选
▼