Spring Cloud 微服務架構全鏈路實踐


閱讀目錄:

  • 1. 網關請求流程
  • 2. Eureka 服務治理
  • 3. Config 配置中心
  • 4. Hystrix 監控
  • 5. 服務調用鏈路
  • 6. ELK 日志鏈路
  • 7. 統一格式返回

Java 微服務框架選型(Dubbo 和 Spring Cloud?)

目前公司使用的 Spring Cloud 整個技術組件,基本包含了上面圖中所包含的,不得不說,Spring Cloud 整個生態真的很強大,使用起來也很方便有效。

后面有時間再針對每個組件進行使用解讀,這篇文章主要說下 Spring Cloud 架構的鏈路圖,順便把自己的思路整理下來,以備查閱。

1. 網關請求流程

在 Spring Cloud 整個組件庫中,Spring Cloud Zuul 是最容易被忽視,但也是最重要的,Spring Cloud Zuul 可以和 Eureka 注冊中心集成,我們目前使用 Spring Cloud Zuul 的功能如下:

  • Filter 過濾器
  • Router 路由
  • Ribbon 負載均衡
  • Hystrix 熔斷
  • Retry 重試

有些功能是 Spring Cloud Zuul 自帶的,比如 Filter 和 Router,有些是結合 Spring Cloud 其他組件,比如 Ribbon 和 Hystrix。

這里重點介紹下 Filter 過濾器,分為四個過濾類型:

  • pre:Zuul 轉發請求之前執行,我們目前的實現是AccessTokenFilter,用於 oAuth2.0 JWT 的授權驗證。
  • route:Zuul 路由時執行,目前項目沒用到。
  • post:Zuul 路由轉發后執行,也就是已經請求成功了后端服務,我們目前的實現是CustomResponseFilter,用於統一請求格式的封裝,比如 code/msg/data 等。
  • error:以上過濾器發生錯誤時執行,我們目前的實現是CustomErrorFilter,用於攔截過濾器執行的出現的錯誤,然后統一格式封裝返回,另外,error 過濾器好像並不能捕獲后端服務執行出現的錯誤。

另外,關於 oAuth2.0 JWT 的授權驗證,實現的方式有兩種:

  • 授權的配置在后端服務中(每個服務都需要當作 Resource Server 進行配置,需要配置公鑰,接口的授權具體配置在注解中),Zuul 只做轉發,並不進行授權的驗證。
  • 授權的配置在 Zuul 中,也就是把 Zuul 當作 Resource Server,后端服務不需要進行任何處理,Zuul 中具體的實現就是AccessTokenFilter,里面的邏輯是手動解析 JWT,然后判斷是否正確,以及解析出用戶信息/Scope/Role,然后根據當前的請求 API,對授權 Map 中的配置進行匹配,如果匹配錯誤,直接拋出 401 授權錯誤。

我們目前采用的是第二種方式,這兩種方式都有利有弊,關鍵在於自己的取舍,為什么采用第二種方式?目的就是發揮 Zuul 的作用,對外網關進行統一授權驗證。

關於授權 Map,里面存儲了所有服務接口的配置,示例配置:

private static final Map ROUTE_MAPS;
static
{
    ROUTE_MAPS = new HashMap<String, String>();
    ROUTE_MAPS.put("eureka-client/home", "read:ROLE_ADMIN");
    ROUTE_MAPS.put("eureka-client/user", "read:ROLE_ADMIN");
    ROUTE_MAPS.put("eureka-client/error", "read:ROLE_ADMIN");
}

這是我們目前的配置,是一個靜態的 Map,后面會存儲在 Spring Cloud Config 配置中心,Zuul 啟動時進行加載,利用 Spring Cloud Bus 動態刷新。

關於 Zuul 網關,其實還有很多需要說的,后面有機會再進行針對說明。

2. Eureka 服務治理

Eureka 遵循的是 AP 原則(服務可用性和分區容錯性),是服務治理最理想的遵循 CAP 分布式原則。

Eureka 集群中的節點是彼此平級,不像 Consul 有 master/worker 之分,集群中的 Eureka 節點彼此兩兩注冊,所以,Eureka 集群最好部署三個節點,這也是我們目前的部署方式。

另外,Eureka 的自我保護機制,可以參考這篇文章

服務之間的相互調用,負載有兩種使用方式:

  • Feign:基於聲明式,顧名思義,就是需要定義接口,就像我們平常使用對象調用一樣。
  • Ribbon:軟負載,通過往 RestTemplate 中注入負載 Handler,然后通過負載算法選取調用(通過 Eureka 獲取服務注冊信息)。

我們目前打算使用 Ribbon 負載方式,為什么?看下面代碼就知道了:

restTemplate.getForObject("http://eureka-client/hello", String.class);

3. Config 配置中心

我們目前配置中心使用的是 Spring Cloud Config,當然你也可以使用功能更強大的 Polly(攜程開源),但 Config 目前也能滿足我們的需求,存儲倉庫我們現在使用的是 Git。

Config 配置中心提供了數據加密功能,你可以使用 RSA 的加密方式,這樣存儲在 Git 中的配置都是密文形式,Config Client 獲取加密配置的時候,Config Server 會自動進行解密返回。

配置中心的使用場景,我們目前主要是兩個地方:

  • 項目啟動的配置信息,比如數據庫的連接字符串等。
  • 業務服務的配置信息,也就是業務相關的配置。

另外,需要說明的是,默認情況下,如果 Git 中的配置更新了,Config Client 不會進行更新配置,我們目前的解決方式是,使用 Spring Cloud Bus 進行動態刷新配置(Config Server 中配置),具體的流程:

  • Git 中添加 WebHooks 腳本,比如curl -X POST http://manager1:8180/bus/refresh,當 Git 倉庫中的配置更新后,自動執行。
  • Config Server 中配置 Spring Cloud Bus,接受 Git 的配置刷新請求,然后利用 RabbitMQ 廣播通知所有的 Config Client 訂閱方,刷新配置信息。

4. Hystrix 監控

Hystrix 主要是用於服務熔斷/降級/隔離處理,Hystrix 配置在調用方,當被調用方服務不可用時,觸發 Hystrix 熔斷,會執行指定的 Fallback 方法,進行特殊處理。

我之前以為,Hystrix 熔斷的觸發條件是服務不可用,也就是服務請求超時(比如服務掛掉了),但我自己測試了下,服務出現 500 錯誤,也會觸發 Hystrix 熔斷,而且會自動忽略 Hystrix 的超時時間設置。

我們目前使用 Hystrix,主要有兩個地方:

  • 內部服務調用:可以對某個 API 接口進行熔斷處理。
  • Zuul 網關使用:就是當 Zuul 路由轉發調用時,但有個局限性,就是只能對服務進行熔斷,並不能針對某個 API 接口熔斷。

上面圖中,主要畫的是 Hystrix 的監控流程,我們目前主要使用 RabbitMQ 進行采集傳輸,turbine-server 進行數據流的聚合,hystrix-dashboard 進行圖形化的展示。

5. 服務調用鏈路

服務調用鏈路的概念,就是當服務請求發起時,記錄整個請求鏈路的數據,以備查詢。

目前市面上,幾乎所有服務調用鏈路的實現,理論基礎都是基於 Google Dapper 的那篇論文,其中最重要的概念就是 traceId 和 spanId。

  • traceId 記錄整個服務鏈路的 ID,由首次請求方創建,服務鏈路中唯一。
  • spanId 記錄當前服務塊的 ID,由當前服務方創建。
  • parentId 記錄上一個請求服務的 spanId。

下面我描述下,我們目前的服務調用鏈路過程:

  • H5 發起請求,到 Zuul 網關,Zuul 創建全局的 traceId 和自己的 spanId,然后攜帶這些數據到業務服務 A,並利用 Spring Cloud Sluth 傳輸到 RabbitMQ。
  • 業務服務 A,接收到 Zuul 傳輸的 traceId 和 spanId,然后把 Zuul 的 spanId 設置成 parentId,並生成自己的 spanId,然后攜帶這些數據到業務服務 B,並利用 Spring Cloud Sluth 傳輸到 RabbitMQ。
  • ....

上面圖中,詳細說明了整個服務調用鏈路的過程,這邊再說下使用的技術棧:

  • Spring Cloud Sluth:和 SkyWalking 的探針概念比較類似,每個服務都進行配置,收集當然服務的請求數據(traceId 和 spanId),然后利用stream-sluthbinder-rabbit組件,將請求數據傳輸到 RabbitMQ。
  • Spring Cloud Zipkin:主要用於請求鏈路的 UI 展示,Zipkin 會從 RabbitMQ 讀取請求數據,然后存儲到 ElasticSearch 中,然后下次顯示直接從 ElasticSearch 中讀取。
  • Kibana:Kibana 也可以顯示 ElasticSearch 中的請求數據,只不過不是圖形化的,需要索引配置創建。

6. ELK 日志鏈路

ELK 可以參考下之前的幾篇文章:

上面圖中已經很詳細介紹了下 ELK 的流程,ELK 默認技術棧里是沒有 Filebeat 的,Logstash 用作日志收集的時候,CPU 和內存會占用資源比較大,所以我們使用輕量化的 Filebeat 進行日志的收集,Filebeat 部署在每個業務服務所在的服務器,然后將收集到的日志數據傳輸到 Logstash,Logstash 可以部署兩到三台服務器上,用作日志的過濾和分析工作,然后再將處理后的日志數據,傳輸到 ElasticSearch 存儲。

7. 統一格式返回

關於統一格式返回,圖中已經詳細的說明了,如果你有更好的方案,歡迎探討。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM