Dubbo 配置实战

快速入门 dubbo

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

配置说明

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

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

1 启动时检查

  • 启动时会在注册中心检查依赖的服务是否可用,不可用时会抛出异常
  • 在消费方编写初始化容器的 main 方法启动(tomcat 启动方式,必须访问一次 action 才能初始化

    spring)
  • 想想为什么要有这个配置呢?
    • 可以提前发现服务提供方是否可用
示例代码

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

  • 我这里测试,现在是没有启动提供者
  • 因为我们测试的目的就是让他没有提供者,会不会有报错提示
/**
* @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,内容如下:
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 配置文件中加上就不会有异常提示了

  • 可以看到,我这里的这个配置是注释掉的,在实际开发中我们是需要这个异常提示的,不推荐关闭
<!--默认是true:抛异常;false:不抛异常-->
<dubbo:consumer check="false" />

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


2 超时时间

  • 由于网络或服务端不可靠,会导致调用过程中出现不确定的阻塞状态(超时)
  • 为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间
  • 在服务提供者添加如下配置:
<!--设置超时时间为2秒,默认为1秒-->
<dubbo:provider timeout="2000"/>
  • 可以将服务实现 HelloServiceImpl.java 中加入模拟的网络延迟进行测试:
@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 提供方配置:
<!-- 消费方连接第1次不算,再来重试3次,总共重试4次 -->
<dubbo:provider timeout="2000" retries="3"/>

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

@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 次 第一次不算

引入问题

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

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

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

  • 需要再添加一个方法,作对比
  1. 提供方接口添加 sayNo()方法并实现
public interface HelloService {
String sayHello(String name);
String no();
}
@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()方法声明
public interface HelloService {
String sayHello(String name);
String no();
}
  1. 消费方 controller
@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. 消费方配置方法重试次数
    <dubbo:reference interface="service.HelloService" id="helloService">
<dubbo:method name="sayHello" retries="3"/>
<dubbo:method name="no" retries="0"/>
</dubbo:reference>

启动项目,访问

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


4 多版本

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

为 HelloService 定义了两个版本

    <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 接口

注意:必须使用构造方法的方式注入

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();
}
}
修改消费者配置文件
  • 添加的是红框位置的参数

    <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项目 然后打包启动

负载均衡策略

  • 负载均衡(Load Balance), 其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作

    任务。
  • 简单的说,好多台服务器,不能总是让一台服务器干活,应该“雨露均沾”
  • dubbo 一共提供 4 种策略,缺省为 random 随机分配调用

示例代码
  • 修改提供者配置并启动 3 个提供者,让消费者对其进行访问

    • tomcat 端口 8001,8002,8003
    • provider 端口 20881,20882,20883
<dubbo:provider timeout="2000" retries="3" port="20881"/>

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

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

启动 consumer 进行测试

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

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

消费方修改权重

loadbalance 取值文章

    <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 值,不抛异

    常。用来容忍不重要服务不稳定时对调用方的影响。

10 Dubbo 配置实战的更多相关文章

  1. PHP-5.5.10+Apache httpd-2.4.9在Windows系统下配置实战

    原文 PHP-5.5.10+Apache httpd-2.4.9在Windows系统下配置实战 环境配置:   程序准备: PHP windows版本下载地址: http://windows.php. ...

  2. 深入浅出 SSL 管理配置实战

    我们生活在一个信息大爆炸的时代,几乎每天都在和互联网打交道,购物.网银转账.支付宝付款.搜索信息.查看邮件.观看视频.微信聊天.上网冲浪.阅读新闻等,无不时时刻刻在和网络打交道.那如何保护网络安全就相 ...

  3. DUBBO配置规则详解

    研究DUBBO也已经大半年了,对它的大部分源码进行了分析,以及对它的内部机制有了比较深入的了解,以及各个模块的实现.DUBBO包含很多内容,如果想了解DUBBO第一步就是启动它,从而可以很好的使用它, ...

  4. dubbo配置清单-超详细版

    服务发布者 在服务发布者的springboot主配置文件application.properties中添加dubbo配置 #dubbo服务名 spring.dubbo.application.name ...

  5. dubbo配置指南

    dubbo配置指南 SLA配置在此完成!Service Layer Agreement ApplicationConfig 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者. Regist ...

  6. zabbix proxy配置实战案例

    zabbix proxy配置实战案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.zabbix proxy概述 上一篇博客我们分享了zabbix agent有两种工作模式,即 ...

  7. Sentry 监控 - Snuba 数据中台本地开发环境配置实战

    系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...

  8. kafka0.9.0及0.10.0配置属性

    问题导读1.borker包含哪些属性?2.Producer包含哪些属性?3.Consumer如何配置?borker(0.9.0及0.10.0)配置Kafka日志本身是由多个日志段组成(log segm ...

  9. suse linux 10 下配置vpn服务器(pptp)

     一.安装所需的软件包:      pptpd-*.rpm      ppp-*.rpm      pptp-*.rpm     一般情况下系统已经将pptp和ppp包安装好了,所以只需安装pptpd ...

随机推荐

  1. ONNXRuntime学习笔记(四)

    接上一篇在Python端的onnx模型验证结果,上一篇在Pytorch和onnxruntime-gpu推理库上分别进行效果效率统计分析,结论要比最初设置的50ms高很多,这一篇我将在C++端写个测试代 ...

  2. .NET ORM 仓储层必备的功能介绍之 FreeSql Repository 实现篇

    写在开头 2018年11月的某一天,头脑发热开启了 FreeSql 开源项目之旅,时间一晃已经四年多,当初从舒服区走向一个巨大的坑,回头一看后背一凉.四年时间从无到有,经历了数不清的日夜奋战(有人问我 ...

  3. Java学习笔记-基础语法Ⅶ-集合

    集合 集合类特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变 这里需要回顾一下,因为数组和字符串一旦创建,就不可改变,需要区分一下 import java.util.ArrayLi ...

  4. Go内存管理一文足矣

    最早学习C.C++语言时,它们都是把内存的管理全部交给开发者,这种方式最灵活但是也最容易出问题,对人员要求极高:后来出现的一些高级语言像Java.JavaScript.C#.Go,都有语言自身解决了内 ...

  5. 【多线程】创建线程方式二:实现Runnable接口

    创建线程方式二:实现Runnable接口 代码示例: /** * @Description 实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口实现类,调用start方法 * ...

  6. Python写安全小工具-TCP全连接端口扫描器

    通过端口扫描我们可以知道目标主机都开放了哪些服务,下面通过TCP connect来实现一个TCP全连接端口扫描器. 一个简单的端口扫描器 #!/usr/bin/python3 # -*- coding ...

  7. Python技法:用argparse模块解析命令行选项

    1. 用argparse模块解析命令行选项 我们在上一篇博客<Linux:可执行程序的Shell传参格式规范>中介绍了Linux系统Shell命令行下可执行程序应该遵守的传参规范(包括了各 ...

  8. 每天一个 HTTP 状态码 101

    101 Switching Protocols 当客户端的请求具有 Upgrade HTTP 首部,表示要求服务器切换到指定协议:此时服务器端就可以向客户端响应 101 Switching Proto ...

  9. CenterNet训练时黑白图片不能画框的问题

    解决CenterNet在detect.py中不能画框的问题 在第centernet.py的第198行的中加上这一行 image = image.convert('RGB')

  10. [NOI2011]阿狸打字机

    题意:一开始是个空串s,有三种操作:(1.末尾加一个字符 2.末尾减一个字符 3.存储该字符串) 思路: 一开始在trie树上动态加点很好处理,3操作的时候记录一下此时trie树上的pos,同时记录d ...