XXL-RPC框架分析

XXL-RPC框架分析

作者官方已经提供了比较完善的文档。算是比较简单易学的RPC框架。适合初学者学习。

一般一个完整的RPC架构四个核心的组件,分别是Client,Client Stub,Server,Server Stub,这个Stub可以理解为存根。
客户端(Client),服务的调用方。
客户端存根(Client Stub),存放服务端的地址消息,再将客户端的请求参数打包成网络消息,发送给服务方。在java中我们可以使用动态代理技术(Proxy,字节码技术也行),来生成代理对象,获取请求方法名字,参数等信息,封装起来
服务端(Server),真正的服务提供者。
服务端存根(Server Stub),接收客户端发送过来的消息,将消息解包,并调用本地的方法。使用java反射技术,对某个类的某个方法进行反射执行
支持多种序列号方案

主要包结构

类图:

配置

@XxlRpcReference
@XxlRpcService
ProviderFactory

bug:
XxlRpcSpringProviderFactory corePoolSize,maxPoolSize 默认大小要调整比如10,不然zk下会报错是bug
java.lang.NoClassDefFoundError: org/apache/zookeeper/Watcher 加入下面mvn配置

1
2
3
4
5
6
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.4-beta</version>
<scope>compile</scope>
</dependency>

registry

服务发现与注册,包括zookeeper、LocalServiceRegistry(本地服务注册)、XxlRegistryServiceRegistry(作者写的注册中心)。可选组件,可不启用注册中心,直接指定服务提供方机器地址通讯

XXL-RPC中每个服务在zookeeper中对应一个节点,子节点类型为zookeeper的EPHMERAL类型,该类型节点有个特点,当机器和zookeeper集群断掉连接后节点将会被移除。consumer底层可以从zookeeper获取到可提供服务的provider集群地址列表,从而可以向其中一个机器发起RPC调用。如果使用zookeeper不要忘记引包

xxl-rpc-sample-springboot修改成zk的demo修改配置XxlRpcProviderConfig,XxlRpcInvokerConfig修改类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Configuration
public class XxlRpcProviderConfig {
private Logger logger = LoggerFactory.getLogger(XxlRpcProviderConfig.class);

@Value("${xxl-rpc.remoting.port}")
private int port;

@Value("${xxl-rpc.registry.xxlregistry.address}")
private String address;

@Value("${xxl-rpc.registry.xxlregistry.env}")
private String env;

@Bean
public XxlRpcSpringProviderFactory xxlRpcSpringProviderFactory() {

XxlRpcSpringProviderFactory providerFactory = new XxlRpcSpringProviderFactory();
providerFactory.setPort(port);
providerFactory.setServiceRegistryClass(ZkServiceRegistry.class);
providerFactory.setServiceRegistryParam(new HashMap<String, String>(){{
put(ZkServiceRegistry.ZK_ADDRESS, "127.0.0.1:2181");
put(ZkServiceRegistry.ZK_DIGEST, "");
put(ZkServiceRegistry.ENV, "test");
}});

logger.info(">>>>>>>>>>> xxl-rpc provider config init finish.");
return providerFactory;
}

}

还有就是添加zookeeper maven配置
前面提到的XxlRpcSpringProviderFactory两个poolSize配置

remoting

服务提供者,服务调用者,网络通信

XxlRpcRequest 请求实体设计

requestId:唯一的标识,请求与响应对应,作者使用的uuid
createMillisTime:时间戳,主要是用于服务提供者进行超时检测用的
accessToken:用于服务调用者权限验证用的
className:需要调用的类的全类名
methodName:该类的方法名,服务调用者找到要执行的对象后就会invoke该方法
parameterTypes:方法参数类型数组
parameters:方法参数的值
version:服务提供着版本

XxlRpcResponse 响应实体设计

requestId:与XxlRpcRequest中的requestId一一对应,为的是异步的时候能找到对应的响应
errorMsg:错误信息,超时,权限验证失败
result:方法的执行结果

route 负载均衡算法
  1. XxlRpcLoadBalanceRandomStrategy 随机
  2. XxlRpcLoadBalanceRoundStrategy 轮询 使用次数%服务提供者的数量
  3. XxlRpcLoadBalanceLRUStrategy 最近使用最少
  4. XxlRpcLoadBalanceConsistentHashStrategy 一致性Hash:将所有提供该服务的机器按照hash值(节点)从小到大的顺序排列到hash环上,,然后计算出这个服务key的hash值,也按照循序放到hash环上,然后顺时针取挨着你最近的那个节点就行了 ,这样每次这个服务都去找这个节点
  5. LFU 最近访问频率低淘汰

serialize

列化功能

util

网络工具类

xxl-rpc-simple

服务提供者启动过程分析

大体流程: 收集配置→启动服务→服务注册

  1. XxlRpcService注解 version记录服务版本
  2. XxlRpcSpringProviderFactory spring的@Configuration配置类会创建该工厂,负责找出@XxlRPcService注解进行基础配置。public class XxlRpcSpringProviderFactory extends XxlRpcProviderFactory implements ApplicationContextAware, InitializingBean,DisposableBean 实现ApplicationContextAware同时重写setApplicationContext(),setApplicationContext()中遍历注解调用addService()添加服务。
  3. XxlRpcSpringProviderFactory 还实现类InitializingBean接口,重写afterPropertiesSet方法,进行数据相关初始化序列化等相关,还调用了父类initConfig() ,start()通过请求配置的NeType进行启动服务,如果配置的是netty就会调用NettyServer start()
  4. 一般我们使用netty框架,然后调用onStarted方法,设置回调,回调函数把服务最终registry到注册中心(127.0.0.1:8888,127.0.0.1:9999)

服务请求过程

  1. client 去注册中心获取可用服务信息(192.168.38.2:7080),XxlRpcSpringInvokerFactory 配置调用信息,afterPropertiesSet()里调用 xxlRpcInvokerFactory.start();,start()里面再调用ZkServiceRegistry start() 进行xxlZkClient初始化,设置回调处理,新启线程定时refreshDiscoveryData 获取服务(192.168.38.2:7080)
  2. 调用XxlRpcSpringInvokerFactory.postProcessAfterInstantiation() 分析XxlRpcReferenceBean生成服务serviceKey, ReflectionUtils.doWithFields 处理Controller对象然后xxlRpcInvokerFactory.getServiceRegistry().discovery(serviceKeyList); 查询服务
  3. 浏览器访问client Controller接口,会调用 XxlRpcSpringReferenceBean中getObject()进行对象初始化 会调用 return xxlRpcReferenceBean.getObject() 里面再调用 client.asyncSend(finalAddress, xxlRpcRequest); 去调用服务端服务 服务端返回信息封装入XxlRpcResponse

参考