分佈式系統設計策略

服務調用方式

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 是否跨域 原因
http://www.lagou.com/ https://www.lagou.com/ 跨域 協議不同(http、https)
http://www.lagou.com/ http://www.baidu.com 跨域 主域名不同
http://www.lagou.com/ http://kuai.lagou.com 跨域 子域名不同
http://www.lagou.com:8080 http://www.lagou.com:8090 跨域 端口不同

常見的解決方案

  1. 使用jsonp解決網站跨域

缺點:不支持post請求,代碼書寫比較複雜

  1. 使用HttpClient內部轉發

  2. 使用設置響應頭允許跨域

response.setHeader(“Access-Control-Allow-Origin”, “*”); 設置響應頭允許跨域.

  1. 基於Nginx搭建接口API網關

  2. 使用Zuul搭建微服務API網關

分佈式服務治理

1. 服務協調

分佈式協調技術主要用來解決分佈式環境當中多個進程之間的同步控制,讓他們有序的去訪問某種臨界資源,防止造成“髒數據”的後果。

分佈式鎖兩種實現方式:

  1. 基於Redis實現分佈式鎖
  2. 基於ZooKeeper實現

2. 服務削峯

削峯從本質上來說就是更多的延緩用戶請求,以及層層過濾用戶的訪問需求,遵從“落地到數據庫的請求數要儘量少”的原則

  1. 消息隊列
  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. 服務熔斷

在互聯網系統中,當下遊系統變慢或宕機時,上游服務爲了保護系統整體的可用性,可以暫時切斷對下游服務的調用。這種犧牲局部,保全整體的措施就叫做熔斷。

一般的熔斷機制:

  1. 開啓熔斷

在固定時間窗口內,接口調用超時比率達到一個閾值,會開啓熔斷。進入熔斷狀態後,後續對服務接口的調用不再經過網絡,直接執行本地的默認方法,達到服務降級的效果。
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調用對外暴露的一個接口,可能需要很多個服務協同才能完成這個接口功能。隨着服務的越來越多,對調用鏈的分析會越來越複雜。

鏈路追蹤的作用:

  1. 故障快速定位
  2. 分析各個調用環節的性能
  3. 數據分析,可以分析用戶的行爲路徑。
  4. 生成服務調用拓補圖

鏈路跟蹤設計原則

  1. 設計目標
  • 低侵入性,應用透明
  • 低損耗
  • 大範圍部署,擴展性
  1. 埋點和生成日誌

埋點即系統在當前節點的上下文信息,可以分爲客戶端埋點、服務端埋點,以及客戶端和服務端雙向型埋點。埋點日誌通常要包含以下內容:TraceId、RPCId、調用的開始時間,調用類型,協議類型,調用方ip和端口,請求的服務名等信息;調用耗時,調用結果,異常信息,消息報文等
3. 抓取和存儲日誌

日誌的採集和存儲有許多開源的工具可以選擇,一般來說,會使用離線+實時的方式去存儲日誌,主要是分佈式日誌採集的方式。典型的解決方案如Flume結合Kafka。

  1. 分析和統計調用鏈數據
    一條調用鏈的日誌散落在調用經過的各個服務器上,首先需要按 TraceId 彙總日誌,然後按照RpcId對調用鏈進行順序整理。調用鏈數據不要求百分之百準確,可以允許中間的部分日誌丟失。

  2. 計算和展示
    彙總得到各個應用節點的調用鏈日誌後,可以針對性的對各個業務線進行分析。需要對具體日誌進行整理,進一步儲存在HBase或者關係型數據庫中,可以進行可視化的查詢。

大的互聯網公司都有自己的分佈式跟蹤系統,比如Google的Dapper,Twitter的zipkin,淘寶的鷹眼,新浪的Watchman,京東的Hydra,國內開源愛好者開源的Skywalking。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章