Apache Seata Mac下的Seata Demo环境搭建

server/2024/9/18 8:13:02/ 标签: apache, macos, 分布式事务, seata, 分布式

本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。
本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。

Mac下的Seata Demo环境搭建(AT模式)

前言

最近因为工作需要,研究学习了Seata分布式事务>分布式事务框架,本文把自己学习的知识记录一下

Seata总览

cloc代码统计

先看一下seata项目cloc代码统计(截止到2020-07-20)

在这里插入图片描述

Java代码行数大约是 97K

代码质量

单元测试覆盖率50%

seata-at-demo-in-mac%2Fcoverage.png%3Fraw%3Dtrue&pos_id=img-BACMqBgl-1720258923243" alt="外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传" />

Demo代码

本文讲的Demo代码是seata-samples项目下的seata-samples-dubbo模块,地址如下:

https://github.com/apache/incubator-seata-samples/tree/master/dubbo

解决的核心问题

AT模式的Demo例子给出了一个典型的分布式事务>分布式事务场景:

  • 在一个采购交易中,需要:
  1. 扣减商品库存
  2. 扣减用户账号余额
  3. 生成采购订单
  • 很明显,以上3个步骤必须:要么全部成功,要么全部失败,否则系统的数据会错乱
  • 而现在流行的微服务架构,一般来说,库存,账号余额,订单是3个独立的系统
  • 每个微服务有自己的数据库,相互独立

这里就是分布式事务>分布式事务的场景。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解决方案

AT模式解决这个问题的思路其实很简单,一句话概括就是:

分布式事务>分布式事务过程中,记录待修改的数据修改前和修改后的值到undo_log表,万一交易中出现异常,通过这个里的数据做回滚

当然,具体代码实现起来,我相信很多细节远没这么简单。

Demo代码结构

从github上clone最新的代码

git clone git@github.com:apache/incubator-seata-samples.git

阅读Demo代码结构

$ cd seata-samples/dubbo/
$ tree -C  -I 'target' .
.
├── README.md
├── pom.xml
├── seata-samples-dubbo.iml
└── src└── main├── java│   └── io│       └── seata│           └── samples│               └── dubbo│                   ├── ApplicationKeeper.java│                   ├── Order.java│                   ├── service│                   │   ├── AccountService.java│                   │   ├── BusinessService.java│                   │   ├── OrderService.java│                   │   ├── StorageService.java│                   │   └── impl│                   │       ├── AccountServiceImpl.java│                   │       ├── BusinessServiceImpl.java│                   │       ├── OrderServiceImpl.java│                   │       └── StorageServiceImpl.java│                   └── starter│                       ├── DubboAccountServiceStarter.java│                       ├── DubboBusinessTester.java│                       ├── DubboOrderServiceStarter.java│                       └── DubboStorageServiceStarter.java└── resources├── file.conf├── jdbc.properties├── log4j.properties├── registry.conf├── spring│   ├── dubbo-account-service.xml│   ├── dubbo-business.xml│   ├── dubbo-order-service.xml│   └── dubbo-storage-service.xml└── sql├── dubbo_biz.sql└── undo_log.sql13 directories, 27 files
  • 在io.seata.samples.dubbo.starter包下的4个*Starter类,分别模拟上面所述的4个微服务

    • Account
    • Business
    • Order
    • Storage
  • 4个服务都是标准的dubbo服务,配置文件在seata-samples/dubbo/src/main/resources/spring目录下

  • 运行demo需要把这4个服务都启动起来,Business最后启动

  • 主要的逻辑在io.seata.samples.dubbo.service,4个实现类分别对应4个微服务的业务逻辑

  • 数据库信息的配置文件:src/main/resources/jdbc.properties

时序图

seata-at-demo-in-mac%2Ftiming-diagram.png%3Fraw%3Dtrue&pos_id=img-IOU1tjXc-1720258923243" alt="外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传" />

Ok, 赶紧动手, Make It Happen!

运行Demo

MySQL

建表

执行seata-samples/dubbo/src/main/resources/sql的脚本dubbo_biz.sql和undo_log.sql

mysql> show tables;
+-----------------+
| Tables_in_seata |
+-----------------+
| account_tbl     |
| order_tbl       |
| storage_tbl     |
| undo_log        |
+-----------------+
4 rows in set (0.01 sec)

执行完之后,数据库里应该有4个表

修改seata-samples/dubbo/src/main/resources/jdbc.properties文件

根据你MySQL运行的环境修改变量的值

jdbc.account.url=jdbc:mysql://localhost:3306/seata
jdbc.account.username=your_username
jdbc.account.password=your_password
jdbc.account.driver=com.mysql.jdbc.Driver
# storage db config
jdbc.storage.url=jdbc:mysql://localhost:3306/seata
jdbc.storage.username=your_username
jdbc.storage.password=your_password
jdbc.storage.driver=com.mysql.jdbc.Driver
# order db config
jdbc.order.url=jdbc:mysql://localhost:3306/seata
jdbc.order.username=your_username
jdbc.order.password=your_password
jdbc.order.driver=com.mysql.jdbc.Driver

ZooKeeper

启动ZooKeeper,我的本地的Mac是使用Homebrew安装启动的

$ brew services start zookeeper 
==> Successfully started `zookeeper` (label: homebrew.m$ brew services list           
Name              Status  User    Plist
docker-machine    stopped         
elasticsearch     stopped         
kafka             stopped         
kibana            stopped         
mysql             started portman /Users/portman/Librar
y/LaunchAgents/homebrew.mxcl.mysql.plist
nginx             stopped         
postgresql        stopped         
redis             stopped         
zookeeper         started portman /Users/portman/Librar
y/LaunchAgents/homebrew.mxcl.zookeeper.plist

启动TC事务协调器

在这个链接里页面中,下载对应版本的seata-server程序,我本地下载的是1.2.0版本

  1. 进入文件所在目录并解压文件
  2. 进入seata目录
  3. 执行启动脚本
$ tar -zxvf seata-server-1.2.0.tar.gz
$ cd seata
$ bin/seata-server.sh

观察启动日志是否有报错信息,如果一切正常,并看到了以下的Server started的信息,说明启动成功了。

2020-07-23 13:45:13.810 INFO [main]io.seata.core.rpc.netty.RpcServerBootstrap.start:155 -Server started ...

IDE中启动模拟的微服务

  1. 首先要把seata-samples项目导入到本地IDE中,这里我用的是IntelliJ IDEA
  2. 刷新Maven的工程依赖
  3. 先启动Account,Order,Storage这个3个服务,然后Business才能去调用,对应的启动类分别是:
io.seata.samples.dubbo.starter.DubboStorageServiceStarter
io.seata.samples.dubbo.starter.DubboOrderServiceStarter
io.seata.samples.dubbo.starter.DubboStorageServiceStarter

每个服务启动完之后,看到这句提示信息,说明服务启动成功了

Application is keep running ...

seata-at-demo-in-mac%2Fservice-boot.png%3Fraw%3Dtrue&pos_id=img-vhnR0gpF-1720258923244" alt="外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传" />

启动成功后,account_tbl,storage_tbl表会有两条初始化的数据,分别是账户余额和商品库存

mysql> SELECT * FROM account_tbl; SELECT * FROM storage_tbl;
+----+---------+-------+
| id | user_id | money |
+----+---------+-------+
|  1 | U100001 |   999 |
+----+---------+-------+
1 row in set (0.00 sec)+----+----------------+-------+
| id | commodity_code | count |
+----+----------------+-------+
|  1 | C00321         |   100 |
+----+----------------+-------+
1 row in set (0.00 sec)

使用Business验证效果

正常情况

还是在IDE中执行DubboBusinessTester类的主函数,程序跑完会自动退出

在程序一切正常的情况下,每个微服务的事物都应该是提交了的,数据保持一致

我们来看一下MySQL中数据的变化

mysql> SELECT * FROM account_tbl; SELECT * FROM order_tbl; SELECT * FROM storage_tbl;
+----+---------+-------+
| id | user_id | money |
+----+---------+-------+
|  1 | U100001 |   599 |
+----+---------+-------+
1 row in set (0.00 sec)+----+---------+----------------+-------+-------+
| id | user_id | commodity_code | count | money |
+----+---------+----------------+-------+-------+
|  1 | U100001 | C00321         |     2 |   400 |
+----+---------+----------------+-------+-------+
1 row in set (0.00 sec)+----+----------------+-------+
| id | commodity_code | count |
+----+----------------+-------+
|  1 | C00321         |    98 |
+----+----------------+-------+
1 row in set (0.00 sec)

从3个表的数据可以看到:账户余额扣减了400块;订单表增加了1条记录;商品库存扣减了2个

这个结果是程序的逻辑是一致的,说明事务没有问题

异常情况

其实即使不加入分布式事务>分布式事务的控制,一切都正常情况下,事务本身就不会有问题的

所以我们来重点关注,当程序出现异常时的情况

现在我把BusinessServiceImpl的抛异常的代码注释放开,然后再执行一次DubboBusinessTester,来看看有什么情况发生

		@Override@GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")public void purchase(String userId, String commodityCode, int orderCount) {LOGGER.info("purchase begin ... xid: " + RootContext.getXID());storageService.deduct(commodityCode, orderCount);orderService.create(userId, commodityCode, orderCount);//放开这句抛异常的注释,模拟程序出现异常throw new RuntimeException("portman's foooooobar error.");}

接着,我再一次执行DubboBusinessTester,执行过程中在控制台可以看到异常报错信息

Exception in thread "main" java.lang.RuntimeException: portman's foooooobar error.

现在我们再看一下MySQL里的数据变化,发现数据没有任何变化,说明分布式事务>分布式事务的控制已经起作用了

待思考问题

上面的步骤只是演示了seata最简单的demo程序,更多更复杂的情况后续大家可以一起讨论和验证

学习过程中还有一些问题和疑惑,后续进一步学习

  • 全局锁对性能的影响程度
  • undo_log日志可以回滚到原来状态,但是如果数据状态已经发生变化如何处理(比如增加的用户积分已经被别的本地事务花掉了)

参考文献

  • Seata 是什么?
  • 快速开始

作者信息

许晓加,金蝶软件架构师

Github


http://www.ppmy.cn/server/59780.html

相关文章

竞速赛车游戏推荐:极品飞车14:热力追踪 (Win/Mac) 安装包

《极品飞车14:热力追踪》(Need for Speed: Hot Pursuit)是《极品飞车》系列的第14部作品,于2010年11月发行。这款游戏是继《极品飞车:热力追踪2》后,系列再次回归该名称。 游戏采用 Criterion Games 的开放…

github 下载提速的几种方法

1. 代理下载(无需注册) //toolwa.com/github/ //d.serctl.com/2. 转入 Gitee 加速 将项目镜像到 Gitee 中下载加速 3. 使用 Watt Toolkit 加速 Watt Toolkit //steampp.net/选择合适的版本下载 选择 github,一键加速 4.CDN 加速 (修改…

人脸检测+调整分辨率+调整帧率

初始检测:只在视频的前几秒内进行一次人脸检测,以确定主持人的大致位置。计算裁剪框:基于检测到的主持人位置,计算一个以主持人面部为中心的固定裁剪框。视频裁剪:使用计算出的裁剪框对整个视频进行裁剪,将…

【vue】下载 打印 pdf (问题总结)- 持续更新ing

这里是目录标题 一、pdf1.查看 下载一、pdf 1.查看 下载 样式 Code<template><div><el-table :data="pdfList" style="width: 100%" border ><el-table-columnprop="index"label="序号"width="80"ali…

CUDA原子操作

代码 #include <cuda_runtime.h> #include <stdio.h>__global__ void atomicAddAndGet(int *result, int *valueToAdd) {// 原子加法int addedValue atomicAdd(result, *valueToAdd);// 通过原子操作后读取值&#xff0c;确保是加法后的值addedValue *valueToAd…

用 MATLAB Function 模块在 Simulink 中实现 MATLAB 函数

MATLAB Function 模块使您能够使用 MATLAB 语言在 Simulink 模型中定义自定义函数。MATLAB Function 模块支持从 Simulink Coder 和 Embedded Coder生成 C/C 代码。 在以下情况下使用这些模块&#xff1a; 您有现有 MATLAB 函数可用于对自定义功能进行建模&#xff0c;或您可…

Uniapp表单提交

template中&#xff1a; <template><view class""><button class"tianjia" click"tianjia">添加</button><view class"divOne" v-show"a"><text class"guanbi" click"gua…

我的PHP8编译日志

编译命令在arm和x86架构上是一样的&#xff0c;如果缺少依赖库&#xff0c;按需要安装&#xff1a; 登录后复制 yuminstall libcurl libcurl-devel yum install openssl openssl-devel yum install pcre2 pcre2-devel yum install libxml2 libxml2-devel 1.2.3.4. 配置和编译&…

针对vue3的render函数添加自定义指令

话不多说 直接上代码 主要是给h函数设置自定义指令控制 import /styles/reset.css import /styles/global.scss import uno.cssimport { createApp } from vue import App from ./App.vue import { setupRouter } from ./router import { setupStore } from ./store import …

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第一篇 嵌入式Linux入门篇-第四章 Ubuntu启用root用户

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

Spring Boot集成Atomix快速入门Demo

1.什么是Atomix&#xff1f; Atomix是一个能用的Java框架&#xff0c;用来构建高可用的分布式系统。它是基于RAFT协议的实现&#xff0c;为用户提供了各种原子数据结构&#xff0c;比如map/set/integer等&#xff0c;这些数据结构都可以在整个集群中共享并保证一致性&#xff…

文档去重(TF-IDF,MinHash, SimHash)

2个doc有些相似有些不相似&#xff0c;如何衡量这个相似度&#xff1b; 直接用Jaccard距离&#xff0c;计算量太大 TF-IDF: TF*IDF TF&#xff1a;该词在该文档中的出现次数&#xff0c; IDF&#xff1a;该词在所有文档中的多少个文档出现是DF&#xff0c;lg(N/(1DF)) MinHash …

深入理解 Cowboy WebSocket:使用 Erlang/OTP 构建高效的即时通讯(IM)应用

深入理解 Cowboy WebSocket&#xff1a;使用 Erlang/OTP 构建高效的即时通讯(IM)应用 引言 实时通信技术在现代 Web 应用中扮演着核心角色&#xff0c;而 WebSocket 作为其中的关键技术&#xff0c;已成为即时通讯(IM)系统不可或缺的一部分。Cowboy&#xff0c;这个基于 Erla…

【深度学习】数据增强基本介绍和常用的数据增强方法

一 数据增强简介 数据增强&#xff08;Data Augmentation&#xff09;是一种技术&#xff0c;通过对现有数据进行各种变换和处理来生成新的训练样本&#xff0c;从而增加数据集的多样性和数量。这些变换可以是几何变换、颜色变换、噪声添加等&#xff0c;使模型在训练过程中能…

禅道二次开发——禅道zentaoPHP框架扩展机制——对样式表和js进行扩展

一、样式表的扩展 如果相对某一个页面的样式进行修改&#xff0c;可以有两种方法。一种就是通过前面所讲的视图文件的扩展来进行。还有一种方法就是单独为这个页面定义样式。比如我想对bug模块的create页面进行样式的重新定义&#xff0c;可以这样定义&#xff1a; 在extensi…

科普文:jvm笔记

一、JVM概述# 1. JVM内部结构# 跨语言的平台&#xff0c;只要遵循编译出来的字节码的规范&#xff0c;都可以由JVM运行 虚拟机 系统虚拟机 VMvare 程序虚拟机 JVM JVM结构 HotSpot虚拟机 详细结构图 前端编译器是编译为字节码文件 执行引擎中的JIT Compiler编译器是把字节…

element UI时间组件两种使用方式

加油&#xff0c;新时代打工&#xff01; 组件官网&#xff1a;https://element.eleme.cn/#/zh-CN/component/date-picker 先上效果图&#xff0c;如下&#xff1a; 第一种实现方式 <div class"app-container"><el-formref"submitForm":model&q…

SpringCloud--Eureka集群

Eureka注册中心集群 为什么要集群 如果只有一个注册中心服务器&#xff0c;会存在单点故障&#xff0c;不可以高并发处理所以要集群。 如何集群 准备三个EurekaServer 相互注册&#xff0c;也就是说每个EurekaServer都需要向所有的EureakServer注册&#xff0c;包括自己 &a…

Spring Boot对接大模型:实战价值与技巧

Spring Boot对接大模型&#xff1a;实战价值与技巧 随着大数据和人工智能技术的飞速发展&#xff0c;大模型&#xff08;Large-scale Models&#xff09;在各个行业中的应用越来越广泛。为了充分利用这些大模型的能力&#xff0c;我们需要将其与现有的应用框架进行对接。Sprin…

如何在Spring Boot中集成Hibernate

如何在Spring Boot中集成Hibernate 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Spring Boot项目中集成Hibernate。Hibernate是一个广泛…