分布式事务解决方案之 Alibaba Seata1.3.0 seata-server 1.3.0
分布式事務解決方案之 Alibaba Seata1.3.0
一 Seata 是什么?
Seata 是一款開源的分布式事務解決方案,致力于提供高性能和簡單易用的分布式事務服務。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務模式,為用戶打造一站式的分布式解決方案。
詳情查看官方文檔https://seata.io/zh-cn/docs/overview/what-is-seata.html
術語
TC (Transaction Coordinator) - 事務協調者
維護全局和分支事務的狀態,驅動全局事務提交或回滾。
TM (Transaction Manager) - 事務管理器
定義全局事務的范圍:開始全局事務、提交或回滾全局事務。
RM (Resource Manager) - 資源管理器
管理分支事務處理的資源,與TC交談以注冊分支事務和報告分支事務的狀態,并驅動分支事務提交或回滾。
二 docker安裝seata-server
docker
https://seata.io/zh-cn/docs/ops/deploy-by-docker.html
下載zip到本地
https://seata.io/zh-cn/blog/download.html
# 拉取鏡像 docker pull seataio/seata-server # 啟動一個seata-server的容器 docker run -id --name seata-fs -p 8091:8091 --network host seataio/seata-server:latest2.1 seata需要的數據表
取名為seata庫,執行下面的表
DROP TABLE IF EXISTS `branch_table`; CREATE TABLE `branch_table` (`branch_id` bigint(20) NOT NULL,`xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`transaction_id` bigint(20) NULL DEFAULT NULL,`resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`status` tinyint(4) NULL DEFAULT NULL,`client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`gmt_create` datetime(6) NULL DEFAULT NULL,`gmt_modified` datetime(6) NULL DEFAULT NULL,PRIMARY KEY (`branch_id`) USING BTREE,INDEX `idx_xid`(`xid`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ---------------------------- -- Records of branch_table -- ------------------------------ ---------------------------- -- Table structure for global_table -- ---------------------------- DROP TABLE IF EXISTS `global_table`; CREATE TABLE `global_table` (`xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`transaction_id` bigint(20) NULL DEFAULT NULL,`status` tinyint(4) NOT NULL,`application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`timeout` int(11) NULL DEFAULT NULL,`begin_time` bigint(20) NULL DEFAULT NULL,`application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`gmt_create` datetime(0) NULL DEFAULT NULL,`gmt_modified` datetime(0) NULL DEFAULT NULL,PRIMARY KEY (`xid`) USING BTREE,INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE,INDEX `idx_transaction_id`(`transaction_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ---------------------------- -- Records of global_table -- ------------------------------ ---------------------------- -- Table structure for lock_table -- ---------------------------- DROP TABLE IF EXISTS `lock_table`; CREATE TABLE `lock_table` (`row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`transaction_id` bigint(20) NULL DEFAULT NULL,`branch_id` bigint(20) NOT NULL,`resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`gmt_create` datetime(0) NULL DEFAULT NULL,`gmt_modified` datetime(0) NULL DEFAULT NULL,PRIMARY KEY (`row_key`) USING BTREE,INDEX `idx_branch_id`(`branch_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ---------------------------- -- Records of lock_table -- ------------------------------ ---------------------------- -- Table structure for undo_log -- ---------------------------- DROP TABLE IF EXISTS `undo_log`; CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`context` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime(0) NOT NULL,`log_modified` datetime(0) NOT NULL,`ext` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `ux_undo_log`(`xid`, `branch_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;2.2 seata-server配置文件修改
# 進入seata-server容器docker exec -it seata-server /bin/bash# cd到cd resources/# 修改file.conf配置文件 vim file.conf# 提示:bash: vim: command not found # 解決方案 這是因為vim沒有安裝。使用如下命令安裝: apt-get update apt-get install vim2.2.1 修改file.conf文件
記住手動添加service模塊
## transaction log store, only used in seata-server#這里手動加入service模塊 service {#transaction service group mapping#修改,可不改,fs_group隨便起名字。vgroup_mapping.fs_group = "default"#only support when registry.type=file, please don't set multiple addresses# 此服務的地址default.grouplist = "47.112.174.148:8091"#disable seatadisableGlobalTransaction = false }store {## store mode: file、db、redis#這里修改為dbmode = "db"## file store propertyfile {## store location dirdir = "sessionStore"# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptionsmaxBranchSessionSize = 16384# globe session size , if exceeded throws exceptionsmaxGlobalSessionSize = 512# file buffer size , if exceeded allocate new bufferfileWriteBufferCacheSize = 16384# when recover batch read sizesessionReloadReadSize = 100# async, syncflushDiskMode = async}## database store propertydb {## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.datasource = "druid"## mysql/oracle/postgresql/h2/oceanbase etc.dbType = "mysql"#如果你是mysql8.0以上,則修改這里的驅動,不是則不修改driverClassName = "com.mysql.jdbc.Driver"url = "jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai"user = "賬戶"password = "密碼"minConn = 5maxConn = 30globalTable = "global_table"branchTable = "branch_table"lockTable = "lock_table"queryLimit = 100maxWait = 5000}## redis store propertyredis {host = "127.0.0.1"port = "6379"password = ""database = "1"minConn = 1maxConn = 10queryLimit = 100}}2.2.2 修改registry.conf文件
registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa# 修改這里為nacostype = "nacos"nacos {application = "seata-server"serverAddr = "47.112.174.148:8848"group = "SEATA_GROUP"namespace = ""cluster = "default"username = "nacos"password = "nacos"}eureka {serviceUrl = "http://localhost:8761/eureka"application = "default"weight = "1"}redis {serverAddr = "localhost:6379"db = 0password = ""cluster = "default"timeout = 0}zk {cluster = "default"serverAddr = "127.0.0.1:2181"sessionTimeout = 6000connectTimeout = 2000username = ""password = ""}consul {cluster = "default"serverAddr = "127.0.0.1:8500"}etcd3 {cluster = "default"serverAddr = "http://localhost:2379"}sofa {serverAddr = "127.0.0.1:9603"application = "default"region = "DEFAULT_ZONE"datacenter = "DefaultDataCenter"cluster = "default"group = "SEATA_GROUP"addressWaitTime = "3000"}file {name = "file.conf"} }config {# file、nacos 、apollo、zk、consul、etcd3#修改這里為nacostype = "nacos"nacos {serverAddr = "47.112.174.148:8848"namespace = ""group = "SEATA_GROUP"username = "nacos"password = "nacos"}consul {serverAddr = "127.0.0.1:8500"}apollo {appId = "seata-server"apolloMeta = "http://192.168.1.204:8801"namespace = "application"}zk {serverAddr = "127.0.0.1:2181"sessionTimeout = 6000connectTimeout = 2000username = ""password = ""}etcd3 {serverAddr = "http://localhost:2379"}file {name = "file.conf"} }2.2.3 最后退出重啟seata-server容器
在nacos中查看seata-server是否注冊上
三 seata配置文件注冊到注冊中心
3.1 到seata地址下載源碼https://github.com/seata/seata
3.2 修改配置文件
下載解壓后進入seata-1.3.0\seata-1.3.0\script\config-center目錄下修改config.txt文件
transport.type=TCP transport.server=NIO transport.heartbeat=true transport.enableClientBatchSendRequest=false transport.threadFactory.bossThreadPrefix=NettyBoss transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler transport.threadFactory.shareBossWorker=false transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector transport.threadFactory.clientSelectorThreadSize=1 transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread transport.threadFactory.bossThreadSize=1 transport.threadFactory.workerThreadSize=default transport.shutdown.wait=3 # 配置seata-server的信息 fs_group就是之前在file.conf中配置的 service.vgroupMapping.fs_group=default # 配置seata-server的ip service.default.grouplist=47.112.174.148:8091service.enableDegrade=false service.disableGlobalTransaction=false client.rm.asyncCommitBufferLimit=10000 client.rm.lock.retryInterval=10 client.rm.lock.retryTimes=30 client.rm.lock.retryPolicyBranchRollbackOnConflict=true client.rm.reportRetryCount=5 client.rm.tableMetaCheckEnable=false client.rm.sqlParserType=druid client.rm.reportSuccessEnable=false client.rm.sagaBranchRegisterEnable=false client.tm.commitRetryCount=5 client.tm.rollbackRetryCount=5 client.tm.degradeCheck=false client.tm.degradeCheckAllowTimes=10 client.tm.degradeCheckPeriod=2000 # 這里改為db store.mode=db store.file.dir=file_store/data store.file.maxBranchSessionSize=16384 store.file.maxGlobalSessionSize=512 store.file.fileWriteBufferCacheSize=16384 store.file.flushDiskMode=async store.file.sessionReloadReadSize=100 store.db.datasource=druid store.db.dbType=mysql # mysql 版本5的就是這個驅動,8要改 store.db.driverClassName=com.mysql.jdbc.Driver # mysql地址 store.db.url=jdbc:mysql://47.112.174.148:3306/seata?useUnicode=true # mysql用戶名密碼 store.db.user=root store.db.password=root store.db.minConn=5 store.db.maxConn=30 store.db.globalTable=global_table store.db.branchTable=branch_table store.db.queryLimit=100 store.db.lockTable=lock_table store.db.maxWait=5000 store.redis.host=127.0.0.1 store.redis.port=6379 store.redis.maxConn=10 store.redis.minConn=1 store.redis.database=0 store.redis.password=null store.redis.queryLimit=100 server.recovery.committingRetryPeriod=1000 server.recovery.asynCommittingRetryPeriod=1000 server.recovery.rollbackingRetryPeriod=1000 server.recovery.timeoutRetryPeriod=1000 server.maxCommitRetryTimeout=-1 server.maxRollbackRetryTimeout=-1 server.rollbackRetryTimeoutUnlockEnable=false client.undo.dataValidation=true client.undo.logSerialization=jackson client.undo.onlyCareUpdateColumns=true server.undo.logSaveDays=7 server.undo.logDeletePeriod=86400000 client.undo.logTable=undo_log client.log.exceptionRate=100 transport.serialization=seata transport.compressor=none metrics.enabled=false metrics.registryType=compact metrics.exporterList=prometheus metrics.exporterPrometheusPort=98983.3 執行nacos-config.sh腳本
然后執行源碼seata\seata-1.3.0\script\config-center\nacos\nacos-config.sh 這個腳本
注意需要編輯nacos-config.sh 腳本中得nacos地址
可以使用git命令窗口執行,看到如下圖片則代表執行成功
3.4 去nacos查看配置文件是否推送成功
nacos配置管理,配置列表中可以看到如下圖所示配置,即代表成功
四 快速開始SEATA AT 模式
4.1 環境搭建docker
nacos mysql seata-server
4.1.1 本地啟動seata-server
去nacos查看seata-server是注冊成功
讓我們從一個微服務示例開始
4.2 數據準備
用戶購買商品的業務邏輯。整個業務邏輯由3個微服務提供支持:
- 倉儲服務:對給定的商品扣除倉儲數量。
- 訂單服務:根據采購需求創建訂單。
- 帳戶服務:從用戶帳戶中扣除余額。
4.3 為示例業務創建表
創建庫存表,訂單表,賬戶表
# 庫存表 DROP TABLE IF EXISTS `storage_tb`; CREATE TABLE `storage_tb` (`id` int(11) NOT NULL AUTO_INCREMENT,`commodity_code` varchar(255) DEFAULT NULL,`count` int(11) DEFAULT 0,PRIMARY KEY (`id`),UNIQUE KEY (`commodity_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;# 訂單表 DROP TABLE IF EXISTS `order_tb`; CREATE TABLE `order_tb` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` varchar(255) DEFAULT NULL,`commodity_code` varchar(255) DEFAULT NULL,`count` int(11) DEFAULT 0,`money` int(11) DEFAULT 0,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;# 賬戶表 DROP TABLE IF EXISTS `account_tb`; CREATE TABLE `account_tb` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` varchar(255) DEFAULT NULL,`money` int(11) DEFAULT 0,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;4.4 創建 UNDO_LOG 表(每個庫下都要創建)
創建 UNDO_LOG 表 SEATA AT 模式需要 UNDO_LOG 表-- 注意此處0.3.0+ 增加唯一索引 ux_undo_log CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;最終表結構如圖
4.4.1 為每個表初始化默認數據
4.5 搭建springcloud項目
4.5.1 源代碼
大致就是order服務生成訂單使用feign遠程調用去減庫存,扣錢,和生成訂單
在生成訂單的未付的方法上使用@GlobalTransactional就實現了全局事務控制
若在扣完錢后制造除0異常,就會導致訂單生成不成功,但是扣了錢和減了庫存,所以需要使用分布式事務控制
4.5.2 seata pom依耐
<dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-seata</artifactId><version>2.2.0.RELEASE</version><exclusions><exclusion><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId></exclusion><exclusion><groupId>io.seata</groupId><artifactId>seata-all</artifactId></exclusion></exclusions></dependency><dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.3.0</version></dependency><dependency><groupId>io.seata</groupId><artifactId>seata-all</artifactId><version>1.3.0</version></dependency></dependencies>4.5.3 application.yml(以order-service為例子)
server:port: 8001 spring:application:name: seata-orderdatasource:username: 賬戶password: 密碼url: jdbc:mysql://47.112.174.148:3306/orderbasedriver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource #自定義數據源cloud:nacos:discovery:server-addr: 47.112.174.148:8848 #seata配置 seata:enabled: true# 起個當前服務的seata名字application-id: seata-order#這里的名字與file.conf中vgroup_mapping.my_test_tx_group = "default"相同tx-service-group: fs_groupenable-auto-data-source-proxy: true# use-jdk-proxy: falseservice:#這里的名字與file.conf中vgroup_mapping.my_test_tx_group = "default"相同vgroup-mapping:my_test_tx_group: default#這里的名字與file.conf中default.grouplist = "127.0.0.1:8091"相同grouplist:default: 127.0.0.1:8091# disable-global-transaction: falseconfig:type: nacosnacos:namespace:#這里的地址就是你的nacos的地址,可以更換為線上serverAddr: 47.112.174.148:8848#這里的名字就是registry.conf中 nacos的group名字group: SEATA_GROUPuserName: "nacos"password: "nacos"registry:type: nacosnacos:application: seata-server#這里的地址就是你的nacos的地址,可以更換為線上server-addr: 47.112.174.148:8848#這里的名字就是registry.conf中 nacos的group名字group: SEATA_GROUPnamespace:userName: "nacos"password: "nacos"# feign配置 feign:hystrix:enabled: trueclient:config:default: #配置全局的feign的調用超時時間 如果 有指定的服務配置 默認的配置不會生效connectTimeout: 60000 # 指定的是 消費者 連接服務提供者的連接超時時間 是否能連接 單位是毫秒readTimeout: 60000 # 指定的是調用服務提供者的 服務 的超時時間() 單位是毫秒 #hystrix 配置 hystrix:command:default:execution:timeout:#如果enabled設置為false,則請求超時交給ribbon控制enabled: trueisolation:strategy: SEMAPHOREthread:# 熔斷器超時時間,默認:1000/毫秒timeoutInMilliseconds: 20000# 配置日志 #mybatis-plus: # configuration: # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl4.5.4 啟動微服務測試
在生成訂單的未付的方法上使用@GlobalTransactional就實現了全局事務控制
在order的生成訂單的業務中制作異常,查看事務是否被控制
總結
以上是生活随笔為你收集整理的分布式事务解决方案之 Alibaba Seata1.3.0 seata-server 1.3.0的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ElasticSearch,docker
- 下一篇: Netty-案例 WebSocket与n