前言
Dubbo作为一个强大的RPC框架,他的功能和特性很多。这里针对其中使用比较多的功能和特性进行测试和记录。
负载均衡
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/loadbalance/
作为一个RPC框架,负载均衡这个功能是一定存在的。
Dubbo负载均衡策略目前有4种
- random:随机,按权重设置随机概率
- roundrobin:轮询,按公约后的权重设置轮询比率
- leastactive:最少活跃调用数,消费者记录对每一个提供者调用次数,然后尽可能的请求调用次数比较少的提供者,相同就随机
- consistenthash:一致性 Hash,相同参数请求调用同一个提供者
可以在服务端服务级别,服务端方法级别,消费端服务级别,消费端方法级别
优先级:消费端方法级别>消费端服务级别>服务端方法级别>服务端服务级别
demo
// 服务端服务级别
@DubboService(loadbalance = "roundrobin")
// 服务端方法级别
@DubboService(methods = {@Method(name = "testCallback", loadbalance = "roundrobin")})
// 消费端服务级别
@DubboReference(loadbalance = "random")
// 消费端方法级别
@DubboReference(methods = {@Method(name = "testCallback", loadbalance = "random")})
自定义扩展负载均衡
接口:LoadBalance
通过Dubbo SPI进行扩展
src/main/resource/META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance文件添加内容
demo=my=com.demo.dubbo.DemoLoadBalance
@DubboService(loadbalance = "roundrobin")
服务超时
服务提供者和服务消费者都可以配置超时时间,意义确不一样。
- 服务消费者的超时时间表示时间内没有收到响应结果抛出异常,但此时服务提供者不受影响继续执行直到执行完
- 服务提供者的超时时间表示时间内没有执行结束,提供者直接返回异常
集群容错
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/fault-tolerent-strategy/
服务调用失败后所采取的措施
- Failover:失败自动切换,通过retries设置(不包含第一次)
- Failfast:直接失败
- Failsafe:出现异常,直接忽略
- Failback:失败自动恢复,后台记录失败请求,定时重发
- Forking:并行调用多个服务提供者,有一个成功即可,可通过
forks="2"来设置最大并行数 - broadcast:广播调用,有一个失败就失败
服务降级
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/local-mock/
服务降级表示:服务消费者在调用某个服务提供者时,如果该服务提供者报错了,所采取的措施。
集群容错和服务降级的区别在于:
- 集群容错是整个集群范围内的容错
- 服务降级是单个服务提供者的自身容错
使用方法
force:在服务引用上标注force: return 123 表示强制返回123,不会进行服务调用
@DubboReference(mock = "force: return 123")
private DemoService demoService;
fail:在服务引用上标注fail: return 123 在服务调用失败时返回123
@DubboReference(mock = "fail: return 123")
private DemoService demoService;
throw:当调用出错时,抛出一个默认的 RPCException
@DubboReference(mock = "throw")
private DemoService demoService;
逻辑:调用出错时,mock一段逻辑返回
@DubboReference(mock="com.foo.BarServiceMock")
private DemoService demoService;
本地存根
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/local-stub/
本地存根简单来说就是在服务消费者端执行一段逻辑,这段逻辑可以在服务调用前或调用后执行,一般由服务提供者编码。可利用这种机制在服务调用前进行参数验证或服务调用后进行结果缓存等
使用方法
@DubboReference(stub = "true")
private DemoService demoService;
接口层编写
public class DemoServiceStub implements DemoService {
private final DemoService demoService;
// 构造函数传入真正的远程代理对象
public DemoServiceStub(DemoService demoService){
this.demoService = demoService;
}
@Override
public String sayHello(String name) {
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
try {
return demoService.sayHello(name); // safe null
} catch (Exception e) {
// 你可以容错,可以做任何AOP拦截事项
return "容错数据";
}
}
}
异步调用
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/async-call/
异步调用顾名思义就是异步的,可以直接看使用方法
使用方法
消费者
@ApiOperation(value = "异步调用测试", notes = "无参数")
@GetMapping("/testAsync")
public void testAsync() {
DemoDTO demoDTO = new DemoDTO();
demoDTO.setId(112233344L);
CompletableFuture<String> future = dubboDemoService.testAsync(demoDTO);
future.whenComplete((v, t) -> {
if (t != null) {
t.printStackTrace();
} else {
// 调用结束后执行,验证异步
log.info(v);
}
});
log.info("调用结束");
}
接口层
CompletableFuture<String> testAsync(DemoDTO demoDTO);
提供者
@Override
public CompletableFuture<String> testAsync(DemoDTO demoDTO) {
System.out.println("执行了异步服务");
return CompletableFuture.supplyAsync(() -> test(demoDTO));
}
泛化调用
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-reference/
在没有API接口的情况下可以通过泛化调用的方式调用服务
使用方法
消费者
@DubboReference(version = "generic", protocol = "${service.demo.provider.protocol}", interfaceName = "com.dm.api.service.DubboDemoService", generic = true)
GenericService genericService;
@ApiOperation(value = "泛化测试", notes = "无参数")
@GetMapping("/testGeneric")
public void testGeneric() {
DemoDTO demoDTO = new DemoDTO();
demoDTO.setId(112233344L);
genericService.$invoke("test", new String[]{"com.inroad.nest.demo.api.model.dto.DemoDTO"}, new Object[]{demoDTO});
}
这里表示的是调用DubboDemoService下的test方法,传参是demoDTO,中间并没有像之前的引入接口包
泛化服务
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-service/
在服务端没有API接口的时候可以使用
服务提供者可以暴露一个泛化服务供消费端调用,一般可以用于服务测试
使用方法
提供者
@DubboService(interfaceName = "com.dm.DemoService", version = "generic")
public class GenericDemoService implements GenericService {
@Override
public Object $invoke(String s, String[] strings, Object[] objects) throws GenericException {
System.out.println("执行了generic服务");
return "执行的方法是" + s;
}
}
这时没有引用任何接口包
消费者
@DubboReference(version = "generic")
private DemoService demoService;
@RequestMapping("/default")
public String test(){
return demoService.called("默认服务");
}