本文已参与【新人创作礼】活动,一起开启掘金创作之路。
目录
1.说明需求
某个电商系统,订单服务(消费方)需要调用用户服务(服务方)获取某个用户的所有地址;
我们现在需要创建两个服务模块进行测试
| 模块 | 功能 |
| 订单服务(消费方) | 生成订单 |
| 用户服务(服务方) | 返回用户地址 |
测试预期结果:
订单服务在A服务器,用户服务模块在B服务器,A可以远程调用B的功能。
2.工程架构
编辑
服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持。
3.引入pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.atguigu</groupId>
<artifactId>boot-user-service-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot-user-service-provider</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>gmall-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 引入dubbo -->
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
注意starter版本适配:
编辑
4.gmall-interface (公共接口层)
1)bean模型
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserAddress implements Serializable {
private Integer id;
private String userAddress;
private String userId;
private String userName;
private String phoneNum;
private String isDefault; //是否默认地址,Y-是 N-否
}
2)service接口
public interface OrderService {
/**
* 生成订单
* @param userId
* @return
*/
public UserAddress initOrder(String userId);
}
public interface UserService {
/**
* 按照用户id返回所有的收货地址
* @param userId
* @return
*/
public UserAddress getUserAddressList(String userId);
}
5.gmall-user用户模块(服务方)
1)实现用户查询的方法
@Service //dubbo注解
public class UserServiceImpl implements UserService {
@Override
public UserAddress getUserAddressList(String userId) {
//生成用户信息
ArrayList<UserAddress> userAddresses = new ArrayList<>();
UserAddress address1 = new UserAddress(1, "北京", "1","李老师","11111111", "Y");
UserAddress address2 = new UserAddress(2, "南京", "2", "宋老师","22222222", "N");
userAddresses.add(address1);
userAddresses.add(address2);
//模拟查询
UserAddress userAddress = userAddresses.get(Integer.parseInt(userId));
return userAddress;
}
}
2)yml文件
dubbo:
application:
name: user-service-provider
registry:
address: 192.168.16.106:2181
protocol: zookeeper
protocol:
name: dubbo
port: 20880
scan:
base-packages: com.atguigu.gmall
monitor:
protocol: registry
application.name就是服务名,不能跟别的dubbo提供端重复
registry.protocol 是指定注册中心协议
registry.address 是注册中心的地址加端口号
protocol.name 指定通信规则,使用dubbo协议(有很多协议)
protocal.port:服务暴露在20880端口(默认)
base-package 注解方式要扫描的包
monitor.protocal:所有服务配置连接监控中心,进行监控统计,监控中心协议
如果为protocol="registry",表示从注册中心发现监控中心地址,否则直连监控中心。
Simple Monitor 挂掉不会影响到 Consumer 和 Provider 之间的调用,所以用于生产环境不会有风险。
6.gmall-order-web(消费方)
1)实现生成订单的方法
@Service //spring注解
public class OrderServiceImpl implements OrderService {
@Reference //dubbo注解
UserService userService;
/**
* 初始化订单,查询用户所有的地址并返回
* @param userId
*/
@Override
public UserAddress initOrder(String userId) {
//1.查询用户的收货地址
UserAddress userAddress = userService.getUserAddress(userId);
return userAddress;
}
}
2)controller层
@Controller
public class OrderController {
@Autowired
OrderService orderService;
@ResponseBody
@RequestMapping("/initOrder")
public UserAddress initOrder(@RequestParam("uid") String userId){
return orderService.initOrder(userId);
}
}
3)yml文件
server:
port: 8081
dubbo:
application:
name: boot-order-service-consumer
registry:
address: 192.168.16.106:2181
protocol: zookeeper
scan:
base-packages: com.atguigu.gmall
monitor:
protocol: registry
7.dubbo注解解释
@Service:指定需要暴露的服务
@Reference:生成远程服务代理
【如果没有在配置中写dubbo.scan.base-package,还需要使用@EnableDubbo注解】
8.Dubbo配置
说明:以下xml文件均可被注解代替,我这样写只是为了更清楚的解释
1)配置原则
编辑
JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。
XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。
Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名。
2)重试次数
重试次数配置如下:
<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
或
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
幂等:对数据库执行多次的效果和一次的效果一样(设置重试次数)【查询】【删除】【修改】效果一样
非幂等:(不能设置重试次数)
3)超时时间
由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间。
①Dubbo消费端
全局超时配置
<dubbo:consumer timeout="5000" />
指定接口以及特定方法超时配置
<dubbo:reference interface="com.foo.BarService" timeout="2000">
<dubbo:method name="sayHello" timeout="3000" />
</dubbo:reference>
②Dubbo服务端
全局超时配置
<dubbo:provider timeout="5000" />
指定接口以及特定方法超时配置
<dubbo:provider interface="com.foo.BarService" timeout="2000">
<dubbo:method name="sayHello" timeout="3000" />
</dubbo:provider>
配置原则
dubbo推荐在Provider上尽量多配置Consumer端属性:
1、作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间,合理的重试次数,等等
2、在Provider配置后,Consumer不配置则会使用Provider的配置值,即Provider配置可以作为Consumer的缺省值。否则,Consumer会使用Consumer端的全局设置,这对于Provider不可控的,并且往往是不合理的
配置的覆盖规则:
方法级配置别优于接口级别,即小Scope优先
Consumer端配置 优于 Provider配置 优于 全局配置,
最后是Dubbo Hard Code的配置值(见配置文档)
编辑
4)版本号
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
- 在低压力时间段,先升级一半提供者为新版本
- 再将所有消费者升级为新版本
- 然后将剩下的一半提供者升级为新版本
老版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
新版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" />
老版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
新版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />
如果不需要区分版本,可以按照以下的方式配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
9.高可用
1)zookeeper宕机与dubbo直连
现象:zookeeper注册中心宕机,还可以消费dubbo暴露的服务。
健壮性
- 监控中心宕掉不影响使用,只是丢失部分采样数据
- 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
- 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
- 服务提供者无状态,任意一台宕掉后,不影响使用
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
高可用:通过设计,减少系统不能提供服务的时间;
//Dubbo直连,绕过注册中心
@Reference(url = "192.168.16.106:20882")
\