RPC:Dubbo、gRPC、HSF

  • 服务注册

  • 服务发现

  • 服务治理

1 Dubbo(HSF)

1.1 架构

  • 注册中心:注册中心负责服务地址的注册与查找,生产者在此注册并发布内容,消费者在此订阅并接收发布的内容。

  • 消费者:客户端,从注册中心获取到方法,可以调用生产者中的方法。

  • 生产者:服务端,生产内容,生产前需要依赖容器(先启动容器)。

1.2 Dubbo调用流程

1、服务提供者启动,开启Netty服务,创建Zookeeper客户端,向注册中心注册服务;

2、服务消费者启动,通过Zookeeper向注册中心获取服务提供者列表,与服务提供者通过Netty建立长连接;

3、服务消费者通过接口开始远程调用服务,ProxyFactory通过初始化Proxy对象,Proxy通过创建动态代理对象;

4、动态代理对象通过invoke方法,层层包装生成一个Invoker对象,该对象包含了代理对象;

5、Invoker通过路由,负载均衡选择了一个最合适的服务提供者,在通过加入各种过滤器,协议层包装生成一个新的DubboInvoker对象;

6、再通过交换成将DubboInvoker对象包装成一个Reuqest对象,该对象通过序列化通过NettyClient传输到服务提供者的NettyServer端;

7、到了服务提供者这边,再通过反序列化、协议解密等操作生成一个DubboExporter对象,再层层传递处理,会生成一个服务提供端的Invoker对象;

8、这个Invoker对象会调用本地服务,获得结果再通过层层回调返回到服务消费者,服务消费者拿到结果后,再解析获得最终结果。

1.3 Invoker

Invoker 就是 Dubbo 对远程调用的抽象。

1.4 负载均衡策略

  • 随机

  • 轮询

  • 一致性哈希

  • 最少活跃调用数

1.5 序列化协议

JDK 自带的序列化、hessian2、JSON、Kryo、FST、Protostuff,ProtoBuf 等等。

[!question] 如何解决重载问题?

2 RPC和HTTP

现在电脑上装的各种联网软件,比如 xx 管家,xx 卫士,它们都作为客户端(Client) 需要跟服务端(Server) 建立连接收发消息,此时都会用到应用层协议,在这种 Client/Server (C/S) 架构下,它们可以使用自家造的 RPC 协议,因为它只管连自己公司的服务器就 ok 了。

但有个软件不同,浏览器(Browser) ,不管是 Chrome 还是 IE,它们不仅要能访问自家公司的服务器(Server) ,还需要访问其他公司的网站服务器,因此它们需要有个统一的标准,不然大家没法交流。于是,HTTP 就是那个时代用于统一 Browser/Server (B/S) 的协议。

也就是说在多年以前,HTTP 主要用于 B/S 架构,而 RPC 更多用于 C/S 架构。但现在其实已经没分那么清了,B/S 和 C/S 在慢慢融合。 很多软件同时支持多端,比如某度云盘,既要支持网页版,还要支持手机端和 PC 端,如果通信协议都用 HTTP 的话,那服务器只用同一套就够了。而 RPC 就开始退居幕后,一般用于公司内部集群里,各个微服务之间的通讯。

2.1 HTTP和RPC区别

浏览器-服务器客户端-服务端

重载实现

2.1.1 服务发现

首先要向某个服务器发起请求,你得先建立连接,而建立连接的前提是,你得知道 IP 地址和端口 。这个找到服务对应的 IP 端口的过程,其实就是 服务发现。

在 HTTP 中,你知道服务的域名,就可以通过 DNS 服务 去解析得到它背后的 IP 地址,默认 80 端口。

而 RPC 的话,就有些区别,一般会有专门的中间服务去保存服务名和 IP 信息,比如 Consul、Etcd、Nacos、ZooKeeper,甚至是 Redis。想要访问某个服务,就去这些中间服务去获得 IP 和端口信息。由于 DNS 也是服务发现的一种,所以也有基于 DNS 去做服务发现的组件,比如 CoreDNS。

可以看出服务发现这一块,两者是有些区别,但不太能分高低。

2.1.2 底层连接方式

以主流的 HTTP1.1 协议为例,其默认在建立底层 TCP 连接之后会一直保持这个连接(keep alive),之后的请求和响应都会复用这条连接。

而 RPC 协议,也跟 HTTP 类似,也是通过建立 TCP 长链接进行数据交互,但不同的地方在于,RPC 协议一般还会再建个 连接池,在请求量大的时候,建立多条连接放在池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用,可以说非常环保。

image.png

2.1.3 传输的内容

基于 TCP 传输的消息,说到底,无非都是 消息头 Header 和消息体 Body。

Header 是用于标记一些特殊信息,其中最重要的是 消息体长度。

Body 则是放我们真正需要传输的内容,而这些内容只能是二进制 01 串,毕竟计算机只认识这玩意。所以 TCP 传字符串和数字都问题不大,因为字符串可以转成编码再变成 01 串,而数字本身也能直接转为二进制。但结构体呢,我们得想个办法将它也转为二进制 01 串,这样的方案现在也有很多现成的,比如 JSON,Protocol Buffers (Protobuf) 。

这个将结构体转为二进制数组的过程就叫 序列化 ,反过来将二进制数组复原成结构体的过程叫 反序列化。

3 参考

  1. 有了 HTTP 协议,为什么还要有 RPC ? | JavaGuide

  2. Dubbo 原理和机制详解 (非常全面) - mikechen的互联网架构 - 博客园 (cnblogs.com)

  3. 深入理解 Dubbo:分布式服务框架的核心原理与实践_dubbo的实现架构-CSDN博客