本片文章是一篇servicecomb-pack的使用教程说明,理论知识会另起一篇文章再详细说明(架构理论传送门1,架构理论传送门2)
servicecomb是华为开源的一个微服务框架,后进入Apache软件基金会孵化,现已毕业,是apache顶级开源项目,而servicecomb-pack是servicecomb孵化的三个子项目之一,是分布式事务最终一致性解决方案,0.3.0版本之前叫saga,现改名为servicecomb-pack,支持saga和tcc两种分布式事务协议,相关理论知识请移步(传送门),本文主要介绍saga模式,下一篇介绍tcc模式
注意:alpha-server目前并没有提供starter,因此需要从GitHub上获取源码本地自行编译运行
源码获取
Github地址:https://github.com/apache/servicecomb-pack
git命令:$ git clone https://github.com/apache/servicecomb-pack.git
修改配置文件
找到alpha-server/src/main/resource/application.yaml,修改datasource信息为本地信息即可
本地构建alpha-server
$ cd servicecomb-pack
只构建可执行文件(推荐)
$ mvn clean install -DskipTests -Pspring-boot-2
同时构建可执行文件和docker镜像
$ mvn clean install -DskipTests -Pdocker,spring-boot-2
同时构建可执行文件以及pack发行包
$ mvn clean install -DskipTests -Prelease,spring-boot-2
在执行上面任一指令后,可在alpha/alpha-server/target/saga/alpha-server-${version}-exec.jar中找到alpha-server的可执行jar包
启动alpha-server
通过docker运行:
docker run -d -p 8080:8080 -p 8090:8090 -e "JAVA_OPTS=-Dspring.profiles.active=prd -Dspring.datasource.url=jdbc:postgresql://${host_address}:5432/saga?useSSL=false" alpha-server:${saga_version}
通过可执行文件运行:
java -Dspring.profiles.active=prd -D"spring.datasource.url=jdbc:postgresql://${host_address}:5432/saga?useSSL=false" -jar alpha-server-${saga_version}-exec.jar
注意:请在执行命令前将${saga_version}和${host_address}更改为实际值
至此,alpha-server全局事务管理器已经启动成功
替换postgresql为mysql
alpha-server默认使用postgresql,因此如想替换成mysql需以下步骤:
修改pom文件,添加依赖:alpha-server/pom.xml,添加mysql依赖(因为配置文件中需要配置driver信息)
dependency>
mysql
mysql-connector-java
runtime
8.0.15
找到alpha-server/src/main/resource/application.yaml,修改datasource信息为本地信息即可;注:url需添加serverTimezone,并增加driver-class-name属性
spring:
profiles: mysql
datasource:
username: ${username}
password: ${password}
url: jdbc:mysql://${host_address}:${port}/${database_name}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false
platform: mysql
continue-on-error: false
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
properties:
eclipselink:
ddl-generation: none
注意:${username},${password},${host_address},${port},${database_name}需替换为实际值
添加依赖
org.apache.servicecomb.pack
omega-spring-starter
${servicecomb-pack.version}
org.apache.servicecomb.pack
omega-spring-cloud-consul-starter
${servicecomb-pack.version}
org.apache.servicecomb.pack
omega-transport-resttemplate
${servicecomb-pack.version}
注意:请将${servicecomb-pack.version}更改为实际的版本号(目前最新release为0.4.0)
修改配置文件
添加这一配置即可,其他应用配置自行添加,address可根据alpha-server中的配置实际添加
# 配置alpha-service 集群/单机 服务访问地址
alpha:
cluster:
address: localhost:8080
添加saga的注解以及相关的补偿方法配置
EnableOmega
注解来初始化Omega的配置并与alpha-server建立连接(@EnableOmega注解在当前版本已经标注为过时注解,但是不妨碍功能,后续应该会把注解转换为在配置文件中配置开关属性,目前版本中还没开始这种做)@SpringBootApplication
@EnableOmega
public class CarApplication {
public static void main(String[] args) {
SpringApplication.run(CarApplication.class, args);
}
}
@SagaStart(timeout = 5) //开启saga分布式事务,默认情况下,超时设置需要显示声明才生效
@GetMapping("/booking/{name}/{rooms}/{cars}")
public String booking(@PathVariable String name,@PathVariable Integer rooms,
@PathVariable Integer cars) throws Exception{}
注意:默认情况下,超时设置需要显示声明才能生效
Compensable
注解并指明其对应的补偿方法@Override
@Transactional
@Compensable(timeout = 5, compensationMethod = "cancel")
public CarBooking order(CarBooking carBooking) {
return repository.save(carBooking);
}
补偿方法
//补偿逻辑 入参和try方法一致
@Transactional
public void cancel(CarBooking carBooking) {
//demo只进行取消/删除 设置状态; 实际开发中可针对实际业务进行逻辑编码
//修改状态
carBooking.setCancelled(Boolean.TRUE);
repository.save(carBooking);
//删除记录
// repository.delete(toSpecification(carBooking));
}
注意:实现的服务和补偿方法必须满足幂等的要求
注意:默认情况下,超时需要显示声明
注意:若全局事务起点与子事务重合,需同时声明@SagaStart和@Compensable注解
注意:补偿方法的入参必须与try方法入参一致,否则启动时会报错(alpha-server找不到补偿方法)
至此,正常启动服务即完成saga模式配置
@SpringBootApplication
@EnableOmega
public class OrderingApplication {
public static void main(String[] args) {
SpringApplication.run(OrderingApplication.class, args);
}
}
@TccStart(timeout = 5) //当前版本的tcc还不支持timeout
@PostMapping("/order/{userName}/{productName}/{productUnit}/{unitPrice}")
public String order(@PathVariable String userName,@PathVariable String productName,
@PathVariable Integer productUnit,@PathVariable Integer unitPrice) throws Exception{}
注意:当前版本tcc还不支持timeout
@Override
@Transactional
@Participate(confirmMethod = "confirm", cancelMethod = "cancel")
public void reserve(ProductOrder productOrder) {
Product product = new Product();
product.setName(productOrder.getProductName());
product = productRepository.findOne(toSpecification1(product)).get();
if (product.getInStock() >= productOrder.getUnits()) {
product.setInStock(product.getInStock() - productOrder.getUnits());
productRepository.save(product);
productOrderRepository.save(productOrder);
} else {
throw new IllegalArgumentException("The Product is out of stock!");
}
}
确认方法
public void confirm(ProductOrder productOrder) {
......
}
补偿方法
public void cancel(ProductOrder productOrder) {
......
}
注意:confirm和cancel方法的入参必须和try方法一致
至此,正常启动服务即完成tcc模式配置
到此,saga和tcc已经基本搭建完成