摘要:一個(gè)客戶端請求從發(fā)出到被響應(yīng)經(jīng)歷了哪些組件哪些微服務(wù)請求總時(shí)長每個(gè)組件所花時(shí)長等信息我們有必要了解和收集,以幫助我們定位性能瓶頸進(jìn)行性能調(diào)優(yōu),因此監(jiān)控整個(gè)微服務(wù)架構(gòu)的調(diào)用鏈?zhǔn)钟斜匾疚膶㈥U述如何使用搭建微服務(wù)調(diào)用鏈追蹤中心。
一個(gè)完整的微服務(wù)系統(tǒng)包含多個(gè)微服務(wù)單元,各個(gè)微服務(wù)子系統(tǒng)存在互相調(diào)用的情況,形成一個(gè) 調(diào)用鏈。一個(gè)客戶端請求從發(fā)出到被響應(yīng) 經(jīng)歷了哪些組件、哪些微服務(wù)、請求總時(shí)長、每個(gè)組件所花時(shí)長 等信息我們有必要了解和收集,以幫助我們定位性能瓶頸、進(jìn)行性能調(diào)優(yōu),因此監(jiān)控整個(gè)微服務(wù)架構(gòu)的調(diào)用鏈?zhǔn)钟斜匾疚膶㈥U述如何使用 Zipkin 搭建微服務(wù)調(diào)用鏈追蹤中心。
注: 本文首發(fā)于 My 公眾號(hào) CodeSheep ,可 長按 或 掃描 下面的 小心心 來訂閱 ↓ ↓ ↓
正如 Ziplin官網(wǎng) 所描述,Zipkin是一款分布式的追蹤系統(tǒng),其可以幫助我們收集微服務(wù)架構(gòu)中用于解決延時(shí)問題的時(shí)序數(shù)據(jù),更直白地講就是可以幫我們追蹤調(diào)用的軌跡。
Zipkin的設(shè)計(jì)架構(gòu)如下圖所示:
要理解這張圖,需要了解一下Zipkin的幾個(gè)核心概念:
Reporter
在某個(gè)應(yīng)用中安插的用于發(fā)送數(shù)據(jù)給Zipkin的組件稱為Report,目的就是用于追蹤數(shù)據(jù)收集
Span
微服務(wù)中調(diào)用一個(gè)組件時(shí),從發(fā)出請求開始到被響應(yīng)的過程會(huì)持續(xù)一段時(shí)間,將這段跨度稱為Span
Trace
從Client發(fā)出請求到完成請求處理,中間會(huì)經(jīng)歷一個(gè)調(diào)用鏈,將這一個(gè)整個(gè)過程稱為一個(gè)追蹤(Trace)。一個(gè)Trace可能包含多個(gè)Span,反之每個(gè)Span都有一個(gè)上級(jí)的Trace。
Transport
一種數(shù)據(jù)傳輸?shù)姆绞剑热缱詈唵蔚腍TTP方式,當(dāng)然在高并發(fā)時(shí)可以換成Kafka等消息隊(duì)列
看了一下基本概念后,再結(jié)合上面的架構(gòu)圖,可以試著理解一下,只有裝配有Report組件的Client才能通過Transport來向Zipkin發(fā)送追蹤數(shù)據(jù)。追蹤數(shù)據(jù)由Collector收集器進(jìn)行手機(jī)然后持久化到Storage之中。最后需要數(shù)據(jù)的一方,可以通過UI界面調(diào)用API接口,從而最終取到Storage中的數(shù)據(jù)。可見整體流程不復(fù)雜。
Zipkin官網(wǎng)給出了各種常見語言支持的OpenZipkin libraries:
本文接下來將 構(gòu)造微服務(wù)追蹤的實(shí)驗(yàn)場景 并使用 Brave 來輔助完成微服務(wù)調(diào)用鏈追蹤中心搭建!
利用Docker來部署Zipkin服務(wù)再簡單不過了:
docker run -d -p 9411:9411 --name zipkin docker.io/openzipkin/zipkin
完成之后瀏覽器打開:localhost:9411可以看到Zipkin的可視化界面:
我們來構(gòu)造一個(gè)如下圖所示的調(diào)用鏈:
圖中包含 一個(gè)客戶端 + 三個(gè)微服務(wù):
Client:使用/servicea接口消費(fèi)ServiceA提供的服務(wù)
ServiceA:使用/serviceb接口消費(fèi)ServiceB提供的服務(wù),端口8881
ServiceB:使用/servicec接口消費(fèi)ServiceC提供的服務(wù),端口8882
ServiceC:提供終極服務(wù),端口8883
為了模擬明顯的延時(shí)效果,準(zhǔn)備在每個(gè)接口的響應(yīng)中用代碼加入3s的延時(shí)。
簡單起見,我們用SpringBt來實(shí)現(xiàn)三個(gè)微服務(wù)。
ServiceA的控制器代碼如下:
@RestController public class ServiceAContorller { @Autowired private RestTemplate restTemplate; @GetMapping("/servicea”) public String servicea() { try { Thread.sleep( 3000 ); } catch (InterruptedException e) { e.printStackTrace(); } return restTemplate.getForObject("http://localhost:8882/serviceb", String.class); } }
ServiceB的代碼如下:
@RestController public class ServiceBContorller { @Autowired private RestTemplate restTemplate; @GetMapping("/serviceb”) public String serviceb() { try { Thread.sleep( 3000 ); } catch (InterruptedException e) { e.printStackTrace(); } return restTemplate.getForObject("http://localhost:8883/servicec", String.class); } }
ServiceC的代碼如下:
@RestController public class ServiceCContorller { @Autowired private RestTemplate restTemplate; @GetMapping("/servicec”) public String servicec() { try { Thread.sleep( 3000 ); } catch (InterruptedException e) { e.printStackTrace(); } return "Now, we reach the terminal call: servicec !”; } }
我們將三個(gè)微服務(wù)都啟動(dòng)起來,然后瀏覽器中輸入localhost:8881/servicea來發(fā)出請求,過了9s之后,將取到ServiceC中提供的微服務(wù)接口所返回的內(nèi)容,如下圖所示:
很明顯,調(diào)用鏈可以正常work了!
那么接下來我們就要引入Zipkin來追蹤這個(gè)調(diào)用鏈的信息!
編寫與Zipkin通信的工具組件從Zipkin官網(wǎng)我們可以知道,借助OpenZipkin庫Brave,我們可以開發(fā)一個(gè)封裝Brave的公共組件,讓其能十分方便地嵌入到ServiceA,ServiceB,ServiceC服務(wù)之中,完成與Zipkin的通信。
為此我們需要建立一個(gè)新的基于Maven的Java項(xiàng)目:ZipkinTool
pom.xml中加入如下依賴:
4.0.0 com.hansonwang99 ZipkinTool 1.0-SNAPSHOT org.apache.maven.plugins maven-compiler-plugin 6 jar org.springframework.boot spring-boot 2.0.1.RELEASE provided org.springframework spring-webmvc 4.3.7.RELEASE provided io.zipkin.brave brave-spring-web-servlet-interceptor 4.0.6 io.zipkin.brave brave-spring-resttemplate-interceptors 4.0.6 io.zipkin.reporter zipkin-sender-okhttp3 0.6.12 org.projectlombok lombok RELEASE compile
編寫ZipkinProperties類
其包含endpoint和service兩個(gè)屬性,我們最后是需要將該兩個(gè)參數(shù)提供給ServiceA、ServiceB、ServiceC微服務(wù)作為其application.properties中的Zipkin配置
@Data @Component @ConfigurationProperties("zipkin") public class ZipkinProperties { private String endpoint; private String service; }
用了lombok之后,這個(gè)類異常簡單!
【注意:關(guān)于lombok的用法,可以看這里】
編寫ZipkinConfiguration類
這個(gè)類很重要,在里面我們將Brave的BraveClientHttpRequestInterceptor攔截器注冊到RestTemplate的攔截器調(diào)用鏈中來收集請求數(shù)據(jù)到Zipkin中;同時(shí)還將Brave的ServletHandlerInterceptor攔截器注冊到調(diào)用鏈中來收集響應(yīng)數(shù)據(jù)到Zipkin中
上代碼吧:
@Configuration
@Import({RestTemplate.class, BraveClientHttpRequestInterceptor.class, ServletHandlerInterceptor.class})
public class ZipkinConfiguration extends WebMvcConfigurerAdapter {
@Autowired
private ZipkinProperties zipkinProperties;
@Autowired
private RestTemplate restTemplate;
@Autowired
private BraveClientHttpRequestInterceptor clientInterceptor;
@Autowired
private ServletHandlerInterceptor serverInterceptor;
@Bean
public Sender sender() {
return OkHttpSender.create( zipkinProperties.getEndpoint() );
}
@Bean
public Reporter reporter() {
return AsyncReporter.builder(sender()).build();
}
@Bean
public Brave brave() {
return new Brave.Builder(zipkinProperties.getService()).reporter(reporter()).build();
}
@Bean
public SpanNameProvider spanNameProvider() {
return new SpanNameProvider() {
@Override
public String spanName(HttpRequest httpRequest) {
return String.format(
"%s %s",
httpRequest.getHttpMethod(),
httpRequest.getUri().getPath()
);
}
};
}
@PostConstruct
public void init() {
List interceptors = restTemplate.getInterceptors();
interceptors.add(clientInterceptor);
restTemplate.setInterceptors(interceptors);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(serverInterceptor);
}
}
ZipkinTool完成以后,我們需要在ServiceA、ServiceB、ServiceC三個(gè)SpringBt項(xiàng)目的application.properties中加入Zipkin的配置:
以ServiceA為例:
server.port=8881 zipkin.endpoint=http://你Zipkin服務(wù)所在機(jī)器的IP:9411/api/v1/spans zipkin.service=servicea
我們最后依次啟動(dòng)ServiceA、ServiceB、和ServiceC三個(gè)微服務(wù),并開始實(shí)驗(yàn)來收集鏈路追蹤數(shù)據(jù) !
瀏覽器打開Zipkin的UI界面,可以查看 依賴分析:
圖中十分清晰地展示了ServiceA、ServiceB和ServiceC三個(gè)服務(wù)之間的調(diào)用關(guān)系!
注意,該圖可縮放,并且每一個(gè)元素均可以點(diǎn)擊,例如點(diǎn)擊 ServiceB這個(gè)微服務(wù),可以看到其調(diào)用鏈的上下游!
接下來我們看一下調(diào)用鏈相關(guān),點(diǎn)擊 服務(wù)名,可以看到Zipkin監(jiān)控到個(gè)所有服務(wù):
同時(shí)可以查看Span,如以ServiceA為例,其所有REST接口都再下拉列表中:
以ServiceA為例,點(diǎn)擊 Find Traces,可以看到其所有追蹤信息:
點(diǎn)擊某個(gè)具體Trace,還能看到詳細(xì)的每個(gè)Span的信息,如下圖中,可以看到 A → B → C 調(diào)用過程中每個(gè)REST接口的詳細(xì)時(shí)間戳:
點(diǎn)擊某一個(gè)REST接口進(jìn)去還能看到更詳細(xì)的信息,如查看/servicec這個(gè)REST接口,可以看到從發(fā)送請求到收到響應(yīng)信息的所有詳細(xì)步驟:
后記作者更多的原創(chuàng)文章在此,歡迎觀賞
My Personal Blog
作者更多的SpringBt實(shí)踐文章在此:
Spring Boot應(yīng)用監(jiān)控實(shí)戰(zhàn)
SpringBoot應(yīng)用部署于外置Tomcat容器
ElasticSearch搜索引擎在SpringBt中的實(shí)踐
初探Kotlin+SpringBoot聯(lián)合編程
Spring Boot日志框架實(shí)踐
SpringBoot優(yōu)雅編碼之:Lombok加持
如果有興趣,也可以抽點(diǎn)時(shí)間看看作者一些關(guān)于容器化、微服務(wù)化方面的文章:
利用K8S技術(shù)棧打造個(gè)人私有云 連載文章
從一份配置清單詳解Nginx服務(wù)器配置
Docker容器可視化監(jiān)控中心搭建
利用ELK搭建Docker容器化應(yīng)用日志中心
RPC框架實(shí)踐之:Apache Thrift
RPC框架實(shí)踐之:Google gRPC
微服務(wù)調(diào)用鏈追蹤中心搭建
Docker容器跨主機(jī)通信
Docker Swarm集群初探
高效編寫Dockerfile的幾條準(zhǔn)則
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/27272.html
摘要:注本文首發(fā)于公眾號(hào),可長按或掃描下面的小心心來訂閱擴(kuò)展組件是在微服務(wù)調(diào)用鏈追蹤中心搭建一文中編寫的與通信的工具組件,利用其追蹤微服務(wù)調(diào)用鏈的,現(xiàn)在我們想追蹤數(shù)據(jù)庫調(diào)用鏈的話,可以擴(kuò)展一下其功能。 showImg(https://segmentfault.com/img/remote/1460000014751186); 概述 在前面:微服務(wù)調(diào)用鏈追蹤中心搭建 一文中我們利用Zipki...
摘要:在文章微服務(wù)調(diào)用鏈追蹤中心搭建一文中模擬出來的調(diào)用鏈就是一個(gè)遠(yuǎn)程調(diào)用的例子,只不過這篇文章里是通過這種同步調(diào)用方式,利用的是協(xié)議在應(yīng)用層完成的,這種方法雖然奏效,但有時(shí)效率并不高。 showImg(https://segmentfault.com/img/remote/1460000014858219); 一、概述 RPC(Remote Procedure Call)即 遠(yuǎn)程過程調(diào)...
摘要:在文章微服務(wù)調(diào)用鏈追蹤中心搭建一文中模擬出來的調(diào)用鏈就是一個(gè)遠(yuǎn)程調(diào)用的例子,只不過這篇文章里是通過這種同步調(diào)用方式,利用的是協(xié)議在應(yīng)用層完成的,這種方法雖然奏效,但有時(shí)效率并不高。 showImg(https://segmentfault.com/img/remote/1460000014858219); 一、概述 RPC(Remote Procedure Call)即 遠(yuǎn)程過程調(diào)...
摘要:概述應(yīng)用一旦容器化以后,需要考慮的就是如何采集位于容器中的應(yīng)用程序的打印日志供運(yùn)維分析。 showImg(https://segmentfault.com/img/remote/1460000014146680); 概述 應(yīng)用一旦容器化以后,需要考慮的就是如何采集位于Docker容器中的應(yīng)用程序的打印日志供運(yùn)維分析。典型的比如 SpringBoot應(yīng)用的日志 收集。本文即將闡述如何利...
閱讀 3730·2021-10-11 10:59
閱讀 1318·2019-08-30 15:44
閱讀 3489·2019-08-29 16:39
閱讀 2898·2019-08-29 16:29
閱讀 1813·2019-08-29 15:24
閱讀 819·2019-08-29 15:05
閱讀 1272·2019-08-29 12:34
閱讀 2354·2019-08-29 12:19