Dubbo
- 简介
- Dubbo的快速入门
- Dubbo的基本架构
- 安装DubboAdmin
- 入门案例
- Dubbo的最佳实践
- Dubbo的高级特性
- 启动检查
- 多版本
- 超时与重试
- 负载均衡
- SpringCloud整合Dubbo
- 案例
简介
Dubbo是阿里巴巴公司开源的一个高性能、轻量级的Java RPC框架。
致力于提高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案
官网
目前Dubbo在企业中有两种开发思路
- 基于SOA思想
- 将传统单一应用拆分为Web(消费者)模块和Service(提供者)模块,基于Dubbo通信
- 辅助SpringCloud架构提升效率
- Dubbo基于TCP(传输层)协议,效率更高。可以替换Feign,提升高并发压力
Dubbo的快速入门
Dubbo的基本架构
- 服务提供者在启动时,向注册中心注册自己提供的服务
- 消费者在启动时,向注册中心订阅自己所需的服务
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
- 服务消费者,从提供者地址列表中,基于负载均衡算法,选择提供者进行调用。
- 服务消费者和提供者,在内存中累积调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
安装DubboAdmin
DubboAdmin是阿里巴巴管理提供的管理控制台,可以实现服务查询,详细展示,服务测试等功能。皆有DubboAdmin可以更好的帮助开发人员对服务进行管理和监控
DubboAdmin的源代码托管在GitHub上,可以通过命令拉取,修改配置并运行
# 下载代码
git clone https://gitcode.net/mirrors/apache/dubbo-admin.git
# 在dubbo-admin-server/src/main/resources/application.properties中指定注册中心
# 构建
mvn clean package -D maven.test.skip=true
#启动
mvn --projects dubbo-admin-server spring-boot:run
或者
cd dubbo-admin-distribution/target; java -jar dubbo-admin-0.1.jar
# 访问
http://localhost:8080
# 默认用户名与密码为:root
入门案例
-
创建数据库
CREATE DATABASE `dubbo-demo` ; USE `dubbo-demo`; DROP TABLE IF EXISTS `tb_order`; CREATE TABLE `tb_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id', `userId` bigint(20) NOT NULL COMMENT '用户id', `name` varchar(100) DEFAULT NULL COMMENT '商品名称', `price` bigint(20) NOT NULL COMMENT '商品价格', `num` int(10) DEFAULT '0' COMMENT '商品数量', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `username` (`name`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; insert into `tb_order`(`id`,`userId`,`name`,`price`,`num`) values (101,1,'Apple 苹果 iPhone 12 ',699900,1),(102,2,'雅迪 yadea 新国标电动车',209900,1),(103,3,'骆驼(CAMEL)休闲运动鞋女',43900,1),(104,4,'小米10 双模5G 骁龙865',359900,1),(105,5,'OPPO Reno3 Pro 双模5G 视频双防抖',299900,1),(106,6,'美的(Midea) 新能效 冷静星II ',544900,1),(107,2,'西昊/SIHOO 人体工学电脑椅子',79900,1),(108,3,'梵班(FAMDBANN)休闲男鞋',31900,1); DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(100) DEFAULT NULL COMMENT '收件人', `address` varchar(255) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `username` (`username`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; insert into `tb_user`(`id`,`username`,`address`) values (1,'柳岩','湖南省衡阳市'),(2,'文二狗','陕西省西安市'),(3,'华沉鱼','湖北省十堰市'),(4,'张必沉','天津市'),(5,'郑爽爽','辽宁省沈阳市大东区'),(6,'范兵兵','山东省青岛市');
-
导入工程
需求:使用Dubbo构建分布构架,完成根据用户id查询用户
搭建服务提供者user-provider
-
创建提供者模块并引入依赖
<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!--dubbo的起步依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.8</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>2.7.8</version> </dependency> </dependencies>
-
编写引导类
package com.xiaowu.user; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @MapperScan("com.xiaowu.user.mapper") @SpringBootApplication public class UserProviderApplication { public static void main( String[] args ) { SpringApplication.run(UserProviderApplication.class,args); } }
-
将service,Mapper,domain导入到提供者模块中
-
将UserService暴露为Dubbo服务
//暴露Dubbo服务 @DubboService public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; public User queryById(Long id) { return userMapper.findById(id); } }
-
application.yml配置
server: port: 18081 spring: datasource: url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver application: name: user-provider logging: level: com.xiaowu: debug pattern: dateformat: HH:mm:ss:SSS # 配置Dubbo提供者 dubbo: protocol: name: dubbo # 协议 port: 20881 # dubbo端口 registry: address: nacos://127.0.0.1:8848 #注册中心地址 scan: base-packages: com.xiaowu.user.service # dubbo注解的包扫描
搭建服务消费者user-consumer
-
创建user-consumer模块导入依赖
<dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--dubbo的起步依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.8</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>2.7.8</version> </dependency> </dependencies>
-
将Controller,service接口导入到消费者模块中
-
配置引导类
package com.xiaowu.user; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class UserConsumerApplication { public static void main( String[] args ) { SpringApplication.run(UserConsumerApplication.class,args); } }
-
在Controller中引入dubbo服务
@Slf4j @RestController @RequestMapping("/user") public class UserController { @DubboReference //引入dubbo服务 private UserService userService; /** * 路径: /user/110 * @param id 用户id * @return 用户 */ @GetMapping("/{id}") public String queryById( @PathVariable("id") Long id) { return userService.queryById(id); } }
-
application.yml配置
server: port: 18080 spring: application: name: user-consumer # 配置dubbo服务消费者 dubbo: registry: address: nacos://127.0.0.1:8848
Dubbo的最佳实践
将API接口抽取为独立模块,并且把接口有关的domain都放到这个模块中
然后引入这个模块的依赖
Dubbo的高级特性
启动检查
为了保障服务的正常可用,Dubbo缺省会启动时检查依赖的服务是否可用,不可用时会抛出异常
- 在正式环境这是很有必要的一项配置,可以保证整个调用链路的平稳运行
- 在开发时,往往会存在没有提供者的情况。由于启动检查的原因,可能导致开发测试出现问题
- 可以通过check=false关闭
多版本
在正式系统中,为了保证系统可用性和更好的并发性,往往通过集群部署
Dubbo提供了提供者多版本的支持,平滑处理项目功能升级部署
具体实现:
-
编写新的UserServer实现类,作为新版本代码
//暴露Dubbo服务 @DubboService(version = "1.0") public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; public User queryById( Long id) { return userMapper.findById(id); } }
-
在暴露服务时,指定服务版本
//暴露Dubbo服务 @DubboService(version = "1.0")
-
消费者引用服务时,指定引用的服务版本
public class UserController { @DubboReference(version = "1.0") //引入dubbo服务 private UserService userService; }
超时与重试
服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去。在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。
- Dubbo:利用超时机制来解决这个问题(使用timeout属性配置超时时间,默认值1000,单位毫秒)
- 若超时时间较短,当网络波动时请求就会失败,Dubbo通过重试机制避免此类问题的发生
设置重试机制的方法
-
在消费者引用Dubbo服务时,加retries参数设置重试机制
@Slf4j @RestController @RequestMapping("/user") public class UserController { @DubboReference(version = "1.0",retries = 0) //引入dubbo服务 private UserService userService; /** * 路径: /user/110 * @param id 用户id * @return 用户 */ @GetMapping("/{id}") public User queryById( @PathVariable("id") Long id) { return userService.queryById(id); } }
-
在application.yml配置重试机制
# 配置dubbo服务消费者 dubbo: registry: address: nacos://127.0.0.1:8848 consumer: check: false retries: 0 # 重试机制(0次)
负载均衡
在集群部署时,Dubbo提供了4中负载均衡策略,帮助消费者找到最优提供者并调用
- Random:按权重随机,默认。按权重设置随机概率
- RoundRobin:按权重轮询
- LeastActive:最少活跃调用数,相同活跃数的随机
- ConsistentHash:一致性Hash,相同参数的请求总是发到同一提供者
更改负载均衡策略,在消费者引用Dubbo时加入 loadbalance
参数
@DubboReference(version = "1.0",retries = 0,loadbalance = "Random") //引入dubbo服务
SpringCloud整合Dubbo
- Feign基于Http协议(应用层),在高并发场景下性能不够理想,容易成为性能瓶颈
- Dubbo框架的通信协议采用TCP协议(数据传输层)
- Dubbo框架的通信协议采用RPC协议,属于传输层协议
- Dubbo默认通过Netty构造TCP长连接的方式进行通信,性能较高
- 使用SpringCloud整合Dubbo,即为强强联合
案例
根据订单id查询订单功能
需求:根据订单id查询订单的同时,把订单所属的用户信息一起返回
模块分析
- 使用Dubbo进行服务调用,一般将公共接口独立抽取为模块
- 消费者引入依赖,引用Dubbo服务
- 提供者引入依赖,编写接口实现类,暴露服务
抽取接口模块
-
创建dubbo-api模块,引入依赖
<dependencies> <dependency> <groupId>com.xiaowu</groupId> <artifactId>dubbo-domain</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
-
抽取公共接口
改造提供者
-
引入依赖
<!--nacos注册中心的依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--springcloud alibaba dubbo依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> </dependency> <!--dubbo-api--> <dependency> <groupId>com.xiaowu</groupId> <artifactId>dubbo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
-
编写实现类,暴露Dubbo服务
@DubboService public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; public User queryById(Long id) { return userMapper.findById(id); } }
-
application.yml配置
server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver application: name: user-service cloud: nacos: discovery: server-addr: localhost:8848 #配置dubbo,注册中心,暴露的端口和协议,dubbo注解的包扫描 dubbo: protocol: name: dubbo port: 20881 registry: address: spring-cloud://localhost #使用SpringCloud中的注册中心 scan: base-packages: com.xiaowu.user.service #dubbo中包扫描 logging: level: com.xiaowu: debug pattern: dateformat: HH-mm ss:SSS
改造服务消费者
-
引入依赖
<!--nacos注册中心的依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--springcloud alibaba dubbo依赖 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> </dependency> <!--dubbo-api--> <dependency> <groupId>com.xiaowu</groupId> <artifactId>dubbo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
-
使用@DubboReference引入Dubbo服务,远程调用服务
@DubboReference private UserService userService; @Autowired private OrderMapper orderMapper; public Order queryOrderById(Long orderId) { // 1.根据id查询订单 Order order = orderMapper.findById(orderId); // 2.获取订单中的用户ID Long userId = order.getUserId(); // 3.根据用户id,调用Dubbo服务查询用户 User user = userService.queryById(userId); order.setUser(user); // 4.返回 return order; }
-
application.yml进行配置
server: port: 8082 spring: datasource: url: jdbc:mysql://localhost:3306/dubbo-demo?useSSL=false username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver cloud: nacos: discovery: server-addr: localhost:8848 application: name: order-service # dubbo消费者 dubbo: registry: address: spring-cloud://localhost logging: level: com.xiaowu: debug pattern: dateformat: HH:mm:ss:SSS
启动测试
- 查询用户
- 查询订单