分布式架構:原理,設計與實戰,目前公司每個月都要出賬,出賬就是每個月有要把之前的一個月的賬目盤算清楚,做到錯誤的0容忍,一筆都不能錯,錯一筆客戶都會找你,偏準確性。4個9,5個9并不是說后面設計的,而是在開發之初就要考慮的。

分布式服務的發展歷程
- J2EE架構
俗稱JEE。對于大概有5年以上工作經驗的老鐵,應該都聽過這個名詞。基本分為3層。
- web容器
- EJB容器
- 數據庫和數據存取的ORM
那時候的容器之間都沒有進行物理的隔離,都是部署在同一個jvm上的。所以久而久之,它們之間互相的耦合互相的依賴,業務之前有千絲萬縷的,添加和修改增加新的業務的時候,他們變的很復雜,經常導致服務不可用。這個時代就是有了層次,但是層次之前沒有進行物理的隔離。帶來了一些問題。

- SSH架構
開源框架SSH = struts + spring + hibernate,實際上它跟JEE的架構是基本相似的,也把組件分成了三層。
- struts MVC UI組件
- spring 業務組件,實現業務的邏輯
- ORM 對象管理映射層,連接數據庫的
那時候的SSH非常流行,因為那個時期都是給傳統的行業和制造行業來做的系統,在互聯網行業里面ssh架構就不靈了。

- Web Service 架構
互聯網行業偏向于服務化,最流行的微服務起源于服務化,服務化最早體現在web service,web service 以IBM為首的各大公司制定的標準,webservice特點服務開發完畢后,不在部署在同一臺機器,同一個JVM上面,拆分成不同的服務,例如圖中的web service1 ,web service2,web service3 它們3個各自有各自的角色,各自有各自的功能,服務和服務之前都是通過遠程調用的方式來實現互相實現和交流的,遠程調用是遵循已定的標準,當時標準是SOAP協議,這個協議是在http協議之上的,來傳輸xml來完成的。有了這些的服務。需要服務的發現機制,通過webservice的目錄來實現的。所有的服務對外提供服務的功能,需要在webservice注冊。發現服務UDDI,找到服務WSDL找到服務。這個時代服務主要的特點是:職責拆分,服務部署隔離,服務調用遵守協議。webservice定義的協議是非常重的,首先xml序列化,xml有冗余的標簽,服務性能上不來的。webservice注冊通信化的服務,通信化的注冊服務一定要保證高可用。在互聯網里面如果不是高可用的,服務也不是最優化的。

- ESB架構
企業服務總線,側重于企業服務總線。 上邊是提供的服務,下面是數據庫數據源,消息隊列,大數據,ERP。所有的服務和資源只要都進入ESB中,就會進行編排,完成特定的功能。這個時期,ESB功能進行了拆分,也有各自的職責,都進行了拆分,在不同的物理機,在不同JVM中。主要體現在可插拔,快速的添加刪除服務,快速的加入資源。

- 微服務架構
最流行的架構,跟傳統架構是一脈相承的,并不是矛盾的。采用的是分層的概念,上層的服務依賴下層的服務,基本兩層,第一層:業務服務一;第二層:業務服務2,3,4。上一層跟下一層是依賴的,但是不是循環依賴的。每個服務之間自己是用數據庫的,實際上數據庫緩存和消息隊列都是自治的,這就使微服務有自我管理的權限,微服務內可以快速的消化需求,敏捷上線,提高開發和運維的效率,微服務之前是通過遠程的服務調用來先實現的。遠程服務調用,并沒有特定的要求是通過使用restful還是rpc,要求服務之間一定要有契約,契約可以服務生產者提出,也可以服務消費者提出的服務生產者契約,也可以是多個服務消費者一起找服務的生產者提要求,服務生產者提供一個公共的契約,保證通信沒有問題的。例如:來了個需求,先進行服務的拆分,拆分到不同的微服務里面,微服務有了良好的通信契約,不在管對外的功能,就在服務內把需求消化掉了。上線和響應市場也是非常敏捷的。微服務每個節點他們的拆分都是比較單一的,都是比較細的,職責單一后,專業的人干專業的事情,這樣很難犯錯誤,這樣系統的可用性就提高起來了。

- 微服務的團隊管理
團隊其實也是自治的。微服務團隊里面可能是有產品,運營,測試,開發。如果系統分配到某個團隊內,在團隊內的開發可以非常敏捷的溝通,很快的開發上線,并不需要跨團隊的溝通,跨團隊的協調,回顧下當初的SSH,公司分為UI組,開發組,測試組,DB人團隊溝通,都不是微服務的團隊導致溝通效率很低。所以這就是微服務倡導的敏捷,專業的人干專業的事。

- 分布式服務架構的精髓
敏捷上線,微服務下的自治,有效的減少不可用的因素。服務化和微服務都使用了分而治之的思想,分布式服務和分布式系統架構里面,無論是提高性能,提高吞吐量,提高敏捷性。

- 微服務架構的痛點
- 一致性
強一致性和弱一致性
- 高性能
容量評估和性能測試
- 高可用
4個9和5個9
- 可擴展
可修改,迭代新功能,可插拔
- 可伸縮
應用層和資源層,隨著硬件投入的增加性能和能力相應的增長
- 安全性
防偷窺,防泄漏,防抵賴,防篡改,防中間人攻擊
保證分布式一致性的最佳方案
周朝的時候,分而治之,后來都不聽周王的話,導致不一致。不一致導致的痛點是很大的。如何去解決不一致的問題。線上趟過的坑和總結的經驗分享。
- 一致性原理
本質上需要理解下面的3種,本身是什么,應用的場景。

image.png
ACID,數據庫理論的時候,我們都學過ACID就是強一致性。四個名詞代表的是一個事務是不可以在進行拆分的,要么都成功,要么都失敗。在傳統的數據庫里面都是單體的應用,單體的應用必須保持強一致性的,尤其是我們的關系型數據庫。猶豫在互聯網高并發的線上。用戶量非常大,上千,上萬,上億的,單體的服務架構和單體數據庫很難撐起來這么大的量,所以就需要它們之前進行分而治之,在網上進行分開,進行分開,分片。帶來的問題,當網絡出現問題的時候,這些應用是否可以正常的工作。這就引入了CAP原則。
CAP,之間肯定是網絡通信,一定要有分區容錯性,也就是某個節點網絡不能正常的通信時。網絡斷了,或者閃斷的話,各自之間還要繼續的工作。P肯定是要有的。這個原則是如果三者只能選擇其中的二個,P已經必須要了,那就需要在C和A之間選擇一個。例如:網絡上有一份數據,數據是通過復制來完成的。一份是主數據,一份是從數據,當你存一份數據的時候到主數據的時候,同時也需要往從數據中存一份,如果從出現問題,是繼續還是返回給主,這就是一致性和可用性的解讀。如果主從必須保持一致,主從都存起來后才可以返回的話,那就保證一致性,可用性就不好,如果網絡出問題,就一致等待都一致才返回。不會在有限的時間內返回給客戶端的請求,可用性就很差,所以一致性和可用性就是互斥的。如果是很快的返回客戶端,那就可能犧牲了一致性保持了可用性。總結就是在容錯性的基礎之上,可用性和一致性是互斥的。不可兼得。
BASE,基本可用,中間有軟狀態,最終保持了一致。基本可用是條件,最終保持一致是目標。軟狀態就是事先的BASE的方法,就是我們要做一個事,達到目的中間的過程需要2,3個階段,做完一個階段記錄狀態信息,然后做第二個階段,我們可以從出問題的那個位置恢復到出問題的地方。互聯網上很多的高并發項目,都使用了分布式事務都進行打折了,完成了最終一致性。使用了BASE原理,CAP限制了它不可能三者同時存在。
- 一致性協議
兩個階段的協調者

image.png
三階段的協調者

TCC(Try)

- 最終一致性
查詢模式

補償模式

異步確保模式

定期校對模式

可靠消息模式


image.png
- 服務交互的模式
同步模式

異步模式

image.png
消息模式

- 同步與異步的抉擇
盡量使用異步來替換同步操作
能用同步解決的問題,不要引入異步
- 超時模式
同步兩個狀態的接口超時

同步兩個狀態的內部超時

同步三狀態的內部超時

異步受理超時

消息隊列發送超時

消息對壘接收超時

- 補償的博弈

服務1調用服務2,如果服務2響應服務1,并且告訴服務1消息我接收了,那么服務1的任務就結束了,如果服務2處理失敗,服務2應該負責重試或者補償。在這種情況下,服務2通常先持久化消息后再告訴服務1接收成功,隨后服務2才開始處理持久的消息,避免服務進程被傻吊丟失消息的情況。

服務1調用服務2,如果服務2沒有給出明確的接收響應,那么服務1應該持久嘗試重試,知道服務2明確表達已經接收消息,這種情況下,容易出現消息重復,因此在服務2中通常要保證濾重或者冪等性。

- 緩存使用的一致性模式
緩存是用來加速的,犧牲了一致性,獲得高性能,只適合特殊場景。
保持數據庫和緩存的強一致性是個偽命題
如果性能要求不是非常的高,盡量使用分布式緩存,而不是使用本地緩存,本地緩存可能你現在讀的時候本地是開,其實另一個時間其他人讀的是關,你想想多可怕。
種緩存的時候一定種完全,如果緩存數據的一部分有效,一部分無效,寧可放棄種緩存,也不要把部分數據中入緩存
通常情況下讀的順序要先緩存,后數據庫,寫的順序要先數據庫,后緩存
- 遷移開關的設計模式
新舊系統的遷移。
不要用統一配置開關,開關是定義在某個業務上。在一個系統做濾重,比在多個系統做濾重簡單。
不要用節點獨立的開關
遷移開關必須使用訂單開關
開關要用權限控制。開關的重要,特定經驗的人來操作。
開關要能開能關
遷移開關要大小力度都有
PS:了解分布式架構,是對自己從心智上的一種提升,敲代碼只是往下看,建議多往前方看看。架構這條路不好走,需要多接觸,多趟多走,才能前方一路小平破。