1. 程式人生 > >分布式服務跟蹤及Spring Cloud的實現

分布式服務跟蹤及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中的響應時間,以及請求成功與否等信息,就可以在發生問題的時候,找到異常的服務;根據歷史數據,還可以從系統整體層面分析出哪裏性能差,定位性能優化的目標。

實現

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的運行狀態。

接下來需要改造已有的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.properties、application.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);

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

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