寫在前面: 由於工作需要,公司的微服務項目需解決分散式事務的問題,且由我進行分散式事務框架搭建和整合工作。 那麼藉此機會好好的將解決分散式事務的內容進行整理一下。這邊公司分散式事務框架選型是LCN框架(以後肯定會升級成seata)。 我整理的大綱如下: 1 CAP定律和BASE理論 有人問,為什麼需 ...
寫在前面:
由於工作需要,公司的微服務項目需解決分散式事務的問題,且由我進行分散式事務框架搭建和整合工作。
那麼藉此機會好好的將解決分散式事務的內容進行整理一下。這邊公司分散式事務框架選型是LCN框架(以後肯定會升級成seata)。
我整理的大綱如下:
1 CAP定律和BASE理論
有人問,為什麼需要瞭解這個,這個其實是分散式事務基於的理論依據,所以需要瞭解一下。
1.1 CAP定律
這個定理的內容是指的是在一個分散式系統中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),三者不可得兼。
(一)一致性(C)
在分散式系統中的所有數據備份,在同一時刻是否同樣的值。(等同於所有節點訪問同一份最新的數據副本)
(二)可用性(A)
在集群中一部分節點故障後,集群整體是否還能響應客戶端的讀寫請求。(對數據更新具備高可用性)
(三)分區容錯性(P)
以實際效果而言,分區相當於對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味著發生了分區的情況,必須就當前操作在C和A之間做出選擇。
(四)總結一下
以上可以知道分區容錯性(P)主要代表網路波動產生的錯誤,這是不可避免的,且這個三個模式不可兼得,所以目前就只有兩種模式:CP和AP模式。
其中CP表示遵循一致性原則,但不能保證高可用性,其中zookeeper作為註冊中心就是採用CP模式,因為zookeeper有過半節點不可以的話整個zookeeper將不可用。
AP表示遵循於可用性原則,例如Eureka作為註冊中心用的是AP模式,因為其為去中心化,採用你中有我我中有你的相互註冊方式,只要集群中有一個節點可以使用,整個eureka服務就是可用的,但可能會出現短暫的數據不一致問題。
1.2 BASE理論
BASE是Basically Available(基本可用)、Soft state(軟狀態)和 Eventually consistent(最終一致性)三個短語的縮寫。BASE理論是對CAP中一致性和可用性權衡的結果,其來源於對大規模互聯網系統分散式實踐的總結, 是基於CAP定理逐步演化而來的。BASE理論的核心思想是:即使無法做到強一致性,但每個應用都可以根據自身業務特點,採用適當的方式來使系統達到最終一致性。
(一)基本可用
基本可用是指分散式系統在出現不可預知故障的時候,允許損失部分可用性,註意,這絕不等價於系統不可用。
比如:響應時間上的損失。正常情況下,一個線上搜索引擎需要在0.5秒之內返回給用戶相應的查詢結果,但由於出現故障,查詢結果的響應時間增加了1~2秒。
系統功能上的損失:正常情況下,在一個電子商務網站上進行購物的時候,消費者幾乎能夠順利完成每一筆訂單,但是在一些節日大促購物高峰的時候,由於消費者的購物行為激增,為了保護購物系統的穩定性,部分消費者可能會被引導到一個降級頁面。
(二)軟狀態
軟狀態指允許系統中的數據存在中間狀態,並認為該中間狀態的存在不會影響系統的整體可用性,即允許系統在不同節點的數據副本之間進行數據同步的過程存在延時。
(三)最終一致性
最終一致性強調的是所有的數據副本,在經過一段時間的同步之後,最終都能夠達到一個一致的狀態。因此,最終一致性的本質是需要系統保證最終數據能夠達到一致,而不需要實時保證系統數據的強一致性。
2 瞭解分散式事務
2.1 分散式事務產生的背景
在分散式產生之前,互聯網公司的項目都是傳統的單體項目,整個項目都共用了一個數據源,那麼進行業務執行對資料庫進行操作的時候,不會產生這種事務不一致問題,因為是同一個數據源用的一個本地事務。
但隨著我們架構的演變,從單體架構到分散式架構到SOA架構項目再到如今公司採用的微服務架構,我們對服務進行了業務拆分,那麼數據源也被拆分,一般微服務項目是一個服務對應一個數據源。
那麼在這種架構下,每個服務都有自己獨立的數據源有自己的本地事務,從而便會產生分散式事務,可能造成服務間數據不一致問題。
2.2 不同架構體系下解決事務的問題
(一)單體架構(單數據源)
在單體的項目中,多個不同業務邏輯都是在同一個數據源中實現事務管理,是不存在分散式事務的問題,因為同一數據源的情況下都是採用事務管理器,相當於每個事務管理器對應一個數據源。
(一)單體架構(多數據源)
在單體的項目中,有多個不同的數據源,每個數據源中都有自己獨立的事務管理器,互不影響,那麼這時候也會存在多數據源事務管理:解決方案jta+ Atomikos。
(一)分散式/微服務架構
在分散式/微服務架構,每個服務都有自己獨立的數據源和事務管理器,那麼在這種情況下如果有業務要進行RPC遠程調用的時候,那就必然可能產生分散式事務。目前主要解決方案有:MQ、LCN、Seata等方案。
3 LCN解決分散式事務
3.1 瞭解LCN
3.1.1 LCN背景
LCN框架在2017年6月份發佈第一個版本,從開始的1.0,已經發展到了5.0版本。
LCN名稱是由早期版本的LCN框架命名,在設計框架之初的1.0 ~ 2.0的版本時框架設計的步驟是如下,各取其首字母得來的LCN命名。
5.0以後由於框架相容了LCN、TCC、TXC三種事務模式,為了避免區分LCN模式,特此將LCN分散式事務改名為TX-LCN分散式事務框架。
3.1.2 LCN定位
TX-LCN定位於一款事務協調性框架,框架其本身並不操作事務,而是基於對事務的協調從而達到事務一致性的效果。(LCN不生產事務,它只是事務的搬運工...woc這有點像農夫山泉的文案)
3.2 LCN分散式事務原理(自己理解的,白話文通俗易懂)
(上圖來源官網)
1) 首先我們的lcn協調者(TM)會和lcn客戶端(TC)通過引入的netty一直保持著長連接(持續監聽)。
2) 當請求的發起方(調用方)進入介面業務之前,會通過AOP技術進到@LcnTransaction註解中去LCN協調者那邊生成註冊一個全局的事務組Id(groupId)。
3) 當發起方(調用方)通過rpc調用參與方(被調用方)的時候,lcn重寫了Feign客戶端,會從ThreadLocal中拿到該事務組Id(groupId),並將該事務組Id設置到請求頭中。
4) 參與方(被調用方)在請求頭中獲取到了這個groupId的時候,lcn會標識該服務為參與方並加入到該事務組,並會被lcn代理數據源,當該服務業務邏輯執行完成後,進行數據源的假關閉,並不會真正的提交或回滾當前服務的事務。
5) 當發起方執行完全部業務邏輯的時候,如果無異常會告知lcn協調者,lcn協調者再分別告訴該請求鏈上的所有參與方可以提交了,再進行真正的提交。若發起方調用完參與方後報錯了,也會告知lcn協調者,lcn協調者再告知所有的參與方進行真正的回滾操作,這樣就解決了分散式事務的問題。
3.3 LCN本地環境部署
3.3.1 本地部署註冊中心
註冊中心是微服務中最為重要的一個組件,提供了服務間在調用時需要的一些ip和埠等列表信息。
我這邊採用nacos作為註冊中心,具體如何一分鐘快速搭建本地nacos可參見:https://nacos.io/zh-cn/docs/quick-start.html 註冊中心的部署略過不做詳細的說明。搭建好nacos後,訪問127.0.0.1:8848/nacos進行訪問(賬號密碼預設為nacos),出現如下界面即完成了nacos本地的搭建。
3.3.2 本地部署協調者TM環境
在部署TX-LCN中有遇到問題或想查看部署詳細的操作可以訪問如下地址:http://www.txlcn.org/zh-cn/docs/start.html 。
1) 我們要去github中先將tx-lcn的源碼下載下來,這邊我們選擇的是5.0.2的版本,github下載源碼地址:https://github.com/codingapi/tx-lcn/releases。
2) 創建相應的資料庫表,先創建MySQL資料庫, 名稱為: tx-manager,再創建資料庫表t_tx_exception。
CREATE TABLE `t_tx_exception` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `transaction_state` tinyint(4) NULL DEFAULT NULL, `registrar` tinyint(4) NULL DEFAULT NULL, `remark` varchar(4096) NULL DEFAULT NULL, `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解決 1已解決', `create_time` datetime(0) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
3) 打開我們下好的源碼,找到txlcn-tm模塊,修改其配置文件application.properties,具體修改的內容根據自己業務而定,官方也有相應配置內容,但需要註意首次運行要將配置文件的這段設置為create:spring.jpa.hibernate.ddl-auto=create。
4) 準備將txlcn-tm模塊打包成jar包,先執行打包命令: mvn clean package -Dmaven.test.skip=true ,打包完成後可以在模塊中看到出現了jar包。
5) 開始對jar包進行運行,進入到target目錄,執行命令啟動jar包:java -jar txlcn-tm-5.0.2.RELEASE.jar
6) 運行成功後可以看到tomcat啟動成功。
7) 訪問控制台的埠為7919,預設密碼codingapi。
至此,TM部署並啟動完成。
3.3.3 本地配置客戶端TC環境
TC就是我們的客戶端,也就是我們的微服務,配置相對簡單如下:
1) 引入相關依賴,其中一個是lcn核心包,一個是建立長連接的netty包。
<dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-tc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-txmsg-netty</artifactId> <version>5.0.2.RELEASE</version> </dependency>
2) 配置yml文件,設置服務連接到lcn服務。(註意下lcn控制台是7970,這個8070是lcn通訊埠號)
tx-lcn: client: manager-address: 127.0.0.1:8070 logger: enabled: true
3) 引入依賴並配置好yml文件後,在服務的啟動類上添加@EnableDistributedTransaction註解,開啟分散式事務。
4) 在業務的方法上面添加註解@LcnTransaction和@Transactional,如下圖。
5) 做好這些配置後,開始啟動項目,啟動成功項目後可以在lcn控制台看到相應的服務列表,能夠看到則說明服務已經實現了對lcn事務協調者管理器的註冊。
看到服務都能夠成功註冊進TM後,便全部完成TX-LCN本地環境的搭建,後續可以開始測試自己的業務代碼是否解決了分散式事務的問題。