Dubbo

基于 Spring Boot Starter 开发微服务应用

https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/

Dubbo Demo

https://github.com/apache/dubbo-samples

高级特性和用法

框架与服务

1 版本与分组

Dubbo服务中,接口并不能唯一确定一个服务,只有 接口+分组+版本号 的三元组才能唯一确定一个服务。

  • 当同一个接口针对不同的业务场景、不同的使用需求或者不同的功能模块等场景,可使用服务分组来区分不同的实现方式。同时,这些不同实现所提供的服务是可并存的,也支持互相调用。
  • 当接口实现需要升级又要保留原有实现的情况下,即出现不兼容升级时,我们可以使用不同版本号进行区分。
使用方式

使用 @DubboService 注解,配置 group 参数和 version 参数:

生产者
//接口定义
public interface DevelopService {
    String invoke(String param);
}

//接口实现1 都是同一个接口不同是的实现类
@DubboService(group = "group1", version = "1.0")
public class DevelopProviderServiceV1 implements DevelopService{
    @Override
    public String invoke(String param) {
        StringBuilder s = new StringBuilder();
        s.append("ServiceV1 param:").append(param);
        return s.toString();
    }
}

//接口实现2
@DubboService(group = "group2", version = "2.0")
public class DevelopProviderServiceV2 implements DevelopService{
    @Override
    public String invoke(String param) {
        StringBuilder s = new StringBuilder();
        s.append("ServiceV2 param:").append(param);
        return s.toString();
    }
}
消费者

@DubboReference(group = "group1", version = "1.0")
private DevelopService developService;

@DubboReference(group = "group2", version = "2.0")
private DevelopService developServiceV2;

//group值为*,标识匹配任意服务分组
@DubboReference(group = "*")
private DevelopService developServiceAny;

@Override
public void run(String... args) throws Exception {
    //调用DevelopService的group1分组实现
    System.out.println("Dubbo Remote Return ======> " + developService.invoke("1"));
    //调用DevelopService的另一个实现
    System.out.println("Dubbo Remote Return ======> " + developServiceV2.invoke("2"));
}

2 参数校验

特性说明

参数验证功能是基于 JSR303 实现的,用户只需标识 JSR303 标准的验证 annotation,并通过声明 filter 来实现验证。

Maven 依赖
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.0.0.GA</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.2.0.Final</version>
</dependency>

使用场景

服务端在向外提供接口服务时,解决各种接口参数校验问题。

参考用例 https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-validation

使用方式
参数标注示例
import java.io.Serializable;
import java.util.Date;
 
import javax.validation.constraints.Future;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
 
public class ValidationParameter implements Serializable {
    private static final long serialVersionUID = 7158911668568000392L;
 
    @NotNull // 不允许为空
    @Size(min = 1, max = 20) // 长度或大小范围
    private String name;
 
    @NotNull(groups = ValidationService.Save.class) // 保存时不允许为空,更新时允许为空 ,表示不更新该字段
    @Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")
    private String email;
 
    @Min(18) // 最小值
    @Max(100) // 最大值
    private int age;
 
    @Past // 必须为一个过去的时间
    private Date loginDate;
 
    @Future // 必须为一个未来的时间
    private Date expiryDate;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public Date getLoginDate() {
        return loginDate;
    }
 
    public void setLoginDate(Date loginDate) {
        this.loginDate = loginDate;
    }
 
    public Date getExpiryDate() {
        return expiryDate;
    }
 
    public void setExpiryDate(Date expiryDate) {
        this.expiryDate = expiryDate;
    }
}
分组验证示例
public interface ValidationService { // 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class)   
    @interface Save{} // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选
    void save(ValidationParameter parameter);
    void update(ValidationParameter parameter);
}
方法中参数验证示例
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
 
public interface ValidationService {
    void save(@NotNull ValidationParameter parameter); // 验证参数不为空
    void delete(@Min(1) int id); // 直接对基本类型参数验证
}

3 集群容错

在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。

各节点关系:

  • 这里的 Invoker 是 Provider 的一个可调用 Service 的抽象,Invoker 封装了 Provider 地址及 Service 接口信息
  • Directory 代表多个 Invoker,可以把它看成 List<Invoker> ,但与 List 不同的是,它的值可能是动态变化的,比如注册中心推送变更
  • Cluster 将 Directory 中的多个 Invoker 伪装成一个 Invoker,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个
  • Router 负责从多个 Invoker 中按路由规则选出子集,比如读写分离,应用隔离等
  • LoadBalance 负责从多个 Invoker 中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选
Failover Cluster

失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)

重试次数配置如下:

<dubbo:service retries="2" />

或

<dubbo:reference retries="2" />

或

<dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
Failsafe Cluster 失败安全

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

Failback Cluster 失败自动恢复

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

Forking Cluster 并行调用多个服务器

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源可通过 forks="2" 来设置最大并行数。

Broadcast Cluster 广播调用

广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

现在广播调用中,可以通过 broadcast.fail.percent 配置节点调用失败的比例,当达到这个比例后,BroadcastClusterInvoker 将不再调用其他节点,直接抛出异常。 broadcast.fail.percent 取值在 0~100 范围内。默认情况下当全部调用失败后,才会抛出异常。 broadcast.fail.percent 只是控制的当失败后是否继续调用其他节点,并不改变结果(任意一台报错则报错)。broadcast.fail.percent 参数 在 dubbo2.7.10 及以上版本生效。

Broadcast Cluster 配置 broadcast.fail.percent。

broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常,不再调用其他节点。

@reference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"})

集群模式配置

按照以下示例在服务提供方和消费方配置集群模式

<dubbo:service cluster="failsafe" />

<dubbo:reference cluster="failsafe" />

4 服务降级

Dubbo服务降级通常是指在服务不可用或负载过高时,为某些服务调用提供备选方案,以防止系统崩溃或性能下降。在Dubbo中,可以使用Mock机制来实现服务降级。

Mock伪造返回数据,可用作服务降级

  • 强制返回null
<dubbo:reference id="demoService" interface="com.example.DemoService" mock="return null"/>
  • 这种方式强制执行本地伪装逻辑,即使远程调用正常也会执行降级逻辑。
  • 一般用这种,直接降级
<dubbo:reference id="demoService" interface="com.example.DemoService" mock="force:true"/>

或者

@DubboService(version = "1.0.0",timeout = 3000, mock = "force:true")
  • 1 mock = force:return+null:强制服务返回null,不会进行RPC调用
  • 2 mock = fail:return+null:调用服务失败后返回null,会进行RPC调用。
  • 3 mock = throw:直接跑RpcException,不会RPC调用

以下是使用Dubbo Mock机制的步骤:

  1. 实现Mock接口。

  2. 配置Mock规则。

1 定义一个服务接口:

public interface MyService {
    String sayHello(String name);
}
2 实现Mock接口:

public class MyServiceMock implements MyService {
    @Override
    public String sayHello(String name) {
        return "Mocked: Hello, " + name;
    }
}
3 在provider的配置文件中添加Mock规则:

<dubbo:service interface="MyService" ref="myService" mock="MyServiceMock"/>
或者在注解配置中使用:

@Service(version = "1.0.0", mock = "MyServiceMock")
public class MyServiceImpl implements MyService {
    // ...
}

MyService不可用时,Dubbo会自动使用MyServiceMock的实现。

注意:

  • 确保Mock类和服务接口在同一个ClassLoader下。

  • 如果使用注解配置,请确保Mock类在服务提供者的类路径下。

  • 如果服务提供者不可用,Dubbo也会使用Mock

以上是Dubbo服务降级的一种简单实现方式,具体的降级策略可能需要根据实际情况进行定制。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值