服務化的關鍵是服務治理。
服務治理主要包括服務發現、負載均衡、限流、熔斷、超時、重試、服務追蹤。
4.1 服務發現
如果服務少,可以通過硬編碼或配置文件提供服務地址。但是面對大量服務實例和頻繁的上線部署,服務之間如果想知道彼此的服務地址和運行狀態,這時候就需要服務發現組件來實現。
4.1.1 服務發現概述
使用一個注冊中心來記錄分布式系統中全部服務信息,以便讓其他服務能快速找到這些已經注冊的服務。要盡量做到高可用。
服務發現模塊需要有服務注冊、服務查找、服務健康檢查和服務變更通知等關鍵功能。
可以通過服務名稱來查找和使用服務,而不需要提供網絡地址和端口號。
DNS可以說是最早的服務發現實例。
微服務更新、發布頻繁,並且常根據負載情況進行彈性伸縮,因此微服務IP地址變化是常態。
服務發現基本機制:
- 服務提供者在服務啟動時,將服務名稱、IP地址、訪問端口以及其他服務的元數據信息注冊到注冊中心。
- 注冊中心與服務提供者無法維持心跳探測時會將服務從注冊中心剔除。
- 服務消費者從注冊中心獲取服務提供者最新信息時,可以使用定期拉取和事件通知兩種方式。
CAP定理:
在一個分布式計算機系統中,只能滿足一致性(Consistency),可用性(Availability)、和分區容錯性(Partition tolerance),中的兩個,這就是CAP定理。
分區容錯性: 服務期間的通信即使在一定時間內無法保持暢通也不會影響系統繼續運行。分布式系統中,分區容錯性是必須的。
對於分布式系統:AP和CP之間抉擇;
業界提供的用於服務發現的注冊中心,本質上都滿足AP或CP系統。
高可用:
為了保證注冊中心的可用性,要多節點部署,而且還需要自愈和調整的能力。注冊中心需要具備判斷集群內節點健康狀況的能力,可以將訪問超時節點剔除,恢復的節點重新加入。
4.1.2 Zookeeper
一個高可用(因為zk是一個集群,單點故障下仍然可以恢復)且具備嚴格順序訪問控制能力(一定要保證事件的因果順序)的分布式協調系統,它是一個分布式數據一致性(保證分布式情況下,數據一致)的解決方案。
zk提供了分布式通知和協調、配置管理、命名服務、主節點選舉、分布式鎖、分布式隊列等解決方案。
其中分布式通知和協調被廣泛用於服務發現(是服務發現領域歷史最悠久、使用最廣泛的產品)。
ZK也是Hadoop和HBased分布式協調組件。
ZK本質上是一個強一致性的產品,在集群發生分區時它會保證一致性而舍棄可用性,它是一個基於CP的系統。
ZK的每個服務端(Server)存儲的數據都是一致的,存在唯一一個leader。客戶端(Client)連接到任意一個ZK的服務端都能得到一致的最新數據副本。
Paxos算法和Zab協議:
zk是如何保證多個服務端的數據一致性呢:(就是說多個ZK server是為了高可用,但是如何保證多個server之間的數據一致性呢?在kafka中,kafka brokers就是clients,它們連到多個ZK server上,必須要保證這些ZK server數據一致。)
zk是通過消息傳遞保持分布式節點之間的數據一致性。zab是專門針對ZK而設計的支持崩潰恢復的原子廣播協議。
ZK的客戶端是隨機連接到zk集群的某個節點上的。read請求直接從連接的ZK server上讀取;write請求,會由收到的server向leader server 提交事務,再由leader節點廣播事務。只有超過半數的節點都寫入成功,write請求才會被提交。
zab協議規定,消息傳遞需要遵循三個規則: 可靠遞交、完全有序、和因果有序。
在主節點崩潰的情況下,zab協議通過主節點快速選舉、初始化、同步從節點、廣播這幾個階段來保證數據的一致性和主節點選舉的高效性:
- 階段0: 主節點快速選舉 - 在集群剛剛重啟或者主節點剛剛崩潰時,只要超過半數的節點投票就可以生效。不需要等所有節點都投票就可以選舉出leader。
- 階段1: 初始化 - 從節點根據主節點新生成的“年號”更新它們的Epoch。
- 階段2: 同步從節點 - 從節點與主節點同步最近接收的事務提議。
- 階段3: 廣播 - zk集群正式對外提供服務。
核心概念:
1 集群角色:主節點(leader)、從節點(Follower)、和觀察者(Observer ),
在ZK集群中,服務器數量是奇數被認為是最佳實踐( zk集群對外可用的必要條件是:超過半數的服務器正常工作。
) 2台的宕機容忍度為0; 3台的宕機容忍度是1;4台的宕機容忍度也是1.
2 會話:zk集群中,客戶端與服務端是通過TCP建立長連接的。客戶端和服務端通過心跳來保持連接。斷了后可以在會話允許時間內再建立連接不影響工作。
3 數據節點:zk中數據節點的英文名字是Znode,樹形結構。
4 監聽:zk允許客戶端在其感興趣的Znode上注冊監聽器,該Znode的狀態發生變更時,服務端將直接通知客戶端處理。
使用zk實現服務發現:
每個服務啟動時,在zk中注冊。這是zk是一個注冊中心的角色。服務使用方通過Znode快速查找相應的服務。如果服務宕機,那么這個服務節點會與ZK在超過會話時間后失效,那么這個Znode會被刪除,而監聽它們的客戶端監聽器得到宕機消息,進而得到最新的服務列表。
客戶端:zk提供了命令行(shell界面查詢Znode數據)以及基於java和C的原生客戶端,可以對ZK節點執行增刪改查。
可以通過java開發出具有服務發現功能的應用程序(包括連接ZK的API/注冊服務的API/監聽服務變化的API等)
原生API太底層,需要實現的東西太多,一般不自己用。
有一些定三方的ZK客戶端對原生API進行封裝,比如ZkClient, Curator。
zk的優勢與不足:
zk是使用最為廣泛的分布式協調組件,最大的優點是使用廣泛。
zk不是服務發現領域的最佳選擇了,它的優勢是選舉和分布式鎖等分布式強一致性的場景。
ZK在主節點故障的時候,要選舉,這個時候集群不可用,導致注冊服務在選舉的時候癱瘓(這是因為強一致性導致的不可用)。
4.1.3 Erueka: 與ZK不同的是,zk是基於CP的,Erueka是基於AP的。
專門是Java語言的服務注冊工具。
Eureka比ZK更加適合服務發現,優先保證可用性,去中心化,服務集群由對等節點組成。
4.2 負載均衡
實現高可用、網絡流量疏導、和擴容的重要手段。
本質是通過算法將請求分攤到多個服務節點。
4.2.1 服務端負載均衡
負載均衡器會維護一個可用服務列表,並通過心跳檢測將發生故障而無法及時響應心跳的服務移除。當負載均衡器接收到客戶端請求時,通過輪詢、權重或流量負載等負載均衡算法將請求轉發到相應的服務器。
傳輸層(第四層)負載均衡:基於IP地址和端口號進行負載均衡。
通過修改報文中的目標地址和端口號,轉發請求。
四層負載均衡的性能強於七層負載均衡。
應用層(第七層)負載均衡:基於URL和請求頭。解析應用層的內容,轉發請求。
七層的優勢是充分理解應用層協議的意義,轉發更加靈活。Nginx是七層的。
服務端負載均衡的:
優勢:對業務開發無侵入性;不影響應用代碼。
缺點:服務端負載均衡器是整個系統處理的瓶頸。
另外需要經過負載均衡器進行轉發,效率低。
服務端負載均衡多用於前端與后端交互、應用與數據庫交互等場景。
對於應用后端服務之間的調用,還是通過客戶端負載均衡實現的方案居多。
4.2.2 客戶端負載均衡
與服務端負載均衡的區別是,客戶端來選擇連接到哪個服務器,而不是由客戶端連接到一個服務端再由服務端分發請求。
優點:由客戶端內部程序實現,並且直接連到服務端,而不是經過中間負載均衡器轉發。
繞過了中心化的負載均衡和代理節點,不用考慮中心節點的高可用。
缺點: 應用程序更加復雜。
無法做到異構語言之間的負載均衡透明化。
客戶端和服務端的連接多。
采用客戶端負載均衡的框架有:Dubbo 和 Spring Cloud的Ribbon(這些都是侵入式治理方案)。
Ribbon提供了客戶端的負載均衡算法,並可以與服務發現和注冊中心(Eureka)有效的整合到一起(Ribbon會通過Eureka注冊中心獲取服務列表)。另外,Ribboon還提供了連接超時和重試的能力。
Ribbon提供了五個核心接口:
- 1 ILoadBalancer:
- 2 IRule: 負載均衡規則 :並發請求最小優先/ 過濾掉總失敗的/ 根據響應時間/ 重試 / 輪詢 / 隨機 / 衡量性能和可用性。
- 3 IPing: 定義與服務端的通信方式, 判斷服務是否存在
- 4 ServerList: 服務器對象的集合
- 5 ServerListFilter:
4.3 限流
保護服務不會被突然的流量洪峰沖垮。對一個時間窗口內的請求流量進行限速來實施對系統的保護。一旦達到限速閾值,則進入限流的處理流程:
- 拒絕服務: 定向到錯誤頁面,或返回失敗。
- 排隊等待:將請求放入隊列,等有時間再處理,客戶端通常有超時等待時間。適用於 “秒殺”或搶購。
- 應用降級:提供默認行為或數據,比如默認顯示無任何評論、庫存有貨。
4.3.1 限流算法
計數器限流算法: 統計一段時間窗口之內的請求數量來進行限流。
漏桶算法:容量固定的桶,桶底有一個洞,入桶速度任意,但是出桶速度固定。這個方法主要是控制其他系統的回調洪峰。
令牌桶算法:使用存放固定數量的令牌的桶,按照固定速率向桶中添加令牌,如果有請求需要被處理,就從桶中取出令牌,當令牌用光了,就將請求放入隊列或直接被拒絕。
令牌桶算法與漏桶算法最明顯的區別是: 其允許一定程度上的流量突發。
4.3.2 限流實現方案
客戶端限流:只能控制單個客戶端對服務端的訪問。
服務端限流:服務端需要根據自身的的狀態進行限流保護。
Tomcat 和 Dubbo都提供了過載保護。
各種中間件和數據庫產品有又限流配置。
Zuul是開源的網管,有限流功能。
zuul功能:
安全校驗 -
精確路由 -
精准限流 -
壓力測試 -
Metrics統計 -
zuul定義了四種過濾器:
Pre:請求被路由前調用
Routing:請求被路由到業務應用時調用
post: 請求執行完調用
error: 出錯時調用
接入端限流:通常使用負載均衡器實現。
四層負載均衡和七層負載均衡器限流有很大的區別: 四層的只能無差別的限流,無法根據業務需要靈活的限流;
4.3.3 限流的維度與粒度
限流維度:IP地址、URL、用戶令牌、用戶組、設備信息等。
限流粒度: 集群粒度、服務粒度、接口粒度。
4.4 熔斷
4.4.1 概述:
流量過載時,禁止客戶端對服務端訪問。比如當大量響應超時,熔斷可以讓對該服務的調用快速返回,防止目標服務宕機。
熔斷可以防止雪崩。
4.4.2 熔斷器模式
-
-
- 關閉狀態:對應用無干涉,僅僅計算時間窗口內的失敗次數。
- 開啟狀態:對服務的訪問立即返回錯誤。
- 半開啟狀態:只允許少量請求調用服務,如果調用結果符合預期,就認為服務端問題已經修復,這樣熔斷器會關閉;否則認為熔斷器仍然有問題,轉換到開啟狀態,並重新計時。
-
4.4.3 Hystrix
提供了熔斷、隔離、失效轉義、緩存和監控等功能。