實施微服務架構的關鍵技術

原文連接:mp.weixin.qq.com/s/oI3Py2PZY…前端

本文來自CCTC2017大會孫玄的演講。數據庫

你們都在提微服務架構,微服務架構究竟是什麼?它有哪些特色和設計模式?咱們在打造微服務架構過程當中,這些設計模式在實戰當中如何應用?數據的一致性應該如何保證?今天我將針對上述疑問分享一下個人思考。設計模式

微服務架構特色

什麼是微服務架構?看下圖的這段英文,這是Martin Fowler 在2014年提出來的,微服務架構是一種架構模式,既然是架構模式,那麼,它就必然須要知足一些特色。他提到,微服務架構是一系列小的微服務構成的組合,那麼,什麼是「小的微服務」?可能每一個人的理解都不同,你們都應該都知道SOA架構,SOA架構的粒度是比較粗的,到底咱們應該以什麼樣的粒度拆分微服務?我認爲,微服務架構本質上一個業務架構,那麼對業務瞭解的越深入,你的微服務拆分就越合理。微信

好比咱們作二手交易平臺(轉轉),該平臺包括用戶體系、商品體系、交易體系以及搜索推薦體系。由於各個體系比較獨立,那麼咱們就能夠按照各個業務模塊來拆分微服務。固然,這樣作還不夠,由於你的商品裏面還有不少功能,可是大的思路是按照具體商品內部的邏輯來進一步拆分。架構

第二,圍繞具體業務建模。一切脫離業務場景談微服務架構都是耍流氓。異步

方法有二:首先將某一領域的模型做爲獨立的業務單元:好比二手交易中的商品、訂單、用戶等;其次將業務的行爲做爲獨立的業務單元:好比發送郵件、單點登陸驗證、push服務。分佈式

第三,整個微服務均可以獨立地部署,由於每個微服務Process都是獨立的,因此按照每一個模塊進行獨立的部署也是很容易理解的。微服務

第四,去中心化管理。打造去中心化管理意思就是微服務的每一個模塊和開發語言、運行平臺沒有關係,開發語言能夠是C++,能夠是go,也能夠是世界上最好的語言,運行的平臺是Linux,Unix、Windows等均可以。spa

最後一點就是輕量級通訊,這點很容易理解,通訊和模塊語言、平臺沒有關係。儘量選用輕量級的通訊來作這個事情,這樣實施跨平臺、跨語言的時候就很容易。架構設計

講完這些特色,咱們能夠看一看一個標準DEMO級的微服務架構究竟是由哪些元素組成的?以下圖,主要包括網關、微服務、數據存儲、註冊中心、配置中心

既然是DEMO級的,和實際狀況下相比確定有所差異。那麼,實際案例中,咱們到底應該如何作這件事情?這個例子也是最近我在作的二手交易平臺——轉轉。這裏和DEMO有些不同的地方。前面的第一層仍是網關,下面有微服務的聚合層,做用是作各類業務邏輯的處理;聚合層下面是咱們的數據原子層,主要作數據訪問代理,只不過根據業務的不一樣垂直分開了。能夠看到,網關、數據層,註冊中心、配置中心都有,只不過在業務處理部分分紅兩層:一層是原子層,也就是整個數據訪問的代理層,提供了用戶的接口;另一層就是上層的業務聚合層。

架構設計模式及實踐案例

上面我大概講了下微服務的一些特色以及DEMO級的微服務包括哪些部分以及實際案例中咱們的設架構設計模式。那麼,咱們爲何要採用這種模式去作?除了這種架構模式以外還有哪些其它的架構模式?這裏,模式仍是很是多的,我會重點講這幾點:鏈式設計模式、聚合器設計模式和異步共享模式。

首先咱們來講下鏈式設計模式,在這種模式下,APP前端請求首先要通過網關層,接下來連續調用兩個微服務,調了微服務1以後還要調微服務2。爲何叫作鏈式呢?由於在調用過來之後先到微服務1,而後再同步地調用微服務2,微服務2會作一些處理,處理之後微服務2纔會反饋給微服務1,微服務1再反饋給Gateway,最後反饋到APP。在實際業務場景中,涉及到交易和訂單的業務場景都會用到這種模式。

接下來是聚合器設計模式,APP前端一個調用請求通過Gateway,到達聚合層,須要調用三個微服務,聚合層將三個微服務的返回結果作一些聚合處理,好比能夠進行一些排序或者去重,聚合以後再反饋到Gateway和APP前端,這是一個典型的聚合器設計模式。

第三種模式是數據共享模式,這種模式相對比較簡單,好比APP通過微服務網關,接下來調用微服務1和微服務2,理想狀況下微服務1和微服務2都有本身獨立的DB,可是有些狀況下因爲微服務1和微服務2的請求量和存儲量較小,從資源利用率的角度來說,這兩個微服務的DB是共享的,所以這種就是數據的共享模式。

最後一種是異步消息設計模式,不論是鏈式設計、聚合器模式仍是共享數據模式,架構模式都是同步模式。也就是說個人一個請求發出去必須等到每一個環節都處理完纔會給客戶端。若是請求不須要關注處理結果,這時候能夠異步來實施。APP更新請求通過微服務網關,持久化到MQ,寫入MQ成功後立刻Response給APP客戶端,以後微服務根據須要從MQ裏面訂閱更新消息進行異步處理,咱們爲了提升吞吐量也會採用這種模式。

我從百度到轉轉這幾年經歷了不少業務場景,使用的無非就是聚合器、異步和數據共享的數據模式,特別是前面兩個用得特別多,下面咱們來看一些例子。

接下來咱們看個例子,這是咱們在2015年作的一個二手交易平臺(轉轉),這個二手交易平臺包括商品、分類搜索、關鍵詞搜索、商品推薦等功能。一個用戶請求過來,先通過網關,網關下面就是咱們的聚合層,聚合層再去調用商品、交易、推薦以及搜索相關的,最終在聚合層把各個微服務原子層的結果彙總起來Response給到客戶端。具體以下圖所示:

異步消息模式的這個案例比較早了,當時咱們作了Feed 流,相似如今的微信朋友圈,這是我在百度作的事情。當時,咱們採用的架構模式是異步架構模式。前面是咱們的APP,通過了網關,到達異步提交層,能夠認爲是持久化功能的MQ。用戶請求通過網關到消息異步提交層後就返回了,業務處理部分從MQ裏面讀取數據再進行異步處理。這個時候吞吐量會增長,可是會帶來必定的困惑。好比這個時候我發了一條Feed,用戶再一查就直接到數據庫裏面查,可能異步提交消息隊列有延遲,查不到,用戶就困惑了,這個問題怎麼解決?咱們就想能不能在前端幫咱們作一些事情?好比提交了MQ返回Response 200之後,前段配合插入這條Feed。用戶再次刷新時候我相信已是好幾秒之後的事情了,即便有延遲,這個消息早就被你的業務處理完了。固然,咱們這裏是有特定場景的,社區時候能夠這樣去作,可是涉及到和金融相關的場景確定不會這麼去作。

數據一致性實踐

微服務模塊比較分散、數據也比較分散,整個系統複雜性很是高,如何進行數據一致性實踐?在一個單體模塊裏面能夠作Local Transaction,可是在微服務體系裏面就不奏效。雖然難解決,可是不能不解決,不解決的話微服務架構就很難實施。咱們知道微服務中作強一致性性的事情是很是難的,今天分享的更多的是解決最終一致性。由於在微服務下基於不一樣的數據庫,Local Transaction是不可用的。你們在在分佈式事務裏面必定據說過兩階段提交和三階段提交,這種場景其實在微服務架構裏面也行不通,緣由是由於它本質上是同步的模式,同步的模式之下作數據一致性吞吐量下降的很是多。

咱們的業務場景無非是兩種:第一種是異步調用,就是一個請求過來就寫到消息隊列裏面就行,這種模式相對簡單。今天主要講下同步調用的場景之下怎麼打造數據的最終一致性。既然是同步調用場景,而且不能下降業務系統的吞吐量,那麼應該怎麼作呢?創建一個異步的分佈式事務,業務調用失敗後,經過異步方式來補償業務。咱們的想法是能不能在整個業務邏輯層實現分佈式事務語義策略?如何實現,無非有兩種,第一是在調正常請求的時候要記錄業務調用鏈(調用正常接口的完整參數),第二是異常時沿調用鏈反向補償。

基於這個思路,咱們架構設計上的關鍵點有三,第一是基於補償機制,第二是記錄調用鏈,第三是提供冪等補償接口。架構層面,看下圖,右邊是聚合器架構設計模式,左邊是異步補償服務。

首先須要在聚合層引入一個Proxy。首先基於方法,在方法名加註解標註補償方法名,好比:- @Compensable(cancelMethod=「cancelRecord」)

另外,聚合層在調用原子層以前,經過代理記錄當前調用請求參數。若是業務正常,調用結束後,當前方法的調用記錄存檔或刪除,若是業務異常,查詢調用鏈回滾。

原子層咱們作了哪些事情呢?主要是兩方面,第一是提供正常的原子接口,其次是提供補償冪等接口。

分佈式事務關鍵是兩個表(如上圖),第一是事務組表,假設A->B->C三個請求是一個事務,首先針對ABC生成一個事務的ID,寫在這個表裏面,而且會記錄這個事務的狀態,默認的狀況下正常的,執行失敗之後咱們再把狀態由1(正常)變成2(異常);第二個表是事務調用組表,主要記錄事務組內的每一次調用以及相關參數,因此調用原子層以前須要記錄一下請求參數。若是失敗的話咱們須要把這個事務的狀態由1變成2;第三,一旦狀態從1變成2就執行補償服務。這是咱們的補償邏輯,就是不斷地掃描這個事務所處的表,好比一秒鐘掃一次事務組表,看一看這個表裏面有沒有狀態爲2的,須要執行補償的服務。這個思路對業務的侵入比較小。

具體看下咱們實際的例子,好比二手交易平臺裏面建立訂單事務組的正常流程,從鎖庫存到減紅包再到建立訂單,建立事務組完畢以後開始調用業務,首先Proxy記錄鎖庫存調用的參數,以後開始鎖庫存服務調用,成功後以後又開始減紅包和建立訂單過程,若是都成功了直接返回。

再看一下異常的流程,前面幾步都是同樣的,只是在調紅包服務、Proxy建立紅包的時候若是失敗了就會拋出異常,業務正常返回,聚合層Proxy須要把事務組的狀態由1改爲2,這個時候由左邊的補償服務異步地補償調用。

 

推薦閱讀

  掃碼關注有驚喜!

file
相關文章
相關標籤/搜索