首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >10 Dubbo 配置实战

10 Dubbo 配置实战

作者头像
用户7630333
发布于 2023-12-07 10:50:30
发布于 2023-12-07 10:50:30
26900
代码可运行
举报
文章被收录于专栏:look Javalook Java
运行总次数:0
代码可运行

Dubbo 配置实战

快速入门 dubbo

建议看这篇文章是在学习了快速入门 dubbo 那篇文章的基础上来学习

配置说明

文档地址 https://dubbo.apache.org/zh/index.html

关于 dubbo 的配置说明 在文档中都有比较详细的说明,下面举例的都是较为常用的

1 启动时检查

  • 启动时会在注册中心检查依赖的服务是否可用,不可用时会抛出异常
  • 在消费方编写初始化容器的 main 方法启动(tomcat 启动方式,必须访问一次 action 才能初始化 spring)
  • 想想为什么要有这个配置呢?
    • 可以提前发现服务提供方是否可用
示例代码

直接启动这个测试类,注意 spring 配置文件的位置

  • 我这里测试,现在是没有启动提供者
  • 因为我们测试的目的就是让他没有提供者,会不会有报错提示
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * @author : look-word
 * 2022-07-19 09:44
 **/
public class TestCheckException {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring.xml");
        // 让程序一直读取, 目的是不让他停止
        System.in.read();
    }
}

当我们启动后会发现,诶,怎么没有错误呢,是下面 log4j 的提示呢?

  • 这里没有错误提示的原因呢,就是说我们没有正确的去配置 log4j,的确我们也没有去配置
  • 系统级别日志,需要配合 log4j 才输出,在 resources 下添加 log4j.properties,内容如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=dubbo.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n
log4j.rootLogger=error, stdout,file

再次启动,会发现。如我们所愿它出错了。

错误信息

  • 翻译的意思:说在 zookeeper 中没有找到可用的服务

java.lang.IllegalStateException: Failed to check the status of the service service.HelloService. No provider available for the service service.HelloService from the url zookeeper:

关闭检查

在 spring.xml 配置文件中加上就不会有异常提示了

  • 可以看到,我这里的这个配置是注释掉的,在实际开发中我们是需要这个异常提示的,不推荐关闭
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!--默认是true:抛异常;false:不抛异常-->
<dubbo:consumer check="false" />

然后启动测试文件即可,这里不做演示了


2 超时时间

  • 由于网络或服务端不可靠,会导致调用过程中出现不确定的阻塞状态(超时)
  • 为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间
  • 在服务提供者添加如下配置:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!--设置超时时间为2秒,默认为1-->
<dubbo:provider timeout="2000"/>
  • 可以将服务实现 HelloServiceImpl.java 中加入模拟的网络延迟进行测试:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@com.alibaba.dubbo.config.annotation.Service
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "Hello," + name + "!!!";
    }
}
  • 超时设置 2 秒,而模拟的网络延迟有 3 秒,超出时限,报错!

错误代码: com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout.

  • 服务器响应超时。

配置原则:

dubbo 推荐在Provider上尽量多配置Consumer端属性

  1. 服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试 次数,等等
  2. 在Provider配置后,Consumer不配置则会使用 Provider 的配置值,即 Provider 配置可 以作消费者的缺省值

3 重试次数

  • 当出现失败,自动切换并重试其它服务器,dubbo 重试的缺省值是 2 次,我们可以自行设置
  • 在 provider 提供方配置:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!-- 消费方连接第1次不算,再来重试3次,总共重试4-->
<dubbo:provider timeout="2000" retries="3"/>

修改实现类代码: 增加次数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@com.alibaba.dubbo.config.annotation.Service
public class HelloServiceImpl implements HelloService {
    int a;
    @Override
    public String sayHello(String name) {
        System.out.println("被调用第"+(++a)+"次");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "Hello," + name + "!!!";
    }
}

可以看到 重试了 3 次 第一次不算

引入问题

并不是所有的方法都适合设置重试次数

  • 幂等方法:适合(当参数一样,无论执行多少次,结果是一样的,例如:查询,修改)
  • 非幂等方法:不适合(当参数一样,执行结果不一样,例如:删除,添加)

我们需要单独为某个方法设置重试次数

  • 需要再添加一个方法,作对比
  • 提供方接口添加 sayNo()方法并实现
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface HelloService {
    String sayHello(String name);
    String no();
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@com.alibaba.dubbo.config.annotation.Service
public class HelloServiceImpl implements HelloService {
    int a,b;
    @Override
    public String sayHello(String name) {
        System.out.println("sayHello被调用第"+(++a)+"次");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "Hello," + name + "!!!";
    }

    @Override
    public String no() {
        System.out.println("no被调用第"+(++b)+"次");
        return "no";
    }
}
  1. 消费方接口添加 sayNo()方法声明
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface HelloService {
    String sayHello(String name);
    String no();
}
  1. 消费方 controller
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestController
public class HelloAction {
	// Resource 注解 指定名称注入
    @Resource(name = "helloService")
    private HelloService hs;

    @RequestMapping("hello/{name}")
    @ResponseBody
    public String hello(@PathVariable String name) {
        return hs.sayHello(name);
    }

    @RequestMapping("no")
    @ResponseBody
    public String no() {
        return hs.no();
    }
}
  1. 消费方配置方法重试次数
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <dubbo:reference interface="service.HelloService" id="helloService">
        <dubbo:method name="sayHello" retries="3"/>
        <dubbo:method name="no" retries="0"/>
    </dubbo:reference>

启动项目,访问

  • http://localhost:8002/no
  • http://localhost:8002/hello/zhangsan

可以看到,我们为每种方法配置的重试次数成功了


4 多版本

  • 一个接口,多个(版本的)实现类,可以使用定义版本的方式引入
  • 为 HelloService 接口定义两个实现类,提供者修改配置:
配置文件

为 HelloService 定义了两个版本

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <dubbo:service interface="service.HelloService" class="service.impl.HelloServiceImpl1" version="1.0.0">
    </dubbo:service>
    <dubbo:service interface="service.HelloService" class="service.impl.HelloServiceImpl2" version="2.0.0">
    </dubbo:service>
修改实现类

  • 复制 HelloServiceImpl 重命名为 1 和 2
  • 分别为每个实现类标识版本信息
  • 因为提供者定义了版本所以消费者就可以根据 version 的版本,选择具体的服务版本 这里是消费者配置文件

注意:消费者的控制层要改为自动注入,因为@Reference 注解和 dubbo:reference在这里冲突

  • Resource 注解默认是根据变量名去 spring 容器中找对应的 bean 的
  • 需要在直接参数中配置 bean 的名称 和 上面图中 id 对应

启动测试

注意 每次修改配置文件 都需要重启项目

访问: http://localhost:8002/no

  • 当消费者的版本修改为 version="*",那么就会随机调用服务提供者的版本 这是访问多次 http://localhost:8002/no 控制台输出的信息

5 本地存根

为什么要有本地存根?

  • 目前我们的分布式架构搭建起来有一个严重的问题,就是所有的操作全都是 消费者发起,由服务 提供者执行
  • 消费者动动嘴皮子却什么活都不干,这样会让提供者很累,例如简单的参数验证,消费者完全能够 胜任,把合法的参数再发送给提供者执行,效率高了,提供者也没那么累了
  • 例如:去房产局办理房屋过户,请带好自己的证件和资料,如果什么都不带,那么办理过户手续会 很麻烦,得先调查你有什么贷款,有没有抵押,不动产证是不是你本人,复印资料等操作。一天肯 定办不完。明天还要来。如果你能提前将这些东西准备好,办理过户,1 个小时足矣,这就是“房产 中介办事效率高的原因”
  • 话不多说,先在消费者处理一些业务逻辑,再调用提供者的过程,就是“本地存根”
示例代码

代码实现肯定在 消费者,创建一个 HelloServiceStub 类并且实现 HelloService 接口 注意:必须使用构造方法的方式注入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class HelloServiceStub implements HelloService {
    private HelloService helloService;
    // 注入HelloService
    public HelloServiceStub(HelloService helloService) {
        this.helloService = helloService;
    }

    @Override
    public String sayHello(String name) {
        System.out.println("本地存根数据验证。。。");
        if(!StringUtils.isEmpty(name)){
            return helloService.sayHello(name);
        }
        return "i am sorry!";
    }

    @Override
    public String no() {
        return helloService.no();
    }
}
修改消费者配置文件

  • 添加的是红框位置的参数
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <dubbo:reference interface="service.HelloService" id="helloService" version="*" stub="service.impl.HelloServiceStub">
        <dubbo:method name="sayHello" retries="3"/>
        <dubbo:method name="no" retries="0"/>
    </dubbo:reference>

老样子,clean项目 然后打包启动

  • 因为我们只对 sayHello 方法进行了存根校验,所以访问
  • http://localhost:8002/hello/zhangsan

负载均衡策略

  • 负载均衡(Load Balance), 其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作 任务。
  • 简单的说,好多台服务器,不能总是让一台服务器干活,应该“雨露均沾”
  • dubbo 一共提供 4 种策略,缺省为 random 随机分配调用
示例代码

  • 修改提供者配置并启动 3 个提供者,让消费者对其进行访问
    • tomcat 端口 8001,8002,8003
    • provider 端口 20881,20882,20883
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dubbo:provider timeout="2000" retries="3" port="20881"/>

HelloServiceImpl2 类,服务器 1,服务器 2,服务器 3

  • 在每次修改 tomcat 端口号 和 provider 端口是 修改 HelloServiceImpl2 的内容
  • 因为我这里用的是 2.0.0 的版本,所以修改的是 HelloServiceImpl2 的内容
启动 consumer 进行测试

启动一个消费者,三个提供者

  • 底下我已经访问了一次,当我们访问多次,去控制台查看输出信息时,会发现他是随机的去调用提供者
消费方修改权重

loadbalance 取值文章

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <dubbo:reference loadbalance="roundrobin" interface="service.HelloService" id="helloService" version="2.0.0" stub="service.impl.HelloServiceStub">
        <dubbo:method name="sayHello" retries="3"/>
        <dubbo:method name="no" retries="0"/>
    </dubbo:reference>
  • 最好使用管理端修改权重

然后启动测试即可

高可用

1 zookeeper 宕机

  • zookeeper 注册中心宕机,还可以消费 dubbo 暴露的服务
    • 监控中心宕掉不影响使用,只是丢失部分采样数据 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务 注册中心对等集群,任意一台宕掉后,将自动切换到另一台 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯 服务提供者无状态,任意一台宕掉后,不影响使用 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
  • 测试:
  • 正常发出请求
  • 关闭 zookeeper:./zkServer.sh stop
  • 消费者仍然可以正常消费

服务降级

  • 壁虎遇到危险会自动脱落尾巴,目的是损失不重要的东西,保住重要的
  • 服务降级,就是根据实际的情况和流量,对一些服务有策略的停止或换种简单的方式处理,从而释 放服务器的资源来保证核心业务的正常运行
1 为什么要服务降级

  • 而为什么要使用服务降级,这是防止分布式服务发生雪崩效应
  • 什么是雪崩?就是蝴蝶效应,当一个请求发生超时,一直等待着服务响应,那么在高并发情况下, 很多请求都是因为这样一直等着响应,直到服务资源耗尽产生宕机,而宕机之后会导致分布式其他 服务调用该宕机的服务也会出现资源耗尽宕机,这样下去将导致整个分布式服务都瘫痪,这就是雪 崩。
2 服务降级实现方式

  • 在 管理控制台配置服务降级:屏蔽和容错
  • 屏蔽:mock=force:return+null 表示消费方对该服务的方法调用都 直接返回 null 值,不发起远程 调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • 容错:mock=fail:return+null 表示消费方对该服务的方法调用在 失败后,再返回 null 值,不抛异 常。用来容忍不重要服务不稳定时对调用方的影响。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Swift 笔记#1 - 10 分钟掌握 Swift Package Manager
Swift Package Manager(Swift 包管理器,一般简称 SwiftPM 或者 SPM)是苹果官方提供的一个用于管理源代码分发的工具,旨在使分享代码和复用其他人的代码变得更加容易。
JSCON简时空
2020/03/16
2.1K0
Swift 笔记#1 - 10 分钟掌握 Swift Package Manager
如何使用Swift Package Manager那么,让我门开始吧
Swift Package Manager 是苹果推出的用于创建使用swift的库和可执行程序的工具。
Leacode
2018/09/26
2.8K0
构建自己的Python开源包
项目地址:https://github.com/shikanon/BaiduMapAPI
机械视角
2019/10/23
1.2K0
构建自己的Python开源包
cocoapods项目迁移至swift package manager
记录一下把 业火输入法 的项目依赖从 cocoapods 迁移至 swift package manager 所经历的重重磨难
扰乱
2023/11/02
1.3K0
cocoapods项目迁移至swift package manager
Swift Perfect - Ubuntu 服务器部署
在 Ubuntu 部署遇到坑多,几乎快要 “从入门到放弃”,最后无意在Slack 看到 Perfect-Ubuntu,心想再试一试,再不行就准备“从Vapor入门到。。”(Vapor部署成功,坑少),最后这Perfect-Ubuntu解决了数据库的问题部署成功!
LeeCen
2018/10/11
1.9K0
Swift Perfect - Ubuntu 服务器部署
Swift3.0服务端开发(三) Mustache页面模板与日志记录
本篇博客主要介绍如果在Perfect工程中引入和使用Mustache页面模板与日志记录系统。Mustache页面模板类似于PHP中的smarty模板引擎或者Java中的JSTL标签。当然Mustache页面模板的功能要弱的多。Mustache页面模板的主要功能是将html页面中的标签变量(比如“{{name}}”)进行替换,要想引入Mustache页面模板相关的库,只需要在Package.swift文件中添加相应的库的连接地址然后再编译连接即可。本篇博客还会介绍如果将日志记录到相应的日志文件,在开发中日志是
lizelu
2018/01/11
9460
Swift3.0服务端开发(三) Mustache页面模板与日志记录
使用 Swift 6 语言模式构建 Swift 包
我最近了解到,Swift 6 的一些重大变更(如完整的数据隔离和数据竞争安全检查)将成为 Swift 6 语言模式的一部分,该模式将在 Swift 6 编译器中作为可选功能启用。
Swift社区
2024/06/19
3530
使用 Swift 6 语言模式构建 Swift 包
lerna + dumi + eslint多包管理实践
在开发大型项目时, 我们通常会遇到同一工程依赖不同组件包, 同时不同的组件包之间还会相互依赖的问题, 那么如何管理组织这些依赖包就是一个迫在眉睫的问题.
徐小夕
2021/10/14
1.3K0
Setuptools 【Python工具包详解】
setuptools是Python distutils增强版的集合,它可以帮助我们更简单的创建和分发Python包,尤其是拥有依赖关系的。用户在使用setuptools创建的包时,并不需要已安装setuptools,只要一个启动模块即可。
IT茂茂
2020/11/04
1.2K0
Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)
本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客。当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现。Perfect框架是加拿大一个创业团队开发的,目前是Perfect2.0版本,关于Perfect框架,下方会详细的介绍。本篇博客会演示一个完整的Demo, 该Demo完全由Swift3.0开发,其中包括服务端和iOS客户端,数据库采用的是MySQL。 进一步说,本篇博客将会演示一个使用Swift3.0开发的记事本,当然该记事本的服务端和iOS端都是使用
lizelu
2018/01/11
1.6K0
Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)
如何自己写一个公用的NPM包
IMWeb前端团队
2017/12/29
1.8K0
Python包的创建、打包和发布
在这篇文章中,我将向你展示如何创建一个 Python 包,然后将其打包并发布到 Python 包索引(PyPI)上。这是一个非常实用的技能,可以让你的代码更容易被其他人使用和分享。
蚂蚁蚂蚁
2024/03/27
1.1K0
如何发布一个自己的Composer依赖包
Composer是 用PHP开发的用来管理项目依赖的工具,当你在项目中声明了依赖关系后,composer可以自动帮你下载和安装这些依赖库,并实现自动加载代码。
Tinywan
2024/01/02
6180
如何发布一个自己的Composer依赖包
新手如何发布第一个Python项目开源包?
作者以 SciTime 项目(一个对算法训练时间进行估计的包)的发布为例,详细解释了发布的每个步骤。
iOSDevLog
2019/06/15
1.1K0
Python包管理工具setuptools
setuptools是Python distutils增强版的集合,它可以帮助我们更简单的创建和分发Python包,尤其是拥有依赖关系的。用户在使用setuptools创建的包时,并不需要已安装setuptools,只要一个启动模块即可。
周小董
2019/03/25
1.8K0
Flask web项目目录解读
在 Python 中,Flask 项目的目录结构可以根据项目的复杂度和规模有所不同。以下是一个基础的 Flask 项目目录结构示例,适用于中小型web项目:
空洞的盒子
2024/08/09
1.7K1
Sourcery 的 Swift Package 命令行插件
Sourcery 是当下最流行的 Swift 代码生成工具之一。其背后使用了 SwiftSyntax[1],旨在通过自动生成样板代码来节省开发人员的时间。Sourcery 通过扫描一组输入文件,然后借助模板的帮助,自动生成模板中定义的 Swift 代码。
Swift社区
2022/12/12
1.3K0
Vapor奇幻之旅(03上手)
在Vapor奇幻之旅(02部署)一篇中,我介绍了如何在ubuntu上部署并运行vapor项目,这篇文章我来讲讲怎么样来上手开发Vapor项目。
Leacode
2018/08/22
1K0
Vapor奇幻之旅(03上手)
在多包项目中统一管理资源
随着 SPM( Swift Package Manager ) 功能的不断完善,越来越多的开发者开始在他的项目中通过创建多个 Package 的方式来分离功能、管理代码。SPM 本身提供了对包中各类资源( 包括本地化资源 )的管理能力,但主要局限于在本包中使用这些资源,难以将资源进行共享。在有多个 Target 均需调用同一资源的情况下,原有的方式很难应对。本文将介绍一种在拥有多个 SPM 包的项目中,对资源进行统一管理的方法。
东坡肘子
2022/12/16
1.7K0
在多包项目中统一管理资源
将 iOS 应用体积缩小一半的秘籍:妥善运用动态框架
每个开发新手,在编写软件前都听说过这样一条原则:“别自我重复”。但 App Store 上不少体量最大的 iOS 应用却仍在犯下同样的致命错误:不必要地照搬整个模块。
深度学习与Python
2024/04/12
5180
将 iOS 应用体积缩小一半的秘籍:妥善运用动态框架
推荐阅读
相关推荐
Swift 笔记#1 - 10 分钟掌握 Swift Package Manager
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档