guide-rpc-framework笔记(一):项目框架

66 阅读8分钟

🎯 项目简介

guide-rpc-framework 是一个基于 Netty + Kryo + Zookeeper 实现的轻量级 RPC 框架。该项目代码结构清晰,注释详细,非常适合学习 RPC 框架的底层原理和 Java 编程实践。

什么是 RPC? RPC(Remote Procedure Call,远程过程调用)是一种计算机通信协议,允许程序调用另一个地址空间(通常是远程服务器)的过程或函数,就像调用本地函数一样简单。

链接:github.com/Snailclimb/…

🏗️ 项目架构总览

guide-rpc-framework/
├── rpc-framework-common/     # 公共模块:工具类、枚举、异常等
├── rpc-framework-simple/     # 核心模块:RPC框架的主要实现
├── hello-service-api/        # API定义模块:接口和数据传输对象
├── example-server/           # 服务端示例:演示如何提供RPC服务
├── example-client/           # 客户端示例:演示如何调用RPC服务
└── config/                   # 配置文件:CheckStyle等代码规范配置

📦 模块详细解析

1. hello-service-api 模块 - API 定义层

作用: 定义服务接口和数据传输对象,是客户端和服务端的契约。

核心文件:

HelloService.java - 服务接口

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

Hello.java - 数据传输对象

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
@ToString
public class Hello implements Serializable {
    private String message;
    private String description;
}

为什么需要这个模块?

  • 🔗 解耦合:客户端和服务端只需要依赖接口,不需要依赖具体实现
  • 📋 契约定义:明确定义了服务的输入输出格式
  • 🔄 版本管理:便于接口版本的管理和升级

2. rpc-framework-common 模块 - 公共基础设施

作用: 提供框架运行所需的基础设施,包括工具类、枚举、异常处理等。

主要包结构:

  • enums/ - 枚举类:错误码、响应状态等
  • utils/ - 工具类:常用的辅助方法
  • factory/ - 工厂类:对象创建和管理
  • exception/ - 异常类:自定义异常处理
  • extension/ - 扩展机制:SPI 相关实现

核心功能:

  • 🛠️ 工具支持:提供字符串、集合等常用工具方法
  • 🏭 对象管理:通过工厂模式管理对象的创建
  • ⚠️ 异常处理:统一的异常定义和处理机制
  • 🔌 扩展机制:支持 SPI 机制,便于功能扩展

3. rpc-framework-simple 模块 - 核心实现层

这是整个框架的核心模块,实现了 RPC 框架的所有主要功能。

3.1 remoting 包 - 网络通信层

作用: 处理客户端和服务端之间的网络通信。

dto 子包 - 数据传输对象
  • RpcRequest.java - RPC 请求对象
public class RpcRequest implements Serializable {
    private String requestId;        // 请求唯一标识
    private String interfaceName;    // 接口名称
    private String methodName;       // 方法名称
    private Object[] parameters;     // 方法参数
    private Class<?>[] paramTypes;   // 参数类型
    private String version;          // 服务版本
    private String group;            // 服务分组
}
  • RpcResponse.java - RPC 响应对象
public class RpcResponse<T> implements Serializable {
    private String requestId;        // 对应的请求ID
    private Integer code;            // 响应状态码
    private String message;          // 响应消息
    private T data;                  // 响应数据
}
  • RpcMessage.java - 网络传输消息包装器
transport 子包 - 传输层实现

设计模式: 策略模式 + 模板方法模式

  • RpcRequestTransport.java - 传输层接口
  • socket/ - 基于传统 Socket 的实现
  • netty/ - 基于 Netty 的高性能实现

Netty 实现优势:

  • 🚀 高性能:基于 NIO,支持高并发
  • 💓 心跳机制:保持长连接,避免频繁建连
  • 🔄 连接复用:避免重复创建连接
  • 📦 协议定制:支持自定义通信协议

3.2 proxy 包 - 动态代理层

作用: 通过动态代理让远程调用像本地调用一样简单。

RpcClientProxy.java - 核心代理类

@Slf4j
public class RpcClientProxy implements InvocationHandler {
    private final RpcRequestTransport rpcRequestTransport;
    private final RpcServiceConfig rpcServiceConfig;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        // 1. 构建 RPC 请求
        // 2. 发送请求到服务端
        // 3. 获取响应结果
        // 4. 返回结果给调用方
    }
}

工作原理:

  1. 🎭 代理创建:为接口创建代理对象
  2. 📦 请求封装:将方法调用封装成 RpcRequest
  3. 🌐 网络传输:通过网络发送请求到服务端
  4. 📥 结果处理:接收响应并返回给调用方

3.3 registry 包 - 服务注册发现

作用: 实现服务的注册与发现,支持分布式部署。

核心接口:
  • ServiceRegistry.java - 服务注册接口
  • ServiceDiscovery.java - 服务发现接口
Zookeeper 实现:
  • ZkServiceRegistryImpl.java - 基于 ZK 的服务注册
  • ZkServiceDiscoveryImpl.java - 基于 ZK 的服务发现

服务注册流程:

  1. 🏷️ 服务启动:服务提供者启动时注册服务信息
  2. 📍 路径创建:在 ZK 中创建服务路径节点
  3. 💾 信息存储:存储服务的 IP、端口等信息
  4. 👁️ 健康检查:通过临时节点实现服务健康检查

服务发现流程:

  1. 🔍 查询服务:客户端根据服务名查询可用实例
  2. 📋 获取列表:从 ZK 获取服务实例列表
  3. ⚖️ 负载均衡:根据负载均衡算法选择实例
  4. 🔄 缓存更新:缓存服务列表并监听变化

3.4 serialize 包 - 序列化层

作用: 将 Java 对象转换为字节流进行网络传输。

支持的序列化方式:

  • Kryo - 高性能序列化框架(推荐)
  • Hessian - 跨语言序列化协议
  • Protostuff - 基于 Protobuf 的序列化

Kryo 优势:

  • 性能优异:序列化速度快,体积小
  • 🔧 易于使用:API 简单,集成方便
  • 🛡️ 安全可靠:避免了 JDK 序列化的安全问题

3.5 loadbalance 包 - 负载均衡

作用: 在多个服务实例中选择一个进行调用。

实现的算法:

  • RandomLoadBalance - 随机选择算法
  • ConsistentHashLoadBalance - 一致性哈希算法

一致性哈希优势:

  • 📊 数据倾斜少:分布相对均匀
  • 🔄 扩展性好:节点增减影响小
  • 💾 缓存友好:相同请求总是路由到同一节点

3.6 provider 包 - 服务提供者管理

作用: 管理本地服务实例,处理服务调用请求。

ServiceProvider.java - 服务提供者接口

  • 📝 服务注册:注册本地服务实例
  • 🔍 服务查找:根据服务名查找服务实例
  • 📋 服务管理:管理所有已注册的服务

3.7 annotation 包 - 注解支持

作用: 提供注解方式的服务声明和注入。

核心注解:

  • @RpcService - 标记服务实现类
@RpcService(group = "test1", version = "version1")
public class HelloServiceImpl implements HelloService {
    // 服务实现
}
  • @RpcReference - 注入远程服务
@Component
public class HelloController {
    @RpcReference(version = "version1", group = "test1")
    private HelloService helloService;
}
  • @RpcScan - 扫描服务注解
@RpcScan(basePackage = {"github.javaguide.serviceimpl"})
public class NettyServerMain {
    // 应用启动类
}

3.8 spring 包 - Spring 集成

作用: 与 Spring 框架集成,支持自动服务注册和注入。

核心类:

  • SpringBeanPostProcessor - Bean 后置处理器
  • CustomScanner - 自定义扫描器
  • CustomScannerRegistrar - 扫描器注册器

集成原理:

  1. 🔍 自动扫描:扫描带有 @RpcService 注解的类
  2. 📝 自动注册:将服务自动注册到注册中心
  3. 💉 自动注入:为带有 @RpcReference 注解的字段注入代理对象

4. example-server 模块 - 服务端示例

作用: 演示如何使用框架提供 RPC 服务。

核心文件:

HelloServiceImpl.java - 服务实现

@Slf4j
@RpcService(group = "test1", version = "version1")
public class HelloServiceImpl implements HelloService {
    @Override
    public String hello(Hello hello) {
        log.info("HelloServiceImpl收到: {}.", hello.getMessage());
        String result = "Hello description is " + hello.getDescription();
        log.info("HelloServiceImpl返回: {}.", result);
        return result;
    }
}

服务启动示例:

  • 🔧 注解方式:通过 @RpcScan 自动扫描和注册服务
  • 🖐️ 手动方式:通过 API 手动注册服务

5. example-client 模块 - 客户端示例

作用: 演示如何使用框架调用远程 RPC 服务。

调用方式:

注解方式:

@Component
public class HelloController {
    @RpcReference(version = "version1", group = "test1")
    private HelloService helloService;

    public void test() {
        String result = helloService.hello(new Hello("111", "222"));
        System.out.println(result);
    }
}

编程方式:

ClientTransport rpcRequestTransport = new SocketRpcClient();
RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
        .group("test2").version("version2").build();
RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcRequestTransport, rpcServiceConfig);
HelloService helloService = rpcClientProxy.getProxy(HelloService.class);
String hello = helloService.hello(new Hello("111", "222"));

🔧 核心技术栈

网络通信

  • Netty 4.x - 高性能 NIO 网络框架
  • 自定义协议 - 包含魔数、消息类型、序列化方式等
  • 长连接 - 支持连接复用和心跳保活

序列化

  • Kryo - 主推的高性能序列化框架
  • Hessian - 跨语言序列化支持
  • Protostuff - 基于 Protobuf 的 Java 实现

服务治理

  • Zookeeper - 分布式协调服务,实现服务注册发现
  • 负载均衡 - 支持随机和一致性哈希算法
  • 服务分组 - 支持服务的分组和版本管理

框架集成

  • Spring - 与 Spring 框架深度集成
  • 注解驱动 - 支持注解方式的服务声明和注入
  • SPI 机制 - 支持插件化扩展

🚀 RPC 调用流程

服务端启动流程

  1. 🏗️ 服务实现:编写服务接口的实现类
  2. 🏷️ 服务标记:使用 @RpcService 注解标记服务
  3. 📝 服务注册:启动时将服务注册到 Zookeeper
  4. 👂 监听请求:启动 Netty 服务器监听客户端请求
  5. 处理请求:接收请求,调用本地方法,返回结果

客户端调用流程

  1. 💉 服务注入:使用 @RpcReference 注解注入服务代理
  2. 🔍 服务发现:从 Zookeeper 获取可用服务实例列表
  3. ⚖️ 负载均衡:根据负载均衡算法选择一个服务实例
  4. 📦 请求封装:将方法调用封装成 RpcRequest 对象
  5. 🌐 网络传输:通过 Netty 发送请求到服务端
  6. 📥 结果处理:接收响应,反序列化后返回给调用方

详细时序图

客户端                    注册中心(ZK)              服务端
  |                          |                      |
  |------ 1.服务发现 -------->|                      |
  |<----- 2.返回服务列表 ------|                      |
  |                          |                      |
  |------ 3.建立连接 ------------------------->|
  |------ 4.发送RPC请求 ---------------------->|
  |                          |         5.处理请求   |
  |                          |         6.调用本地方法|
  |<----- 7.返回响应结果 ----------------------|