# RpcFramework
**Repository Path**: Ge-JY/rpc-framework
## Basic Information
- **Project Name**: RpcFramework
- **Description**: RPC框架项目后台代码(程序员鱼皮编程导航项目)
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2025-01-20
- **Last Updated**: 2025-02-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
V1.0:简易版本
+ example-common:示例代码的公共依赖,包括接口、model等
+ example-consumer:示例服务消费者代码
+ example-provider:示例服务提供者代码
+ rpc:RPC框架
+ 提供一个Web服务器,用于接受处理请求、返回相应,可以使用Spring Boot内嵌的Tomcat、Netty等,此处使用NIO框架Vert.x
+ 提供一个本地服务注册器,主要目的是跑通流程,暂不引入第三方服务注册中心(nacos等)
+ 提供一个序列化器,用于对Java对象进行序列化和反序列化,此处使用Java原生的序列化器进行实现,也可以使用JSON、Hessian、Kryo、protobuf等
V2.0:完善优化
+ 配置信息全局加载
+ 支持Mock:Mock指模拟对象,通常用于测试代码中,如远程调用时,目标服务还未上线,就先模拟一个返回对象,便于跑通流程
+ 序列化器
+ 常用序列化器的对比
+ JSON:易读性好,便于调试,跨语言支持广泛,但序列化后的数据量相对较大,不能很好地处理复杂的数据结构和循环引用
+ Hessian:二进制序列化,序列化后的数据量较小,支持跨语言,但性能比JSON略低(对象需要转换为二进制格式),且对象必须实现Serializable接口
+ Kryo:高性能,支持循环引用和自定义序列化器,无需实现Serializable接口,但仅支持Java,序列化格式不友好,不易读和调试
+ Protobuf:高效,序列化后的数据量绩效,跨语言,但配置相对复杂,需要先定义数据结构的消息格式,序列化格式不易读懂
+ 优化方向:
+ 使用更好的序列化器实现流程
+ 由使用者指定要使用的序列化器
+ 由使用者自己定制序列化器
+ 优化内容
+ 提供JSON、Kryo、Hessian序列化器的实现
+ 提供序列化器工厂,使用工厂模式+单例模式,序列化器可以服用,没必要每次都重新创建
+ 服务注册
+ 通过注册中心帮助服务消费者获取服务提供者的调用地址,而不是将调用地址硬编码到项目中
+ 主流的注册中心中间件有 ZooKeeper、Nacos 等,教程中使用 Etcd 存储注册信息,但 Etcd 的 0.6.x 以上版本要求 JDK11,此处先使用Redis进行注册信息缓存
+ 与序列化器相同,基于SPI,保留后续扩展接口
+ 优化内容:
+ 心跳检测和续期:通常是定期调用服务内的一个健康检查接口,判断节点是否正常提供服务;本项目用另一种思路,服务提供者初始化rpc框架、注册服务信息时,在本地缓存自身的节点注册信息,并定时更新服务注册的过期时间
+ 服务节点下线通知:JVM的ShutdownHook机制,允许在JVM即将关闭前,执行一些清理工作,Spring Boot也有类似的优雅停机能力
+ 消费端服务缓存:正常情况下,服务节点信息列表的更新频率不高,消费者在获取节点信息后,可以缓存在本地;同时消费者需要监听服务下线并及时更新缓存
+ 注:本项目使用Redis进行服务注册实现,仅为仿照原项目etcd实现流程进行编写,未启动Redis进行测试
+ 自定义协议
+ HTTP协议的头信息、请求响应格式比较重,会影响网络传输性能,而RPC框架比较注重性能,因此基于传输层的TCP协议做一个自定义协议
+ RPC消息需要的信息
+ 魔数:用于安全校验(类似于HTTPS的安全证书)
+ 版本号:保证请求和响应的一致性
+ 序列化方式:告诉服务端和客户端如何解析数据(类似HTTP的Content-Type内容类型)
+ 类型:标识是请求还是响应,还是心跳检测等其他用途
+ 状态:如果是响应,记录响应的结果
+ 请求id:TCP是双向通信,用于跟踪每个请求
+ 请求体
+ 请求体数据长度:TCP协议本身会有半包和粘包问题,用于完整获取请求体内容信息
+ 使用TCP协议连续发送和接收请求时,可能出现接收到的消息与发送的消息不一致,半包是指接收到的消息比发送的消息少,粘包是指接收到的消息比发送的消息多
+ 解决半包和粘包的核心思路是,在消息头中设置请求体的长度,每次只读取指定长度的信息,不完整时不读取,超出的部分留到下次再读取
+ Vert.x框架中,提供了RecordParser.newFixed(messageLength),用于读取特定长度的字符
+ 由于消费者ServiceProxy和提供者TcpServerHandler都需要接收Buffer,都要考虑读取数据的问题,使用**装饰者模式**进行代码封装,用RecordParser对原有的Buffer处理器进行增强
+ 自定义消息结构时,需要尽量节省空间,使用轻量的类型,byte字节类型只占用1个字节、8个bit,由于Java实现bit位运算拼接比较麻烦,因此尽量给每个数据凑到整字节
+
+ 整个消息结构设计如上图,共占用17个字节
+ 此前使用HttpServer,Vert.x同样支持TCP服务器,但要注意Vert.x的TCP服务器收发的消息是Buffer类型,不能直接写入一个对象,因此需要编码器和解码器,将Java对象与Buffer进行相互转换
+ 负载均衡
+ 同一个服务可能会有多个提供者,为了合理利用多个节点的资源,降低单个节点的压力,要将请求转发给不同的提供者
+ 常用的负载均衡技术有Nginx(七层负载均衡)、LVS(四层负载均衡)等
+ 主要的负载均衡算法:轮询、随机、加权轮询、加权随机、最小连接数、IP Hash(根据客户端IP的哈希值选择服务器,保证同一客户端的请求始终被分配到同一台服务器,适用于保持会话一致性的场景)
+ 一致性Hash:一种经典的Hash算法,用于将请求分配到多个节点或服务器上,思路是将整个哈希值空间划分成一个环形,每个节点或服务器在环上占据一个位置,每个请求根据哈希值映射到环的一个点,顺时针寻找第一个大于等于该哈希值的节点
+ 这种结构可以处理**节点下线**的负载分摊问题,并可以通过将每个物理节点映射成多个虚拟节点,解决资源**倾斜**问题
+ 重试机制
+ 接口调用失败,有时可能只是网络不稳定或者服务提供者重启等临时性问题,服务消费者最好有自动重试的能力,提高系统可用性
+ 重试机制的核心问题:
+ 重试条件:在什么条件下进行重试,什么条件下停止重试
+ 重试时间:即重试等待策略
+ 固定重试间隔:每次重试之间使用固定的时间间隔
+ 指数退避重试:每次失败后,重试的间隔时间以指数级增加,以避免请求过于密集
+ 随机延迟重试:每次重试之间使用随机的时间间隔,避免请求同时发生
+ 可变延迟重试:根据先前重试的成功或失败情况,动态调整下一次的重试时间,如根据前一次的响应时间调整下一次重试的等待时间
+ 重试工作:重试时,执行原本要做的操作,如果超过重试上限,可以通知告警让认为接入,也可以降级调用其他接口或执行其他操作
+ 容错机制
+ 在系统出现异常时,通过一定的策略保证系统稳定运行,提高系统的可靠性和健壮性
+ 常见的容错策略:
+ Fail-Over 故障转移:一次调用失败后,切换另一个节点再次调用,也算是一种重试
+ Fail-Back 失败自动恢复:某个功能出现调用失败或错误时,通过其他方式恢复该功能,相当于降级,如重试、调用其他服务等
+ Fail-Safe 静默处理:非重要功能出现异常时,直接忽略掉,不做任何处理
+ Fail-Fast 快速失败:出现调用错误时,立刻报错,交由外层调用方处理
+ 容错实现方式:重试、限流、降级、熔断、超时控制等
+ 框架启动优化
+ 一个好用的框架,除了用户数、社区活跃度,还要简单易用易上手,最好能开箱急用
+ 启动机制:将启动代码封装成一个专门的启动类,由服务提供者/服务消费者调用即可
+ 服务提供者需要初始化框架配置、注册服务、启动Web服务器
+ 服务消费者只需要初始化框架配置
+ 注解驱动:通过一个注解,快速注册和使用服务,实现注解驱动有两种常见方式
+ 主动扫描:让开发者指定要扫描的路径,遍历所有的类文件,针对有注解的类文件,执行自定义的操作
+ 监听Bean加载:在Spring项目中,通过实现BeanPostProcessor接口,在Bean初始化后执行自定义操作
进一步完善扩展点:
+ RPC请求支持携带参数列表,如携带token进行安全校验等
+ 服务管理界面,类似Nacos的注册中心面板
+ 支持读取更多类型的配置文件
+ 实现拦截器机制,参考Spring MVC,使用责任链模式,在服务提供者处理前后、消费者调用前后,增加拦截器,用于日志记录、安全校验等,可使用SPI机制支持用户自定义拦截器
+ 自定义异常
+ 支持指定版本号
+ 支持消费方指定负载均衡、重试策略、容错策略、超时时间等
+ 服务注册优化,支持区分服务key,缓存多个服务节点,支持服务分组