说明:内容主要来至于官方文档
官方文档地址: https://dubbo.apache.org/
配置优先级:
Dubbo支持的配置来源,默认有四种配置来源:
- JVM System Properties,-D参数
- Externalized Configuration,外部化配置
- ServiceConfig、ReferenceConfig等编程接口采集的配置
- 本地配置文件dubbo.properties,在Springboot中application.yml中也可以配置,dubbo-spring-boot-starter做了支持
配置的粒度说明:
dubbo的很多配置粒度可以细化到方法级别,也可以粗放到一个接口(接口又分为消费者、调用者),甚至可以粗放到所有消费者和服务提供者。
通过上面图,我们知道针对Dubbo配置的优先级、以及配置的粒度,那么接一下我对配置的说明都针对@Service、@Reference注解来进行配置。
1、启动依赖检查,启动检查作用:在服务启动时检查可用性,让服务问题尽早暴露出来。
/** 可以在指定的接口中设置是否检查可用性 */
@Reference(check = true)
private DemoService demoService;
可以在注解上针对某个服务设置启动时
或者在 application.yml中可以配置
spring:
application:
name: hello-api
dubbo:
# 指定注册中心
registry:
address: zookeeper://192.168.50.220:2181
# 指定消费者,提供者所在的包路径
scan:
base-packages:
- com.example.demo.web
# 设置消费者启动时不检查服务可用性,默认是true,需要检查可用性,建议开启
consumer:
check: true
改配置是针对消费者启动时,是否进行服务可用性检查,当然也可以在配置中针对指定服务进行配置,但是不建议那样配置!至于为什么?可以自己想想的。
2、集群容错
集群容错:我理解的是,保证服务调用可用性,及为集群容错
dubbo提供了多种集群容错方案,默认为failover。
Failover Cluster
失败自动切换,当出现失败,重试其它服务器 [1]。通常用于读操作,但重试会带来更长延迟。可通过 retries="2"
来设置重试次数(不含第一次)。
重试次数配置如下:
@Reference(retries = 1)
private DemoService demoService2;
或者 针对方法进行配置
@Reference(methods = { @Method(name = "sayHello", retries = 1) })
private DemoService demoService2;
或者 配置中针对所有提供者
dubbo:
provider:
retries: 1
更多配置方式参考官方文档: https://dubbo.apache.org/zh-cn/docs/user/demos/fault-tolerent-strategy.html
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
@Reference(cluster = "failfast")
private DemoService demoService3;
代码说明:cluster的值,可以点到注解的cluster方法上查看。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2"
来设置最大并行数。
@Reference(cluster = "forking")
private DemoService demoService;
我没有在注解中找到: forks这个配置参数
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。
3、负载均衡
@Reference(loadbalance = "random")
private DemoService demoService3;
Random LoadBalance
- 随机,按权重设置随机概率。
- 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
- 轮询,按公约后的权重设置轮询比率。
- 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
- 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
- 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance
- 一致性 Hash,相同参数的请求总是发到同一提供者。
- 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
- 算法参见:http://en.wikipedia.org/wiki/Consistent_hashing
- 缺省只对第一个参数 Hash,如果要修改,请配置
<dubbo:parameter key="hash.arguments" value="0,1" />
- 缺省用 160 份虚拟节点,如果要修改,请配置
<dubbo:parameter key="hash.nodes" value="320" />
从官网的配置看,存在4中负载均衡策略,但是从配置中看是3中配置,一致性Hash不再,需要专题看看这个问题。以及自定义负载均衡器。
/**
* Load balance strategy, legal values include: random, roundrobin, leastactive
*
* see Constants#DEFAULT_LOADBALANCE
*/
String loadbalance() default "";
4、直连、只订阅
这两种方式的组合,正好支持本地开发调试的操作。
只订阅配置:
dubbo:
registry:
address: zookeeper://192.168.50.220:2181
register: false
直连配置:
@Reference(url = "dubbo://192.168.50.30:12345")
private DemoService demoService;
4、只注册
如果有两个镜像环境,两个注册中心,有一个服务只在其中一个注册中心有部署,另一个注册中心还没来得及部署,而两个注册中心的其它应用都需要依赖此服务。这个时候,可以让服务提供者方只注册服务到另一注册中心,而不从另一注册中心订阅服务。
目的:让另一个注册中心的其他服务可以使用该服务,但是该服务运行时所需要的服务不从另一个注册中心订阅。
基于application.yml的多注册中心支持配置: https://blog.csdn.net/q258523454/article/details/103481326
5、多协议暴露
Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。
不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议
一个服务也可以同时暴露多种协议。
基于application.yml的多协议暴露配置: https://blog.csdn.net/u013887008/article/details/89738398
6、多注册中心配置
支持一个服务同时注册到多个注册中心
支持不同的服务从不同的注册到不同的注册中心。
支持不同服务从不同的注册中心注册。
多注册中心配置,竖号分隔表示同时连接多个不同注册中心,同一注册中心的多个集群地址用逗号分隔
7、服务分组
当一个接口有多种实现时,可以用 group 区分。
@Service(group = "message")
public class DemoServiceImpl implements DemoService {
private final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@Override
public String sayHello(String name) {
logger.info("welcome {}", name);
return name + ", hi";
}
}
8、多版本
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
- 在低压力时间段,先升级一半提供者为新版本
- 再将所有消费者升级为新版本
- 然后将剩下的一半提供者升级为新版本
9、分组聚合
基于注解不支持聚合!!!!
10、回声检查
回声测试用于检测服务是否可用,回声测试按照正常请求流程执行,能够测试整个调用是否通畅,可用于监控。
所有服务自动实现 EchoService
接口,只需将任意服务引用强制转型为 EchoService
,即可使用。
package com.example.demo.web;
import java.util.List;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.rpc.service.EchoService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.hello.service.DemoService;
@RestController
public class TestController {
@Reference
private DemoService demoService;
@GetMapping("/test")
public String hello(String name) {
EchoService echoService = (EchoService) demoService;
Object status = echoService.$echo("hello");
System.out.println("回声检查:" + status);
return demoService.sayHello(name);
}
}
11、参数回调
参数回调方式与调用本地 callback 或 listener 相同,只需要在 Spring 的配置文件中声明哪个参数是 callback 类型即可(注解中指明也可以)。Dubbo 将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。
示例:以创建订单为例,创建完成后回调调用方,告知最终状态。
定义回调接口:
package com.example.hello.service.callback;
@FunctionalInterface
public interface CreatedOrderCallback {
Boolean done(Integer orderId, Integer orderStatus);
}
定义创建订单接口:
package com.example.hello.service;
import com.example.hello.service.callback.CreatedOrderCallback;
public interface CreateOrderService {
Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback);
}
服务提供者 - 实现创建订单:
package com.example.demo.provider.service;
import org.apache.dubbo.config.annotation.Argument;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
import com.example.hello.service.CreateOrderService;
import com.example.hello.service.callback.CreatedOrderCallback;
@Service(callbacks = 1000, connections = 1, methods = {
@Method(name = "createdOrder", arguments = {
@Argument(index = 2, callback = true)
})
}
)
public class CreateOrderServiceImpl implements CreateOrderService {
@Override
public Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback) {
System.out.println("created, id: " + id + ", count: " + count);
// 可以先将callback示例存储起来,可以在异步处理后进行callback,执行这个回调
callback.done(id, -10);
return id;
}
}
注解说明: 配置callbacks的超时时间,通过methods定义方法配置,通过Method的arguments指定参数配置,在参数配置中指定第几个参数是回调对象,index从0开始,callback设置为true
服务消费者-调用方实现
@Reference
private CreateOrderService createOrderService;
@GetMapping("/order")
public Integer order(Integer id, Integer count) {
return createOrderService.createdOrder(id, count, (orderId, status) -> {
System.out.println("callback success, orderId: " + orderId + ", status: " + status);
return Boolean.TRUE;
});
}
执行结果:
12、本地存根,类似Feign的异常Handler
基于【参数回调】中的例子,进行测试
新建CreateOrderServiceStub.java,用于本地存根处理,该代码放到公共Jar中
package com.example.hello.service.stub;
import com.example.hello.service.CreateOrderService;
import com.example.hello.service.callback.CreatedOrderCallback;
public class CreateOrderServiceStub implements CreateOrderService {
private final CreateOrderService createOrderService;
public CreateOrderServiceStub(CreateOrderService createOrderService) {
this.createOrderService = createOrderService;
}
@Override
public Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback) {
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
try {
return createOrderService.createdOrder(id, count, callback);
} catch (Exception e) {
System.out.println(e.getMessage());
// 你可以容错,可以做任何AOP拦截事项
return -1;
}
}
}
说明:
-
Stub 必须有可传入 Proxy 的构造函数。 ↩︎
-
在 interface 旁边放一个 Stub 实现,它实现 BarService 接口,并有一个传入远程 BarService 实例的构造函
服务提供者,修改一下注解配置
package com.example.demo.provider.service;
import org.apache.dubbo.config.annotation.Argument;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
import com.example.hello.service.CreateOrderService;
import com.example.hello.service.callback.CreatedOrderCallback;
@Service(callbacks = 1000, connections = 1, methods = {
@Method(name = "createdOrder", arguments = {
@Argument(index = 2, callback = true)
})
}, stub = "com.example.hello.service.stub.CreateOrderServiceStub"
)
public class CreateOrderServiceImpl implements CreateOrderService {
@Override
public Integer createdOrder(Integer id, Integer count, CreatedOrderCallback callback) {
System.out.println("created, id: " + id + ", count: " + count);
// 这一步callback操作,可以在异步处理后,执行这个回调
callback.done(id, -10);
if(id.intValue() == -100) {
throw new RuntimeException("任性的异常抛出");
}
return id;
}
}
说明: @Service注解上新增stub属性,指定stub的实现类的类名