当前位置: 首页 > news >正文

(一)Dubbo快速入门、介绍、使用

1、介绍

Dubbo官方文档:https://dubbo.apache.org/zh

目前Dubbo最新的是Dubbo3。

Dubbo3 格式的 Provider 地址不能被 Dubbo2 的 Consumer 识别到,反之 Dubbo2 的消费者也不能订阅到 Dubbo3 Provider。

这里的架构和使用都是基于Dubbo2.7 版本,Dubbo2(2.7以下)和Dubbo3两个版本的注解有区别。

Registry是注册中心,用于发现服务者和消费者。

注册中心可以选择 zookeeper、consul、nacos,推荐使用zookeeper。

dubboRPC通信的原理:

img

2、架构

Dubbo三大组件:

  • 注册中心。协调 Consumer 与 Provider 之间的地址注册与发现
  • 配置中心。
    • 存储 Dubbo 启动阶段的全局配置,保证配置的跨环境共享与全局一致性
    • 负责服务治理规则(路由规则、动态配置等)的存储与推送。
  • 元数据中心。
    • 接收 Provider 上报的服务接口元数据,为 Admin 等控制台提供运维能力(如服务测试、接口文档等)
    • 作为服务发现机制的补充,提供额外的接口/方法级别配置信息的同步能力,相当于注册中心的额外扩展

以上三个中心并不是运行 Dubbo 的必要条件,用户完全可以根据自身业务情况决定只启用其中一个或多个,以达到简化部署的目的。

通常情况下,所有用户都会以独立的注册中心 开始 Dubbo 服务开发,而配置中心、元数据中心则会在微服务演进的过程中逐步的按需被引入进来。

3、使用

依赖:(推荐使用2.7.13版本)

普通项目集成:

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.7.13</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-dependencies-zookeeper</artifactId>
    <version>2.7.13</version>
</dependency>

springboot与dubbo集成:

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.13</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-registry-zookeeper</artifactId>
    <version>2.7.13</version>
</dependency>

3.1、spring.xml配置

1、服务端

在服务提供方实现接口(对服务消费方隐藏实现):

spring-provider.xml :

<!--注意:配置集群的情况下需要同一集群的name值相同-->
<dubbo:application name="demo-provider" />
<!-- 使用zookeeper注册中心暴露服务地址 --> 
<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181" />
<!--实际项目中使用properties文件的形式定义zookeeper的地址 -->
<!-- <dubbo:registry protocol="zookeeper" address="${zookeeper.address}"  check="false" file="dubbo.properties" /> -->


<dubbo:provider token="true" />
<!-- beanId -->
<bean id="demoService" class="org.apache.dubbo.samples.basic.impl.DemoServiceImpl"/>

<!--用 Spring 配置声明暴露服务,ref="demoService" 是 beanId,必填 -->
<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService" />
 <!--使用dubbo协议,声明服务的端口-->
<dubbo:protocol name="dubbo" port="20898"/>

一般来说,我们会把 beanId 交给 spring 去管理只需要在 xml 里面声明扫描包,然后使用 @Service 声明实现类 即可:

<context:component-scan base-package="org.apache.dubbo.samples.basic.impl"/>

2、客户端

spring-consumer.xml:

<dubbo:application name="demo-consumer"/>

<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
<!-- 服务方引用的beanId -->
<dubbo:reference id="demoService" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService"/>

3.2、springboot配置

1、服务端

上面例子的 spring-provider.xml 换成 properties 文件的写法是这样的:

# 应用名
dubbo.application.name=demo-provider
# 注册中心地址
dubbo.registry.address=zookeeper://localhost:2181
# 调用协议地址
dubbo.protocol.name=dubbo
dubbo.protocol.port=28080
#开启包扫描,可替代 @EnableDubbo 注解
#dubbo.scan.base-packages=com.meizui.quickgame

开启基于注解的dubbo功能(主要是包扫描@DubboComponentScan):

// 开启基于注解的dubbo功能(主要是包扫描@DubboComponentScan)
// 也可以在配置文件中使用dubbo.scan.base-package来替代@EnableDubbo
@EnableDubbo(scanBasePackages = {"com.meizui.quickgame"})
@SpringBootApplication
public class UserServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceProviderApplication.class, args);
    }
}

2、客户端

# 应用名
dubbo.application.name=demo-consumer
# 注册中心地址
dubbo.registry.address=zookeeper://localhost:2181
dubbo.consumer.timeout=1000

使用例子1:

dubbo和spring可以完美结合,只需要在spring配置文件声明即可。

provider:

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-provider.xml");
        context.start();
        new CountDownLatch(1).await();
    }

consumer:

public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-demo-consumer.xml");
        context.start();
        DemoService demoService = (DemoService) context.getBean("demoService");
        String hello = demoService.sayHello("world");
}

使用例子2:

这里展示注解的方式,需要声明@EnableDubbo

provider:

@DubboService(version = "1.0.0")
public class UserServiceImpl implements UserService{
    
}

consumer:

@DubboReference(version = "*", protocol = "dubbo,hessian", loadbalance = "random" )
private UserService userService;

4、其他

4.1、负载均衡:

xml:

服务端级别:

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService" loadbalance="roundrobin" timeout="5000"/>

服务端方法级别:

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService" timeout="5000">
	<dubbo:method name="sayHello" loadbalance="roundrobin"/>
</dubbo:service>

客户端级别:

<dubbo:reference id="demoService" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService" loadbalance="roundrobin"/>

客户端方法级别:

<dubbo:reference id="demoService" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService">
	<dubbo:method name="sayHello" loadbalance="roundrobin"/>
</dubbo:reference>

当多个provider注册到zk,consumer会选择指定的负载均衡算法自动请求,遇到上线或者下线会重新计算。

常见有四种负载均衡:

  • random

随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

  • roundRobin (默认)

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

  • leastActive

最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

  • consistentHash

一致性Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者,不会引起剧烈变动

4.2多协议:

dubbo支持多种协议:

  • dubbo
  • hessian
  • http
  • rmi
  • webservice
  • thrift
  • memcached
  • redis

不同服务不同协议

不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议

<?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> 
    <dubbo:application name="world"  />
    <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
    <!-- 多协议配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="rmi" port="1099" />
    <!-- 使用dubbo协议暴露服务 -->
    <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
    <!-- 使用rmi协议暴露服务 -->
    <dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" /> 
</beans>

多协议暴露服务

需要与 http 客户端相互操作

<?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://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:application name="world"  />
    <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
    <!-- 多协议配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="hessian" port="8080" />
    <!-- 使用多个协议暴露服务 -->
    <dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />
</beans>

4.3、多注册中心

两个不同注册中心,使用竖号分隔多个不同注册中心地址:

<!-- 多注册中心配置,竖号分隔表示同时连接多个不同注册中心,同一注册中心的多个集群地址用逗号分隔 -->
<dubbo:registry address="10.20.141.150:9090|10.20.154.177:9010" />
<!-- 引用服务 -->
<dubbo:reference id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" />

不同服务使用不同注册中心:

<!-- 多注册中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<!-- 向中文站注册中心注册 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" />
<!-- 向国际站注册中心注册 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />

还可以这样:

<!-- 多注册中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
<!-- 引用中文站服务 -->
<dubbo:reference id="chinaHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="chinaRegistry" />
<!-- 引用国际站站服务 -->
<dubbo:reference id="intlHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="intlRegistry" />

4.4、超时、重试

超时默认重试 1000ms

重试默认重试2次,不算第一个调用,一共会调用三次

如服务方设置:

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService2" loadbalance="roundrobin" timeout="500" retries="1"/>

注意,本人测试了一下,虽然服务方设置重试次数为1,消费者默认,最终结果还是会重试2次(消费者默认值),所以服务方提供的重试次数无效,建议在消费者设置,但是超时时间是生效的。

超时、重试建议在消费者设置:

<dubbo:reference id="demoService01" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService"
        retries="1" timeout="3000"/>

4.5、分组

当一个接口有多种实现时,可以用 group 区分。

provider.xml

    <dubbo:service id="groupADubboService" group="groupA" interface="org.apache.dubbo.samples.group.api.GroupService"
                   ref="groupAService"/>

    <dubbo:service id="groupBDubboService" group="groupB" interface="org.apache.dubbo.samples.group.api.GroupService"
                   ref="groupBService"/>

consumer.xml

<!-- * 表示 任意组-->
<dubbo:reference group="*" id="groupAService" check="false"
                     interface="org.apache.dubbo.samples.group.api.GroupService" />
<!-- 调用groupB接口 -->
    <!--<dubbo:reference group="groupB" id="groupBService" check="false"-->
                     <!--interface="org.apache.dubbo.samples.group.api.GroupService"/>-->

group="*"group="groupA,groupB" 是一样的效果,但总是只调一个可用组的实现。(不能实现负载均衡)

这里有个坑,reference group=“*” ,consumer在启动的时候已经选好了分组,并不是轮询两个分组

如果你要使用group进行负载均衡,consumer就不要写group

4.6、版本

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />


<dubbo:service interface="com.foo.BarService" version="1.0.0" />

consumer 设置 version=“*” 可以 轮询 调用provider,而group不能,这是和group的最大区别

4.6、直连模式

直连模式一般应用于测试模式。

消费者:

<dubbo:registry id="na" address="N/A" />
<!--使用直连的方式,不需要注册中心 这里的check表示开启token-->
<dubbo:reference id="demoService01" check="true" interface="org.apache.dubbo.samples.basic.api.DemoService"
url="dubbo://172.16.44.48:20897"
protocol="dubbo" registry="na"
timeout="3000"
retries="3"
/>

服务方不需要修改,如果开启了token验证,需要在<dubbo:provider> 或者 <dubbo:service>声明:

<dubbo:registry id="default" address="zookeeper://${zookeeper.address:127.0.0.1}:2181" />    
<!--使用dubbo协议,声明服务的端口-->
<dubbo:protocol id="dubbo1" name="dubbo" port="20897" />
<dubbo:protocol id="dubbo2" name="dubbo" port="20898"/>
<dubbo:provider token="123456" registry="default">
    <!--用 Spring 配置声明暴露服务 ref 的 值要等 beanId 的 值-->
    <dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService02" loadbalance="roundrobin"
                   timeout="5000" retries="1" protocol="dubbo1"/>
</dubbo:provider>

消费者需要携带token:

RpcContext.getContext().setAttachment("token","123456");

如果不需要token验证,设置成 false 即可

5、不同协议的区别

duboo3.0 的默认协议是 dubbo,较2.0版本来说是一个新的协议(官方称为triple)

dubbo

rmi

hessian

http

webservice

thrift

传输协议

TCP

TCP

HTTP

HTTP

HTTP

thrif

传输方式

NIO异步传输

同步

同步

同步

同步

同步、异步

序列化

Hessian二进制序列化

Java标准二进制序列化

Hessian二进制序列化

表单序列化

SOAP文本序列化

Thrift

适用范围

传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要使用dubbo协议传输大文件或超大字符串

传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。

传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件。

传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。

系统集成,跨语言调用。

跨语言

约束

参数及返回值需实现Serializable接口

参数及返回值需实现Serializable接口

参数及返回值需实现Serializable接口

不能在协议中传递null值

dubbo 有多种协议,不同的协议默认使用不同的序列化框架。比如:

dubbo 协议 默认使用 Hessian2 序列化。(说明:Hessian2 是阿里在 Hessian 基础上进行的二次开发,起名为Hessian2 )
rmi协议 默认为 java 原生序列化,

http 协议 默认为 为 json 。

hessian 协议,默认是 hessian 序列化;

webservice 协议,默认是 soap 文本序列化 。

6、注意事项(TODO )

1、使用了dubbo2.7.13 版本,thrift 协议 的name 是native-thrift,而且 RpcContext.getContext().getAttachments 无法获取参数

当前 dubbo 支持的 thrift 协议是对 thrift 原生协议 的扩展,与原生Thrift不兼容 ,使用的是 protocol="tri"

吐槽一下,dubbo3官方的更新进度也太慢了,本人在使用dubbo 3.0.2.1 的时候,并没有 triple 协议,官方文档也没有找到demo,最后是在dubbo-benchmark项目才知道如何使用。

2、协议的支持

dubbo2.7使用默认的序列化协议是hessian,如果参数是泛型 ,返回值可能为null,此时可以修改序列化为 kryo,并加入:

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
</dependency>
<dependency>
    <groupId>de.javakaffee</groupId>
    <artifactId>kryo-serializers</artifactId>
</dependency>

3、版本的区别

目前dubbo 2.7 版本(包括2.7以下)建议使用dubbo作为RPC调用协议(也是默认)。

本人测试了一下,dubbo 3.0 版本情况下即使按照官方文档,引入 hessian 协议的依赖,仍然报:

No such extension org.apache.dubbo.rpc.Protocol by name hessian, no related exception was found, please check whether related SPI module is missing.

暂时没有找到解决方案。

使用dubbo 2.7.13 版本,是可以单独使用hessian协议的。

除此之外本人从网上+测试验证:

  • dubbo3.0版本是2021年6月才出来的,新版本默认是使用 trilple 协议,还不兼容旧版本协议
  • dubbo3.0官方并没有详细的使用文档,本人测试了一下,与2.7的兼容性还有很大问题,所以建议还是使用2.7版本
  • dubbo更新太慢(3年都没有更新3.0版本,捐赠给Apache后基本无维护),网上找到的资料不如springcloud多

参考:

  • 使用直连模式:https://blog.csdn.net/hcz666/article/details/115058048
  • dubbo官方文档:https://dubbo.apache.org/zh

相关文章:

  • java-多线程,一个线程执行完毕,其他线程跳出运算-利用线程组ThreadGroup(子线程中执行当前线程组的interrupt方法)
  • 三分钟读懂什么是动作捕捉
  • Android—Surface,ViewRootImpl.relayoutWindow
  • <C++>详解string类
  • (一) springboot详细介绍
  • (一)UDP基本编程步骤
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • 新作文杂志新作文杂志社新作文编辑部2022年第8期目录
  • d的nan讨论4
  • Python 运算符和表达式
  • 【LeetCode】2022 8月 每日一题
  • AcWing-1-递归实现指数型枚举
  • 易基因|文献科普:DNA甲基化测序揭示DNMT3a在调控T细胞同种异体反应中的关键作用
  • 基于springboot小型车队管理系统毕业设计源码061709
  • 大数据ClickHouse进阶(一):ClickHouse使用场景和集群安装
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • Go 语言编译器的 //go: 详解
  • Java 网络编程(2):UDP 的使用
  • JavaScript的使用你知道几种?(上)
  • Puppeteer:浏览器控制器
  • React Native移动开发实战-3-实现页面间的数据传递
  • Shadow DOM 内部构造及如何构建独立组件
  • Vue小说阅读器(仿追书神器)
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 构建工具 - 收藏集 - 掘金
  • 京东美团研发面经
  • 两列自适应布局方案整理
  • 学习HTTP相关知识笔记
  • 一个完整Java Web项目背后的密码
  • 一起参Ember.js讨论、问答社区。
  • Semaphore
  • UI设计初学者应该如何入门?
  • zabbix3.2监控linux磁盘IO
  • 说说我为什么看好Spring Cloud Alibaba
  • ###STL(标准模板库)
  • #if 1...#endif
  • (10)STL算法之搜索(二) 二分查找
  • (二)WCF的Binding模型
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (数据结构)顺序表的定义
  • (五)MySQL的备份及恢复
  • (原創) 未来三学期想要修的课 (日記)
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)linux下的时间函数使用
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .Net Remoting(分离服务程序实现) - Part.3
  • .Net各种迷惑命名解释
  • .NET学习教程二——.net基础定义+VS常用设置
  • .NET业务框架的构建
  • .NET中两种OCR方式对比