分布式服務跟蹤及Spring Cloud的實現


在分布式服務架構中,需要對分布式服務進行治理——在分布式服務協同向用戶提供服務時,每個請求都被哪些服務處理?在遇到問題時,在調用哪個服務上發生了問題?在分析性能時,調用各個服務都花了多長時間?哪些調用可以並行執行?…… 為此,分布式服務平台就需要提供這樣一種基礎服務——可以記錄每個請求的調用鏈;調用鏈上調用每個服務的時間;各個服務之間的拓撲關系…… 我們把這種行為稱為“分布式服務跟蹤”。

背景

現今業界分布式服務跟蹤的理論基礎主要來自於 Google 的一篇論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,使用最為廣泛的開源實現是 Twitter 的 Zipkin,為了實現平台無關、廠商無關的分布式服務跟蹤,CNCF 發布了布式服務跟蹤標准 Open Tracing。國內,淘寶的“鷹眼”、京東的“Hydra”、大眾點評的“CAT”、新浪的“Watchman”、唯品會的“Microscope”、窩窩網的“Tracing”都是這樣的系統。

淘寶鷹眼

原理

一般的,一個分布式服務跟蹤系統,主要有三部分:數據收集、數據存儲和數據展示。根據系統大小不同,每一部分的結構又有一定變化。譬如,對於大規模分布式系統,數據存儲可分為實時數據和全量數據兩部分,實時數據用於故障排查(troubleshooting),全量數據用於系統優化;數據收集除了支持平台無關和開發語言無關系統的數據收集,還包括異步數據收集(需要跟蹤隊列中的消息,保證調用的連貫性),以及確保更小的侵入性;數據展示又涉及到數據挖掘和分析。雖然每一部分都可能變得很復雜,但基本原理都類似。

服務跟蹤

服務追蹤的追蹤單元是從客戶發起請求(request)抵達被追蹤系統的邊界開始,到被追蹤系統向客戶返回響應(response)為止的過程,稱為一個“trace”。每個 trace 中會調用若干個服務,為了記錄調用了哪些服務,以及每次調用的消耗時間等信息,在每次調用服務時,埋入一個調用記錄,稱為一個“span”。這樣,若干個有序的 span 就組成了一個 trace。在系統向外界提供服務的過程中,會不斷地有請求和響應發生,也就會不斷生成 trace,把這些帶有span 的 trace 記錄下來,就可以描繪出一幅系統的服務拓撲圖。附帶上 span 中的響應時間,以及請求成功與否等信息,就可以在發生問題的時候,找到異常的服務;根據歷史數據,還可以從系統整體層面分析出哪里性能差,定位性能優化的目標。

trace和span

實現

Spring Cloud 是基於 Java 的分布式服務平台,提供一系列的分布式服務所需的中間件。其中,用於分布式服務跟蹤的模塊是 Spring Cloud Sleuth

Spring Cloud Sleuth 主要用於收集 Spring Boot 程序中的數據,即上文所說的數據收集。其包含的 spring-cloud-sleuth-zipkin 模塊可以把收集到的數據發送到 zipkin 服務器。Zipkin 本身具有數據存儲和展示的功能,這樣,我們就可以在 Spring Boot 系統中埋入 Spring Cloud Sleuth 收集數據,在后台使用 Zipkin 服務作為數據存儲和展示的服務

使用 Zipkin 作為后台的另一個好處是,Zipkin 除了支持 Spring Cloud Sleuth 以外,還支持其他開發語言和平台的數據收集器。這使得在系統中讓不同種種語言開發的服務可以共存。

首先,我們要搭建一個 Zipkin 的后台服務,然后把我們已有的 Spring Boot 服務中埋入 Spring Cloud Sleuth,最后,將 Spring Cloud Sleuth 接入 Zipkin 服務,一個非常簡單的分布式服務跟蹤服務就搭建起來了。

搭建 Zipkin 最簡單的辦法是直接使用 Zipkin 官方的 Docker 鏡像。Zipkin 的存儲引擎也是可以配置的,啟動 Zipkin 時,如果沒有配置 Zipkin 的存儲引擎,那么默認 Zipkin 把數據存在內存中。這里,由於我們已經有了一個 MySQL 的高可用環境,所以配置 MySQL 為 Zipkin 的存儲引擎

# 下載鏡像 docker pull openzipkin/zipkin # 運行鏡像,並指定存儲引擎 docker run -d -p 9411:9411 -e MYSQL_USER=root -e MYSQL_PASS=password -e MYSQL_HOST=192.168.0.8 -e STORAGE_TYPE=mysql openzipkin/zipkin 

Zipkin 運行起來后,可以通過瀏覽器訪問 9411 端口,確認 Zipkin 的運行狀態。

Zipkin UI

接下來需要改造已有的 Spring Boot 服務。

首先,在 pom.xml 中引入 Spring Cloud Sleuth。因為使 zipkin 模塊,所以只引入 spring-cloud-starter-zipkin即可。版本使用 Spring Cloud 統一管理。

<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ... <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> 

使用環境變量,或者直接在 application.propertiesapplication.yml或 bootstrap.yml 配置文件中配置必要的屬性

spring.zipkin.baseUrl=http://zipkin.host.com:9411/ spring.sleuth.sampler.percentage=1.0 

至此,Spring Boot 程序就可以把訪問記錄到 Zipkin 服務器中。

有些時候,譬如,訪問第三方 API,或者數據庫操作等場合,我們也希望在其中添加一些調用信息。那么可以手工插入一些代碼來實現(俗稱“埋點”)。

首先,在需要添加的類中注入Tracer。

import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.Tracer; ... @Autowired private Tracer tracer; 

然后,在調用之前,插入代碼。

// 創建一個 span final Span span = tracer.createSpan("3rd_service"); try { span.tag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, "3rd_service"); span.logEvent(Span.CLIENT_SEND); // 這里時調用第三方 API 的代碼 } finally { ... } 

最后,在調用之后的 finally 中(確保異常后也被調用到),插入代碼。

span.tag(Span.SPAN_PEER_SERVICE_TAG_NAME, "3rd_service"); span.logEvent(Span.CLIENT_RECV); tracer.close(span); 

通過埋點我們可以生成任意詳細的調用記錄,我們就可以看到哪里還欠缺監控,需要手工埋點;哪里調用時間過長,是影響性能的瓶頸;以及哪些調用可以並行,優化性能降低響應時間。

優化性能

串行改並行

 

http://daixiaoyu.com/distributed-tracing.html

 


免責聲明!

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



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