<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## Seata 是什么? * Seata 是一款開源的分布式事務解決方案,致力于提供高性能和簡單易用的分布式事務服務。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務模式,為用戶打造一站式的分布式解決方案。 # AT 模式 前提 * 基于支持本地 ACID 事務的關系型數據庫。 * Java 應用,通過 JDBC 訪問數據庫。 ## 整體機制 兩階段提交協議的演變: * 一階段:業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。 * 二階段: * 提交異步化,非常快速地完成。 * 回滾通過一階段的回滾日志進行反向補償。 ## 寫隔離 * 一階段本地事務提交前,需要確保先拿到全局鎖。 * 拿不到全局鎖,不能提交本地事務。 * 拿全局鎖的嘗試被限制在一定范圍內,超出范圍將放棄,并回滾本地事務,釋放本地鎖。 以一個示例來說明: 兩個全局事務 tx1 和 tx2,分別對 a 表的 m 字段進行更新操作,m 的初始值 1000。 tx1 先開始,開啟本地事務,拿到本地鎖,更新操作 m = 1000 - 100 = 900。本地事務提交前,先拿到該記錄的全局鎖,本地提交釋放本地鎖。 tx2 后開始,開啟本地事務,拿到本地鎖,更新操作 m = 900 - 100 = 800。本地事務提交前,嘗試拿該記錄的全局鎖,tx1 全局提交前,該記錄的全局鎖被 tx1 持有,tx2 需要重試等待全局鎖。 ![](https://img.kancloud.cn/f6/29/f629017140995acc6ea16a711b645a33_2106x1576.png) tx1 二階段全局提交,釋放全局鎖。tx2 拿到全局鎖提交本地事務。 ![](https://img.kancloud.cn/1a/e7/1ae7f9e6a8776ae09b07c9779edbce10_2152x1576.png) 如果 tx1 的二階段全局回滾,則 tx1 需要重新獲取該數據的本地鎖,進行反向補償的更新操作,實現分支的回滾。 此時,如果 tx2 仍在等待該數據的全局鎖,同時持有本地鎖,則 tx1 的分支回滾會失敗。分支的回滾會一直重試,直到 tx2 的全局鎖等鎖超時,放棄全局鎖并回滾本地事務釋放本地鎖,tx1 的分支回滾最終成功。 因為整個過程全局鎖在 tx1 結束前一直是被 tx1 持有的,所以不會發生臟寫的問題。 ## 讀隔離 在數據庫本地事務隔離級別讀已提交(Read Committed)或以上的基礎上,Seata(AT 模式)的默認全局隔離級別是讀未提交(Read Uncommitted)。 如果應用在特定場景下,必需要求全局的讀已提交,目前 Seata 的方式是通過 SELECT FOR UPDATE 語句的代理。 ![](https://img.kancloud.cn/a5/35/a5354050e746fc2549b9f0c808137e41_2184x1586.png) SELECT FOR UPDATE 語句的執行會申請全局鎖,如果全局鎖被其他事務持有,則釋放本地鎖(回滾 SELECT FOR UPDATE 語句的本地執行)并重試。這個過程中,查詢是被 block 住的,直到全局鎖拿到,即讀取的相關數據是已提交的,才返回。 出于總體性能上的考慮,Seata 目前的方案并沒有對所有 SELECT 語句都進行代理,僅針對 FOR UPDATE 的SELECT 語句。 ## 工作機制 以一個示例來說明整個 AT 分支的工作過程。 業務表: product | Field | Type | Key | | --- | --- | --- | | id | bigint(20) | PRI | | name | varchar(100) | | | since | varchar(100) | | AT 分支事務的業務邏輯: ``` update product set name = 'GTS' where name = 'TXC'; ``` ### 一階段 過程: 1. 解析 SQL:得到 SQL 的類型(UPDATE),表(product),條件(where name = 'TXC')等相關的信息。 2. 查詢前鏡像:根據解析得到的條件信息,生成查詢語句,定位數據。 ``` select id, name, since from product where name = 'TXC'; ``` 得到前鏡像: | id | name | since | | --- | --- | --- | | 1 | TXC | 2014 | 3. 執行業務 SQL:更新這條記錄的 name 為 'GTS'。 4. 查詢后鏡像:根據前鏡像的結果,通過主鍵定位數據。 ``` select id, name, since from product where id = 1`; ``` 得到后鏡像: | id | name | since | | --- | --- | --- | | 1 | GTS | 2014 | 5. 插入回滾日志:把前后鏡像數據以及業務 SQL 相關的信息組成一條回滾日志記錄,插入到 UNDO_LOG 表中。 ``` { "branchId": 641789253, "undoItems": [{ "afterImage": { "rows": [{ "fields": [{ "name": "id", "type": 4, "value": 1 }, { "name": "name", "value": "GTS" }, { "name": "since", "type": 12, "value": "2014" }] }], "tableName": "product" }, "beforeImage": { "rows": [{ "fields": [{ "name": "id", "type": 4, "value": 1 }, { "name": "name", "type": 12, "value": "TXC" }, { "name": "since", "type": 12, "value": "2014" }] }], "tableName": "product" }, "sqlType": "UPDATE" }], "xid": "xid:xxx" } ``` 6. 提交前,向 TC 注冊分支:申請 product 表中,主鍵值等于 1 的記錄的全局鎖。 7. 本地事務提交:業務數據的更新和前面步驟中生成的 UNDO LOG 一并提交。 8. 將本地事務提交的結果上報給 TC。 ### 二階段-回滾 1. 收到 TC 的分支回滾請求,開啟一個本地事務,執行如下操作。 2. 通過 XID 和 Branch ID 查找到相應的 UNDO LOG 記錄。 3. 數據校驗:拿 UNDO LOG 中的后鏡與當前數據進行比較,如果有不同,說明數據被當前全局事務之外的動作做了修改。這種情況,需要根據配置策略來做處理,詳細的說明在另外的文檔中介紹。 4. 根據 UNDO LOG 中的前鏡像和業務 SQL 的相關信息生成并執行回滾的語句: ``` update product set name = 'TXC' where id = 1; ``` 5. 提交本地事務。并把本地事務的執行結果(即分支事務回滾的結果)上報給 TC。 ### 二階段-提交 1. 收到 TC 的分支提交請求,把請求放入一個異步任務的隊列中,馬上返回提交成功的結果給 TC。 2. 異步任務階段的分支提交請求將異步和批量地刪除相應 UNDO LOG 記錄。 ## 附錄 ### 回滾日志表 UNDO_LOG Table:不同數據庫在類型上會略有差別。 以 MySQL 為例: | Field | Type | | --- | --- | | branch_id | bigint PK | | xid | varchar(100) | | context | varchar(128) | | rollback_info | longblob | | log_status | tinyint | | log_created | datetime | | log_modified | datetime | ``` -- 注意此處0.7.0+ 增加字段 context 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, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; ``` # TCC 模式 回顧總覽中的描述:一個分布式的全局事務,整體是兩階段提交的模型。全局事務是由若干分支事務組成的,分支事務要滿足兩階段提交的模型要求,即需要每個分支事務都具備自己的: * 一階段 prepare 行為 * 二階段 commit 或 rollback 行為 ![](https://img.kancloud.cn/71/5c/715c0779dc4924fa36872ae8100fe4ee_2112x1180.png) 根據兩階段行為模式的不同,我們將分支事務劃分為Automatic (Branch) Transaction Mode和Manual (Branch) Transaction Mode. AT 模式([參考鏈接 TBD](https://seata.io/zh-cn/docs/overview/what-is-seata.html))基于支持本地 ACID 事務的關系型數據庫: * 一階段 prepare 行為:在本地事務中,一并提交業務數據更新和相應回滾日志記錄。 * 二階段 commit 行為:馬上成功結束,自動異步批量清理回滾日志。 * 二階段 rollback 行為:通過回滾日志,自動生成補償操作,完成數據回滾。 相應的,TCC 模式,不依賴于底層數據資源的事務支持: * 一階段 prepare 行為:調用自定義的 prepare 邏輯。 * 二階段 commit 行為:調用自定義的 commit 邏輯。 * 二階段 rollback 行為:調用自定義的 rollback 邏輯。 所謂 TCC 模式,是指支持把自定義的分支事務納入到全局事務的管理中。 # Saga 模式 Saga模式是SEATA提供的長事務解決方案,在Saga模式中,業務流程中每個參與者都提交本地事務,當出現某一個參與者失敗則補償前面已經成功的參與者,一階段正向服務和二階段補償服務都由業務開發實現。 ![](https://img.kancloud.cn/25/54/255431d061d22d87e6154d15902008fe_1298x1270.png) 理論基礎:Hector & Kenneth 發表論? Sagas (1987) ## 適用場景: * 業務流程長、業務流程多 * 參與者包含其它公司或遺留系統服務,無法提供 TCC 模式要求的三個接口 ## 優勢: * 一階段提交本地事務,無鎖,高性能 * 事件驅動架構,參與者可異步執行,高吞吐 * 補償服務易于實現 ## 缺點: * 不保證隔離性(應對方案見[用戶文檔](https://seata.io/zh-cn/docs/user/saga.html))
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看