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博客