Spring Cloud Seata 系列:Seata-Server (1.7.1)安裝與設定(整合 Nacos)

2023-11-13 06:01:02

一、簡介

Seata 是一款開源的分散式事務解決方案,致力於提供高效能和簡單易用的分散式事務服務。Seata 將為使用者提供了 AT、TCC、SAGA 和 XA 事務模式,為使用者打造一站式的分散式解決方案。

在 Seata 開源之前,Seata 對應的內部版本在阿里經濟體內部一直扮演著分散式一致性中介軟體的角色,幫助經濟體平穩地度過歷年的雙 11,對各 BU 業務進行了有力的支撐。經過多年沉澱與積累,商業化產品先後在阿里雲、金融雲進行售賣。2019 年 1 月為了打造更加完善的技術生態和普惠技術成果,Seata 正式宣佈對外開源,未來 Seata 將以社群共建的形式幫助其技術更加可靠與完備。

官網:https://seata.io/zh-cn/

術語

TC (Transaction Coordinator) - 事務協調者

維護全域性和分支事務的狀態,驅動全域性事務提交或回滾。

TM (Transaction Manager) - 事務管理器

定義全域性事務的範圍:開始全域性事務、提交或回滾全域性事務。

RM (Resource Manager) - 資源管理器

管理分支事務處理的資源,與 TC 交談以註冊分支事務和報告分支事務的狀態,並驅動分支事務提交或回滾。

事務模式

Seata 提供了 XA、AT、TCC 與 SAGA 四種分散式事務模式

XA 模式

https://seata.io/zh-cn/docs/dev/mode/xa-mode

前提:

  • 支援 XA 事務的資料庫。
  • Java 應用,通過 JDBC 存取資料庫。

整體機制:

在 Seata 定義的分散式事務框架內,利用事務資源(資料庫、訊息服務等)對 XA 協定的支援,以 XA 協定的機制來管理分支事務的一種 事務模式。

  • 執行階段:
    • 可回滾:業務 SQL 操作放在 XA 分支中進行,由資源對 XA 協定的支援來保證 可回滾
    • 持久化:XA 分支完成後,執行 XA prepare,同樣,由資源對 XA 協定的支援來保證 持久化(即,之後任何意外都不會造成無法回滾的情況)
  • 完成階段:
    • 分支提交:執行 XA 分支的 commit
    • 分支回滾:執行 XA 分支的 rollback

問題:

  • 回滾紀錄檔無法自動清理,需要手工清理。
  • 多執行緒下對同一個 RM 中的資料進行修改,存在 ABA 問題。

AT 模式

https://seata.io/zh-cn/docs/dev/mode/at-mode

前提:

  • 基於支援本地 ACID 事務的關係型資料庫。
  • Java 應用,通過 JDBC 存取資料庫。

整體機制:

兩階段提交協定的演變:

  • 一階段:業務資料和回滾紀錄檔記錄在同一個本地事務中提交,釋放本地鎖和連線資源。
  • 二階段:
    • 提交非同步化,非常快速地完成。
    • 回滾通過一階段的回滾紀錄檔進行反向補償。

問題:

  • 不支援 NoSQL。
  • 全域性 commit/rollback 階段及回滾紀錄檔的清除過程,完全「自動化」無法實現客製化化過程。

TCC 模式

https://seata.io/zh-cn/docs/dev/mode/tcc-mode

AT 模式基於 支援本地 ACID 事務關係型資料庫

  • 一階段 prepare 行為:在本地事務中,一併提交業務資料更新和相應回滾紀錄檔記錄。
  • 二階段 commit 行為:馬上成功結束,自動 非同步批次清理回滾紀錄檔。
  • 二階段 rollback 行為:通過回滾紀錄檔,自動 生成補償操作,完成資料回滾。

相應的,TCC 模式,不依賴於底層資料資源的事務支援:

  • 一階段 prepare 行為:呼叫 自定義 的 prepare 邏輯。
  • 二階段 commit 行為:呼叫 自定義 的 commit 邏輯。
  • 二階段 rollback 行為:呼叫 自定義 的 rollback 邏輯。

所謂 TCC 模式,是指支援把 自定義 的分支事務納入到全域性事務的管理中。

TCC,Try Confirm/Cancel,同樣也是 2PC 的,其與 AT 的重要區別是,支援將自定義的分支事務納入到全域性事務管理中,即可以實現客製化化的紀錄檔清理與回滾過程。當然,該模式對業務邏輯的侵入性是較大的。

Sage 模式

https://seata.io/zh-cn/docs/dev/mode/saga-mode

對於架構複雜,且業務流程較多較長的系統,一般不適合使用 2PC 的分散式事務模式。因為這種系統一般無法提供 TM、TC、RM 三種介面。此時,我們可以嘗試著選擇 Saga 模式

Saga 模式是 SEATA 提供的長事務解決方案,在 Saga 模式中,業務流程中每個參與者都提交本地事務,當出現某一個參與者失敗則補償前面已經成功的參與者,一階段正向服務和二階段補償服務都由業務開發實現。

其應用場景是:在無法提供 TC、TM、RM 介面的情況下,對於一個流程很長的複雜業務,其會包含很多的子流程(事務)。每個子流程都讓它們真實提交它們真正的執行結果。

只有當前子流程執行成功後才能執行下一個子流程。若整個流程中所有子流程全部執行成功,則整個業務流程成功;只要有一個子流程執行失敗,則可採用兩種補償方式:

  • 向後恢復:對於其前面所有成功的子流程,其執行結果全部復原
  • 向前恢復:重試失敗的子流程直到其成功。當然這個前提是要確保每個分支事務都能夠成功。

2PC 模式的區別

Saga 模式的所有分支事務是序列執行的,而 2PC 的則是並行執行的。

Saga 模式沒有 TC,其是通過子流程間的訊息傳遞來完成全域性事務管理的,而 2PC 則具有 TC,其是通過 TC 完成全域性事務管理的。

說明

無論是 AT 模式,還是 TCC 模式或 XA 模式,都需要有事務協調器 TC,即 Seata Server

下載地址:https://seata.io/zh-cn/docs/download

Seata 的原始碼包與二進位制包均需要下載。因為 Seata Client 需要使用 Seata 的原始碼包中的一個 sql 指令碼檔案。

二、Seata Server 儲存模式

Seata Server 需要對全域性事務與分支事務進行儲存,以便對它們進行管理。其儲存模式目前支援三種:file、db 與 redis。

  • file 模式:會將相關資料儲存在本地檔案中,一般用於 Seata Server 的單機測試。
  • db 模式:會將相關資料儲存在資料庫中,一般用於生產環境下的 Seata Server 叢集部署。生產環境下使用最多的模式。
  • redis 模式:會將相關資料儲存在 redis 中,一般用於生產環境下的 Seata Server 叢集部署。效能略高於 db 模式,如果對效能要求較高,可選擇 redis 模式。

1、file 模式

①修改application.xml

將 seata-server-1.7.1.zip 解壓後,修改 seata 解壓目錄下的 conf 目錄中的 application.yml檔案。預設file模式,在該檔案中需要設定三類資訊:Seata 的設定中心、Seata 的註冊中心,及回滾紀錄檔資訊。不過,對於 file 模式,只需要修改以下位置即可。

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: file
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: file
  store:
    # support: file 、 db 、 redis
    mode: file

②啟動Seata-Server

seata/bin 目錄下直接雙擊 seata-server.sh 批次檔即可啟動。啟動後在該 bin 目錄中就可以直接看到生成的 sessionStore 目錄及其中的 root.data 檔案。

2、db 模式

file 模式一般用於簡單測試,生產環境下使用的是 db 模式

①執行mysql.sql指令碼

在 seata 包解壓目錄的 script/server/db 下找到 mysql.sql 檔案。該指令碼檔案中建立了 4張表。這 4 張表都是用於儲存整個系統中分散式事務相關紀錄檔資料的。

該指令碼檔案中僅有建表語句,沒有建立資料庫的語句,說明使用什麼資料庫名稱都可以。為了方便,我們在指令碼檔案中直接新增了建庫語句,並指定資料庫名稱為 seata。

create database if not exists seata;

②修改application.xml

修改 seata 解壓目錄下的conf目錄中的 application.yml 檔案。在該檔案中需要設定三類資訊:Seata 的設定中心、Seata 的註冊中心,及回滾紀錄檔資訊。

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${log.home:${user.home}/logs/seata}
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata
seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace:
      group: SEATA_GROUP
      username: nacos
      password: nacos
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
      data-id: seataServer.properties
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos:
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
      namespace:
      cluster: default
      username: nacos
      password: nacos
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:    
  store:
    # support: file 、 db 、 redis
    mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
      user: root
      password: 123456
      min-conn: 10
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 1000
      max-wait: 5000
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login

mysql5.7 使用 com.mysql.jdbc.Driver

Mysql8.0 使用 com.mysql.cj.jdbc.Driver

③修改 config.txt

修改 seata 解壓目錄的script/config-center下的 config.txt 檔案。這裡的內容都是 key-value,將來都是作為 nacos 設定中心中的資料出現的,將來開啟 nacos 可以根據其 key 逐條檢視到

修改儲存模式

指定這裡要使用的儲存模式為 db

store.modestore.lock.modestore.session.mode 中原來的 file 值修改為 db。再將公鑰行註釋掉。

修改db的連線四要素
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456

刪除其它儲存模式設定

由於這裡指定的儲存模式是db,所以需要將file模式與redis模式相關的設定全部刪除。

定義seataServer.properties

在 Nacos 設定中心定義 seataServer.properties 檔案。該檔案是在上述 application.yml 中指定的 data-id 檔案。將前面修改後的 config.txt 檔案內容全部複製到 seataServer.properties檔案中。

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
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
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
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=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
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.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption
#store.publicKey=

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#Transaction rule configuration, only for the server
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
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

④啟動 Seata-server

執行命令

在 seata 解壓目錄下的 bin 目錄中有個檔案 seata-server.sh,在命令列執行這個批次檔

./seata-server.sh -m db

⑤檢視 nacos

在 nacos 中可以看到 seata-server 的服務時,表示 seata 啟動成功了。

⑥seata web介面

埠預設7091、賬號密碼:seata

三、FAQ

https://seata.io/zh-cn/docs/overview/faq

1.Seata 目前可以用於生產環境嗎?
2.Seata 目前支援高可用嗎?
3.undo_log表log_status=1的記錄是做什麼用的?
4.怎麼使用Seata框架,來保證事務的隔離性?
5.髒資料回滾失敗如何處理?
6.為什麼分支事務註冊時, 全域性事務狀態不是begin?
7.Nacos 作為 Seata 設定中心時,專案啟動報錯找不到服務。如何排查,如何處理?
8.Eureka做註冊中心,TC高可用時,如何在TC端覆蓋Eureka屬性?
9.java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.jsontype.TypeSerializer.typeId(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonToken;)?
10.為什麼mybatis沒有返回自增ID?
11.io.seata.codec.protobuf.generated不存在,導致seata server啟動不了?
12.TC如何使用mysql8?
13.支援多主鍵?
14.使用HikariDataSource報錯如何解決 ?
15.是否可以不使用conf型別組態檔,直接將設定寫入application.properties?
16.如何自己修改原始碼後打包seata-server ?
17. Seata 支援哪些 RPC 框架 ?
18. java.lang.NoSuchMethodError: com.alibaba.druid.sql.ast.statement .SQLSelect.getFirstQueueBlockLcom/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock;
19. apache-dubbo 2.7.0出現NoSuchMethodError ?
20. 使用 AT 模式需要的注意事項有哪些 ?
21. win系統使用同步指令碼進行同步設定時為什麼屬性會多一個空行?
22. AT 模式和 Spring @Transactional 註解連用時需要注意什麼 ?
23. Spring boot 1.5.x 出現 jackson 相關 NoClassDefFoundException ?
24. SpringCloud xid無法傳遞 ?
25. 使用動態資料來源後的常見問題 ?
26. Could not found global transaction xid = %s, may be has finished.
27. TC報這個錯:An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception是什麼原因?
28. 資料庫開啟自動更新時間戳導致髒資料無法回滾?
29. 還沒到全域性事務超時時間就出現了timeoutrollcking?
30. Seata現階段支援的分庫分表解決方案?
31. Seata 使用註冊中心註冊的地址有什麼限制?
32. seata-server cannot be started due to Unrecognized VM option 'CMSParallelRemarkEnabled' Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.導致seata-server無法啟動?
33. Seata的SQL支援範圍?
34. Seata的JDK版本要求?
35. Oracle的NUMBER長度超過19之後,實體使用Long對映,導致獲取不到行資訊,導致undo_log無法插入,也無法回滾?
36. 怎麼處理 io.seata.rm.datasource.exec.LockConflictException: get global lock fail ?
37. 為什麼在使用者端在編譯和執行時 JDK 版本都是 1.8 的情況下還會出現 java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer 錯誤 ?
38. 為什麼在使用Apple的M1晶片下載maven依賴時,無法下載依賴com.google.protobuf:protoc:exe:3.3.0
39. 1.4.2及以下版本回滾時丟擲Cannot construct instance of java.time.LocalDateTime
40. Seata-Server 使用 DB 作為儲存模式時,有哪些注意事項?
41. Oracle使用timestamp欄位型別回滾失敗?
42. 丟擲異常後事務未回滾?
43. 怎麼處理@FeignClient註解url不起效,提示 Load balancer does not have available server for client錯誤?