手动实现一款轻量 高效的分布式RPC框架

一、概述手动实现一款轻量,高效的RPC框架,基于TCP的二进制协议实现
github源码:
https://github.com/wosn00/srpc
二、特征

  • 基于netty的主从Reactor模型,NIO通信
  • 支持同步,异步,携带回调等调用方式
  • 支持spring项目下引入starter包开箱即用,整合spring,实现服务接口透明使用
  • 支持非spring项目下单独使用,可不依赖spring环境
  • 支持多种序列化类型,Protostuff,Kryo,Json,Jdk等
  • 支持多种压缩算法,SnAppy,Lz4,gzip,bzip2,Deflate,Lzo等
  • 支持注册中心,自动服务注册和发现,默认实现zookpeer,也可不使用注册中心,手动指定服务端节点地址列表
  • 支持多种负载均衡策略,随机,轮询,一致性hash等
  • 支持服务容错,连接/调用异常情况下自动排除服务端故障节点
  • 支持SPI扩展点,可扩展负载均衡策略,压缩算法,序列化类型,线程池,注册中心等
  • 支持TLS双向认证加密
  • 支持流量整形,请求异常重试,服务端请求去重等功能
三、设计
手动实现一款轻量 高效的分布式RPC框架

文章插图
 
可能对RPC框架性能产生影响的几个因素:
  • 网络IO线程模型
  • 通信协议设计
  • 序列化性能
  • 服务调用管理方式
  • 连接池的维护
3.1 RPC协议
手动实现一款轻量 高效的分布式RPC框架

文章插图
 
协议上设计尽量紧凑,4位bit用于标识序列化类型,压缩类型和指令类型,方法映射上不需要像dubbo那样传输完整的类 方法 参数信息导致的无用流量增大,而是自行生成对应rpc调用方法的唯一标识字符串
3.2 同步线程模型
手动实现一款轻量 高效的分布式RPC框架

文章插图
 
3.3 异步线程模型
手动实现一款轻量 高效的分布式RPC框架

文章插图
 
 
四、使用示例
4.1、spring环境下maven依赖
<dependency><groupId>com.hex</groupId><artifactId>srpc-spring-boot-starter</artifactId><version>1.1.0</version></dependency>若需使用zookeeper作为注册中心则引入
<dependency><groupId>com.hex</groupId><artifactId>srpc-registry-zookeeper</artifactId><version>1.1.0</version></dependency>server端使用【手动实现一款轻量 高效的分布式RPC框架】1.定义服务接口
@SRpcClient(serviceName = "testService")public interface HelloService {String hello(String name);}接口添加@SRpcClient注解,serviceName属性为rpc服务都在注册中心的服务名称,若不使用注册中心,则注解nodes属性需手动指定服务端节点集群地址,将根据负载均衡策略自动选取节点调用
@SRpcClient(nodes = {"127.0.0.1:9955","127.0.0.1:9956","127.0.0.1:9957"})public interface HelloService {String hello(String name);}2.服务接口实现
@SRpcRoutepublic class HelloServiceImpl implements HelloService {@Overridepublic String hello(String name) {return name + " Hey bro, it's a good day";}}实现类添加@SRpcRoute注解,便会自动注册为spring的单例bean,可视为等同@Comphonent使用,内部可用@Autowired等spring相关注解,也可被其他bean注入 。
3.配置yml
因同时包含了rpc客户端和服务端,所以客户端和服务端都需要配置,如需个性化配置的地方在yml或properties文件按需配置即可,以srpc.server或srpc.client为前缀 。所有可自由配置的选项如下
服务端默认配置:
@ConfigurationProperties(prefix = "srpc.server")public class RpcServerProperties {private Integer port = 9957; //绑定端口private Integer businessThreads = 200; //业务处理线程池大小,0为不设置private Integer businessQueueSize = 500; //业务线程池队列大小private Integer connectionIdleTime = 180;//超过连接空闲时间(秒)未收发数据则关闭连接private Integer printConnectionNumInterval = 0; //打印服务端当前连接详情, 时间间隔(秒), 0为不打印private Boolean isPrintHearBeatPacketInfo = false; //是否打印心跳包信息private CompressType compressType = CompressType.SNAPPY; //压缩算法类型,无需压缩为NONEprivate SerializeType serializeType = SerializeType.PROTOSTUFF; //序列化类型,默认protostuffprivate Integer sendBuf = 65535; //tcp发送缓冲区private Integer receiveBuf = 65535; //tcp接收缓冲区private Integer lowWaterLevel = 1024 * 1024; //netty低水位private Integer highWaterLevel = 10 * 1024 * 1024; //netty高水位private boolean deDuplicateEnable = false; //是否开启去重处理private Integer duplicateCheckTime = 10; //请求去重缓存时长(秒)private Long duplicateMaxSize = 1024 * 64L; //最大缓存请求个数private Boolean trafficMonitorEnable = false; //是否开启流控private Long maxReadSpeed = 10 * 1000 * 1000L; //带宽限制,最大读取速度private Long maxWriteSpeed = 10 * 1000 * 1000L; //带宽限制,最大写出速度// ----tls加密部分配置private Boolean useTLS = false; //是否开启tls加密private String keyPath; //私钥文件路径private String keyPwd; //密码private String certPath; //证书文件路径private String trustCertPath; //受信任ca证书路径private String clientAuth; //是否要求客户端认证// ----注册中心配置部分private Boolean enableRegistry = false; //是否使用注册中心private String registrySchema; //注册中心模式名称private List<String> registryAddress; //注册中心地址


推荐阅读