Dubbo常用配置

Dubbo常用配置

使用Dubbo作为项目的RPC框架,可以根据项目实际需要,选择Dubbo提供的自定义配置,本文介绍了Dubbo常用的配置选项

启动时检查

默认情况下,消费者服务启动时,会检查注册中心是否有启用的提供者服务,如果没有,会造成检查不通过,启动失败

在这里插入图片描述

有时候在开发过程中,需要绕过启动检查,可以使用check属性,将值设置为false既可

@Service
public class OrderServiceImpl implements OrderService {

    @DubboReference(check = false)
    UserService userService;

}

或者在配置文件中添加以下配置

dubbo:
  consumer:
    check: false

或者添加以下配置,效果相同

dubbo:
  registry:
    check: false

超时失败

在进行远程调用时,可以配置调用的超时时间,在超时时间内没有受到返回时,则视为调用失败,抛出异常或者执行容错逻辑,配置调用的超时时间,可以使用timeout属性,单位为毫秒

我们创建一个服务提供者,在执行过程中阻塞3秒,以模拟执行时间超时的情况

@Service
@DubboService
public class UserServiceImpl implements UserService {
    @Override
    public List<UserAddress> getUserAddressList() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        UserAddress userAddress1 = new UserAddress(1, "HZ", "00000", "小王", "15652211111", "1");
        UserAddress userAddress2 = new UserAddress(2, "BJ", "00001", "小张", "17911111111", "1");
        return Arrays.asList(userAddress1, userAddress2);
    }
}

在服务消费者通过timeout属性配置超时时间为1秒

@Service
public class OrderServiceImpl implements OrderService {

    @DubboReference(timeout = 1000)
    UserService userService;

    @Override
    public UserAddress initOrder(String userId) {
        List<UserAddress> userAddressList = userService.getUserAddressList();
        for (UserAddress userAddress : userAddressList) {
            if (userAddress.getUserId().equals(userId)) {
                return userAddress;
            }
        }
        return null;
    }
}

执行远程调用,发现过了1秒后,消费者服务抛出超时异常

在这里插入图片描述

超时配置也可以在配置文件中设置,在消费者端使用以下的配置

dubbo:
  consumer:
    timeout: 1000

或者在提供者端使用dubbo.provider.timeout配置或者@DubboService注解的timeout属性

失败重试

当服务调用失败时,可以通过配置来指定失败后重试的次数,默认的重试次数为两次

使用之前服务超时的情景来模拟调用失败,并打印服务被调用的次数

@Service
@Slf4j
@DubboService
public class UserServiceImpl implements UserService {

    private static int count = 0;

    @Override
    public List<UserAddress> getUserAddressList() {
        count++;
        log.info("调用次数:{}", count);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        UserAddress userAddress1 = new UserAddress(1, "HZ", "00000", "小王", "15652211111", "1");
        UserAddress userAddress2 = new UserAddress(2, "BJ", "00001", "小张", "17911111111", "1");
        return Arrays.asList(userAddress1, userAddress2);
    }
}

在消费者端使用retries属性设置重试次数,注意这个重试次数指的是失败后重试的次数,例如以下配置为3,那么还会重试3次,一共就会进行4次调用

@Service
public class OrderServiceImpl implements OrderService {

    @DubboReference(timeout = 1000,retries = 3)
    UserService userService;

    @Override
    public UserAddress initOrder(String userId) {
        List<UserAddress> userAddressList = userService.getUserAddressList();
        for (UserAddress userAddress : userAddressList) {
            if (userAddress.getUserId().equals(userId)) {
                return userAddress;
            }
        }
        return null;
    }
}

在服务端查看后台日志,发现被调用了4次

在这里插入图片描述

在多个服务提供者的情况下默认使用轮询的方式重试

多版本

Dubbo提供了对api添加版本号,进行版本控制和灰度发布的功能,使用这个功能,可以在服务提供者端使用version属性设置Service类下的api的版本号

为了测试,我们编写一个服务的实现类,设置版本号为1.0.0

@Service
@DubboService(version = "1.0.0")
public class UserServiceImpl implements UserService {

    @Override
    public List<UserAddress> getUserAddressList() {
        UserAddress userAddress1 = new UserAddress(1, "HZ", "00000", "小王", "15652211111", "1");
        UserAddress userAddress2 = new UserAddress(2, "BJ", "00001", "小张", "17911111111", "1");
        return Arrays.asList(userAddress1, userAddress2);
    }
}

然后再编写一个不同返回的服务实现类,设置版本号为2.0.0

@Service
@DubboService(version = "2.0.0")
public class NewUserServiceImpl implements UserService {

    @Override
    public List<UserAddress> getUserAddressList() {
        UserAddress userAddress1 = new UserAddress(1, "LA", "00000", "Tim", "15652211111", "1");
        UserAddress userAddress2 = new UserAddress(2, "NY", "00001", "John", "17911111111", "1");
        return Arrays.asList(userAddress1, userAddress2);
    }
}

在消费者端,也使用version属性,来选择调用时所选择的api版本号

@Service
public class OrderServiceImpl implements OrderService {

    @DubboReference(version = "1.0.0")
    UserService userService;

    @Override
    public UserAddress initOrder(String userId) {
        List<UserAddress> userAddressList = userService.getUserAddressList();
        for (UserAddress userAddress : userAddressList) {
            if (userAddress.getUserId().equals(userId)) {
                return userAddress;
            }
        }
        return null;
    }
}

测试可以发现,调用了1.0.0版本的api

在这里插入图片描述

将消费者端指定调用的版本号改为2.0.0,可以发现调用了不同的版本

在这里插入图片描述

Dubbo还可以实现简单的灰度发布,只要将消费者调用的接口版本号设置为*,Dubbo就会随机地从现有的版本中选取一个版本进行调用

本地存根

类似Spring框架中AOP的作用,有时候调用方需要在远程调用的前后实现一些增强逻辑,类似可以做一些前置的参数验证,或者查询数据缓存,调用失败容错数据等等,但是每处调用的地方都需要写一次额外的代码太麻烦了,而且这样调用增强的逻辑和本地的业务逻辑耦合性太强,这时候可以使用本地存根功能

使用本地存根,需要实现一个自定义的Stub类,实现服务提供者的服务接口,在Stub类中使用构造器注入一个服务接口,并且在接口的实现方法中增加增强逻辑,这就实现了代理功能

@Slf4j
public class UserServiceStub implements UserService {

    private final UserService userService;

    public UserServiceStub(UserService userService) {
        this.userService = userService;
    }
    
    @Override
    public List<UserAddress> getUserAddressList() {
        log.info("调用本地存根");
        return userService.getUserAddressList();
    }
}

在调用时使用stub属性绑定自定义的Stub类,既可使用存根功能

@Service
public class OrderServiceImpl implements OrderService {

    @DubboReference(version = "*",stub = "com.blackball.service.stub.UserServiceStub")
    UserService userService;

}

每次调用前会先执行存根中的日志打印增强逻辑

在这里插入图片描述

配置优先级

以上Dubbo的配置,都可以从消费者服务的@DubboReference注解,提供者服务的@DubboService注解中的属性做局部配置,也可以从消费者服务的dubbo.consumer配置下和提供者服务的dubbo.provider配置下做全局配置,那么如果多处都做了同样的配置,哪个配置优先生效呢?

首先按照精确度匹配,局部配置优先级高于全局配置,其次在精确度一样的情况下,消费者的配置优先级高于提供者的配置


版权声明:本文为blackball1998原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。