Skip to content
/ my-rpc Public

基于 Java + Netty + Spring 实现的一个 RPC 框架,基于 Netty 实现节点之间的网络传输,实现了自定义通讯协议。支持与 Spring Boot 集成、开箱即用。

Notifications You must be signed in to change notification settings

lyzzzz/my-rpc

Folders and files

NameName
Last commit message
Last commit date
Mar 19, 2022
Mar 19, 2022
Mar 19, 2022
Mar 18, 2022
Mar 19, 2022
Mar 18, 2022
Mar 20, 2022
Mar 19, 2022

Repository files navigation

My-RPC 框架

基于 Java + Netty + Spring 实现的一个最基础的 RPC 框架,满足 RPC 框架的最低要求,实现了以下功能:

  • 集成注册中心
  • 基于 Netty 实现节点之间的网络传输,实现自定义通讯协议
  • 实现服务提供者、服务消费者的架构
  • 使用动态代理,自动生成通信类
  • 与 Spring Boot 集成,开箱即用

架构

Loading
graph BT
  consumer[服务消费者 Consumer]
  provider[服务提供者 Provider]
  interface[服务接口 Facade]
  registry[注册中心]
  consumer -.直接连接.-> provider
  consumer -.注册--> registry
  provider -.注册--> registry
  provider -.实现.-> interface
  consumer -.引用.-> interface
  1. 服务消费者 Consumer 引用相关的服务接口,服务提供者 Provider 实现相关的服务接口
  2. 服务消费者 Consumer、服务提供者 Provider 向注册中心注册
  3. 服务消费者 Consumer 需要消费服务提供者 Provider 对应的服务接口
  4. 服务端消费者 Consumer 从注册中心中找到对应的服务提供者 Provider,并直接连接,调用相关业务

模块说明

rpc-framework:核心的框架部分,耦合 Spring Boot、Netty 等基础组件,提供 RPC 框架服务。

memory-registry:一个 Demo 性质的内存版本注册中心,免得再引用其他第三方注册中心了。

demo-provider:使用 RPC 框架构建的服务提供者。

demo-consumer:使用 RPC 框架构建的服务消费者。

demo-facade:业务接口。

传输协议

Header (17bytes): magic 2bytes | version 1bytes | type 1bytes | status 1bytes | requestId 8bytes | dataLength 4bytes
Body: ? bytes

Header 部分:

用于声明一些元信息。

  • magic(2 bytes):魔法数,用于协议校验与防止粘包,固定为 0x10
  • version(1 bytes):协议版本,用于标记服务版本,目前为 0x1,没有作处理
  • type(1 bytes):包类型,目前有请求、返回两种
  • status(1 bytes):标记这个数据包是否发生了成功与错误
  • requestId(8 bytes):用于追踪和标记该次请求的唯一 ID
  • dataLength(4 bytes):Body 数据长度

Body 部分:

用于存放真正的数据,大小不定。

使用

定义服务接口

定义供给服务提供者和服务消费者的接口:

public interface HelloService {
    String demo(String hello);
}

开启服务提供者

  1. 在 Spring Boot 配置 application.yml 中增加如下配置:
rpc:
  registry:
    enabled: true
    type: MEMORY # 注册中心类型,目前只支持 MEMORY
    config:
      host: 127.0.0.1 # 注册中心地址
      port: 8070 # 注册中心端口
  provider:
    enabled: true
    host: 127.0.0.1 # 服务提供者的地址
    port: 8071 # 服务提供者的端口
    instance-id: test-provider # 服务提供者的 id
  1. 实现相关服务,并用 @RpcService 注解来声明实现:
@RpcService(interfaceClass = HelloService.class, version = "1.0.0") // 标记服务接口,服务版本
public class HelloServiceImpl implements HelloService { // 实现服务接口
    @Override
    public String demo(String hello) {
        return new Random().nextInt() + hello;
    }
}

开启服务消费者

  1. 在 Spring Boot 配置 application.yml 中增加如下配置:
rpc:
  registry:
    enabled: true
    type: MEMORY # 注册中心类型,目前只支持 MEMORY
    config:
      host: 127.0.0.1 # 注册中心地址
      port: 8070 # 注册中心端口
  consumer:
    enabled: true # 开启服务消费者功能
  1. 在业务类中引用 Rpc 服务,使用 @RpcReference 注解:
@RestController
public class HelloController {
    @RpcReference // 引用 RPC 服务
    private HelloService helloService;

    @GetMapping({ "/", "" })
    public Mono<?> demo(@RequestParam String hello) {
        return Mono.fromCallable(() -> helloService.demo(hello));
    }
}

TODO

  • 负载均衡算法
  • 支持多种序列化协议
  • 支持多种第三方注册中心
  • 注册中心服务发现
  • 注册中心服务掉线
  • Netty Channel 复用
  • 更好的容错处理

原理分析

注册中心

使用 Spring Boot 的条件注入定义注册中心的开关。

注册中心的要点:

  • 要设计足够的抽象,并且能够提供统一的调用门面。

流程:

  1. 使用 FactoryBean,利用工厂模式创建注册中心服务
  2. 抽象注册中心接口,并内置多实现
  3. 创建注册中心时,使用 Binder 类,进行多种种类的注册中心配置读取

服务提供者

使用 Spring Boot 的条件注入定义服务提供者的开关。

服务提供者的要点:

  • 将相关的 RPC 服务注册进 RPC 框架。
  • 启动一个 Netty 服务器,Netty 服务器可以处理对方发送过来的协议,并找到调用方法,并给出符合协议的响应。

流程:

  1. 处理 @RpcService 的 Bean
    1. 使用 BeanPostProcessor 处理每一个 Bean,如果有相关注解,则在 RPC 框架中添加相关的 RPC 服务(可能是一个 Map,以便后续能够进行 RPC 服务的查找)
  2. 启用 RPC 服务提供服务者
    1. 启动时,往注册中心注册
    2. 启动 Netty 服务器
    3. Netty 服务需要包括三个关键的处理逻辑:
      1. 使用协议 Decoder 将网络上的协议转换为 Java 类,以便请求处理器处理
      2. 请求处理器找到相关的 RPC 服务业务方法进行调用
      3. 使用协议 Encoder 将步骤 2 中获得的结果返回成网络上的协议

服务消费者

使用 Spring Boot 的条件注入定义服务消费者的开关。

服务消费者的要点:

  • 读取到相关的 RPC 服务引用,使用动态代理技术创建相关的代理类,代理类的逻辑负责真正调用远程方法。
  • 调用远程方法时,需要将内存中的 Java 类转换为网络上的协议,然后收到相关协议,转换为响应的类。

流程:

  1. 读取相关 RPC 服务引用,处理有 @RpcReference 的 Bean
    1. 使用 BeanFactoryPostProcessor 读取初始化完的 Bean,如果有相关注解,创建相关的代理类
    2. 利用 Spring FactoryBean 工厂模式,创建动态代理类
    3. 创建真正的代理类,代理类需要可以访问注册中心,并且可以调用 Netty 方面的逻辑
  2. 服务消费者的 Netty 调用端,需要包括三个关键的处理逻辑:
    1. 使用协议 Encoder 将 Java 类转换为网络上的协议,以便服务提供者处理
    2. 使用协议 Decoder 接受网络上的响应协议,将其转换为 Java 类
    3. 使用 Netty 自带的 Promise 类维持每个请求 ID 的请求状态,超过时间则进行超时

联系我

如有问题,可以提出 issue,或私信我个人主页上的邮箱。

About

基于 Java + Netty + Spring 实现的一个 RPC 框架,基于 Netty 实现节点之间的网络传输,实现了自定义通讯协议。支持与 Spring Boot 集成、开箱即用。

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages