前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >servicecomb-saga开发实战

servicecomb-saga开发实战

作者头像
jeremyxu
发布2019-03-13 14:59:07
2.4K5
发布2019-03-13 14:59:07
举报

最近的工作主要是微服务框架的设计与开发,期间要解决多个微服务的分布式事务问题,由于要解决的主要场景是用spring boot写的java项目,最终选择了业界成熟的servicecomb-saga方案,这里稍微记录下以备忘。

为何会有分布式事务

这里不作深入叙述,网上有相当好的参考资料-聊聊分布式事务,再说说解决方案

为何选择saga方案

参考聊聊分布式事务,再说说解决方案,可以看到

  1. 两阶段提交方案实现较复杂,而且对性能影响太大;
  2. TCC方案好像只有阿里内部在大规模使用;
  3. 本地消息表方案消息表会耦合到业务系统,不太优雅;
  4. MQ事务消息方案依赖于有事务消息的MQ中间件。

最后好像也只好选择saga方案,另外有了servicecomb-saga后,spring-boot应用要使用分布式事务还是挺容易的。

servicecomb-saga的架构

servicecomb-saga的架构可直接参考其官方文档,写得还是比较详细的。

概览

Pack中包含两个组件,即 alphaomega

  • alpha充当协调者的角色,主要负责对事务的事件进行持久化存储以及协调子事务的状态,使其得以最终与全局事务的状态保持一致。
  • omega是微服务中内嵌的一个agent,负责对网络请求进行拦截并向alpha上报事务事件,并在异常情况下根据alpha下发的指令执行相应的补偿操作。
Pack Architecture
Pack Architecture

Omega内部运行机制

omega是微服务中内嵌的一个agent。当服务收到请求时,omega会将其拦截并从中提取请求信息中的全局事务id作为其自身的全局事务id(即Saga事件id),并提取本地事务id作为其父事务id。在预处理阶段,alpha会记录事务开始的事件;在后处理阶段,alpha会记录事务结束的事件。因此,每个成功的子事务都有一一对应的开始及结束事件。

Omega Internal
Omega Internal

服务间通信流程

服务间通信的流程与Zipkin的类似。在服务生产方,omega会拦截请求中事务相关的id来提取事务的上下文。在服务消费方,omega会在请求中注入事务相关的id来传递事务的上下文。通过服务提供方和服务消费方的这种协作处理,子事务能连接起来形成一个完整的全局事务。

Inter-Service Communication
Inter-Service Communication

具体处理流程

成功场景

成功场景下,每个开始的事件都会有对应的结束事件。

Successful Scenario
Successful Scenario
异常场景

异常场景下,omega会向alpha上报中断事件,然后alpha会向该全局事务的其它已完成的子事务发送补偿指令,确保最终所有的子事务要么都成功,要么都回滚。

Exception Scenario
Exception Scenario
超时场景

超时场景下,已超时的事件会被alpha的定期扫描器检测出来,与此同时,该超时事务对应的全局事务也会被中断。

Timeout Scenario
Timeout Scenario

使用servicecomb-saga

下面的过程也是参考官方文档,但由于我这里使用mysql数据库作为底层数据库,修改了少量操作。

准备环境

  1. 安装JDK 1.8
  2. 安装Maven 3.x

编译

获取源码:

代码语言:javascript
复制
$ git clone https://github.com/apache/incubator-servicecomb-saga.git
$ cd incubator-servicecomb-saga

构建mysql的可执行文件:

代码语言:javascript
复制
$ mvn clean install -DskipTests -Pmysql

创建数据库

创建数据库并给予用户访问该数据库的权限

代码语言:javascript
复制
$ mysql
mysql> create database saga default character set utf8;
mysql> GRANT ALL PRIVILEGES ON saga.* to 'saga'@'localhost' identified by '123456';
mysql> flush priveleges;
mysql> exit

启动alpha-server

直接使用java命令启动alpha-server

代码语言:javascript
复制
java -Dspring.profiles.active=mysql -D"spring.datasource.url=jdbc:mysql://localhost:3306/saga?useSSL=false" -D"spring.datasource.username=saga" -D"spring.datasource.password=123456"  -jar alpha/alpha-server/target/saga/alpha-server-0.3.0-SNAPSHOT-exec.jar

配置Omega

按照servicecomb-saga的架构,所有支持分布式事务的spring-boot应用须配置Omega。其实也比较简单,大概有以下这些步骤。

引入Saga的依赖

应用的pom.xml配置文件中引入servicecomb-saga的依赖

代码语言:javascript
复制
    <dependency>
      <groupId>org.apache.servicecomb.saga</groupId>
      <artifactId>omega-spring-starter</artifactId>
      <version>0.3.0-SNAPSHOT</version>
    </dependency>
    <dependency>
      <groupId>org.apache.servicecomb.saga</groupId>
      <artifactId>omega-transport-resttemplate</artifactId>
      <version>0.3.0-SNAPSHOT</version>
    </dependency>
添加Saga的注解及相应的补偿方法

以一个转账应用为例:

  1. 在应用入口添加 @EnableOmega 的注解来初始化omega的配置并与alpha建立连接。
代码语言:javascript
复制
   @SpringBootApplication
   @EnableOmega
   public class Application {
     public static void main(String[] args) {
       SpringApplication.run(Application.class, args);
     }
   }
  1. 在全局事务的起点添加 @SagaStart 的注解。
代码语言:javascript
复制
   @SagaStart(timeout=10)
   public boolean transferMoney(String from, String to, int amount) {
     transferOut(from, amount);
     transferIn(to, amount);
   }

注意: 默认情况下,超时设置需要显式声明才生效。

  1. 在子事务处添加 @Compensable 的注解并指明其对应的补偿方法。
代码语言:javascript
复制
   @Compensable(timeout=5, compensationMethod="cancel")
   public boolean transferOut(String from, int amount) {
     repo.reduceBalanceByUsername(from, amount);
   }
   
   public boolean cancel(String from, int amount) {
     repo.addBalanceByUsername(from, amount);
   }

注意: 实现的服务和补偿必须满足幂等的条件。

注意: 默认情况下,超时设置需要显式声明才生效。

注意: 若全局事务起点与子事务起点重合,需同时声明 @SagaStart@Compensable 的注解。

  1. 对转入服务重复第三步即可。
配置omega的spring配置项

application.properties中添加下面的配置项:

代码语言:javascript
复制
alpha.cluster.address=127.0.0.1:8080 #这个指向alpha server的grpc地址

然后就可以运行相关的微服务了,可通过访问http://127.0.0.1:8090/events 来查询所有的saga事件信息。

总结

本篇只大概介绍了下servicecomb-saga的使用过程,主要内容都是参考其官方文档,其实也花了些时间走读它的源码,对其实现原理有一定了解了,后面抽时间再写一篇具体分析其源代码。

参考

  1. https://github.com/apache/incubator-servicecomb-saga/blob/master/docs
  2. https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为何会有分布式事务
  • 为何选择saga方案
  • servicecomb-saga的架构
    • 概览
      • Omega内部运行机制
        • 服务间通信流程
          • 具体处理流程
            • 成功场景
            • 异常场景
            • 超时场景
        • 使用servicecomb-saga
          • 准备环境
            • 编译
              • 创建数据库
                • 启动alpha-server
                  • 配置Omega
                    • 引入Saga的依赖
                    • 添加Saga的注解及相应的补偿方法
                    • 配置omega的spring配置项
                • 总结
                • 参考
                相关产品与服务
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档