javascript
Spring Cloud综合实战 - 基于TCC补偿模式的分布式事务
2019獨角獸企業重金招聘Python工程師標準>>>
本文通過使用Spring Cloud和Docker構建了一個常見的Microservice體系.
Spring Cloud為開發者提供了快速構建分布式系統中的一些常見工具, 如分布式配置中心, 服務發現與注冊中心, 智能路由, 服務熔斷及降級, 消息總線等.
而Spring Cloud Sleuth為Spring Cloud提供了分布式追蹤方案, 可視化地分析服務調用鏈路和服務間的依賴關系
本次實戰以模擬下單流程作為實戰演示, 使用Try-Confirm-Cancel即TCC模式為分布式事務提供最終一致性.
Try Confirm Cancel補償模式
本實例遵循的是Atomikos公司對微服務的分布式事務所提出的RESTful TCC解決方案
RESTful TCC模式分3個階段執行
系統結構
基礎組件
Zuul Gateway
Zuul在本實例中僅作為路由所使用, 配置降低Ribbon的讀取與連接超時上限
Eureka H.A.
多個對等Eureka節點組成高可用集群, 并將注冊列表的自我保護的閾值適當降低
Config Server
-
如果遠程配置中有密文{cipher}*, 那么該密文的解密將會延遲至客戶端啟動的時候. 因此客戶端需要配置AES的對稱密鑰encrypt.key, 并且客戶端所使用的JRE需要安裝Java 8 JCE, 否則將會拋出Illegal key size相關的異常.
spring:cloud:config:server:git:uri: 'https://git.oschina.net/witless/conf-repo.git'clone-on-start: trueencrypt:enabled: falseapplication:name: 'config-server'
(本例中Docker Compose構建的容器已經安裝了JCE, 如果遠程配置文件沒有使用{cipher}*也不必進行JCE的安裝)
-
為了達到開箱即用, 選用公開倉庫Github或者GitOsc
-
本項目中有兩個自定義注解
@com.github.prontera.Delay 控制方法的延時返回時間@com.github.prontera.RandomlyThrowsException 隨機拋出異常, 人為地制造異常
默認的遠程配置如下
solar:delay:time-in-millseconds: 0exception:enabled: falsefactor: 7這些自定義配置正是控制方法返回的時延, 隨機異常的因子等
我在服務order, product, account和tcc中的所有Controller上都添加了以上兩個注解, 當遠程配置的更新時候, 可以手工刷新/refresh或通過webhook等方法自動刷新本地配置. 以達到模擬微服務繁忙或熔斷等情況.
RabbitMQ
原本作為可靠性事件投遞的Broker, 如今被TCC模式所替代. 可為日后的Spring Cloud Steam或Spring Cloud Bus的集成作為基礎組件而保留
監控服務
Spring Boot Admin
此應用提供了管理Spring Boot服務的簡單UI, 下圖是在容器中運行時的服務健康檢測頁
Hystrix Dashboard
提供近實時依賴的統計和監控面板, 以監測服務的超時, 熔斷, 拒絕, 降級等行為
Zipkin Server
Zipkin是一款開源的分布式實時數據追蹤系統, 其主要功能是聚集來自各個異構系統的實時監控數據, 用來追蹤微服務架構下的系統時延問題. 下圖是對order服務的請求進行追蹤的情況
業務服務
首次啟動時通過Flyway自動初始化數據庫
對spring cloud config server采用fail fast策略, 一旦遠程配置服務無法連接則無法啟動業務服務
account
用于獲取用戶信息, 用戶注冊, 修改用戶余額, 預留余額資源, 確認預留余額, 撤銷預留余額
product
用于獲取產品信息, 變更商品庫存, 預留庫存資源, 確認預留庫存, 撤銷預留庫存
tcc coordinator
TCC資源協調器, 其職責如下
- 對所有參與者發起Confirm請求
- 無論是協調器發生的錯誤還是調用參與者所產生的錯誤, 協調器都必須有自動恢復重試功能, 尤其是在確認的階段, 以防止網絡抖動的情況
order
order服務是本項目的入口, 盡管所提供的功能很簡單
- 下單. 即生成預訂單, 為了更好地測試TCC功能, 在下單時就通過Feign向服務account與product發起預留資源請求, 并且記錄入庫
- 確認訂單. 確認訂單時根據訂單ID從庫中獲取訂單, 并獲取預留資源確認的URI, 交由服務tcc統一進行確認, 如果發生沖突即記錄入庫, 等待人工處理
與其他服務進行通訊, 我們選擇使用Feign
/*** @author Zhao Junjian*/ @FeignClient(name = TccClient.SERVICE_ID, fallback = TccClientFallback.class) public interface TccClient {/*** eureka service name*/String SERVICE_ID = "tcc";/*** api prefix*/String API_PATH = "/api/v1/coordinator";@RequestMapping(value = API_PATH + "/confirmation", method = RequestMethod.PUT, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})void confirm(@RequestBody TccRequest request);@RequestMapping(value = API_PATH + "/cancellation", method = RequestMethod.PUT, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})void cancel(@RequestBody TccRequest request);}Swagger UI
Swagger的目標是為REST APIs 定義一個標準的, 與語言無關的接口, 使人和計算機在看不到源碼或者看不到文檔或者不能通過網絡流量檢測的情況下能發現和理解各種服務的功能. 當服務通過Swagger定義, 消費者就能與遠程的服務互動通過少量的實現邏輯. 類似于低級編程接口, Swagger去掉了調用服務時的很多猜測.
運行
Docker Compose運行
在項目根路徑下執行腳本build.sh, 該腳本會執行Maven的打包操作, 并會迭代目錄下的*-compose.yml進行容器構建
構建完成后需要按照指定的順序啟動
啟動MySQL, RabbitMQ等基礎組件
? solar git:(feature/cleanup) ? docker-compose -f infrastructure-compose.yml up -d啟動Eureka Server與Config Server
? solar git:(feature/cleanup) ? docker-compose -f basic-ms-compose.yml up -d啟動監控服務
? solar git:(feature/cleanup) ? docker-compose -f monitor-ms-compose.yml up -d啟動業務服務
? solar git:(feature/cleanup) ? docker-compose -f business-ms-compose.yml up -dIDE運行
因為程序本身按照Docker啟動, 所以對于hostname需要在hosts文件中設置正確才能正常運行
## solar 127.0.0.1 eureka1 127.0.0.1 eureka2 127.0.0.1 rabbitmq 127.0.0.1 zipkin_server 127.0.0.1 solar_mysql 127.0.0.1 gitlab根據依賴關系, 程序最好按照以下的順序執行
docker mysql > docker rabbitmq > eureka server > config server > zipkin server > 其他微服務
示例
根據附表中的服務字典, 我們通過Zuul或Swagge對order服務進行預訂單生成操作
POST http://localhost:7291/order/api/v1/orders Content-Type: application/json;charset=UTF-8{"product_id": 7,"user_id": 1 }成功后我們將得到預訂單的結果
{"data": {"id": 15,"create_time": "2017-03-28T18:18:02.206+08:00","update_time": "1970-01-01T00:00:00+08:00","delete_time": "1970-01-01T00:00:00+08:00","user_id": 1,"product_id": 7,"price": 14,"status": "PROCESSING"},"code": 20000 }此時我們再確認訂單
(如果想測試預留資源的補償情況, 那么就等15s后過期再發請求, 注意容器與宿主機的時間)
POST http://localhost:7291/order/api/v1/orders/confirmation Content-Type: application/json;charset=UTF-8{"order_id": 15 }如果成功確認則返回如下結果
{"data": {"id": 15,"create_time": "2017-03-28T18:18:02.206+08:00","update_time": "2017-03-28T18:21:32.78+08:00","delete_time": "1970-01-01T00:00:00+08:00","user_id": 1,"product_id": 7,"price": 14,"status": "DONE"},"code": 20000 }至此就完成了一次TCC事務, 當然你也可以測試超時和沖突的情況, 這里就不再贅述
拓展
使用Gitlab作為遠程配置倉庫
本例中默認使用Github或GitOsc中的公開倉庫, 出于自定義的需要, 我們可以在本地構建Git倉庫, 這里選用Gitlab為例.
將以下配置添加至docker compose中的文件中并啟動Docker Gitlab容器
gitlab:image: daocloud.io/daocloud/gitlab:8.16.7-ce.0ports:- "10222:22"- "80:80"- "10443:443"volumes:- "./docker-gitlab/config/:/etc/gitlab/"- "./docker-gitlab/logs/:/var/log/gitlab/"- "./docker-gitlab/data/:/var/opt/gitlab/"environment:- TZ=Asia/Shanghai將項目的config-repo添加至Gitlab中, 并修改config-ms中git倉庫的相關驗證等參數即可
歡迎工作一到五年的Java工程師朋友們加入Java架構開發:855801563
本群提供免費的學習指導?架構資料?以及免費的解答
不懂得問題都可以在本群提出來?之后還會有職業生涯規劃以及面試指導
同時大家可以多多關注一下小編 純干貨?大家一起學習進步
轉載于:https://my.oschina.net/u/3959491/blog/2992484
總結
以上是生活随笔為你收集整理的Spring Cloud综合实战 - 基于TCC补偿模式的分布式事务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ios UITableView顶部向
- 下一篇: 构造数列中的常见变形总结【中阶和高阶辅导