微服务:知识点梳理(SOA、服务拆分、服务治理、分布式事务)
微服務基本
單體應用
單體應用的優點?
--易于開發
 --易于測試
 --易于部署
存在的問題:
--代碼耦合,開發維護困難,提交代碼頻繁出現大量沖突
 --主要業務和次要業務耦合,無法針對不同模塊進行針對性優化
 --單點容錯率低,并發能力差,無法水平擴展
 --技術選型成本高 ?
 --交付周期長,小功能要積累到大版本才能上線,上線開總監級別大會
微服務和SOA
微服務:架構本質是帶自身特點的面向服務的分布式架構模式。
SOA(Service Oriented Architecture):“面向服務的架構”:他是一種設計方法,其中包含多個服務, 服務之間通過相互依賴最終提供一系列的功能。
SOA特點
-- 有序(站在系統的角度,把原先散亂、無規劃的系統間的網狀結構,梳理成 規整、可治理的系統間星形結構)
 -- 復用(站在功能的角度,把業務邏輯抽象成 可復用、可組裝的服務)
 -- 高效(站在企業的角度,把企業職能抽象成 可復用、可組裝的服務)
微服務和SOA區別:
| 功能 | SOA | 微服務 | 
| 組件大小 | 大塊業務邏輯(粗粒度) | 單獨、小塊業務邏輯(細粒度) | 
| 耦合 | 通常松耦合 | 總是松耦合 | 
|   管理  | 著重中央管理 | 去中心化 | 
| 通信 | 輕量級通信 | 企業服務總線(ESB)充當服務之間通信的角色 | 
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ??
微服務解決的問題
快速迭代
--提交代碼頻繁出現大量沖突
--小功能要積累到大版本才能上線,上線開總監級別大會
高并發
--橫向擴展流程復雜,主要業務和次要業務耦合
--熔斷降級全靠if-else
-  
如果核心業務流程和邊角業務流程在同一個進程中,就需要使用大量的if-else語句,根據下發的配置來判斷是否熔斷或者降級,這會使得配置異常復雜,難以維護。
 -  
如果核心業務和邊角業務分成兩個進程,就可以使用標準的熔斷降級策略,配置在某種情況下,放棄對另一個進程的調用,可以進行統一的維護。
 
微服務的設計原則、特征
微服務體系結構由輕量級、松散耦合的服務集合組成。每個服務都實現了單個業務功能。理想情況下,這些服務應該是具有足夠的內聚性,可以獨立地開發、測試、發布、部署、擴展、集成和維護。
1. AKF拆分原則:以業務為中心
AKF擴展立方體,是一個AKF公司的技術專家抽象總結的應用擴展的三個維度,理論上按照這三個擴展模式,可以將一個單體系統進行無限擴展。
- Y軸(功能)——關注應用中功能劃分,基于不同的業務拆分
 - X軸(水平擴展)——關注水平擴展,也就是“加機器解決問題”
 - Z軸(數據區分)——關注服務和數據的優先級劃分,如按地域劃分
 
拆分后,每個服務代表了特定的業務邏輯、圍繞業務組織團隊、能快速的響應業務的變化。每個微服務也都可以動態的進行x軸和z軸的擴展,并適應云環境下的自動化部署;
2.高內聚低耦合、輕量級無狀態通信原則
- 關注微服務的范圍,而不是一味的把服務做小。一個服務的大小應該等于滿足某個特定業務能力所需要的大小。緊密關聯的事物應該放在一起,每個服務是針對一個單一職責的業務能力的封裝,專注做好一件事情。
 - 輕量級的通信方式--同步RESTful能讓服務間的通信變得標準化并且無狀態;異步(消息隊列/發布訂閱)
 - 避免在服務與服務之間共享數據庫,避免產生頻繁的跨庫查詢,避免產生頻繁的分布式事務。
 
依據此,可實現單一職責、輕量級的通信方式、數據獨立的效果
?3. 去中心化、 高度自治原則
 -- 能獨立的開發、部署、發布,進程獨立,獨立的代碼庫、流水線
4. 彈性設計原則
設計可容錯的系統,設計具有自我保護能力的系統
 -- 具有自我保護能力、可容錯 (Netfilix 提供了一個比較好的解決方案,具體的應對措施包括:網絡超時/限制請求的次數/斷路器模式/提供回滾等)
5. 日志與監控原則
聚合你的日志,聚合你的數據,從而當你遇到問題時,可以深入分析原因。
 --日志聚合,監控與警告
開源產品ELK可以用于日志的收集,聚合,展現,并提供搜索功能,基于一定條件,觸發郵件警告。
Spring boot admin也可以用于服務可用性的監控, hystrix除了提供熔斷器機制外,它還收集了一些請求的基本信息(比如請求響應時間,訪問計算,錯誤統計等),并提供現成的dashboard將信息可視化。
6. 自動化原則
在微服務架構下,面臨如下挑戰:
- 分布式系統
 - 多服務,多實例
 - 手動測試,部署,發布太消耗時間
 - 反饋周期太長
 
傳統的手工運維方式必然要被淘汰,微服務的實施是有一定的先決條件:那就是自動化,當服務規模化后需要更多自動化和標準化的手段來提升效能和降低成本。
 --微服務是松耦合的,微服務架構模式使得持續化部署成為可能。持續集成、持續交付
參考鏈接:
https://www.jianshu.com/p/4e582616d565
https://yq.aliyun.com/articles/666604
https://www.servicemesher.com/blog/design-patterns-for-microservices/
https://yq.aliyun.com/articles/618043
https://isdxh.com/86.html
微服務的優缺點
優點:
強模塊化邊界
 可獨立部署
 技術多樣性
缺點:
服務拆分復雜性
 分布式復雜性
 最終一致性(分布式事務)
 測試、運維復雜性
微服務拆分
微服務拆分原則
服務劃分的合理性
服務的業務范圍,是否破壞服務依賴原則,是否滿足單一職責
服務所屬團隊的規模
服務能否獨立交付
微服務的設計模式
鏈式設計模式(按照數據流向就行數據拆分)
 --先后調用多個服務,產生一個經過合并的響應給客戶
 --在整個鏈式調用完成之前,客戶端會一直阻塞
 --服務調用鏈不宜過長,以免客戶端長時間等待
聚合器(API Gateway\BFF\邊緣服務Edge Service)
異步消息傳遞
--同步請求會造成阻塞, 可以選擇使用消息隊列代替同步請求/響應:
事件溯源模式
--采用已事件為中心的方法保存業務實體
物化視圖模式
--多個服務的常用的聚合數據,生成視圖,方便查詢
CQRS模式(讀寫分離)
服務治理
 微服務出現了什么問題?
 
 
 服務治理要做什么
 
- 服務治理就是對服務復雜度膨脹問題的管控及管理。
 
服務的線上的治理
--服務限流
--集群容錯
--服務降級、熔斷
--故障定界定位
--容量規劃
 --資源治理
 --線上生命周期管理
服務的線下的治理
項目管理、版本管理、測試、運維
架構管理
 --異常處理、舊版本兼容
開發管理
 --代碼質量
測試管理
 --測試覆蓋度
構建調測能力
 協同管理治理
服務限流
漏桶算法及令牌桶算法
 集群限流的情況要更復雜一些,首先在各個微服務節點上要有一個計數器,對單位時間片內的調用進行計數,算出這個時間片的總調用量和預先定義的限流閾值進行比對,計算出一個限流比例
服務降級、熔斷
服務降級與熔斷
- 聯系
 
- 區別
 
服務降級手段:
- 容錯降級 
- 我們常說的熔斷,本質上也是容錯降級策略的一種,只不過它比一般容錯降級提供了更為豐富的容錯托底策略,支持半開降級及全開降級模式
 
 - 靜態返回值降級
 - Mock 降級
 - 備用服務降級
 
故障定界定位
調用鏈本質上也是基于日志,只不過它比常規的日志更重視日志之間的關系。在一個請求剛發起的時候,調用鏈會賦予它一個跟蹤號(traceID),這個跟蹤號會隨著請求穿越不同的網絡節點,并隨著日志落盤,日志被收集后,可以根據 traceID 來對日志做聚合,找到所有的關聯日志,并按順序排序,就能構建出這個請求跨網絡的調用鏈,它能詳細描述請求的整個生命周期的狀況。
 分布一致性
 
 強一致性、弱一致性、最終一致性
CAP理論
一致性(C:Consistency)
 可用性(A:Availability)
 分區容錯性(P:Partition tolerance)
- CA?? ?放棄分區容錯性,加強一致性和可用性,其實就是傳統的單機數據庫的選擇
 - AP?? ?放棄一致性(這里說的一致性是強一致性),追求分區容錯性和可用性,這是很多分布式系統設計時的選擇,例如很多NoSQL系統就是如此
 - CP?? ?放棄可用性,追求一致性和分區容錯性,基本不會選擇,網絡問題會直接讓整個系統不可用
 
C A 滿足的情況下,P不能滿足的原因:
 ? ? ? ?數據同步(C)需要時間,也要正常的時間內響應(A),那么機器數量就要少,所以P就不滿足
 ?? ??? ?
CP 滿足的情況下,A不能滿足的原因:
 ?? ??? ??? ?數據同步(C)需要時間, 機器數量也多(P),但是同步數據需要時間,所以不能再正常時間內響應,所以A就不滿足
AP 滿足的情況下,C不能滿足的原因:
 ?? ??? ??? ?機器數量也多(P),正常的時間內響應(A),那么數據就不能及時同步到其他節點,所以C不滿足
BASE理論
BASE理論是對CAP中一致性和可用性權衡的結果
Basically Available(基本可用)
- 基本可用是指分布式系統在出現不可預知故障的時候,允許損失部分可用性
 
Soft state(軟狀態)
- 軟狀態指允許系統中的數據存在中間狀態,并認為該中間狀態的存在不會影響系統的整體可用性,即允許系統在不同節點的數據副本之間進行數據同步的過程存在延時
 
Eventually consistent(最終一致性)
- 最終一致性的本質是需要系統保證最終數據能夠達到一致,而不需要實時保證系統數據的強一致性。
 
服務注冊與發現
服務注冊中心本質上是為了解耦服務提供者和服務消費者。
對于任何一個微服務,原則上都應存在或者支持多個提供者,這是由微服務的分布式屬性決定的。更進一步,為了支持彈性擴縮容特性,一個微服務的提供者的數量和分布往往是動態變化的,也是無法預先確定的。
 因此,原本在單體應用階段常用的靜態LB機制就不再適用了,需要引入額外的組件來管理微服務提供者的注冊與發現,而這個組件就是服務注冊中心。
注冊中心選擇:
Zookeeper:CP設計,保證了一致性,集群搭建的時候,某個節點失效,則會進行選舉行的leader,或者半數以上節點不可用,則無法提供服務,因此可用性沒法滿足
Eureka:AP原則,無主從節點,一個節點掛了,自動切換其他節點可以使用,去中心化
注冊中心分類
應用內:直接集成到應用中,依賴于應用自身完成服務的注冊與發現,最典型的是Netflix提供的Eureka、nacos
應用外:把應用當成黑盒,通過應用外的某種機制將服務注冊到注冊中心,最小化對應用的侵入性,HashiCorp的Consul
Consul強一致性(C)帶來的是:
服務注冊相比Eureka會稍慢一些。因為Consul的raft協議要求必須過半數的節點都寫入成功才認為注冊成功
 Leader掛掉時,重新選舉期間整個consul不可用。
保證了強一致性但犧牲了可用性。
Eureka保證高可用(A)和最終一致性:
服務注冊相對要快,因為不需要等注冊信息replicate到其他節點,也不保證注冊信息是否replicate成功
 當數據出現不一致時,雖然A, B上的注冊信息不完全相同,但每個Eureka節點依然能夠正常對外提供服務,這會出現查詢服務信息時如果請求A查不到,但請求B就能查到。如此保證了可用性但犧牲了一致性。
 其他方面,eureka就是個servlet程序,跑在servlet容器中; Consul則是go編寫而成。
Nacos = Spring Cloud注冊中心 + Spring Cloud配置中心。
服務優雅上下線
-- 停止服務前先截斷服務的流量
 --注冊中心通知所有服務干掉下線實例
 --處理完手頭事務后停止
Eureka 中服務下線的幾種方式
1、直接停掉服務
根據默認的策略,如果在一定的時間內,客戶端沒有向注冊中心發送續約請求,那么注冊中心就會將該實例從注冊中心移除,但是有缺陷,因為服務直接停掉后,實例仍然會在注冊中心存在一小段時間(90s),也有可能注冊中心直接認為你的服務down掉,但是實例仍然存在于注冊中心
2、通過注冊中心接口強制下線
為了讓注冊中心馬上知道服務要下線, 可以向eureka 注冊中心發送delete 請求
// 注冊中心zone
eureka:client:serviceUrl:defaultZone發送一個delete 請求
格式為 /eureka/apps/{application.name}/
 http://你的注冊中心zone/apps/你的實例名稱/你的實例地址加端口
 實例名稱就是Application,地址加端口就是Status的右邊
值得注意的是,Eureka客戶端每隔一段時間(默認30秒)會發送一次心跳到注冊中心續約。如果通過這種方式下線了一個服務,而沒有及時停掉的話,該服務很快又會回到服務列表中。
所以,可以先停掉服務,再發送請求將其從列表中移除。
3、客戶端主動下線
// 客戶端(SpringBoot應用)可以通過如下代碼主動通知注冊中心下線
DiscoveryManager.getInstance().shutdownComponent();
更多參考:
Spring Cloud : 如何優雅下線微服務?
Eureka:常見問題總結
反向代理與負載均衡
Nginx通過反向代理可以實現服務的負載均衡,避免了服務器單節點故障,把請求按照一定的策略轉發到不同的服務器上,達到負載的效果。
常用的負載均衡策略有
1、輪詢
 將請求按順序輪流地分配到后端服務器上,它均衡地對待后端的每一臺服務器,而不關心服務器實際的連接數和當前的系統負載。
2、加權輪詢
給配置高、負載低的機器配置更高的權重,讓其處理更多的請求
3、ip_hash(源地址哈希法)
 根據獲取客戶端的IP地址,通過哈希函數計算得到一個數值,用該數值對服務器列表的大小進行取模運算,得到的結果便是客戶端要訪問服務器的序號。
4、隨機
5、least_conn(最小連接數法)
 動態地選取其中當前積壓連接數最少的一臺服務器來處理當前的請求
服務網關
客戶端訪問這些后端的多個微服務,遇到的問題?
--每個業務都會需要鑒權、限流、權限校驗等邏輯
 --每上線一個新的服務,都需要運維參與,申請域名、配置Nginx等,當上線、下線服務器時,同樣也需要運維參與,另外采用域名這種方式,對于環境的隔離也不太友好
 --后端每個微服務可能是由不同語言編寫的、采用了不同的協議,比如HTTP、Dubbo、GRPC等,但是你不可能要求客戶端去適配這么多種協議
 --后期如果需要對微服務進行重構的話,也會變的非常麻煩,需要客戶端配合你一起進行改造
網關做的不僅僅只是簡單的轉發,也會針對流量做一些擴展,比如鑒權、限流、權限、熔斷、協議轉換、錯誤碼統一、緩存、日志、監控、告警等
服務網關關注:
API注冊
 --(業務方如何接入網關?Swagger的注解、手動錄入)
協議轉換
服務發現
服務調用
緩存
 -- 一些重復的請求,可以在網關層直接處理,而不用打到業務線,降低業務方的壓力
限流
 --令牌桶等方案。還需要考慮根據什么限流,比如是IP、接口、用戶維度、還是請求參數中的某些值,這里可以采用表達式,相對比較靈活
日志
 --提供一個統一的traceId方便關聯所有的日志,可以將這個traceId置于響應頭中,方便排查問題。
優雅下線
--Nginx自身是支持健康監測機制的,如果檢測到某一個節點已經掛掉了,就會把這個節點摘掉,
 對于應用正常下線,需要結合發布系統,首先進行邏輯下線,然后對后續Nginx的健康監測請求直接返回失敗(比如直接返回500),然后等待一段時間(根據Nginx配置決定),然后再將應用實際下線掉。
服務網關不足
目前的網關還是中心化的架構,所有的請求都需要走一次網關
目前比較流行的ServiceMesh,采用去中心化的方案,將網關的邏輯下沉到sidecar中,sidecar和應用部署到同一個節點,并接管應用流入、流出的流量,這樣大促時,只需要對相關的業務壓測,并針對性擴容即可,另外升級也會更平滑,
中心化的網關,即使灰度發布,但是理論上所有業務方的流量都會流入到新版本的網關,如果出了問題,會影響到所有的業務,
但這種去中心化的方式,可以先針對非核心業務升級,觀察一段時間沒問題后,再全量推上線。另外ServiceMesh的方案,對于多語言支持也更友好。
 分布式事務
 
 具體參考:微服務:分布式事務
--事務提供一種機制將一個活動涉及的所有操作納入到一個不可分割的執行單元,組成事務的所有操作
 -- 要么什么都不做,要么做全套(All or Nothing)
事務的ACID屬性
--原子性(Atomicity)要么全部完成,要么全部不完成
 --一致性(Consistency)在事務開始之前和事務結束以后,數據庫數據的一致性約束沒有被破壞
 --隔離性(Isolation)數據庫允許多個并發事務同時對數據進行讀寫和修改的能力
 --持久性(Durability) 事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失
分布式事務的實現方案
二階段提交協議(Two-phase Commit,即2PC)
階段1:準備階段
 階段2:提交階段
2PC方案實現起來簡單,實際項目中使用比較少,主要因為以下問題:
性能問題 :
所有參與者在事務提交階段處于同步阻塞狀態,占用系統資源,容易導致性能瓶頸。
可靠性問題 :
如果協調者存在單點故障問題,如果協調者出現故障,參與者將一直處于鎖定狀態。
數據一致性問題:
在階段2中,如果發生局部網絡問題,一部分事務參與者收到了提交消息,另一部分事務參與者沒收到提交消息,那么就導致了節點之間數據的不一致。
3PC(三階段提交)
 --與二階段提交不同的是,引入超時機制
階段1:canCommit 檢查是否可以提交
階段2:preCommit 執行事務操作
階段3:do Commit 該階段進行真正的事務提交
方案總結
優點
相比二階段提交,三階段貼近降低了阻塞范圍,在等待超時后協調者或參與者會中斷事務。避免了協調者單點問題,階段3中協調者出現問題時,參與者會繼續提交事務。
缺點
數據不一致問題依然存在,當在參與者收到preCommit請求后等待do commite指令時,此時如果協調者請求中斷事務,而協調者無法與參與者正常通信,會導致參與者繼續提交事務,造成數據不一致。
TCC (Try-Confirm-Cancel)事務 —— 最終一致性
 ?
 --Try操作作為一階段,負責資源的檢查和預留。
 --Confirm操作作為二階段提交操作,執行真正的業務。
 --Cancel是預留資源的取消。
 TCC事務機制相對于傳統事務機制(X/Open XA),TCC事務機制相比于上面介紹的XA事務機制,有以下優點:
性能提升: 具體業務來實現控制資源鎖的粒度變小,不會鎖定整個資源。
數據最終一致性: 基于Confirm和Cancel的冪等性,保證事務最終完成確認或者取消,保證數據的一致性。
可靠性: 解決了XA協議的協調者單點故障問題,由主業務方發起并控制整個業務活動,業務活動管理器也變成多點,引入集群。
缺點:
TCC的Try、Confirm和Cancel操作功能要按具體業務來實現,業務耦合度較高,提高了開發成本。
本地消息表 —— 最終一致性
事務主動發起方額外新建事務消息表,事務發起方處理業務和記錄事務消息在本地事務中完成,輪詢事務消息表的數據發送事務消息,事務被動方基于消息中間件消費事務消息表中的事務。
這樣設計可以避免”業務處理成功 + 事務消息發送失敗",或"業務處理失敗 + 事務消息發送成功"的棘手情況出現,保證2個系統事務的數據一致性。
MQ事務 —— 最終一致性
基于MQ的分布式事務方案其實是對本地消息表的封裝,將本地消息表基于MQ 內部,
相比本地消息表方案,MQ事務方案優點是:
- 消息數據獨立存儲 ,降低業務系統與消息系統之間的耦合。
 - 吞吐量高
 
缺點是:
- 一次消息發送需要兩次網絡請求(half消息 + commit/rollback消息)
 - 業務處理服務需要實現消息狀態回查接口
 
Saga事務 —— 最終一致性
每個Saga事務由一系列冪等的有序子事務(sub-transaction) Ti 組成。
 每個Ti 都有對應的冪等補償動作Ci,補償動作用于撤銷Ti造成的結果。
Saga事務常見的有兩種不同的實現方式:
1、命令協調(Order Orchestrator):中央協調器負責集中處理事件的決策和業務邏輯排序。
 中央協調器(Orchestrator,簡稱OSO)以命令/回復的方式與每項服務進行通信,全權負責告訴每個參與者該做什么以及什么時候該做什么。
2、事件編排 (Event Choreography):沒有中央協調器(沒有單點風險)時,每個服務產生并觀察其他服務的事件,并決定是否應采取行動。
集群容錯
容錯模式
艙壁隔離模式
- 微服務容器分組、線程池隔離避免一個服務拖垮整個系統
 
熔斷模式
- 熔斷后快速失敗
 
限流模式
- 高峰期限制訪問的并發量
 
失敗轉移模式
容錯機制
Failover 失敗自動切換
- 當出現失敗,重試其它服務器,通常用于讀操作(推薦使用)。 重試會帶來更長延遲。
 
Failfast??快速失敗
- 只發起一次調用,失敗立即報錯,通常用于非冪等性的寫操作。 如果有機器正在重啟,可能會出現調用失敗 。
 
Failsafe 失敗安全
- 出現異常時,直接忽略,通常用于寫入審計日志等操作。 調用信息丟失 可用于生產環境 Monitor。
 
Failback??失敗自動恢復
- 后臺記錄失敗請求,定時重發。通常用于消息通知操作 不可靠,重啟丟失。 可用于生產環境 Registry。
 
Forking ?并行調用多個服務器
- 只要一個成功即返回,通常用于實時性要求較高的讀操作。 需要浪費更多服務資源 ? 。
 
Broadcast?
- 廣播調用,所有提供逐個調用,任意一臺報錯則報錯。通常用于更新提供方本地狀態 速度慢,任意一臺報錯則報錯 。?
 
容器監控
監控主要解決的是感知系統的狀況
為什么需要監控?
要監控什么
冪等機制
一個冪等操作的特點是指其任意多次執行所產生的影響均與一次執行的影響相同。
冪等場景
冪等解決方案
總結
以上是生活随笔為你收集整理的微服务:知识点梳理(SOA、服务拆分、服务治理、分布式事务)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: Python爬虫利器五Selenium用
 - 下一篇: 手把手教你做产品经理,视频课教程已经发布