02 玩转Dubbo,Dubbo配置参数说明,及使用场景总结

说明:内容主要来至于官方文档

官方文档地址: 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、多版本

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

可以按照以下的步骤进行版本迁移:

  1. 在低压力时间段,先升级一半提供者为新版本
  2. 再将所有消费者升级为新版本
  3. 然后将剩下的一半提供者升级为新版本

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;
		}
	}

}

说明:

  1. Stub 必须有可传入 Proxy 的构造函数。 ↩︎

  2. 在 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的实现类的类名

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章