Dubbo学习(三) —— Dubbo常用配置

@TOC

Dubbo配置

配置原则

首先,从Dubbo支持的配置来源说起,默认有四种配置来源:

JVM System Properties,-D 参数
Externalized Configuration,外部化配置(如application.yml)
ServiceConfig、ReferenceConfig 等编程接口采集的配置(通过编码形式,如写个配置类标注为@Component)
本地配置文件 dubbo.properties

覆盖关系

在这里插入图片描述

优先级顺序:

  • JVM 启动-D参数优先,这样可以使用户在部署和启动时进行参数的重写,比如在启动时需要改变协议的端口时。
  • XML次之。如果中有配置项,则dubbo.properties中相应配置项无效。
  • Properties。 相当于缺省值,只有XML没有配置时,dubbo.properties的相应配置项才会生效。

参见Dubbo 官网 配置加载流程

重试次数 retries

retries 属性表示远程服务调用重试次数,不包括第一次调用,不需要重试请设为0。默认为2.
如果该服务名下有多台服务器,当出现失败时,会轮询自动切换尝试其他服务器。

注解形式配置

@DubboService 和@DubboReference都有重试次数属性。@DubboService标注在对应接口的实现类上,@DubboReference标注在要注入的远程调用对象上。

@Service  // 放进springboot容器中
//服务提供者接口实现类需要被@DubboService 驱动
@DubboService(retries = 3)  //默认重试次数是2次
public class UserServiceImpl implements UserService {



    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("UserServiceImpl..1.....");
        UserAddress address1 = new UserAddress(1, "北京市朝阳区麦肯锡", "1", "李老师", "010-56253825", "Y");
        UserAddress address2 = new UserAddress(2, "深圳市宝安区珠江工厂)", "1", "王老师", "010-56253825", "N");
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
        return Arrays.asList(address1,address2);
    }
}

}

控制请求超时,打印结果:

UserServiceImpl..1.....
UserServiceImpl..1.....
UserServiceImpl..1.....
UserServiceImpl..1.....

使用注解形式无法实现方法级别的属性设置

Spring XML 配置

<dubbo:service retries="2" /><dubbo:reference retries="2" /><dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />
</dubbo:reference>

超时等待时间 timeout

由于网络或服务端不可靠,会导致出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源挂起耗尽,必须设置超时时间。timeout该属性远程服务调用超时时间(毫秒),默认时间为1000ms。

配置的覆盖规则:

  1. 方法级配置别优于接口级别,即小Scope优先
  2. Consumer端配置 优于 Provider配置 优于 全局配置,
  3. 最后是Dubbo Hard Code的配置值(见配置文档)

配置的覆盖规则:
1、 方法级别的优于接口级别,接口级别的优于全局配置。
2、 Consumer端配置优于Provider

Spring XML 形式

consumer.xml

服务提供者
项目结构
在这里插入图片描述
主启动类
由于是使用xml暴露服务的,所以不用使用@EnableDubbo

DubboProviderMain20881.java

//@EnableDubbo  //使用xml暴露服务时候不用@EnableDubbo注解
@SpringBootApplication
public class DubboProviderMain20881 {
    public static void main(String[] args) {
        SpringApplication.run(DubboProviderMain20881.class,args);
    }
}

服务接口实现类之一UserServiceImpl

package com.johnny.dubbo.service.impl;

import com.johnny.dubbo.entity.UserAddress;
import com.johnny.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Johnny Lin
 * @date 2021/7/8 17:42
 */
@Service  // 放进springboot容器中
//服务提供者接口实现类需要被@DubboService 驱动
@DubboService  // 一定一定要加上@DubboService注解暴露远程服务给消费者  一开始就是就没有加上
public class UserServiceImpl implements UserService {



    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("UserServiceImpl..v1.....");
        UserAddress address1 = new UserAddress(1, "北京市朝阳区麦肯锡", "1", "李老师", "010-56253825", "Y");
        UserAddress address2 = new UserAddress(2, "深圳市宝安区珠江工厂)", "1", "王老师", "010-56253825", "N");
//        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }

        System.out.println(address1.getId()+"\t"+address1.getUserAddress());
        System.out.println(address2.getId()+"\t"+address2.getUserAddress());

        return Arrays.asList(address1,address2);
    }
}

服务接口实现类之一UserServiceImpl2.java

package com.johnny.dubbo.service.impl;

import com.johnny.dubbo.entity.UserAddress;
import com.johnny.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Johnny Lin
 * @date 2021/7/8 17:42
 */
@Service  // 放进springboot容器中
//服务提供者接口实现类需要被@DubboService 驱动
@DubboService  // 一定一定要加上@DubboService注解暴露远程服务给消费者  一开始就是就没有加上
public class UserServiceImpl2 implements UserService {



    public List<UserAddress> getUserAddressList(String userId) {
        System.out.println("UserServiceImpl..v2.....");
        UserAddress address1 = new UserAddress(3, "北京市朝阳区麦肯锡", "1", "李老师", "010-56253825", "Y");
        UserAddress address2 = new UserAddress(4, "深圳市宝安区珠江工厂)", "1", "王老师", "010-56253825", "N");
//        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }

        System.out.println(address1.getId()+"\t"+address1.getUserAddress());
        System.out.println(address2.getId()+"\t"+address2.getUserAddress());

        return Arrays.asList(address1,address2);
    }
}

服务提供者配置文件provider.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 1、指定当前服务/应用的名字(同样的服务名字相同,不要和别的服务同名) -->
    <dubbo:application name="user-service-dubbo-provider"></dubbo:application>

    <!-- 2、指定注册中心的位置 -->
    <!-- <dubbo:registry address="zookeeper://192.168.59.123:2181"></dubbo:registry> -->
    <dubbo:registry protocol="zookeeper" address="192.168.59.123:2181"></dubbo:registry>

    <!-- 3、指定通信规则(通信协议?通信端口) -->
    <dubbo:protocol name="dubbo" port="20882"></dubbo:protocol>

    <!-- 4、暴露服务 interface:面向的接口  ref:指向服务的真正的实现对象
            version: 版本,通过指定版本可以实现灰度发布
     -->
    <dubbo:service interface="com.johnny.dubbo.service.UserService"
                   ref="userServiceImpl" timeout="1000" version="1.0.0">
        <dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
    </dubbo:service>

    <!--统一设置服务提供方的规则  -->
    <dubbo:provider timeout="1000"></dubbo:provider>


    <!-- 服务的实现 -->
    <bean id="userServiceImpl" class="com.johnny.dubbo.service.impl.UserServiceImpl"></bean>

    <dubbo:service interface="com.johnny.dubbo.service.UserService"
                   ref="userServiceImpl2" timeout="1000" version="2.0.0">
        <dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
    </dubbo:service>

    <bean id="userServiceImpl2" class="com.johnny.dubbo.service.impl.UserServiceImpl2"></bean>

    <!-- 连接监控中心 -->
    <dubbo:monitor protocol="registry"></dubbo:monitor>

</beans>

消费者
项目结构
在这里插入图片描述
注意application
yaml 和 consumer0.xml 都没有用到

**主启动类 ConsumerMain8081 **

@SpringBootApplication
//@EnableDubbo开启Dubbo注解 该注解中有@DubboComponentScan 作用是扫描dubbo注解所在包
//由于使用xml文件暴露服务 所以不需要该注解
//@EnableDubbo 
public class ConsumerMain8081 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerMain8081.class,args);
    }
}

服务实现类 OrderServiceImpl

package com.johnny.dubbo.service.impl;

import com.johnny.dubbo.entity.UserAddress;
import com.johnny.dubbo.service.OrderService;
import com.johnny.dubbo.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author Johnny Lin
 * @date 2021/7/8 0:18
 */

@Service
public class OrderServiceImpl implements OrderService {

    //Reference注解引用服务远程调用
//    @DubboReference
//    UserService userService;
    //通过xml配置文件暴露接口时,接口的调用使用@Autowired注解,不用 @DubboReference
    // 相当于通过spring将这个接口对象注入了

    @Resource
    private UserService userService;

    public List<UserAddress> initOrder(String userId) {
        System.out.println("OrderService 1……");
        return userService.getUserAddressList(userId);
    }
}

**服务控制类 OrderController **

package com.johnny.dubbo.controller;

import com.johnny.dubbo.entity.UserAddress;
import com.johnny.dubbo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author Johnny Lin
 * @date 2021/7/8 23:50
 */

@RestController
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping("/initOrder/{id}")
    public List<UserAddress> initOrder(@PathVariable("id")String userId) {
        return orderService.initOrder(userId);
    }
}

配置文件consumer.xml

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">


    <dubbo:application name="order-service-dubbo-consumer"></dubbo:application>

    <dubbo:registry id="register" protocol="zookeeper" address="192.168.59.123:2181" timeout="25000"></dubbo:registry>
    <!-- retries 重试次数: 不包含第一次调用 0代表不重试
    幂等操作(如查询、删除、修改)需要设置重试次数
    非幂等操作(如新增) 不能设置重试次数
    -->
    <!-- timeout 超时等待时间: 为0 表示默认是1000ms-->
    <!-- 配置当前消费者的统一规则  设置全局超时时间  check=false表示所有服务启动时都不检查是否有提供者-->
    <dubbo:consumer timeout="5000" check="false" ></dubbo:consumer>
    <!-- 指定接口以及特定方法超时配置 -->
    <!-- 通过dubbo:reference 的timeout属性设置接口级的超时时间-->
    <!-- 通过dubbo:reference 标签生成一个id为userService的远程代理对象 该对象的timeout属性 -->
    <!-- register 属性从指定注册中心注册获取服务列表,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔  缺省向所有registry注册 -->
    <!-- 通过dubbo:reference的version属性指定使用消费端的版本实现灰度发布,* 表示所有版本,也可以指定版本  -->
    <dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService"
                     registry="register" timeout="6000"
                    version = "*">
        <!-- 通过dubbo:method 的timeout属性设置方法级的超时时间   方法级别的起作用-->
        <dubbo:method name="getUserAddressList" timeout="1000" ></dubbo:method>
    </dubbo:reference>

    <!-- 指定监控中心协议 会在注册中心寻找监控中心地址 否则直连监控中心 因此无需再填写详细地址-->
    <dubbo:monitor protocol="registry"  ></dubbo:monitor>
    <!-- <dubbo:monitor address="127.0.0.1:7001"></dubbo:monitor> -->


</beans>
非幂等操作(如新增) 不能设置重试次数
    -->
    <!-- timeout 超时等待时间: 为0 表示默认是1000ms-->
    <!-- 配置当前消费者的统一规则  设置全局超时时间 所有服务都不检查-->
    <dubbo:consumer timeout="5000" check="false" ></dubbo:consumer>
    <!-- 指定接口以及特定方法超时配置 -->
    <!-- 设置接口级的超时时间-->
    <!-- 通过dubbo:reference 标签生成一个id为userService的远程代理对象 该对象的timeout属性 -->
    <dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService"
                     timeout="6000">
        <!-- 设置方法级的超时时间 -->
        <dubbo:method name="getUserAddressList" timeout="1000" ></dubbo:method>
    </dubbo:reference>

    <!-- 指定监控中心协议 会在注册中心寻找监控中心地址 否则直连监控中心 因此无需再填写详细地址-->
    <dubbo:monitor protocol="registry"></dubbo:monitor>
    <!-- <dubbo:monitor address="127.0.0.1:7001"></dubbo:monitor> -->


</beans>

bug

No provider available from registry 192.168.59.123:2181 for service com.johnny.dubbo.service.UserService on consumer 192.168.255.1 use dubbo version 2.7.8, please check status of providers(disabled, not registered or in blacklist)

困扰了老子一天 是在想不明白为什么 监控中心也显示该消费服务没有提供者

原来服务提供者对应的接口实现类上也需要加上@DubboService 注解才能暴露服务给消费者

在这里插入图片描述

版本号

当一个接口实现,出现不兼容升级时,可以使用版本号过渡。版本号不同的服务相互不引用。可以按照以下步骤进行版本迁移:

老版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="1.0.0" />

新版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" />

老版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />

新版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />

如果不需要区分版本,可以按照以下的方式配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />

注意当provider只有一个版本时 如果消费者version写的是*,那么消费者会找不到对应服务。

不同粒度配置的覆盖关系

1、 精确优先(即官网所说的 方法级优先、接口级次之,全局配置再次之)
2、 消费者设置优先(同等级别下,消费则优先,提供者次之)。

在这里插入图片描述
Spring配置

consumer.xml

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- retries 重试次数: 不包含第一次调用 0代表不重试
    幂等操作(如查询、删除、修改)需要设置重试次数
    非幂等操作(如新增) 不能设置重试次数
    -->
    <!-- timeout 超时等待时间: 为0 表示默认是1000ms-->
    <!--  设置全局超时时间-->
    <dubbo:consumer timeout="5000" ></dubbo:consumer>
    <!-- 指定接口以及特定方法超时配置 -->
    <!-- 设置接口级的超时时间-->
    <!-- 通过dubbo:reference 标签生成一个id为userService的远程代理对象 该对象的timeout属性 -->
    <dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService"
                     timeout="6000">
        <!-- 设置方法级的超时时间 -->
        <dubbo:method name="getUserAddressList" timeout="5000" ></dubbo:method>
    </dubbo:reference>
</beans>

SSM 方式直接调用时直接读取配置文件从容器中获取该bean

@SpringBootApplication
@EnableDubbo  //开启Dubbo注解 该注解中有@DubboComponentScan 作用是扫描dubbo注解所在包
public class ConsumerMain8081 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerMain8081.class,args);
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
        UserService userService = applicationContext.getBean(UserService.class);
        System.out.println(111);
        System.out.println(userService.getUserAddressList("36"));

    }
}

本地存根

在 Dubbo 中利用本地存根在客户端执行部分逻辑

在这里插入图片描述
消费端:

UserServiceStub

package com.johnny.dubbo.service.impl;

import com.johnny.dubbo.entity.UserAddress;
import com.johnny.dubbo.service.UserService;
import org.apache.dubbo.common.utils.StringUtils;

import java.util.List;

/**
 * @author Johnny Lin
 * @date 2021/7/11 23:44
 */
public class UserServiceStub implements UserService {

    private final UserService userService;


    /**
     * 传入的是userService远程的代理对象
     * @param userService
     */
    public UserServiceStub(UserService userService) {
        super();
        this.userService = userService;
    }


    @Override
    public List<UserAddress> getUserAddressList(String userId) {
        // TODO Auto-generated method stub
        System.out.println("UserServiceStub   stub.....");
        if(!StringUtils.isEmpty(userId)) {
            return userService.getUserAddressList(userId);
        }
        return null;
    }

}

consumer.xml

    <dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService"
                     registry="register" timeout="6000"
                    version = "1.0.0"   stub="com.johnny.dubbo.service.impl.UserServiceStub">

参考文档:
Dubbo 中的端口使用情况

springboot整合dubbo(xml形式)

高可用配置

高可用,通过设计,减少系统不能提供服务的时间
绕过注册中心,直连本地服务提供者:
在consumer的服务实现类OrderServiceImpl上

@DubboReference(url = "dubbo://localhost:20885")
private UserService userService;

Zookeeper宕机,可以与dubbo直连

现象: zookeeper注册中心宕机,还可以消费dubbo暴露的服务
原因:
dubbo的健壮性

  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
  • 注册中心全部宕掉之后,服务提供者和消费者仍能通过本地缓存通讯

其他情况:

  • 监控中心宕掉后不影响使用,只是丢失部分采样数据
  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但是不能注册新服务
  • 服务提供者无状态,任意一台宕掉后,不影响使用
  • 服务提供者全部宕掉后,服务消费应用将无法使用,并无限次重连等待服务提供者恢复。

使用@Reference(url="")

集群下的dubbo负载均衡

Dubbo提供了多种负载均衡策略,缺省为random随机调用

Random LoadBalance

随机,按权重设置随机概率

RoundRobin LoadBalance

轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

ConsistentHash LoadBalance

一致性 Hash,相同参数的请求总是发到同一提供者。

整合Hystrix 服务熔断与降级处理

服务降级

当服务器压力剧增时,根据业务情况及流量,为保证服务端的核心业务的正常运作和避免客户端的过长等待,对于一些服务和页面有策略的不处理或换种简单的方式处理(如提示用户系统繁忙)。

集群容错

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

Failover Cluster

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

Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性操作,比如新增记录。

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

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

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

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

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

<dubbo:service cluster="failsafe" /><dubbo:reference cluster="failsafe" />
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值