• Dubbo3基础使用


    1、Dubbo概述

    现在SpringCloud Alibaba比较火,用的比较多是吧,那dubbo是不是过时的呢? 并不是的,以前有人把Dubbo和SpringCloud进行对比,其实两者是不同维度的,不能对比,dubbo就是一个rpc框架,SpringCloud是一个生态,里面包括很多组件,并且dubbo3也可以和SpringCloudAlibaba一些组件进行整合,并且我认为dubbo和SpringCloud alibaba进行整合后能发挥两个的优势,dubbo的rpc调用的性能会很好,SpringCloudAlibaba服务治理能力很强。微服务中我们经常使用feign,feign是发送http请求而dubbo是rpc,性能要好。我们可以用dubbo代替feign的http请求。并且他作为一个老牌子的分布式框架用的人还是比较多的。

    1.1 什么是分布式系统?

    • 《分布式系统原理与范型》定义:

      • “分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”
      • 分布式系统(distributed system)是建立在网络之上的软件系统。
      • 简单来说:多个(不同职责)人共同来完成一件事!
      • 任何一台服务器都无法满足淘宝的双十一的数据吞吐量,一定是很多台服务器公共来完成的。
    • 歇后语:“三个臭皮匠赛过诸葛亮”,就是分布式系统的真实写照

    1.2 服务架构的演变

    1.2.1 单体架构

    单体架构应该是我们最先接触到的架构实现了,在单体架构中使用经典的三层模型,即表现层,业务逻辑层和数据访问层。

    在这里插入图片描述

    单体架构只适合在应用初期,且访问量比较下的情况下使用,

    优点:

    • 性价比很高
    • 开发速度快
    • 成本低

    缺点:

    • 代码耦合,开发维护困难
    • 无法针对不同模块进行针对性优化
    • 无法水平扩展
    • 单点容错率低,并发能力差

    1.2.2 集群

    针对单个服务器在访问量越来越大的情况越来越吃力的情况,我们可以考虑服务器的集群化处理。

    在这里插入图片描述

    集群的部署大大提高了服务的处理能力,同时利用Nginx提供的负载均衡机制,来分发请求,使用户的体验没有改变。

    1.2.3 垂直拆分

    上面的集群部署是可以解决一部分的服务器压力,但是随着用户访问量的增多,集群节点增加到一定阶段的时候,其实作用就已经不是太大了,因为将所有的业务都集中在一起,造成耦合度很高,这时我们可以考虑业务的拆分。来提高系统的性能。比如将原来在一个系统里面的业务拆分为用户系统,订单系统和商品系统。也就是我们讲的垂直化拆分如下:

    在这里插入图片描述

    服务垂直化拆分后是可以大大的提高整体的服务处理能力,但是也会出现很多的冗余的代码,比如用户系统要操作订单库,要操作商品库,订单系统也有可能要操作用户库和商品库等。

    优点:

    • 系统拆分实现了流量分担,解决了并发问题
    • 可以针对不同模块进行优化
    • 方便水平扩展,负载均衡,容错率提高

    缺点:

    • 系统间相互独立,会有很多重复开发工作,影响开发效率

    1.2.4 分布式服务

    当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式调用是关键。
    在这里插入图片描述

    优点:

    • 将基础服务进行了抽取,系统间相互调用,提高了代码复用和开发效率

    缺点:

    • 系统间耦合度变高,调用关系错综复杂,难以维护

    1.2.5 服务治理(SOA)

    针对垂直化拆分出现的问题,这时就出现了我们经常听到的SOA(面向服务的架构).什么是SOA呢?在《微服务设计》中有这么一段描述

    SOA是一种设计方法,其中包括多个服务,而服务之间通过配合最终会提供一系列功能,一个服务通常以独立的形式存在于操作系统进程中,服务之间通过网络调用,而非采用进程内调用的方式进行通信。
    在这里插入图片描述

    ESB:简单来说ESB就是一根管道,用来连接各个服务节点,为了集成不同的系统,不同协议的服务,ESB要实现消息的转发解释和路由的功能,让不同的服务进行互通

    • 缺点:
      • 每个供应商提供的ESB产品本身有偏差,自身实现起来比较复杂;应用服务多了之后,ESB要去集成所有服务的协议,数据转换和运维部署将变的比较困难,所有服务都是通过一根管道进行通信,直接降低了通信速度。

    1.2.6 微服务化

    微服务架构就是使用一套小服务来开发单体应用的方式或途径,每个服务都是基于单一业务能力构建,运行在自己的进程中,并且使用轻量级的机制进行通信,通常就是HTTP或者RPC,能够通过自动化部署机制来自动部署环境。这些服务可以使用不同的编程语言,不同的数据库存储技术,并保持最低限度的集中式管理。

    在这里插入图片描述

    运维困难: 我们这二三十个服务,二三十个服务对应二三十个服务这样部署

    分布式事务: 商品、交易的等等这些调用会出现调用失败,如果失败就需要回滚,这个是不是就设计到分布式事务了,本地事务就解决不了问题

    定位问题:我们需要定位那个服务出现,并且需要定位具体哪台机器出现问题

    1.3 Dubbo简介

    1.3.1 常见的微服务框架

    • Spring Cloud、Spring Cloud Alibaba
    • Dubbo
    • Thrift (社区活跃度不是很好)

    1.3.2 Dubbo是什么

    • Dubbo是分布式服务框架,是阿里巴巴的开源项目,现交给apache进行维护
    • Dubbo致力于提高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案
    • 简单来说,dubbo是个服务框架,如果没有分布式的需求,是不需要用的、

    1.3.3 里程碑

    里程碑里程碑内容
    2011年10月阿里巴巴完成Dubbo开源
    2012年到2014年Dubbo开源社区蓬勃发展,多个互联网大厂进行封装使用课
    2014年10月Dubbo停止更新
    2017年9月阿里巴巴重启Dubbo的维护和更新
    2018年2月Dubbo进入Apache顶级孵化项目
    2021年3月Dubbo 3.x正式进入发布倒计时

    1.4 Dubbo整体架构

    1.4.1 RPC

    • RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式
    • RPC基本的通信原理
    1. 在客户端将对象进行序列化
    2. 底层通信框架使用netty(基于tcp协议的socket),将序列化的对象发给服务方提供方
    3. 服务提供方通过socket得到数据文件之后,进行反序列化,获得要操作的对象
    4. 对象数据操作完毕,将新的对象序列化,再通过服务提供方的socket返回给客户端
    5. 客户端获得序列化数据,再反序列化,得到最新的数据对象,至此,完成一次

    在这里插入图片描述

    RPC两个核心模块:通讯(socket),序列化

    节点角色说明
    Provider服务的提供方
    Consumer服务的消费方
    Registry服务注册与发现的注册中心
    Monitor监控服务的统计中心
    Container服务运行容器

    1.4.2 Dubbo架构

    在这里插入图片描述
    在这里插入图片描述

    1.服务容器负责启动,加载,运行服务提供者;

    2.服务提供者在启动时,向注册中心注册自己提供的服务;

    3.服务消费者在启动时,向注册中心订阅自己所需的服务;

    4.在注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者;

    5.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用;

    6.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心;

    2、构建Dubbo工程

    2.1 框架依赖

    • Maven
    • SpringBoot 2.6.11
    • Dubbo 3.1.8 + zookeeper 3.4.14

    2.2 搭建Zookeeper

    • 解压
      在这里插入图片描述

    • 修改zk的配置文件

      进入conf,将文件zoo_sample.cfg 改为zoo.cfg
      在这里插入图片描述

    • 测试zk

      启动zookeeper

      执行zookeeper根目录下,bin文件中的zkServer.cmd

    在这里插入图片描述

    上面的CMD窗口不要关闭,这样zookeeper就是出于运行状态了

    2.3 创建工程

    2.3.1 创建父工程

    mdb-dubbo-ann

    父工程控制版本:

    
    
        4.0.0
        
            org.springframework.boot
            spring-boot-starter-parent
            2.6.11
             
        
        
            dubbo-consumer
            dubbo-provider
            dubbo-common
        
        com.msb
        msb-dubbo-ann
        0.0.1-SNAPSHOT
        msb-dubbo-ann
        pom
        Demo project for Spring Boot
    
        
            1.8
            3.1.8
        
        
            
                org.projectlombok
                lombok
            
        
    
        
            
                
                    org.apache.dubbo
                    dubbo-spring-boot-starter
                    ${dubbo-version}
                
                
                    org.apache.dubbo
                    dubbo-rpc-dubbo
                    ${dubbo-version}
                
                
                    org.apache.dubbo
                    dubbo-registry-zookeeper
                    ${dubbo-version}
                
            
        
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    2.3.2 创建提供者

    dubbo-provider

    引入依赖:

    
        org.apache.dubbo
        dubbo-spring-boot-starter
    
    
        org.apache.dubbo
        dubbo-rpc-dubbo
    
    
        org.apache.dubbo
        dubbo-registry-zookeeper
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    增加配置

    server:
      port: 8002
    logging:
      config: classpath:logback.xml
    dubbo:
      application:
        name: dubbo-provider
      protocol:
        name: dubbo
        #客户端链接20880就可以访问我们的dubbo
        port: 20883
      registry:
        address: zookeeper://127.0.0.1:2181
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    更改主类

    import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.ImportResource;
    // 因为是自动装配也可以不加这个注解
    @EnableDubbo(scanBasePackages = "com.msb.dubbo.provider.service")
    @SpringBootApplication
    public class DubboProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(DubboProviderApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    接着增加通信端口

    public interface IUserService {
        User getUserById(Long id);
    }
    
    • 1
    • 2
    • 3
    @Data
    @AllArgsConstructor
    @Builder
    public class User implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private Long id;
        private String name;
        private int age;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    增加实现类

    @DubboService// 定义一个dubbo服务
    public class UserServiceImpl implements IUserService {
        @Override
        public User getUserById(Long id) {
            User user = User.builder().id(id)
                    .age(12)
                    .name("天涯")
                    .build();
            return user;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.3.3 创建客户端

    引入依赖

    
    
        org.apache.dubbo
        dubbo-spring-boot-starter
    
    
    
        org.apache.dubbo
        dubbo-rpc-dubbo
    
    
    
        org.apache.dubbo
        dubbo-registry-zookeeper
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    更改配置

    server:
      port: 8001
    logging:
      config: classpath:logback.xml
    dubbo:
      application:
        name: dubbo-consumer
      registry:
        address: zookeeper://127.0.0.1:2181
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    更改主类

    @EnableDubbo
    @SpringBootApplication
    public class DubboConsumeApplication {
        public static void main(String[] args) {
            SpringApplication.run(DubboConsumeApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    增加调用接口

    public interface IUserService {
        User getUserById(Long id);
    }
    
    • 1
    • 2
    • 3
    @Data
    @AllArgsConstructor
    @Builder
    public class User implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private Long id;
        private String name;
        private int age;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    增加业务调用处理

    @RestController
    public class OrderController {
        @Autowired
        private OrderService orderService;
    
        @RequestMapping("/createOrder/{userId}")
        public String createOrder(@PathVariable("userId") Long userId){
            return orderService.createOrder(userId);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    @Slf4j
    @Service
    public class OrderService {
        // 引用对应的dubbo服务
        @DubboReference
        private IUserService iUserService;
        public String createOrder(Long userId){
            User user = iUserService.getUserById(userId);
            log.info("用户用户信息:{}",user);
            return "创建订单成功";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.3.5 重构创建公共模块

    dubbo-common 存放IUserService 和User

    提供端和消费端

    
        com.msb
        dubbo-common
        0.0.1-SNAPSHOT
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.3.6 测试

    在这里插入图片描述

    2.4 开启rest协议

    如果我们的服务希望既要支持dubbo协议调用,也要能支持http调用,所以,要么仍然保留SpringMVC那一套,如果不想保留那一套,就可以开启 dubbo中的rest协议。

    2.4.1 增加依赖

    
        org.apache.dubbo
        dubbo-rpc-rest
    
    
    • 1
    • 2
    • 3
    • 4

    2.4.2 更改配置

    dubbo:
      application:
        name: dubbo-provider
      # 这里的协议加了s,所以可以设置多个通信协议
      protocols:
        p1:
          name: dubbo
          #客户端链接20883就可以访问我们的dubbo
          port: 20883
        p2:
          name: rest
          #客户端链接20884就可以访问我们的rest
          port: 20884
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.4.3 更改对应代码服务

    @DubboService// 定义一个dubbo服务
    @Path("/user")
    public class UserServiceImpl implements IUserService {
        @GET
        @Path("/{userId}")
        @Produces(MediaType.APPLICATION_JSON)
        @Override
        public User getUserById(@PathParam("userId") Long userId) {
            User user = User.builder().id(userId)
                    .age(12)
                    .name("天涯")
                    .build();
            return user;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.4.4 测试

    在消费端增加RestTemplate

    @EnableDubbo
    @SpringBootApplication
    public class DubboConsumeApplication {
    
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
        public static void main(String[] args) {
            SpringApplication.run(DubboConsumeApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    @Slf4j
    @Service
    public class OrderService {
        @DubboReference
        private IUserService iUserService;
    
        @Autowired
        RestTemplate restTemplate;
        public String createOrder(Long userId){
            User user = restTemplate.getForObject("http://localhost:20884/user/232",User.class);
            log.info("用户用户信息:{}",user);
            return "创建订单成功";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    http://localhost:8001/createOrder/232

    2.4.5 使用接口调用Rest

    将rest协议放到common中

    修改IUserService

    @Path("/user")
    public interface IUserService {
        @GET
        @Path("/{userId}")
        @Produces(MediaType.APPLICATION_JSON)
        User getUserById(@PathParam("userId") Long id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    修改consume里面内容

    @Slf4j
    @Service
    public class OrderService {
        // 指定写协议
        @DubboReference(protocol = "rest")
        private IUserService iUserService;
    
        @Autowired
        RestTemplate restTemplate;
        public String createOrder(Long userId){
            User user = iUserService.getUserById(userId);
            log.info("用户用户信息:{}",user);
            return "创建订单成功";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果我们不能确定是否是走的http,我们可以DispatcherServlet#service 里面打个端点,看是否进入

    3、Tripe协议

    3.1 HTTP1.x协议

    在这里插入图片描述

    POST /user HTTP/1.1                       // 请求行
    Host: www.user.com
    Content-Type: application/x-www-form-urlencoded
    Connection: Keep-Alive
    User-agent: Mozilla/5.0.                  // 以上是请求头
    (此处必须有一空行 |                         // 空行分割header和请求内容 
    name=world                                // 请求体(可选,如get请求时可选)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    它会将上面字符转化为字节流,然后发送给对方,对方解析的时候会根据空格、回车、换行符进行解析

    这里我们可以知道他的请求头比较大,占用空间比较多。

    3.2 Dubbo协议

    在这里插入图片描述

    • Magic - Magic High & Magic Low (16 bits)

      标识协议版本号,Dubbo 协议:0xdabb

    • Req/Res (1 bit)

      标识是请求或响应。请求: 1; 响应: 0。

    • 2 Way (1 bit)

      仅在 Req/Res 为1(请求)时才有用,标记是否期望从服务器返回值。如果需要来自服务器的返回值,则设置为1。

    • Event (1 bit)

      标识是否是事件消息,例如,心跳事件。如果这是一个事件,则设置为1。

    • Serialization ID (5 bit)

      标识序列化类型:比如 fastjson 的值为6。

    • Status (8 bits)

      仅在 Req/Res 为0(响应)时有用,用于标识响应的状态。

      • 20 - OK
      • 30 - CLIENT_TIMEOUT
      • 31 - SERVER_TIMEOUT
      • 40 - BAD_REQUEST
      • 50 - BAD_RESPONSE
      • 60 - SERVICE_NOT_FOUND
      • 70 - SERVICE_ERROR
      • 80 - SERVER_ERROR
      • 90 - CLIENT_ERROR
      • 100 - SERVER_THREADPOOL_EXHAUSTED_ERROR
    • Request ID (64 bits)

      标识唯一请求。类型为long。

    • Data Length (32 bits)

      序列化后的内容长度(可变部分),按字节计数。int类型。

    • Variable Part

      被特定的序列化类型(由序列化 ID 标识)序列化后,每个部分都是一个 byte [] 或者 byte

    dubbo协议在Dubbo框架内使用还是比较舒服的,并且dubbo协议相比于http1.x协议,性能会更好,因为请求中没
    有多余的无用的字节,都是必要的字节,所以dubbo协议成为了Dubbo框架中的默认协议。

    但是dubbo协议一旦涉及到跨RPC框架,比如一个Dubbo服务要调用gPRC服务,就比较麻烦了,因为发一个dubbo
    协议的请求给一个gPRC服务,gPRC服务只会按照gRPC的格式来解析字节流,最终肯定会解析不成功的。

    dubbo协议虽好,但是不够通用,所以这就出现了Triple协议,Triple协议是基于HTTP2,没有性能问题,另外HTTP
    协议非常通用,全世界都认它,兼容起来也比较简单,而且还有很多额外的功能,比如流式调用。

    3.3 Triple 协议

    Triple 协议是 Dubbo3 推出的主力协议。Triple 意为第三代,通过 Dubbo1.0/ Dubbo2.0 两代协议的演进,以及云原生带来的技术标准化浪潮,Dubbo3 新协议 Triple 应运而生。

    3.4 项目改造

    3.4.1 父工程引入依赖版本

    
        org.apache.dubbo
        dubbo-rpc-triple
        ${dubbo-version}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.4.2 服务提供者引入依赖

    
        org.apache.dubbo
        dubbo-rpc-triple
    
    
    • 1
    • 2
    • 3
    • 4

    3.4.3 引入协议

    dubbo:
      application:
        name: dubbo-provider
      protocols:
        p1:
          name: dubbo
          #客户端链接20880就可以访问我们的dubbo  20880 是默认端口
          port: 20883
        p2:
          name: rest
          #客户端链接20884就可以访问我们的rest
          port: 20884
        p3:
          name: tri
          port: 20885
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.4.4 消费方

    引入依赖

    
        org.apache.dubbo
        dubbo-rpc-triple
    
    
    • 1
    • 2
    • 3
    • 4

    调用处更改协议

    @Slf4j
    @Service
    public class OrderService {
    
        @DubboReference(protocol = "tri")
        private IUserService iUserService;
    
        @Autowired
        RestTemplate restTemplate;
        public String createOrder(Long userId){
            User user = iUserService.getUserById(userId);
            log.info("用户用户信息:{}",user);
            return "创建订单成功";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.4.5 测试

    http://localhost:8001/createOrder/232

    3.5 Triple Streaming

    3.5.1 使用场景

    在一些大文件传输、直播等应用场景中, consumer或provider需要跟对端进行大量数据的传输,由于这些情况下的数据量是非常大的,因此是没有办法可以在一个RPC的数据包中进行传输,因此对于这些数据包我们需要对数据包进行分片之后,通过多次RPC调用进行传输,如果我们对这些已经拆分了的RPC数据包进行并行传输,那么到对端后相关的数据包是无序的,需要对接收到的数据进行排序拼接,相关的逻辑会非常复杂。但如果我们对拆分了的RPC数据包进行串行传输,那么对应的网络传输RTT与数据处理的时延会是非常大的。

    为了解决以上的问题,并且为了大量数据的传输以流水线方式在consumer与provider之间传输,因此Streaming RPC的模型应运而生。

    3.5.2 代码实战

    • common中引入jar

      父工程:

      
          org.apache.dubbo
          dubbo-common
          ${dubbo-version}
      
      
      • 1
      • 2
      • 3
      • 4
      • 5

      common中

      
          org.apache.dubbo
          dubbo-common
      
      
      • 1
      • 2
      • 3
      • 4
    • 更改服务端代码

      @Path("/user")
      public interface IUserService {
          // UNARY
          @GET
          @Path("/{userId}")
          @Produces(MediaType.APPLICATION_JSON)
          User getUserById(@PathParam("userId") Long id);
      
          // SERVER_STREAM  服务端流
          default  void sayHelloServerStream(String name, StreamObserver<String> response){
      
          }
      
          // CLIENT_STREAM / BI_STREAM  双端流
          default StreamObserver<String> sayHelloStream(StreamObserver<String> response){
              return response;
          }
      
      
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 服务端流处理

        @DubboService// 定义一个dubbo服务
        public class UserServiceImpl implements IUserService {
            @Override
            public void sayHelloServerStream(String name, StreamObserver<String> response) {
                response.onNext("hello 1");
                response.onNext("hello 2");
                response.onNext("hello 3");
                response.onNext("hello 4");
                response.onCompleted();
        
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        @Service
        public class OrderService {
        
            @DubboReference(protocol = "tri")
            private IUserService iUserService;
            public String createOrder(Long userId){
                iUserService.sayHelloServerStream("李华", new StreamObserver<String>() {
                    @Override
                    public void onNext(String data) {
                        System.out.println("接收到的响应数据:" + data);
                    }
        
                    @Override
                    public void onError(Throwable throwable) {
                        System.err.println("异常处理");
                    }
        
                    @Override
                    public void onCompleted() {
                        System.out.println("响应数据完成");
                    }
                });
                return "创建订单成功";
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
      • 双端流

        @DubboService// 定义一个dubbo服务
        public class UserServiceImpl implements IUserService {
        
            @Override
            public User getUserById(Long userId) {
                User user = User.builder().id(userId)
                        .age(12)
                        .name("天涯")
                        .build();
                return user;
            }
        
            @Override
            public StreamObserver<String> sayHelloStream(StreamObserver<String> response) {
                return new StreamObserver<String>() {
                    @Override
                    public void onNext(String data) {
                        // 接收到客户端发送过来的数据,进行处理,将结果返回
                        try {
                            Thread.sleep(3*1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("接收到客户端数据:" + data);
                        response.onNext("服务端影响:" + data);
                    }
        
                    @Override
                    public void onError(Throwable throwable) {
        
                    }
        
                    @Override
                    public void onCompleted() {
                        System.out.println("服务端处理完毕");
                    }
                };
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
    public class OrderService {
    
        @DubboReference(protocol = "tri")
        private IUserService iUserService;
    
        @Autowired
        RestTemplate restTemplate;
        public String createOrder(Long userId){
    
            StreamObserver streamObserver = iUserService.sayHelloStream(new StreamObserver() {
                @Override
                public void onNext(Object data) {
                    System.out.println("接收到响应数据:" + data);
                }
    
                @Override
                public void onError(Throwable throwable) {
    
                }
    
                @Override
                public void onCompleted() {
                    System.out.println("接收到响应数据完毕");
                }
            });
            streamObserver.onNext("request hello 1");
            streamObserver.onNext("request hello 2");
            streamObserver.onNext("request hello 3");
            streamObserver.onCompleted();
            return "创建订单成功";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    4、dubbo-admin

    4.1下载

    在这里插入图片描述

    4.2 更改配置

    进入application.properties配置文件所在的目录

    dubbo-admin-0.5.0\dubbo-admin-server\src\main\resources\application.properties

    在这里插入图片描述

    设置zk地址

    在这里插入图片描述

    登录时候用户名秘密
    在这里插入图片描述

    更改端口
    在这里插入图片描述

    4.3 进行编译

    mvn clean package
    
    • 1

    在这里插入图片描述

    找到编译后到jar包:

    dubbo-admin-0.5.0\dubbo-admin-distribution\target

    4.4 启动

    jar -jar xxx.jar

    4.5 访问

    localhost:10010

    在这里插入图片描述

    4.6 使用提供jar的注意事项

    注册中心: 127.0.0.1:2181
    端口号: 10010
    用户名/密码: root/root

    5、参数设置

    5.1 版本和分组

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

    使用场景

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

    使用方式

    使用 @DubboService 注解,添加 group 参数和 version 参数 本示例中使用"发布和调用" 中示例代码

    代码处理

    服务端,我们指定组合版本,然后启动两个服务,注意两个服务的端口不能相同

    @DubboService(group = "group1",version = "1.0")// 定义一个dubbo服务
    public class UserServiceImpl implements IUserService {
    
        @Override
        public User getUserById(Long userId) {
            User user = User.builder().id(userId)
                    .age(12)
                    .name("天涯")
                    .build();
            log.info("服务获取用户信息:{}",user);
            return user;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    修改消费端指定版本

    @DubboReference(protocol = "tri",group = "group1",version = "2.0")
    private IUserService iUserService;
    
    • 1
    • 2

    测试,访问只会达到对应的version=“2.0” 的版本

    5.2 启动检查

    启动时会在注册中心检查依赖的服务是否可用,不可用时会抛出异常

    5.3 超时时间

    • 由于网络或服务端不可靠,会导致调用过程中出现不确定的阻塞状态(超时)

    • 为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间

    • 在服务提供者添加如下配置:
      在这里插入图片描述

    • 返回结果
      在这里插入图片描述

    • 配置原则

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

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

    5.4 重试次数

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

    • 在provider提供方配置
      在这里插入图片描述

    • 在consume配置
      在这里插入图片描述

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

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

    备注: 重试是在dubbo协议下重试, tri协议下不会生效, consumer和provider同时设置重试则客户端生效

    • 指定不同方法的重试,这是后我们需要引入xml

    • 增加方法

    • public interface IUserService {
          User getUserById(@PathParam("userId") Long id);
      
          User getUserInfoById(@PathParam("userId") Long id); // 有具体实现类
       }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      
      
      
      
          
          
              
              
          
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      
      
      
      
          
          
              
              
          
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • 这里用Autowired注入

    在这里插入图片描述

    6、过滤器

    6.1 Apache Dubbo Filter介绍

    • Apache Dubbo的Filter与Servlet的Filter功能类似

    • 自定义Filter需要扩展Filter接口

    • 自定义Filter可以通过@Activate注解完成默认开启
      在这里插入图片描述

    • filter 分consumer和provider

    6.2 自定义Filter

    //这里group就是定义提供者还是消费者
    @Activate(group = "provider")
    public class MyFilter implements Filter {
        @Override
        public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
            URL url = invoker.getUrl();
            Class<?> anInterface = invoker.getInterface();
            String simpleName = anInterface.getSimpleName();
            String serviceName = invocation.getServiceName();
            String methodName = invocation.getMethodName();
    
            System.out.println("url = " + url.toFullString());
            System.out.println("simpleName = " + simpleName);
            System.out.println("serviceName = " + serviceName);
            System.out.println("methodName = " + methodName);
            // 调用下一级
            Result result = invoker.invoke(invocation);
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6.3 配置Filter

    创建目录
    在这里插入图片描述

    然后在里面创建接口文件
    在这里插入图片描述

    文件内容:对应实现类的全路径
    在这里插入图片描述

    6.4 访问

    在这里插入图片描述

    7、上下文参数传递

    7.1 使用场景

    1、Dubbo系统间调用时,想传递一些通用参数,可通过Dubbo提供的扩展如Filter等实现统一的参数传递

    2、Dubbo系统间调用时,想传递接口定义之外的参数,可在调用接口前使用setAttachment传递参数。

    7.2 实战使用

    客户端代码:

    package com.msb.dubbo.consumer.filters;
    
    import org.apache.dubbo.common.extension.Activate;
    import org.apache.dubbo.rpc.*;
    
    @Activate(group = "consumer")
    public class ConsumerContextFilter implements Filter {
       
       
       @Override
       public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
       
          Result result = null;
          RpcContext.getClientAttachment()
                .setAttachment("xid","1111111111111");
          try {
             //执行业务逻辑
             result = invoker.invoke(invocation);
    
          }finally {
             //清理
             RpcContext.getClientAttachment().clearAttachments();
          }
          return result;
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    客户端配置

    在这里插入图片描述

    服务端代码

    package com.msb.dubbo.provider.filter;
    
    import com.alibaba.fastjson.JSON;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.dubbo.common.extension.Activate;
    import org.apache.dubbo.rpc.*;
    
    import java.util.Map;
    
    @Slf4j
    @Activate(group = "provider")
    public class ProviderContextFilter implements Filter {
       
       
       @Override
       public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
           //ServerAttachment接收客户端传递过来的参数
          Map<String, Object> serverAttachments = RpcContext.getServerAttachment().getObjectAttachments();
          log.info("ContextService serverAttachments:" + JSON.toJSONString(serverAttachments));
    
    
          String xid = (String)serverAttachments.get("xid");
          log.info("获取传递数据xid:{}",xid);
          //执行业务逻辑
          Result result = invoker.invoke(invocation);
    
          return result;
       }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    服务端配置

    在这里插入图片描述

    8、Dubbo 工程XML配置

    8.1 创建父工程

    更改pom

    
    
        4.0.0
        
            dubbo-provider
            dubbo-consumer
            dubbo-common
        
        
            org.springframework.boot
            spring-boot-starter-parent
            2.5.0
             
        
        com.msb
        msb-dubbo-xml
        0.0.1-SNAPSHOT
        msb-dubbo-xml
        pom
        dubbo学习实例
        
            1.8
            3.1.8
        
        
            
                org.projectlombok
                lombok
            
        
        
            
                
                    org.apache.dubbo
                    dubbo-spring-boot-starter
                    ${dubbo-version}
                
                
                    org.apache.dubbo
                    dubbo-rpc-dubbo
                    ${dubbo-version}
                
                
                    org.apache.dubbo
                    dubbo-rpc-rest
                    ${dubbo-version}
                
                
                    org.apache.dubbo
                    dubbo-rpc-triple
                    ${dubbo-version}
                
                
                    org.apache.dubbo
                    dubbo-common
                    ${dubbo-version}
                
                
                    org.apache.dubbo
                    dubbo-registry-zookeeper
                    ${dubbo-version}
                
            
        
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    8.2 创建Provider

    引入依赖

    
        org.apache.dubbo
        dubbo-spring-boot-starter
    
    
        org.apache.dubbo
        dubbo-rpc-dubbo
    
    
        org.apache.dubbo
        dubbo-registry-zookeeper
    
    
        org.springframework.boot
        spring-boot-starter
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    application.yml配置

    server:
      port: 8001
    logging:
      config: classpath:logback.xml
    
    • 1
    • 2
    • 3
    • 4

    applicationContext-dubbo.xml

    
    
    
        
        
    
        
        
        
    
        
        
        
    
       
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    主类配置

    @ImportResource(locations = {"classpath:applicationContext-dubbo.xml"})
    @SpringBootApplication
    public class DubboProviderApplication {
        public static void main(String[] args) {
            SpringApplication.run(DubboProviderApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    服务实现

    @Slf4j
    public class HelloServiceImpl implements HelloServiceAPI {
        @Override
        public String sayHello(String message) {
    
            log.info("接收到消息:{}",message );
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "生产者接收到数据:" + message;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    dubbo-common工程以及接口创建

    public interface HelloServiceAPI {
        String sayHello(String message);
    }
    
    • 1
    • 2
    • 3

    更改applicationContext-dubbo.xml

     
    
    • 1

    8.3 创建Consumer

    创建工程引入依赖

    
        org.springframework.boot
        spring-boot-starter-web
    
    
        com.msb
        dubbo-common
        0.0.2-SNAPSHOT
    
    
    
        org.apache.dubbo
        dubbo-spring-boot-starter
    
    
    
        org.apache.dubbo
        dubbo-rpc-dubbo
    
    
    
        org.apache.dubbo
        dubbo-registry-zookeeper
    
    
        org.springframework.boot
        spring-boot-starter
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    application.yml配置

    server:
      port: 8002
    logging:
      config: classpath:logback.xml
    
    • 1
    • 2
    • 3
    • 4

    applicationContext-dubbo.xml配置

    
    
    
        
        
    
        
        
    
        
        
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    主类创建

    @ImportResource(locations = {"classpath:applicationContext-dubbo.xml"})
    @SpringBootApplication
    public class DubboConsumeApplication {
        public static void main(String[] args) {
            SpringApplication.run(DubboConsumeApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    业务逻辑

    @RestController
    public class HelloController {
        @Autowired
        private HelloServiceAPI helloServiceAPI;
        @GetMapping("/sayHello")
        public String sayHelle(){
            return helloServiceAPI.sayHello("hello everyBody");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    8.4 测试

    http://localhost:8002/sayHello

  • 相关阅读:
    list根据对象中某个字段属性去重Java流实现
    帝国cms判断隐藏字段值为空的内容信息,列表空白分页不显示怎么弄
    数据库设计步骤
    在pycharm中通过ctrl进入调用函数,如何返回到原函数
    React核心概念
    Node 入门
    ORM多表外键字段的操作
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    java-File类
    docker基本概念与部署和基础命令
  • 原文地址:https://blog.csdn.net/qq_37892401/article/details/132942816