本文經過使用Spring Cloud和Docker構建了一個常見的Microservice體系.html
Spring Cloud爲開發者提供了快速構建分佈式系統中的一些常見工具, 如分佈式配置中心, 服務發現與註冊中心, 智能路由, 服務熔斷及降級, 消息總線等.java
而Spring Cloud Sleuth爲Spring Cloud提供了分佈式追蹤方案, 可視化地分析服務調用鏈路和服務間的依賴關係mysql
本次實戰以模擬下單流程做爲實戰演示, 使用Try-Confirm-Cancel即TCC模式爲分佈式事務提供最終一致性.git
本實例遵循的是Atomikos公司對微服務的分佈式事務所提出的RESTful TCC解決方案github
RESTful TCC模式分3個階段執行web
Zuul在本實例中僅做爲路由所使用, 配置下降Ribbon的讀取與鏈接超時上限面試
多個對等Eureka節點組成高可用集羣, 並將註冊列表的自我保護的閾值適當下降spring
若是遠程配置中有密文{cipher}*
, 那麼該密文的解密將會延遲至客戶端啓動的時候. 所以客戶端須要配置AES的對稱密鑰encrypt.key
, 而且客戶端所使用的JRE須要安裝Java 8 JCE, 不然將會拋出Illegal key size
相關的異常.
(本例中Docker Compose構建的容器已經安裝了JCE, 若是遠程配置文件沒有使用{cipher}*
也沒必要進行JCE的安裝)sql
spring: cloud: config: server: git: uri: 'https://git.oschina.net/witless/conf-repo.git' clone-on-start: true encrypt: enabled: false application: name: 'config-server'
爲了達到開箱即用, 選用公開倉庫Github或者GitOscdocker
本項目中有兩個自定義註解
@com.github.prontera.Delay
控制方法的延時返回時間
@com.github.prontera.RandomlyThrowsException
隨機拋出異常, 人爲地製造異常
默認的遠程配置以下
solar: delay: time-in-millseconds: 0 exception: enabled: false factor: 7
這些自定義配置正是控制方法返回的時延, 隨機異常的因子等
我在服務order
, product
, account
和tcc
中的全部Controller上都添加了以上兩個註解, 當遠程配置的更新時候, 能夠手工刷新/refresh
或經過webhook等方法自動刷新本地配置. 以達到模擬微服務繁忙或熔斷等狀況.
本來做爲可靠性事件投遞的Broker, 現在被TCC模式所替代. 可爲往後的Spring Cloud Steam或Spring Cloud Bus的集成做爲基礎組件而保留
此應用提供了管理Spring Boot服務的簡單UI, 下圖是在容器中運行時的服務健康檢測頁
提供近實時依賴的統計和監控面板, 以監測服務的超時, 熔斷, 拒絕, 降級等行爲
Zipkin是一款開源的分佈式實時數據追蹤系統, 其主要功能是彙集來自各個異構系統的實時監控數據, 用來追蹤微服務架構下的系統時延問題. 下圖是對order
服務的請求進行追蹤的狀況
首次啓動時經過Flyway自動初始化數據庫
對spring cloud config server採用fail fast策略, 一旦遠程配置服務沒法鏈接則沒法啓動業務服務
用於獲取用戶信息, 用戶註冊, 修改用戶餘額, 預留餘額資源, 確認預留餘額, 撤銷預留餘額
用於獲取產品信息, 變動商品庫存, 預留庫存資源, 確認預留庫存, 撤銷預留庫存
TCC資源協調器, 其職責以下
order
服務是本項目的入口, 儘管所提供的功能很簡單
account
與product
發起預留資源請求, 而且記錄入庫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的目標是爲REST APIs 定義一個標準的, 與語言無關的接口, 令人和計算機在看不到源碼或者看不到文檔或者不能經過網絡流量檢測的狀況下能發現和理解各類服務的功能. 當服務經過Swagger定義, 消費者就能與遠程的服務互動經過少許的實現邏輯. 相似於低級編程接口, Swagger去掉了調用服務時的不少猜想.
在項目根路徑下執行腳本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 -d
由於程序自己按照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事務, 固然你也能夠測試超時和衝突的狀況, 這裏就再也不贅述
本例中默認使用Github或GitOsc中的公開倉庫, 出於自定義的須要, 咱們能夠在本地構建Git倉庫, 這裏選用Gitlab爲例.
將如下配置添加至docker compose中的文件中並啓動Docker Gitlab容器
gitlab: image: daocloud.io/daocloud/gitlab:8.16.7-ce.0 ports: - "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
本羣提供免費的學習指導 架構資料 以及免費的解答
不懂得問題均可以在本羣提出來 以後還會有職業生涯規劃以及面試指導
同時你們能夠多多關注一下小編 純乾貨 你們一塊兒學習進步