看了了一個(gè)關(guān)于分布式服務(wù)鏈路追蹤的文章荚孵,覺(jué)得寫(xiě)得不錯(cuò)爷辙,轉(zhuǎn)載記錄左权,原文鏈接:http://daixiaoyu.com/distributed-tracing.html
附上最近學(xué)習(xí)spring cloud做的demo:https://github.com/applenele/springcloudsample
在分布式服務(wù)架構(gòu)中拘领,需要對(duì)分布式服務(wù)進(jìn)行治理——在分布式服務(wù)協(xié)同向用戶提供服務(wù)時(shí)藕帜,每個(gè)請(qǐng)求都被哪些服務(wù)處理烫罩?在遇到問(wèn)題時(shí),在調(diào)用哪個(gè)服務(wù)上發(fā)生了問(wèn)題洽故?在分析性能時(shí)贝攒,調(diào)用各個(gè)服務(wù)都花了多長(zhǎng)時(shí)間?哪些調(diào)用可以并行執(zhí)行时甚?…… 為此隘弊,分布式服務(wù)平臺(tái)就需要提供這樣一種基礎(chǔ)服務(wù)——可以記錄每個(gè)請(qǐng)求的調(diào)用鏈;調(diào)用鏈上調(diào)用每個(gè)服務(wù)的時(shí)間撞秋;各個(gè)服務(wù)之間的拓?fù)潢P(guān)系…… 我們把這種行為稱為“分布式服務(wù)跟蹤”长捧。
背景
現(xiàn)今業(yè)界分布式服務(wù)跟蹤的理論基礎(chǔ)主要來(lái)自于 Google 的一篇論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,使用最為廣泛的開(kāi)源實(shí)現(xiàn)是 Twitter 的 Zipkin吻贿,為了實(shí)現(xiàn)平臺(tái)無(wú)關(guān)串结、廠商無(wú)關(guān)的分布式服務(wù)跟蹤,CNCF 發(fā)布了布式服務(wù)跟蹤標(biāo)準(zhǔn) Open Tracing。國(guó)內(nèi)肌割,淘寶的“鷹眼”卧蜓、京東的“Hydra”、大眾點(diǎn)評(píng)的“CAT”把敞、新浪的“Watchman”弥奸、唯品會(huì)的“Microscope”、窩窩網(wǎng)的“Tracing”都是這樣的系統(tǒng)奋早。
原理
一般的盛霎,一個(gè)分布式服務(wù)跟蹤系統(tǒng),主要有三部分:數(shù)據(jù)收集耽装、數(shù)據(jù)存儲(chǔ)和數(shù)據(jù)展示愤炸。根據(jù)系統(tǒng)大小不同,每一部分的結(jié)構(gòu)又有一定變化掉奄。譬如规个,對(duì)于大規(guī)模分布式系統(tǒng),數(shù)據(jù)存儲(chǔ)可分為實(shí)時(shí)數(shù)據(jù)和全量數(shù)據(jù)兩部分姓建,實(shí)時(shí)數(shù)據(jù)用于故障排查(troubleshooting)诞仓,全量數(shù)據(jù)用于系統(tǒng)優(yōu)化;數(shù)據(jù)收集除了支持平臺(tái)無(wú)關(guān)和開(kāi)發(fā)語(yǔ)言無(wú)關(guān)系統(tǒng)的數(shù)據(jù)收集速兔,還包括異步數(shù)據(jù)收集(需要跟蹤隊(duì)列中的消息墅拭,保證調(diào)用的連貫性),以及確保更小的侵入性憨栽;數(shù)據(jù)展示又涉及到數(shù)據(jù)挖掘和分析帜矾。雖然每一部分都可能變得很復(fù)雜,但基本原理都類似。
服務(wù)追蹤的追蹤單元是從客戶發(fā)起請(qǐng)求(request)抵達(dá)被追蹤系統(tǒng)的邊界開(kāi)始波俄,到被追蹤系統(tǒng)向客戶返回響應(yīng)(response)為止的過(guò)程闹瞧,稱為一個(gè)“trace”。每個(gè) trace 中會(huì)調(diào)用若干個(gè)服務(wù)泪幌,為了記錄調(diào)用了哪些服務(wù),以及每次調(diào)用的消耗時(shí)間等信息,在每次調(diào)用服務(wù)時(shí)唧瘾,埋入一個(gè)調(diào)用記錄,稱為一個(gè)“span”别凤。這樣饰序,若干個(gè)有序的 span 就組成了一個(gè) trace。在系統(tǒng)向外界提供服務(wù)的過(guò)程中规哪,會(huì)不斷地有請(qǐng)求和響應(yīng)發(fā)生求豫,也就會(huì)不斷生成 trace,把這些帶有span 的 trace 記錄下來(lái),就可以描繪出一幅系統(tǒng)的服務(wù)拓?fù)鋱D蝠嘉。附帶上 span 中的響應(yīng)時(shí)間最疆,以及請(qǐng)求成功與否等信息,就可以在發(fā)生問(wèn)題的時(shí)候蚤告,找到異常的服務(wù)努酸;根據(jù)歷史數(shù)據(jù),還可以從系統(tǒng)整體層面分析出哪里性能差杜恰,定位性能優(yōu)化的目標(biāo)获诈。
實(shí)現(xiàn)
Spring Cloud 是基于 Java 的分布式服務(wù)平臺(tái),提供一系列的分布式服務(wù)所需的中間件心褐。其中舔涎,用于分布式服務(wù)跟蹤的模塊是 Spring Cloud Sleuth。
Spring Cloud Sleuth 主要用于收集 Spring Boot 程序中的數(shù)據(jù)檬寂,即上文所說(shuō)的數(shù)據(jù)收集终抽。其包含的 spring-cloud-sleuth-zipkin
模塊可以把收集到的數(shù)據(jù)發(fā)送到 zipkin 服務(wù)器。Zipkin 本身具有數(shù)據(jù)存儲(chǔ)和展示的功能桶至,這樣昼伴,我們就可以在 Spring Boot 系統(tǒng)中埋入 Spring Cloud Sleuth 收集數(shù)據(jù),在后臺(tái)使用 Zipkin 服務(wù)作為數(shù)據(jù)存儲(chǔ)和展示的服務(wù)镣屹。
使用 Zipkin 作為后臺(tái)的另一個(gè)好處是圃郊,Zipkin 除了支持 Spring Cloud Sleuth 以外,還支持其他開(kāi)發(fā)語(yǔ)言和平臺(tái)的數(shù)據(jù)收集器女蜈。這使得在系統(tǒng)中讓不同種種語(yǔ)言開(kāi)發(fā)的服務(wù)可以共存持舆。
首先,我們要搭建一個(gè) Zipkin 的后臺(tái)服務(wù)伪窖,然后把我們已有的 Spring Boot 服務(wù)中埋入 Spring Cloud Sleuth逸寓,最后,將 Spring Cloud Sleuth 接入 Zipkin 服務(wù)覆山,一個(gè)非常簡(jiǎn)單的分布式服務(wù)跟蹤服務(wù)就搭建起來(lái)了竹伸。
搭建 Zipkin 最簡(jiǎn)單的辦法是直接使用 Zipkin 官方的 Docker 鏡像。Zipkin 的存儲(chǔ)引擎也是可以配置的簇宽,啟動(dòng) Zipkin 時(shí)勋篓,如果沒(méi)有配置 Zipkin 的存儲(chǔ)引擎,那么默認(rèn) Zipkin 把數(shù)據(jù)存在內(nèi)存中魏割。這里譬嚣,由于我們已經(jīng)有了一個(gè) MySQL 的高可用環(huán)境,所以配置 MySQL 為 Zipkin 的存儲(chǔ)引擎钞它。
# 下載鏡像
docker pull openzipkin/zipkin
# 運(yùn)行鏡像拜银,并指定存儲(chǔ)引擎
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 運(yùn)行起來(lái)后殊鞭,可以通過(guò)瀏覽器訪問(wèn) 9411 端口,確認(rèn) Zipkin 的運(yùn)行狀態(tài)盐股。
接下來(lái)需要改造已有的 Spring Boot 服務(wù)钱豁。
首先,在 pom.xml
中引入 Spring Cloud Sleuth疯汁。因?yàn)槭?zipkin 模塊牲尺,所以只引入 spring-cloud-starter-zipkin
即可。版本使用 Spring Cloud 統(tǒng)一管理幌蚊。
<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>
使用環(huán)境變量谤碳,或者直接在 application.properties
、application.yml
或 bootstrap.yml
配置文件中配置必要的屬性溢豆。
spring.zipkin.baseUrl=http://zipkin.host.com:9411/
spring.sleuth.sampler.percentage=1.0
至此蜒简,Spring Boot 程序就可以把訪問(wèn)記錄到 Zipkin 服務(wù)器中。
有些時(shí)候漩仙,譬如搓茬,訪問(wèn)第三方 API,或者數(shù)據(jù)庫(kù)操作等場(chǎng)合队他,我們也希望在其中添加一些調(diào)用信息卷仑。那么可以手工插入一些代碼來(lái)實(shí)現(xiàn)(俗稱“埋點(diǎn)”)。
首先麸折,在需要添加的類中注入Tracer锡凝。
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
...
@Autowired
private Tracer tracer;
然后,在調(diào)用之前垢啼,插入代碼窜锯。
// 創(chuàng)建一個(gè) span
final Span span = tracer.createSpan("3rd_service");
try {
span.tag(Span.SPAN_LOCAL_COMPONENT_TAG_NAME, "3rd_service");
span.logEvent(Span.CLIENT_SEND);
// 這里時(shí)調(diào)用第三方 API 的代碼
} finally {
...
}
最后,在調(diào)用之后的 finally
中(確保異常后也被調(diào)用到)芭析,插入代碼锚扎。
span.tag(Span.SPAN_PEER_SERVICE_TAG_NAME, "3rd_service");
span.logEvent(Span.CLIENT_RECV);
tracer.close(span);
通過(guò)埋點(diǎn)我們可以生成任意詳細(xì)的調(diào)用記錄,我們就可以看到哪里還欠缺監(jiān)控馁启,需要手工埋點(diǎn)工秩;哪里調(diào)用時(shí)間過(guò)長(zhǎng),是影響性能的瓶頸进统;以及哪些調(diào)用可以并行,優(yōu)化性能降低響應(yīng)時(shí)間浪听。