## 一、 接口定义:
RPC 开始于为所需服务定义明确的接口。这通常使用接口定义语言(Interface Definition Language, IDL)来完成,它定义了可供远程客户端调用的过程和函数、参数以及数据类型。
## 二、客户端存根(Stub):
负责将过程调用的所有参数“序列化”成一串能够通过网络发送的字节流
> 同步调用:客户端等待直至获得响应才继续执行。
异步调用:客户端不用等待响应就可以继续执行其他任务。
## 三、通信:
Socket 或者 Netty
## 四、服务器存根:
反序列化,调用得到结果,序列化返回
Core 核心层是 Netty 最精华的内容,它提供了底层网络通信的通用抽象和实现,包括可扩展的事件模型、通用的通信 API、支持零拷贝的 ByteBuf 等。
协议支持层基本上覆盖了主流协议的编解码实现,如 HTTP、SSL、Protobuf、压缩、大文件传输、WebSocket、文本、二进制等主流协议,此外 Netty 还支持自定义应用层协议。Netty 丰富的协议支持降低了用户的开发成本,基于 Netty 我们可以快速开发 HTTP、WebSocket 等服务。
传输服务层提供了网络传输能力的定义和实现方法。它支持 Socket、HTTP 隧道、虚拟机管道等传输方式。Netty 对 TCP、UDP 等数据传输做了抽象和封装,用户可以更聚焦在业务逻辑实现上,而不必关系底层数据传输的细节。
EventLoop (事件循环对象)本质是一个单线程执行器(同时维护了一个 Selector),里面有 run 方法处理 Channel 上源源不断的 io 事件。事件循环组EventLoopGroup 是一组 EventLoop,Channel 一般会调用 EventLoopGroup 的 register 方法来绑定其中一个 EventLoop,后续这个 Channel 上的 io 事件都由此 EventLoop 来处理(保证了 io 事件处理时的线程安全)
EventLoopGroup
用于管理 EventLoop ,包括将 EentLoop 分配给 Channel ,包括 EventLoop 的协同
- 动态性:在生产环境中,服务实例可能会因为部署、扩展、故障转移等原因动态地增加或减少。服务发现机制可以帮助客户端找到当前可用的服务实例。
- 负载均衡:服务发现通常与负载均衡结合使用。当有多个服务实例可用时,客户端需要知道向哪个实例发送请求,以便合理分配负载,并避免某些实例过载。
- 抽象和解耦:服务发现使客户端无需硬编码服务实例的地址。这降低了微服务架构中各服务之间的耦合度,提高了系统的灵活性和可维护性。
- 故障检测和处理:服务注册表通常具备健康检查的功能,可以从注册表中自动剔除故障的服务实例,保证客户端总是连接到健康的实例上。
- 服务注册:在服务启动时,将其地址和元数据注册到服务发现系统中,如Etcd或Zookeeper。
- 服务健康检查:注册的服务应定期发送心跳或通过其他机制来维持其在服务发现系统中的状态。
- 服务解析器:gRPC客户端使用一个服务解析器来查询服务发现系统,以获得最新的服务实例列表。
- 负载均衡:gRPC客户端根据获取到的服务实例列表执行负载均衡算法,决定将请求发送到哪个实例。
- 使用 Netty(基于 NIO)替代 BIO 实现网络传输;
- 使用开源的序列化机制 Kyro(也可以用其它的)替代 JDK 自带的序列化机制;
- 使用 Zookeeper 管理相关服务地址信息
- Netty 重用 Channel 避免重复连接服务端
- 增加 Netty 心跳机制 : 保证客户端和服务端的连接不被断掉,避免重连。
- 客户端调用远程服务的时候进行负载均衡 :调用服务的时候,从很多服务地址中根据相应的负载均衡算法选取一个服务地址。ps:目前实现了随机负载均衡算法与一致性哈希算法。
- 处理一个接口有多个类实现的情况 :对服务分组,发布服务的时候增加一个 group 参数即可。
- 集成 Spring 通过注解注册服务
- 集成 Spring 通过注解进行服务消费 。
-
使用 Docker 快速安装
下载:
docker pull zookeeper:3.5.8
运行:
docker run -d --name zookeeper -p 2181:2181 zookeeper:3.5.8
-
见examples下