Dubbo学习笔记(快速入门)
RPC:远程过程调用,跨JVM、跨服务器调用方法,像本地调用一样简单。通俗解释:你代码看起来是调用本地方法,实际上调用的是另一台电脑上的代码,屏蔽网络底层。
一、分布式基础
1.1 软件架构四大演变
演变顺序:单体 → 垂直 → 分布式 → 微服务
解释:架构进化本质:为了解决流量变大、代码变多、维护困难。
1)单体架构
所有模块一个工程,一个jar包,全部本地调用;
优点:简单;缺点:耦合严重、一处崩全崩。
通俗解释:所有代码写在一个项目里,商城、会员、订单全部在一起,打包就是一个文件。服务器挂一下,网站直接瘫痪。
2)垂直架构
按业务线拆分多个单体项目;解决宕机连锁问题,但是代码大量重复、无法复用。
通俗解释:把大项目拆成多个独立小项目,比如商城系统、后台管理系统分开部署;但是每个项目都要写一遍短信、文件上传工具,代码重复。
3)分布式架构
抽公共服务,分为web消费层、service提供层;第一次出现远程调用RPC,原生调用极其麻烦。
通俗解释:把重复代码单独抽出来做成服务,专门给别人调用;两个不同项目不在同一台电脑,必须网络传输,也就是远程调用。
4)微服务架构
粒度极致细化,一个功能一个服务;服务数量爆炸,必须使用服务治理框架(Dubbo/SpringCloud)。
通俗解释:拆分到极致,用户服务、订单服务、支付服务全部独立;服务太多人工管不过来,必须用框架治理。
1.2 RPC远程调用核心原理
1.2.1 什么是RPC
RPC:远程过程调用,跨JVM、跨服务器调用方法,像本地调用一样简单。
通俗解释:你代码看起来是调用本地方法,实际上调用的是另一台电脑上的代码,屏蔽网络底层。
1.2.2 RPC五大核心要素
-
客户端(消费者):需要调用别人服务的一方。
-
服务端(提供者):提供接口、被别人调用的一方。
-
序列化:Java对象不能直接网络传输,必须转成二进制字节。
-
网络传输:采用TCP长连接,稳定、可靠、适合业务调用。
-
动态代理:自动生成代理类,不用手写Socket、不用写网络代码。
1.2.3 RPC完整调用流程
消费者调用代理方法 → 序列化参数 → 网络传输 → 服务端反序列化 → 反射执行业务 → 返回结果序列化 → 消费者反序列化拿到数据。
通俗逐句解释:①你调用方法;②把对象变成字节;③通过网络发给服务端;④服务端把字节变回对象;⑤通过反射执行代码;⑥结果再次转字节传回;⑦客户端转回对象展示。
1.3 Dubbo 是什么
- 高性能 RPC 框架,阿里开源,用于分布式服务调用
- 核心:远程调用像本地调用一样简单
- 解决:服务拆分、跨服务通信、服务治理
1.4 Dubbo整体架构五大角色
-
Provider提供者:暴露服务,注册到注册中心。解释:写业务代码、对外提供接口的项目。
-
Consumer消费者:订阅服务,调用远程接口。解释:需要使用别人接口、不写业务逻辑的项目。
-
Registry注册中心:存放服务地址(ZK/Nacos)。解释:中介、通讯录,保存所有服务在哪台服务器。
-
Monitor监控中心:统计调用次数、耗时、异常。解释:日志统计工具,看哪个接口慢、报错多。
-
Container容器:Spring容器启动服务。解释:Dubbo依托Spring运行,本身不是独立服务器。
二、Dubbo环境搭建&快速入门
2.1 注册中心ZooKeeper
2.1.1 为什么选用ZK
节点临时特性、心跳检测、适合Dubbo服务注册;服务下线自动删除节点。
通俗解释:服务挂了,ZK自动检测、自动删掉失效地址,不会让消费者调用死掉的服务。
2.1.2 ZK存储结构
根节点/dubbo → 服务名节点 → 提供者节点、消费者节点、配置节点。
通俗解释:树形结构,类似文件夹,清晰保存每一个服务信息、IP、端口。
2.2 Dubbo管理控制台dubbo-admin
-
作用:可视化查看服务、禁用服务、权重调整、路由配置。解释:网页后台,不用敲命令,肉眼查看服务状态。
-
部署方式:war包部署tomcat、jar直接启动。解释:新版jar一键启动,老版本war包放tomcat。
-
页面功能:服务治理、应用管理、流量管控。解释:上线灰度、临时禁用坏接口全部在这里操作。
2.3 第一个Dubbo入门案例
2.3.1 工程拆分规范
-
公共接口工程(api):存放所有服务接口、实体类。解释:专门放模板,提供者实现、消费者引用。
-
提供者工程(provider):实现接口、暴露服务。解释:干活的服务。
-
消费者工程(consumer):引用接口、调用远程服务。解释:请求方,不实现代码
2.3.2 【代码实操】依赖引入(pom.xml)
<!-- Dubbo核心依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!-- Zookeeper连接依赖 -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
2.3.3 【代码实操】公共API接口类
/**
* 公共服务接口(api工程)
* 提供者实现、消费者引用
*/
public interface UserService {
String sayHello(String name);
}
2.3.4 【代码实操】提供者实现类+XML配置
业务实现类:
public class UserServiceImpl implements UserService {
@Override
public String sayHello(String name) {
return "Dubbo调用成功:"+name;
}
}
提供者dubbo-provider.xml配置:
<?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.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 1.当前服务应用名称 -->
<dubbo:application name="dubbo-provider"/>
<!-- 2.注册中心地址(ZK默认端口2181) -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 3.通信协议及端口 默认20880 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 4.暴露服务接口 -->
<dubbo:service interface="com.lwl.service.UserService" ref="userService"/>
<!-- 5.注入实现类 -->
<bean id="userService" class="com.lwl.service.impl.UserServiceImpl"/>
</beans>
2.3.5 【代码实操】消费者XML配置+调用测试
消费者dubbo-consumer.xml:
<?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.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 应用名称 -->
<dubbo:application name="dubbo-consumer"/>
<!-- 注册中心 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- 引用远程服务 生成代理对象 -->
<dubbo:reference id="userService" interface="com.lwl.service.UserService"/>
</beans>
测试启动类:
public class ConsumerTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
UserService userService = context.getBean(UserService.class);
// 像本地方法一样调用远程服务
String result = userService.sayHello("Dubbo快速入门学习");
System.out.println(result);
}
}
三、Dubbo高级配置大全
3.1 SpringBoot整合Dubbo三种方式
-
XML配置方式:老式写法,企业遗留项目多。解释:早期Spring写法,现在新项目不用。
-
注解方式(主流):@DubboService、@DubboReference。解释:最简单、现在企业通用。
-
JavaConfig配置类:纯代码无xml。解释:大型框架底层使用。
3.1.1 【代码实操】SpringBoot注解版
① 提供者 application.yml 配置
# 服务名称
dubbo:
application:
name: dubbo-boot-provider
# 注册中心
registry:
address: zookeeper://127.0.0.1:2181
# 通信协议
protocol:
name: dubbo
port: 20880
# 扫描注解包
scan:
base-packages: com.lwl.service
# 关闭日志冗余打印
logging:
level:
root: info
② 消费者 application.yml 配置
dubbo:
application:
name: dubbo-boot-consumer
registry:
address: zookeeper://127.0.0.1:2181
# 开发环境关闭启动检查
consumer:
check: false
server:
port: 8080
③ 提供者启动类+服务实现:
// 提供者实现类 暴露服务
@DubboService // 新版注解 暴露服务
public class UserServiceImpl implements UserService {
@Override
public String sayHello(String name) {
return "SpringBoot+Dubbo注解调用成功";
}
}
// 启动类
@EnableDubbo
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args);
}
}
④ 消费者引用:
@RestController
public class UserController {
// 引用远程服务
@DubboReference
private UserService userService;
@GetMapping("/hello")
public String hello(){
return userService.sayHello("注解方式");
}
}
3.2 dubbo.properties全局配置
-
统一配置公共属性:超时、重试、注册中心。解释:把重复配置抽出来,不用每个类写一遍。
-
属性加载优先级(从高到低):①启动命令(-D) ②xml/注解配置 ③dubbo.properties。
3.2.1 【代码实操】dubbo.properties全局配置文件
# 应用名称
dubbo.application.name=dubbo-demo
# 注册中心
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 全局超时
dubbo.provider.timeout=3000
# 全局重试次数
dubbo.provider.retries=1
3.3 启动检查check
-
默认true:消费者启动必须检测服务是否存在,不存在启动报错。解释:生产环境必须保证服务齐全。
-
开发环境常用:check=false,避免服务未启动导致报错。解释:开发时服务没写完,不用卡死启动。
3.3.1 【代码实操】关闭启动检查
① XML写法
<dubbo:reference id="userService"
interface="com.lwl.service.UserService"
check="false"/>
② .properties 写法
# 消费者关闭启动检查(全局默认)
dubbo.consumer.check=false
3.4 超时配置timeout
-
默认1000ms,超时直接抛出异常。解释:一秒没返回直接判定失败。
-
消费者超时优先级高于提供者。解释:调用方说了算,防止服务端卡死。
-
业务耗时较长必须手动加大超时时间。解释:报表、导出、大数据查询必须调大时间。
3.4.1 【代码实操】超时配置(XML + properties 双版本)
① XML写法(消费者局部配置、优先级最高)
<!-- 消费者设置超时5秒 -->
<dubbo:reference id="userService" timeout="5000">
② dubbo.properties 写法
# 消费者全局超时时间 单位ms
dubbo.consumer.timeout=5000
# 提供者全局超时(消费者没配置才生效)
dubbo.provider.timeout=3000
优先级:
1)、精确优先(方法级优先,接口级次之,全局配置再次之)
2)、消费者设置优先(如果级别一样,则消费方优先,提供方次之)
3.5 重试次数retries
-
默认重试2次,加上第一次一共3次请求。解释:失败自动换服务器再试。
-
幂等接口可以重试:查询、删除。解释:查多少次、删多少次结果都一样,不会出错。
-
非幂等禁止重试:下单、扣款(防止重复下单)。解释:扣款重试会扣多遍钱,绝对禁止。
3.5.1 【代码实操】关闭重试(XML + properties 双版本)
① XML写法(单个接口禁用重试)
<dubbo:reference id="payService" retries="0"/>
② dubbo.properties 全局写法(统一全局重试次数)
# 全局重试次数 0=关闭重试
dubbo.consumer.retries=2
# 提供者重试配置
dubbo.provider.retries=2
3.6 多版本version
-
用于灰度发布、平滑升级。解释:新版本怕bug,先少量人测试。
-
老版本服务不升级,新版本并行运行,逐步切流。解释:新旧服务共存,不会一次性全量更新。
-
消费者指定版本调用,互不干扰。解释:A用户调用旧版、B用户调用新版。
3.6.1 【代码实操】版本控制(XML + properties 双版本)
① XML写法
提供者:
<dubbo:service interface="com.lwl.service.UserService"
ref="userService" version="1.0.0"/>
消费者指定版本:
<dubbo:reference interface="com.lwl.service.UserService" id="userService" version="1.0.0"/>
② .properties 配置
# 提供者全局版本号
dubbo.provider.version=1.0.0
# 消费者引用默认版本
dubbo.consumer.version=1.0.0
灰度发布优先XML单独指定版本,properties用来统一默认版本。
3.7 本地存根stub
-
客户端前置增强,在调用远程方法之前执行。解释:还没发网络请求,先在本地执行代码。
-
用途:参数校验、本地缓存、日志打印、权限判断。解释:简单判断不用浪费网络请求。
-
不侵入业务代码,增强扩展性。解释:不用改业务代码就能加功能。
3.7.1 【代码实操】本地存根编写
① 本地存根 Java代码
public class UserServiceStub implements UserService {
// 注入远程代理对象
private UserService userService;
public UserServiceStub(UserService userService){
this.userService = userService;
}
@Override
public String sayHello(String name) {
// 本地前置校验
if(name == null){
return "参数不能为空";
}
// 正常远程调用
return userService.sayHello(name);
}
}
② XML配置(消费者配置,绑定存根类)
<!-- stub:绑定本地存根类,客户端优先执行存根代码 -->
<dubbo:reference id="userService"
interface="com.lwl.service.UserService"
stub="com.lwl.stub.UserServiceStub"/>
总结:
1、存根必须放在消费者端,提供者不需要;
2、必须写有参构造,Dubbo自动注入远程代理;
3、执行顺序:本地存根 → 远程调用。
3.8 SpringBoot与dubbo整合的三种方式
-
1)导入dubbo-starter,在application.properties配置属性,使用@Service【暴露服务】使用@Reference【引用服务】
-
2)保留dubbo xml配置文件; 导入dubbo-starter,使用@ImportResource导入dubbo的配置文件即可
-
3)使用注解API的方式: 将每一个组件手动创建到容器中,让dubbo来扫描其他的组件 //@EnableDubbo //开启基于注解的dubbo功能
package com.lwl.config;
import com.lwl.service.UserService;
import com.lwl.service.impl.UserServiceImpl;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* P19 API编码配置方式
*/
@Configuration
public class MyDubboConfig {
/**
* 1.应用配置
*/
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-api-provider");
return applicationConfig;
}
/**
* 2.注册中心配置
*/
@Bean
public RegistryConfig registryConfig(){
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
return registryConfig;
}
/**
* 3.手动暴露服务
*/
@Bean
public ServiceConfig<UserService> serviceConfig(UserService userService){
ServiceConfig<UserService> serviceConfig = new ServiceConfig<>();
// 设置接口
serviceConfig.setInterface(UserService.class);
// 设置实现类
serviceConfig.setRef(userService);
// 设置版本
serviceConfig.setVersion("1.0.0");
// 方法级配置
List<MethodConfig> methods = new ArrayList<MethodConfig>();
MethodConfig method = new MethodConfig();
method.setName("sayHello");
method.setTimeout(10000);
method.setRetries(0);
methods.add(method);
serviceConfig.setMethods(methods);
return serviceConfig;
}
}
四、Dubbo高可用机制
4.1 ZK宕机故障转移
-
注册中心宕机:消费者本地缓存服务列表,不影响正常调用。通俗解释:消费者把服务地址存在本地内存,ZK崩了照样干活。
-
ZK恢复后自动重新同步服务。解释:重启ZK后自动更新最新服务列表。
-
直连模式:开发调试直接指定提供者IP,绕过注册中心。解释:开发阶段不用启动ZK,直接写死IP调试。
4.1.1 【代码实操】直连模式
<!-- 绕过ZK 直连指定服务地址 -->
<dubbo:reference id="userService"
interface="com.lwl.service.UserService"
url="dubbo://127.0.0.1:20880"/>
@Reference(url="127.0.0.1:20880")
UserService userService;
4.2 四大负载均衡策略
4.2.1 Random随机(默认)
随机挑选节点,简单高效,生产默认。解释:压力分配均匀、不会集中压在一台服务器。
4.2.2 RoundRobin轮询
依次轮流调用,适合性能一致服务器。解释:1号、2号、3号轮流请求,服务器配置一样时使用。
4.2.3 LeastActive最少活跃
优先调用耗时低、并发少的节点,自动避开慢节点。解释:哪台服务器轻松就去哪台,自动规避卡顿机器。
4.2.4 ConsistentHash一致性哈希
相同参数永远访问同一节点,会话保持、缓存命中高。解释:同一个用户永远访问同一台服务,缓存不会失效。
4.2.5 【代码实操】修改负载均衡策略
<!-- 改为轮询负载均衡 -->
<dubbo:reference id="userService"
interface="com.lwl.service.UserService" loadbalance="roundrobin"/>
@Reference(loadbalance="roundrobin")
UserService userService;
4.3 服务降级Mock
-
失败降级:调用失败触发本地mock返回兜底数据。解释:服务崩了,返回写死的默认数据,页面不报错。
-
强制降级:直接禁用远程服务,全部走本地mock。解释:高峰期直接关掉非核心服务,保住主业务。
-
场景:流量洪峰、服务宕机、非核心业务降级保主流程。通俗解释:双十一限流,把公告、积分关掉,保住下单付款。
4.4 集群容错模式
4.4.1 Failover失败重试(默认)
失败自动换节点重试,适合幂等查询接口。解释:查数据失败换一台重试,最常用、默认模式。
4.4.2 Failfast快速失败
只调用一次,失败直接报错,适合下单扣款非幂等接口。解释:支付不能重试,失败直接抛异常。
4.4.3 Failsafe安全失败
失败不报错、返回空,用于日志、统计无关紧要接口。解释:错了也不影响主业务,不用报错。
4.4.4 Failback失败通知
失败后台异步重试,用于消息推送、通知类业务。解释:发短信失败,后台慢慢重试,不用用户等待。
4.4.5 Forking并行调用
同时调用多个节点,取最快返回,高可用、耗资源。解释:同时请求3台服务器,谁快用谁,适合金融高可靠业务。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)