[TOCM]
[TOC]
XXL-RPC 是一个分布式服务框架,提供稳定高性能的RPC远程服务调用功能。拥有"高性能、分布式、注册中心、负载均衡、服务治理"等特性。现已开放源代码,开箱即用。
RPC(Remote Procedure Call Protocol,远程过程调用),调用远程服务就像调用本地服务,在提供远程调用能力时不损失本地调用的语义简洁性;
一般公司,尤其是大型互联网公司内部系统由上千上万个服务组成,不同的服务部署在不同机器,跑在不同的JVM上,此时需要解决两个问题:
“XXL-RPC”可以高效的解决这个问题:
源码仓库地址 | Release Download |
---|---|
https://github.com/xuxueli/xxl-rpc | Download |
https://gitee.com/xuxueli0323/xxl-rpc | Download |
解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可,源码结构如下:
源码目录介绍:
- /doc
- /xxl-rpc-admin :轻量级服务(注册)中心,可选模块;
- /xxl-rpc-core :核心依赖;
- /xxl-rpc-samples :示例项目;
- /xxl-rpc-sample-frameless :无框架版本示例;
- /xxl-rpc-sample-springboot :springboot版本示例;
- /xxl-rpc-sample-springboot-api :公共API接口
- /xxl-rpc-sample-springboot-client :服务消费方 invoker 调用示例;
- /xxl-rpc-sample-springboot-server :服务提供方 provider 示例;
推荐使用 "xxl-rpc-admin" 作为轻量级服务(注册)中心。非常轻量级,一分钟可完成部署工作。 注册中心为可选模块,可以不使用注册中心,也可以选型其他注册中心。
请下载项目源码并解压,获取 "调度数据库初始化SQL脚本" 并执行即可。数据库初始化SQL脚本"位置为:
/xxl-rpc/doc/db/tables_xxl_rpc.sql
服务(注册)中心支持集群部署,集群情况下各节点务必连接同一个mysql实例;如果mysql做主从,集群节点务必强制走主库;
服务(注册)中心项目:xxl-rpc-admin
作用:一个轻量级分布式服务(注册)中心,拥有"轻量级、秒级注册上线、多环境、跨语言、跨机房"等特性。现已开放源代码,开箱即用。
配置文件地址:
/xxl-rpc/xxl-rpc-admin/src/main/resources/application.properties
配置内容说明:
### 数据库配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_rpc?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
### 服务注册数据磁盘同步目录
xxl.rpc.registry.data.filepath=/data/applogs/xxl-rpc/registrydata
### xxl-rpc, access token
xxl.rpc.registry.accessToken=
### 登陆信息配置
xxl.rpc.registry.login.username=admin
xxl.rpc.registry.login.password=123456
如果已经正确进行上述配置,可将项目编译打包部署。 访问地址:http://localhost:8080/xxl-rpc-admin (该地址接入方项目将会使用到,作为注册地址),登录后运行界面如下图所示
至此“服务注册中心”项目已经部署成功。
服务注册中心支持集群部署,提升消息系统容灾和可用性。
集群部署时,几点要求和建议:
// Docker地址:https://hub.docker.com/r/xuxueli/xxl-rpc-admin/
docker pull xuxueli/xxl-rpc-admin
docker run -p 8080:8080 -v /tmp:/data/applogs --name xxl-rpc-admin -d xuxueli/xxl-rpc-admin
/**
* 如需自定义 mysql 等配置,可通过 "PARAMS" 指定,参数格式 RAMS="--key=value --key2=value2" ;
* 配置项参考文件:/xxl-rpc/xxl-rpc-admin/src/main/resources/application.properties
*/
docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_rpc?Unicode=true&characterEncoding=UTF-8" -p 8080:8080 -v /tmp:/data/applogs --name xxl-rpc-admin -d xuxueli/xxl-rpc-admin
以示例项目 “xxl-rpc-sample-springboot” 为例讲解;
开发RPC服务的 “接口 / interface” 和 “数据模型 / DTO”;
可参考如下代码:
com.xxl.rpc.sample.api.DemoService
com.xxl.rpc.sample.api.dto.UserDTO
需引入:XXL-RPC核心依赖 + 公共API接口依赖
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-rpc-core</artifactId>
<version>${parent.version}</version>
</dependency>
// 参考代码位置:com.xxl.rpc.sample.server.conf.XxlRpcProviderConfig
@Bean
public XxlRpcSpringProviderFactory xxlRpcSpringProviderFactory() {
XxlRpcSpringProviderFactory providerFactory = new XxlRpcSpringProviderFactory();
providerFactory.setServer(NettyServer.class);
providerFactory.setSerializer(HessianSerializer.class);
providerFactory.setCorePoolSize(-1);
providerFactory.setMaxPoolSize(-1);
providerFactory.setIp(null);
providerFactory.setPort(port);
providerFactory.setAccessToken(null);
providerFactory.setServiceRegistry(XxlRegistryServiceRegistry.class);
providerFactory.setServiceRegistryParam(new HashMap<String, String>() {{
put(XxlRegistryServiceRegistry.XXL_REGISTRY_ADDRESS, address);
put(XxlRegistryServiceRegistry.ENV, env);
}});
logger.info(">>>>>>>>>>> xxl-rpc provider config init finish.");
return providerFactory;
}
ProviderFactory 参数 | 说明 |
---|---|
setServer | 服务通讯方案,可选范围:NettyServer(默认)、NettyHttpServer ; |
setSerializer | 序列化方案,可选范围: HessianSerializer(默认)、Hessian1Serializer ; |
setCorePoolSize | 业务线程池core大小 |
setMaxPoolSize | 业务线程是max大小 |
ip | 服务方IP,为空自动获取机器IP,支持手动指定 |
port | 服务方端口,默认 7080 |
accessToken | 服务鉴权Token,非空时生效; |
setServiceRegistry | 服务注册中心,可选范围:XxlRegistryServiceRegistry.class、LocalServiceRegistry.class;支持灵活自由扩展; |
setServiceRegistryParam | 服务注册中心启动参数,参数说明可参考各注册中心实现的 start() 的方法注释; |
实现 “服务API” 的接口,开发业务逻辑代码;
可参考如下代码:
com.xxl.rpc.sample.api.DemoService
注意:
1、添加 “@Service” 注解:被Spring容器扫描识别为SpringBean;
2、添加 “@XxlRpcService” 注解:被 “XXL-RPC” 的 ProviderFactory 扫描识别,进行Provider服务注册,如果开启注册中心同时也会进行注册中心服务注册;
XxlRpcService 注解参数 | 说明 |
---|---|
version | 服务版本,默认空;可据此区分同一个“服务API” 的不同版本; |
需引入:XXL-RPC核心依赖 + 公共API接口依赖
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-rpc-core</artifactId>
<version>${parent.version}</version>
</dependency>
// 参考代码位置:com.xxl.rpc.sample.client.conf.XxlRpcInvokerConfig
@Bean
public XxlRpcSpringInvokerFactory xxlJobExecutor() {
XxlRpcSpringInvokerFactory invokerFactory = new XxlRpcSpringInvokerFactory();
invokerFactory.setServiceRegistryClass(XxlRegistryServiceRegistry.class);
invokerFactory.setServiceRegistryParam(new HashMap<String, String>(){{
put(XxlRegistryServiceRegistry.XXL_REGISTRY_ADDRESS, address);
put(XxlRegistryServiceRegistry.ENV, env);
}});
logger.info(">>>>>>>>>>> xxl-rpc invoker config init finish.");
return invokerFactory;
}
InvokerFactory 参数 | 说明 |
---|---|
serviceRegistryClass | 服务注册中心,可选范围:XxlRegistryServiceRegistry.class、LocalServiceRegistry.class;支持灵活自由扩展; |
serviceRegistryParam | 服务注册中心启动参数,参数说明可参考各注册中心实现的 start() 的方法注释; |
// 参考代码位置:com.xxl.rpc.sample.client.controller.IndexController
@XxlRpcReference
private DemoService demoService;
……
UserDTO user = demoService.sayHi(name);
……
“@XxlRpcReference” 注解参数 | 说明 |
---|---|
client | 服务通讯方案,可选范围:NettyClient(默认)、NettyHttpClient ; |
serializer | 序列化方案,可选范围: HESSIAN(默认)、HESSIAN1; |
callType | 请求类型,可选范围:SYNC(默认)、ONEWAY、FUTURE、CALLBACK; |
loadBalance | 负载均衡类型,可选范围:ROUND(默认)、RANDOM、LRU、LFU、CONSISTENT_HASH; |
version | 服务版本,默认空;可据此区分同一个“服务API” 的不同版本; |
timeout | 服务超时时间,单位毫秒; |
address | 服务远程地址,ip:port 格式;选填;非空时将会优先实用该服务地址,为空时会从注册中心服务地址发现; |
accessToken | 服务鉴权Token,非空时生效; |
// 参考代码位置:com.xxl.rpc.sample.client.controller.IndexController
代码中将上面配置的消费方 invoker 远程服务注入到测试 Controller 中使用,调用该服务,查看看是否正常。 如果正常,说明该接口项目通过XXL-RPC从 client 项目调用了 server 项目中的服务,夸JVM进行了一次RPC通讯。
访问该Controller地址即可进行测试:http://127.0.0.1:8081/?name=jack
得益于优良的兼容性与模块化设计,不限制外部框架;除 spring/springboot 环境之外,理论上支持运行在任何Java代码中,甚至main方法直接启动运行;
以示例项目 “xxl-rpc-sample-frameless” 为例讲解;该示例项目以直连IP方式进行演示,也可以选择接入注册中心方式使用。
// 参考代码位置:com.xxl.rpc.sample.server.XxlRpcServerApplication
// init
XxlRpcProviderFactory providerFactory = new XxlRpcProviderFactory();
providerFactory.setServer(NettyServer.class);
providerFactory.setSerializer(HessianSerializer.class);
providerFactory.setCorePoolSize(-1);
providerFactory.setMaxPoolSize(-1);
providerFactory.setIp(null);
providerFactory.setPort(7080);
providerFactory.setAccessToken(null);
providerFactory.setServiceRegistry(null);
providerFactory.setServiceRegistryParam(null);
// add services
providerFactory.addService(DemoService.class.getName(), null, new DemoServiceImpl());
// start
providerFactory.start();
while (!Thread.currentThread().isInterrupted()) {
TimeUnit.HOURS.sleep(1);
}
// stop
providerFactory.stop();
// 参考代码位置:com.xxl.rpc.sample.client.XxlRpcClientAplication
// init client
XxlRpcReferenceBean referenceBean = new XxlRpcReferenceBean();
referenceBean.setClient(NettyClient.class);
referenceBean.setSerializer(HessianSerializer.class);
referenceBean.setCallType(CallType.SYNC);
referenceBean.setLoadBalance(LoadBalance.ROUND);
referenceBean.setIface(DemoService.class);
referenceBean.setVersion(null);
referenceBean.setTimeout(500);
referenceBean.setAddress("127.0.0.1:7080");
referenceBean.setAccessToken(null);
referenceBean.setInvokeCallback(null);
referenceBean.setInvokerFactory(null);
DemoService demoService = (DemoService) referenceBean.getObject();
// test
UserDTO userDTO = demoService.sayHi("[SYNC]jack");
System.out.println(userDTO);
提供稳定高性能的RPC远程服务调用功能,简化分布式服务通讯开发。
概念:
RPC通讯,可大致划分为四个步骤,可参考上图进行理解:(XXL-RPC提供了多种调用方案,此处以 “SYNC” 方案为例讲解;)
consumer和provider采用NIO方式通讯,其中TCP通讯方案可选NETTY具体选型,高吞吐高并发;但是仅仅依靠单个TCP连接进行数据传输存在瓶颈和风险,因此XXL-RPC在consumer端自身实现了内部连接池,consumer和provider之间为了一个连接池,当尽情底层通讯是会取出一条TCP连接进行通讯(可参考上图)。
XXL-RPC采用NIO进行底层通讯,但是NIO是异步通讯模型,调用线程并不会阻塞获取调用结果,因此,XXL-RPC实现了在异步通讯模型上的同步调用,即“sync-over-async”,实现原理如下,可参考上图进行理解:
XXL-RPC的注册中心,是可选组件,支持服务注册并动态发现;
可选择不启用,直接指定服务提供方机器地址通讯;
选择启用时,内置可选方案:“XXL-RPC-ADMIN 轻量级服务注册中心”(推荐)、“ZK注册中心”、“Local注册中心”等;
** a、XXL-RPC-ADMIN 轻量级服务注册中心(推荐) **
推荐使用内置的 "XXL-RPC-ADMIN" 作为注册中心。非常轻量级,一分钟可完成部署工作。
更易于集群部署、横向扩展,搭建与学习成本更低,推荐采用该方式;
** b、ZK注册中心 ** 内置“ZK注册中心”,可选组件,结构图如下:
原理:
XXL-RPC中每个服务在zookeeper中对应一个节点,如图"iface name"节点,该服务的每一个provider机器对应"iface name"节点下的一个子节点,如图中"192.168.0.1:9999"、"192.168.0.2:9999"和"192.168.0.3:9999",子节点类型为zookeeper的EPHMERAL类型,该类型节点有个特点,当机器和zookeeper集群断掉连接后节点将会被移除。consumer底层可以从zookeeper获取到可提供服务的provider集群地址列表,从而可以向其中一个机器发起RPC调用。
服务提供方新增 "/services" 服务目录功能,可查看在线服务列表;暂时仅针对NETTY_HTTP通讯方案,浏览器访问地址 "{端口地址}/services" 即可。
XXL-RPC提供多中通讯方案:支持 TCP 和 HTTP 两种通讯方式进行服务调用;其中 TCP 提供可选方案 NETTY ,HTTP 提供可选方案 NETTY_HTTP (新版本移除了Mina和Jetty通讯方案,主推Netty;如果有需要可以参考旧版本;);
如果需要切换XXL-RPC“通讯方案”,只需要执行以下两个步骤即可:
XXL-RPC的注册中心,是一个可选组件,不强制依赖;支持服务注册并动态发现;
可选择不启用,直接指定服务提供方机器地址通讯;
选择启用时,原生提供多种开箱即用的注册中心可选方案,包括:“XXL-RPC原生轻量级注册中心”、“ZK注册中心”、“Local注册中心”等;
如果需要切换XXL-RPC“注册中心”,只需要执行以下两个步骤即可:
XXL-RPC 提供 "泛化调用" 支持,服务调用方不依赖服务方提供的API;泛化调用通常用于框架集成,比如 "网关平台、跨语言调用、测试平台" 等; 开启 "泛化调用" 时服务方不需要做任何调整,仅需要调用方初始化一个泛化调用服务Reference ("XxlRpcGenericService") 即可。
“XxlRpcGenericService#invoke” 请求参数 | 说明 |
---|---|
String iface | 服务接口类名 |
String version | 服务版本 |
String method | 服务方法 |
String[] parameterTypes | 服务方法形参-类型,如 "int、java.lang.Integer、java.util.List、java.util.Map ..." |
Object[] args | 服务方法形参-数据 |
// 服务Reference初始化-注解方式示例
@XxlRpcReference
private XxlRpcGenericService genericService;
// 服务Reference初始化-API方式示例
XxlRpcGenericService genericService = (XxlRpcGenericService) new XxlRpcReferenceBean(……).getObject();
// 调用方示例
Object result = genericService.invoke(
"com.xxl.rpc.sample.server.service.Demo2Service",
null,
"sum",
new String[]{"int", "int"},
new Object[]{1, 2}
);
// 服务方示例
public class Demo2ServiceImpl implements Demo2Service {
@Override
public int sum(int a, int b) {
return a + b;
}
}
XXL-RPC-ADMIN(原XXL-REGISTRY) 是一个轻量级分布式服务注册中心,拥有"轻量级、秒级注册上线、多环境、跨语言、跨机房"等特性。现已开放源代码,开箱即用。
可参考章节:2.2 搭建部署 "服务(注册)中心"
XXL-RPC默认将 "XXL-RPC-ADMIN" 作为原生注册中心。其他Java服务框架。
其他Java服务框架,如dubbo、springboot等,建议参考 XXL-RPC 提供的实例项目;
非Java语言项目,可以借助提供的 RESTFUL 格式API接口实现服务注册与发现功能。
服务注册中心为支持服务注册与发现功能,提供的 RESTful 格式API接口如下:
说明:新服务注册上线1s内广播通知接入方;需要接入方循环续约,否则服务将会过期(三倍于注册中心心跳时间)下线;
地址格式:{服务注册中心跟地址}/registry
请求参数说明:
1、accessToken:请求令牌;
2、env:环境标识
3、registryDataList:服务注册信息
请求数据格式如下,放置在 RequestBody 中,JSON格式:
{
"accessToken" : "xx",
"env" : "xx",
"registryDataList" : [{
"key" : "service01",
"value" : "address01"
}]
}
说明:新服务摘除下线1s内广播通知接入方;
地址格式:{服务注册中心跟地址}/remove
请求参数说明:
1、accessToken:请求令牌;
2、env:环境标识
3、registryDataList:服务注册信息
请求数据格式如下,放置在 RequestBody 中,JSON格式:
{
"accessToken" : "xx",
"env" : "xx",
"registryDataList" : [{
"key" : "service01",
"value" : "address01"
}]
}
说明:查询在线服务地址列表;
地址格式:{服务注册中心跟地址}/discovery
请求参数说明:
1、accessToken:请求令牌;
2、env:环境标识
3、keys:服务注册Key列表
请求数据格式如下,放置在 RequestBody 中,JSON格式:
{
"accessToken" : "xx",
"env" : "xx",
"keys" : [
"service01",
"service02"
]
}
说明:long-polling 接口,主动阻塞一段时间(三倍于注册中心心跳时间);直至阻塞超时或服务注册信息变动时响应;
地址格式:{服务注册中心跟地址}/monitor
请求参数说明:
1、accessToken:请求令牌;
2、env:环境标识
3、keys:服务注册Key列表
请求数据格式如下,放置在 RequestBody 中,JSON格式:
{
"accessToken" : "xx",
"env" : "xx",
"keys" : [
"service01",
"service02"
]
}
内部通过广播机制,集群节点实时同步服务注册信息,确保一致。客户端借助 long pollong 实时感知服务注册信息,简洁、高效;
得益于服务注册中心集群关系对等特性,集群各节点提供幂等的服务注册服务;因此,异地跨机房部署时,只需要请求本机房服务注册中心即可,实现异地多活;
举个例子:比如机房A、B 内分别部署服务注册中心集群节点。即机房A部署 a1、a2 两个服务注册中心服务节点,机房B部署 b1、b2 两个服务注册中心服务节点;
那么各机房内应用只需要请求本机房内部署的服务注册中心节点即可,不需要跨机房调用。即机房A内业务应用请求 a1、a2 获取配置、机房B内业务应用 b1、b2 获取配置。
这种跨机房部署方式实现了配置服务的 "异地多活",拥有以下几点好处:
类似 Raft 方案,更轻量级、稳定;
欢迎参与项目贡献!比如提交PR修复一个bug,或者新建 Issue 讨论新特性或者变更。
更多接入的公司,欢迎在 登记地址 登记,登记仅仅为了产品推广。
产品开源免费,并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。
无论金额多少都足够表达您这份心意,非常感谢 :) 前往捐赠
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。