系统级别日志,需要配合log4j才输出,在resources下添加log4j.propertie..._dubbo @method">
当前位置:   article > 正文

Dubbo综合实战_dubbo @method

dubbo @method

Dubbo综合实战

1、 配置说明

1.1 启动时检查

  •  启动时会在注册中心检查依赖的服务是否可用,不可用时会抛出异常
  • 在消费方编写初始化容器的main方法启动(tomcat启动方式,必须访问一次action才能初始化 spring)
     
    1. <!--默认为true:抛异常 -->
    2. <dubbo:consumer check="false"/>

     
  • 系统级别日志,需要配合log4j才输出,在resources下添加log4j.properties,内容如下:
    1. log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    2. log4j.appender.stdout.Target=System.out
    3. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    4. log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
    5. log4j.appender.file=org.apache.log4j.FileAppender
    6. log4j.appender.file.File=dubbo.log
    7. log4j.appender.file.layout=org.apache.log4j.PatternLayout
    8. log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n
    9. log4j.rootLogger=error, stdout,file

1.2 超时时间

  • 由于网络或服务端不可靠,会导致调用过程中出现不确定的阻塞状态(超时)
  • 为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间
  • 在服务提供者添加如下配置:
     
    1. <!--设置超时时间为2秒,默认为1秒-->
    2. <dubbo:provider timeout="2000"/>
    1. @Service
    2. public class HelloServiceImpl implements HelloService {
    3. @Override
    4. public String sayHello(String name) {
    5. System.out.println("==========被调用了1次========");
    6. try {
    7. TimeUnit.SECONDS.sleep(3); //模拟网络延迟
    8. } catch (InterruptedException e) {
    9. e.printStackTrace();
    10. }
    11. return "Hello,"+name+"!!!!";
    12. }
    13. }

  • 可以将服务实现HelloServiceImpl.java中加入模拟的网络延迟进行测试

     
  • 超时设置2秒,而模拟的网络延迟有3秒,超出时限,报错!
  • 配置原则:
     

    dubbo推荐在Provider上尽量多配置Consumer端属性:
    1、作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
    2、在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作消费者的缺省值。

1.3 重试次数

  • 当出现失败,自动切换并重试其它服务器,dubbo重试的缺省值是2次,我们可以自行设置
  • 在provider提供方配置:

     
    1. <!-- 消费方连接第1次不算,再来重试3次,总共重试4次 -->
    2. <dubbo:provider timeout="2000" retries="3"/>
    1. @Service
    2. public class HelloServiceImpl implements HelloService {
    3. @Override
    4. public String sayHello(String name) {
    5. System.out.println("==========被调用了1次========");
    6. try {
    7. TimeUnit.SECONDS.sleep(3); //模拟网络延迟
    8. } catch (InterruptedException e) {
    9. e.printStackTrace();
    10. }
    11. return "Hello,"+name+"!!!!";
    12. }
    13. }

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

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

        非幂等方法:不适合(当参数一样,执行结果不一样,例如:删除,添加)
        

  • 单独设置某个方法

    1、提供方接口添加sayNo()方法并实现
     
    1. public interface HelloService {
    2. String sayHello(String name);
    3. String sayNo();
    4. }

    1. @Override
    2. public String sayNo() {
    3. System.out.println("====no 被调用===");
    4. try {
    5. TimeUnit.SECONDS.sleep(3); //模拟网络延迟
    6. } catch (InterruptedException e) {
    7. e.printStackTrace();
    8. }
    9. return "no";
    10. }


    2. 消费方接口添加sayNo()方法声明
     
    1. public interface HelloService {
    2. String sayHello(String name);
    3. String sayNo();
    4. }

    3. 消费方controller
     
    1. @RestController
    2. public class HelloController {
    3. @Reference
    4. private HelloService helloService;
    5. @GetMapping("/hello")
    6. public String sayHi(String name){
    7. return helloService.sayHello(name);
    8. }
    9. @GetMapping("/no")
    10. public String no(){
    11. return helloService.sayNo();
    12. }
    13. }


    4. 消费方配置方法重试次数
    1. <dubbo:reference interface="com.lagou.service.HelloService" id="helloService">
    2. <dubbo:method name="sayHello" retries="3"></dubbo:method> <!--重试3次 执行四次方法-->
    3. <dubbo:method name="sayNo" retries="0"></dubbo:method> <!--不重试 执行一次方法-->
    4. </dubbo:reference>

1.4 多版本

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

     
    1. <dubbo:service interface="com.lagou.service.HelloService"
    2. class="com.lagou.service.impl.HelloServiceImpl01" version="1.0.0"/>
    3. <dubbo:service interface="com.lagou.service.HelloService"
    4. class="com.lagou.service.impl.HelloServiceImpl02" version="2.0.0"/>

     
  • 消费者就可以根据version的版本,选择具体的服务版本
     
    1. <dubbo:reference interface="com.lagou.service.HelloService" id="helloService" version="1.0.0">
    2. <dubbo:method name="sayHello" retries="3"></dubbo:method> <!--重试3次 执行四次方法-->
    3. <dubbo:method name="sayNo" retries="0"></dubbo:method> <!--不重试 执行一次方法-->
    4. </dubbo:reference>

     
  • 注意:消费者的控制层要改为自动注入,因为@Reference注解和 在这里冲突
     
    1. @RestController
    2. public class HelloController {
    3. // @Reference
    4. @Autowired
    5. private HelloService helloService;
    6. }

     
  • 当消费者的版本修改为 version="*",那么就会随机调用服务提供者的版本
    1. v1.0 ====no 被调用===
    2. v1.0 ====no 被调用===
    3. v1.0 ====no 被调用===
    4. v2.0 ==========被调用了1========
    5. v1.0 ==========被调用了1========
    6. v2.0 ==========被调用了1========

 4.1.5 本地存根

  • 目前我们的分布式架构搭建起来有一个严重的问题,就是所有的操作全都是 消费者发起,由服务 提供者执行
  • 消费者动动嘴皮子却什么活都不干,这样会让提供者很累,例如简单的参数验证,消费者完全能够 胜任,把合法的参数再发送给提供者执行,效率高了,提供者也没那么累了
  • 例如:去房产局办理房屋过户,请带好自己的证件和资料,如果什么都不带,那么办理过户手续会 很麻烦,得先调查你有什么贷款,有没有抵押,不动产证是不是你本人,复印资料等操作。一天肯 定办不完。明天还要来。如果你能提前将这些东西准备好,办理过户,1个小时足矣,这就是“房产 中介办事效率高的原因”
  • 话不多说,先在消费者处理一些业务逻辑,再调用提供者的过程,就是“本地存根”
  • 代码实现肯定在 消费者,创建一个HelloServiceStub类并且实现HelloService接口
  • 注意:必须使用构造方法的方式注入
  1. package com.lagou.stub;
  2. import com.lagou.service.HelloService;
  3. /**
  4. * @Author panghl
  5. * @Date 2021/7/18 12:45
  6. * @Description 本地存根
  7. **/
  8. public class HelloServiceStub implements HelloService {
  9. private HelloService helloService;
  10. //本地存根必须以构造方法的形式
  11. public HelloServiceStub(HelloService helloService) {
  12. this.helloService = helloService;
  13. }
  14. @Override
  15. public String sayHello(String name) {
  16. if (name == null || "".equals(name)) {
  17. return "i am sorry";
  18. }
  19. return helloService.sayHello(name);
  20. }
  21. @Override
  22. public String sayNo() {
  23. return helloService.sayNo();
  24. }
  25. }
  • 修改消费者配置:
  1. <dubbo:reference interface="com.lagou.service.HelloService" id="helloService"
  2. version="*"
  3. stub="com.lagou.stub.HelloServiceStub">
  4. <dubbo:method name="sayHello" retries="3"></dubbo:method> <!--重试3次 执行四次方法-->
  5. <dubbo:method name="sayNo" retries="0"></dubbo:method> <!--不重试 执行一次方法-->
  6. </dubbo:reference>

2、  负载均衡策略

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

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

                tomcat端口8001,8002,8003

                provider端口20881,20882,20883

<dubbo:provider timeout="2000" retries="3" port="20881"/>
  • HelloServiceImpl01类,服务器1,服务器2,服务器3
  1. public String sayNo() {
  2. System.out.println("----服务器1---1.0被调用一次-------");
  3. return "no!";
  4. }
  • 消费方修改权重
    1. <dubbo:reference loadbalance="roundrobin" interface="service.HelloService"
    2. id="helloService" version="2.0.0" stub="stub.HelloServiceStub">
    3. <dubbo:method name="sayHello" retries="3"/>
    4. <dubbo:method name="sayNo" retries="0"/>
    5. </dubbo:reference>

  • 最好使用管理端修改权重

 3、高可用

zookeeper宕机

zookeeper注册中心宕机,还可以消费dubbo暴露的服务

        监控中心宕掉不影响使用,只是丢失部分采样数据

        数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务

        注册中心对等集群,任意一台宕掉后,将自动切换到另一台

        注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯

        服务提供者无状态,任意一台宕掉后,不影响使用

        服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

测试:

        正常发出请求

        关闭zookeeper:./zkServer.sh stop

        消费者仍然可以正常消费

4、 服务降级

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

1 为什么要服务降级

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

2 服务降级实现方式

  • 管理控制台配置服务降级:屏蔽和容错
  • 屏蔽:mock=force:return+null 表示消费方对该服务的方法调用都 直接返回 null 值,不发起远程 调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • 容错:mock=fail:return+null 表示消费方对该服务的方法调用在 失败后,再返回 null 值,不抛异 常。用来容忍不重要服务不稳定时对调用方的影响。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/165857
推荐阅读
相关标签
  

闽ICP备14008679号