/highness-rpc

RPC framework for java

Primary LanguageJava

highness-rpc

Based on guide-rpc-framework

🌠 特性概览

  • 可扩展SPI机制
  • ZK服务注册和服务发现
  • 基于的Netty通信模型
  • kryo和prostuff序列化

📑 自定义协议

protocol


字段 描述 空间
MC magic code, 魔法数 4Byte
V version, 版本 1Byte
LEN content length, 消息长度 4Byte
T message type, 消息类型 1Byte
Z compress type, 压缩类型 1Byte
C codec type, 序列化类型 1Byte
ID sequence id, 消息ID 4Byte

🚀 服务注册

服务注册用于服务器

CustomScannerRegistrar使用CustomScanner扫描@RpcScan指定路径下,包含@Component@RpcService注解的bean。

  • CustomScanner实现了Spring的ClassPathBeanDefinitionScanner扫描器,用于扫描包含指定注解的bean。
  • CustomScannerRegistrar实现了Spring的ImportBeanDefinitionRegistrar接口,用于扫描向容器中批量注册带有bean。

SpringBeanPostProcessor实现的Spring的BeanPostProcessor的实例化后和初始化后逻辑:

  • 实例化后逻辑:处理@RpcService注解,即服务的实现类,封装RpcServiceConfig对象,进行服务注册。
  • 初始化后逻辑:处理@RpcReference注解,即服务的调用类,实现客户端的动态代理。

细节说明:

  • 注册流程:

    1. Bean实例化后,判断Bean对应的Class是否被@RpcService标注,是则将该Bean作为service对象,与注解上的groupversion一同封装为RpcServiceConfig
    2. 调用ServiceProviderpublishService方法存储服务,首先在已注册服务registeredServic的集合中添加该rpcServiceName,并在serviceMap中添加(rpcServiceName, service),最后调用ServiceRegistryregisterService方法将服务注册到ZooKeeper中。
  • ZK注册:/根路径/服务名称/服务地址

    • 根路径:my-rpc
    • 服务名称:rpcServiceName = interface name + group + version
    • 服务地址:ip:port
    • 节点类型:persistent

🔍 服务发现

服务发现用于客户端

  1. 客户端需要根据自己的请求RpcRequest进行服务发现,具体调用ServiceDiscoverylookupService方法,该方法根据rpcServiceName 查找/my-rpc/rpcServiceName下的所有子节点,将所有的子节点做一次负载均衡策略拿到具体的子节点,然后子节点的数据ip:port封装成InetSocketAddress返回。

  2. 客户端再根据服务器]InetSocketAddress使用ChannelProvider获取到通信channel,如果channel为空,则让客户端连接服务器并初始化channel并保存,最后将RpcRequest封装成RpcMessage并使用channel发送。

📬 消息解码

Netty的长度解码器LengthFieldBasedFrameDecoder可以防止防止半包和粘包,使用说明:

  1. 从消息开头偏移lengthFieldOffset长度, 到达A位置;

  2. 再从A位置读取lengthFieldLength长度, 到达B位置, 内容是d;

  3. 再从B位置读取( d+lengthAdjustment)长度, 达到D位置;

  4. 从消息开头跳过initialBytesToStrip长度到达C位置;

  5. 将C位置-D位置之间的内容传送给接下来的处理器进行后续处理。

消息解码器RpcMessageDecoder继承了LengthFieldBasedFrameDecoder,具体参数如下:

  • maxFrameLength:最大帧的长度,8 * 1024 * 1024 = 8 MB。
  • lengthFieldOffset:长度域的偏移量,需要跳过4B魔法数和1B的版本数,5B。
  • lengthFiledLength:长度域的长度,即消息的内容长度,4B。
  • lengthAdjustment:从长度域后开始读取内容的长度,这里不再读取,-(5+4)B。
  • initialBytesToSkip:从长度域后跳跃的内容的长度,这里不用跳过,0B。

魔法数和版本数都是为了用于校验:

  • 魔法数:4个字节,具体内容是krpc
  • 版本数:1个字节,具体内容在服务器中定义。