分散式系統設計策略
服務調用方式
1. HTTP協議的通訊框架
1. HttpURLConnection
HttpURLConnection是java原生支援的。
2. Apache Common HttpClient
HttpClient是Apache Common下的,可以用來提供高效的、功能豐富的HTTP協議的客戶端編程工具包。
- 實現了所有的HTTP方法(GET、POST、PUT、HEAD等)
- 支援HTTPS協議
- 支援代理伺服器
3. OKhttp3
OKHttp是一個當前主流的網路請求開源框架,可以替代HttpUrlConnection和Apache HttpClient
- 支援http2.0,對一台機器的請求共享一個socket
- 採用連接池技術,可以有效的減少http連接數量
- 無縫集成GZIP壓縮技術
- 支援Response Cache,避免重複請求
- 域名多IP支援
4. RestTemplate
Spring RestTemplate是Spring提供的用於訪問Rest服務的客戶端。
- 面向URL組件,必須依賴於主機+埠+URI
- RestTemplate不依賴於服務介面,僅關注REST響應內容
- Spring Cloud Feign通訊在使用RestTemplate
2. RPC框架
1. Java RMI
2. Hessian
Hessian是一個輕量級的remoting on http工具,使用簡單的方法提供了RMI的功能。採用的是二進位RPC協議。
3. Dubbo
Dubbo是阿里巴巴公司開源的一個高性能優秀的服務框架,使得應用可通過高性能的 RPC 實現服務的輸出和輸入功能,可以和Spring框架無縫集成。Dubbo是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向介面的遠程方法調用,智慧容錯和負載均衡,以及服務自動註冊和發現
4. gRPC
gRPC是由Google公司開源的一款高性能的遠程過程調用(RPC)框架,可以在任何環境下運行。該框架提供了負載均衡,跟蹤,智慧監控,身份驗證等功能,可以實現系統間的高效連接
3. 跨域
在分散式系統中,會有調用其他業務系統的場景,導致出現跨域問題。跨域實質上是瀏覽器的一種保護處理請求是可以正常發起的,服務端也是正常接受,只是瀏覽器對其進行了攔截,導致響應內容不可用。
產生跨域的幾種情況如下:
當前頁面URL | 被請求頁面URL | 是否跨域 | 原因 |
---|---|---|---|
//www.lagou.com/ | //www.lagou.com/ | 跨域 | 協議不同(http、https) |
//www.lagou.com/ | //www.baidu.com | 跨域 | 主域名不同 |
//www.lagou.com/ | //kuai.lagou.com | 跨域 | 子域名不同 |
//www.lagou.com:8080 | //www.lagou.com:8090 | 跨域 | 埠不同 |
常見的解決方案
- 使用jsonp解決網站跨域
缺點:不支援post請求,程式碼書寫比較複雜
-
使用HttpClient內部轉發
-
使用設置響應頭允許跨域
response.setHeader(「Access-Control-Allow-Origin」, 「*」); 設置響應頭允許跨域.
-
基於Nginx搭建介面API網關
-
使用Zuul搭建微服務API網關
分散式服務治理
1. 服務協調
分散式協調技術主要用來解決分散式環境當中多個進程之間的同步控制,讓他們有序的去訪問某種臨界資源,防止造成「臟數據」的後果。
分散式鎖兩種實現方式:
- 基於Redis實現分散式鎖
- 基於ZooKeeper實現
2. 服務削峰
削峰從本質上來說就是更多的延緩用戶請求,以及層層過濾用戶的訪問需求,遵從「落地到資料庫的請求數要盡量少」的原則
- 消息隊列
- 流量削峰漏斗:通過CDN->快取系統->後台系統->DB ,層層減少後打到DB的流量就少了
3. 服務降級
整個架構整體的負載超出了預設的上限閾值時,為了保證重要或基本的服務能正常運行,我們可以將一些不重要或不緊急的服務或任務進行服務的延遲使用或暫停使用
降級方案:
- 頁面降級 :可視化介面禁用點擊按鈕、調整靜態頁面
- 延遲服務:如定時任務延遲處理、消息入MQ後延遲處理
- 寫降級:直接禁止相關寫操作的服務請求
- 讀降級:直接禁止相關讀服務請求
- 快取降級:使用快取方式來降級部分讀頻繁的介面
後端程式碼層的處理方式:
- 拋異常
- 返回NULL
- 調用Mock數據
- 調用Fallback處理邏輯
可以將服務架構進行故障風暴分級,根據具體的等級進行降級
4. 服務限流
限流是為了對並發請求進行限制來保護系統。一旦達到限制我們可以拒絕服務、排隊或等待
限流演算法:
1. 固定窗口計數器
計數器限制每時間內(如一分鐘內)請求數不超過一定的值,再下一時間內計數器清零重新計算
存在問題:已知客戶端限流1分鐘100次。如果客戶端在第一分鐘的59秒請求了100次,又在第二分鐘的第1秒請求了100次,這樣兩秒內後端就會受到200次請求的壓力
2. 滑動窗口計數器
針對固定時間演算法會在臨界點存在瞬間大流量衝擊的場景,滑動時間窗口計數器演算法應運而生。它將時間窗口劃分為更小的時間片段,每過一個時間片段,時間窗口就右滑一格,每個時間片段都有獨立的計數器。我們計算整個時間窗口內的請求總數時會累加所有時間片段內的計數器。
時間窗口劃分的越細,那麼滑動窗口的滾動就越平滑。
下面舉例說明滑動窗口是如何解決臨界時間瞬間流量的問題:
一個時間窗口是60s,請求數最大100次。我們分為了3個時間片段。
在0:59時打入了100個請求,落在第3個格子(灰色標記)上(統計0:40-1:00的請求)。1:00的時候窗口右滑,1:01時又打入100個請求,此時打到了第四個(藍色標記)格子(統計1:01-1:20)。此時統計整個時間窗口的流量是200個,後續的請求將拒絕。
3. 漏桶演算法
漏桶演算法類似一個限制出水速度的水桶,不管你放多少水,我都是勻速出水,當桶滿了,就會溢出。
實現:一個固定大小的FIFO隊列,定時取元素,隊列滿了再加入請求直接拒接。
- 優點:可以削峰,不會出現流量突刺現象。
- 缺點:桶隊列中的請求會排隊,響應時間變長。
4. 令牌桶演算法
令牌桶演算法是以一個恆定的速度往桶里放令牌,桶滿了就廢棄,每進來一個請求就去桶里拿令牌,拿到令牌就可以處理請求,沒有令牌了就拒絕請求。
- 優點:應對突發流量,桶里有令牌時可以快速響應
- 缺點:相對漏桶一定程度上對下游的保護沒那麼大
5. 服務熔斷
在互聯網系統中,當下游系統變慢或宕機時,上游服務為了保護系統整體的可用性,可以暫時切斷對下游服務的調用。這種犧牲局部,保全整體的措施就叫做熔斷。
一般的熔斷機制:
- 開啟熔斷
在固定時間窗口內,介面調用超時比率達到一個閾值,會開啟熔斷。進入熔斷狀態後,後續對服務介面的調用不再經過網路,直接執行本地的默認方法,達到服務降級的效果。
2. 熔斷恢復
熔斷不可能是永久的,當經過了規定時間之後,服務將從熔斷狀態恢復過來,再次接受調用方的遠程調用。
Spring Cloud Hystrix
Spring Cloud Hystrix是基於Netflix的開源框架Hystrix實現,該框架實現了服務熔斷、執行緒隔離等一系列服務保護功能。
對於熔斷機制的實現,Hystrix設計了三種狀態:
- 熔斷關閉狀態(Closed)
服務沒有故障時,熔斷器所處的狀態,對調用方的調用不做任何限制。 - 熔斷開啟狀態(Open)
在固定時間內(Hystrix默認是10秒),介面調用出錯比率達到一個閾值(Hystrix默認為50%),會進入熔斷開啟狀態。進入熔斷狀態後,後續對該服務介面的調用不再經過網路,直接執行本地的fallback方法。 - 半熔斷狀態(Half-Open)
在進入熔斷開啟狀態一段時間之後(Hystrix默認是5秒),熔斷器會進入半熔斷狀態。所謂半熔斷就是嘗試恢復服務調用,允許有限的流量調用該服務,並監控調用成功率。如果成功率達到預期,則說明服務已恢復,進入熔斷關閉狀態;如果成功率仍舊很低,則重新進入熔斷開啟狀態。
三個狀態的轉化關係如下圖:
Sentinel
Sentinel和Hystrix的原則是一致的,當調用鏈路中某個資源出現不穩定,例如,表現為timeout,異常比例升高的時候,則對這個資源的調用進行限制,並讓請求快速失敗,防止影響到其他的資源。
Sentinel熔斷手段:
- 通過對並發執行緒數進行限制
- 通過響應時間對資源降級
Sentinel和Hystrix對比
6. 鏈路追蹤
分散式微服務架構上通過業務來劃分服務的,通過REST調用對外暴露的一個介面,可能需要很多個服務協同才能完成這個介面功能。隨著服務的越來越多,對調用鏈的分析會越來越複雜。
鏈路追蹤的作用:
- 故障快速定位
- 分析各個調用環節的性能
- 數據分析,可以分析用戶的行為路徑。
- 生成服務調用拓補圖
鏈路跟蹤設計原則
- 設計目標
- 低侵入性,應用透明
- 低損耗
- 大範圍部署,擴展性
- 埋點和生成日誌
埋點即系統在當前節點的上下文資訊,可以分為客戶端埋點、服務端埋點,以及客戶端和服務端雙向型埋點。埋點日誌通常要包含以下內容:TraceId、RPCId、調用的開始時間,調用類型,協議類型,調用方ip和埠,請求的服務名等資訊;調用耗時,調用結果,異常資訊,消息報文等
3. 抓取和存儲日誌
日誌的採集和存儲有許多開源的工具可以選擇,一般來說,會使用離線+實時的方式去存儲日誌,主要是分散式日誌採集的方式。典型的解決方案如Flume結合Kafka。
-
分析和統計調用鏈數據
一條調用鏈的日誌散落在調用經過的各個伺服器上,首先需要按 TraceId 匯總日誌,然後按照RpcId對調用鏈進行順序整理。調用鏈數據不要求百分之百準確,可以允許中間的部分日誌丟失。 -
計算和展示
匯總得到各個應用節點的調用鏈日誌後,可以針對性的對各個業務線進行分析。需要對具體日誌進行整理,進一步儲存在HBase或者關係型資料庫中,可以進行可視化的查詢。
大的互聯網公司都有自己的分散式跟蹤系統,比如Google的Dapper,Twitter的zipkin,淘寶的鷹眼,新浪的Watchman,京東的Hydra,中國開源愛好者開源的Skywalking。