Based on guide-rpc-framework
- 可扩展SPI机制
- ZK服务注册和服务发现
- 基于的Netty通信模型
- kryo和prostuff序列化
字段 | 描述 | 空间 |
---|---|---|
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
注解,即服务的调用类,实现客户端的动态代理。
细节说明:
-
注册流程:
Bean
实例化后,判断Bean
对应的Class
是否被@RpcService
标注,是则将该Bean
作为service
对象,与注解上的group
和version
一同封装为RpcServiceConfig
。- 调用
ServiceProvider
的publishService
方法存储服务,首先在已注册服务registeredServic
的集合中添加该rpcServiceName
,并在serviceMap
中添加(rpcServiceName, service)
,最后调用ServiceRegistry
的registerService
方法将服务注册到ZooKeeper中。
-
ZK注册:/根路径/服务名称/服务地址
- 根路径:my-rpc
- 服务名称:rpcServiceName = interface name + group + version
- 服务地址:ip:port
- 节点类型:persistent
服务发现用于客户端
-
客户端需要根据自己的请求
RpcRequest
进行服务发现,具体调用ServiceDiscovery
的lookupService
方法,该方法根据rpcServiceName
查找/my-rpc/rpcServiceName
下的所有子节点,将所有的子节点做一次负载均衡策略拿到具体的子节点,然后子节点的数据ip:port
封装成InetSocketAddress
返回。 -
客户端再根据服务器]
InetSocketAddress
使用ChannelProvider
获取到通信channel
,如果channel
为空,则让客户端连接服务器并初始化channel
并保存,最后将RpcRequest
封装成RpcMessage
并使用channel
发送。
Netty的长度解码器LengthFieldBasedFrameDecoder
可以防止防止半包和粘包,使用说明:
-
从消息开头偏移
lengthFieldOffset
长度, 到达A位置; -
再从A位置读取
lengthFieldLength
长度, 到达B位置, 内容是d; -
再从B位置读取( d+
lengthAdjustment
)长度, 达到D位置; -
从消息开头跳过
initialBytesToStrip
长度到达C位置; -
将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个字节,具体内容在服务器中定义。