「Java分享客?!闺S時(shí)用隨時(shí)翻:微服務(wù)鏈路追蹤之zipkin搭建

前言

微服務(wù)治理方案中,鏈路追蹤是必修課,SpringCloud的組件其實(shí)使用很簡(jiǎn)單,生產(chǎn)環(huán)境中真正令人頭疼的往往是軟件維護(hù),接口在微服務(wù)間的調(diào)用究竟哪個(gè)環(huán)節(jié)出現(xiàn)了問題,哪個(gè)環(huán)節(jié)耗時(shí)較長(zhǎng),這都是項(xiàng)目上線后一定會(huì)遇到的問題,為了解決這些問題鏈路追蹤便應(yīng)運(yùn)而生了。


主流方案

1)、SkyWalking:這應(yīng)該是目前最主流的方案了,我所在公司今年的新項(xiàng)目就開始使用這個(gè),效果確實(shí)很顯著,功能強(qiáng)大,最重要還是國(guó)產(chǎn)的,后面不用看了我們支持國(guó)產(chǎn)吧!開個(gè)玩笑哈哈,其實(shí)這個(gè)框架也有缺點(diǎn),就是稍微有點(diǎn)重,比較適合稍大一點(diǎn)的項(xiàng)目,但可預(yù)見后面幾年都是最受歡迎的方案;

2)、Zipkin:這個(gè)是老牌鏈路追蹤方案,已經(jīng)被非常多項(xiàng)目驗(yàn)證過實(shí)用性,相比較于SkyWalking,我個(gè)人更喜歡這個(gè)框架,因?yàn)楦p量級(jí),安裝也非常簡(jiǎn)單,是中小規(guī)模的微服務(wù)項(xiàng)目首選方案。


用法

1、zipkin環(huán)境搭建

官方提供了docker版本,十分簡(jiǎn)單。也可以下載編譯好的zipkin.jar來(lái)運(yùn)行,是springboot項(xiàng)目。

官網(wǎng):https://zipkin.io/pages/quickstart.html

1)、啟動(dòng)

默認(rèn)端口號(hào)啟動(dòng)zipkin服務(wù),默認(rèn)端口9411.

java -jar zipkin.jar

2)、指定端口號(hào)

java -jar zipkin.jar --server.port=8080

3)、指定訪問RabbitMQ

java -jar zipkin.jar --zipkin.collector.rabbitmq.addresses=127.0.0.1

4)、啟動(dòng)效果
111.png


2、SpringCloud整合zipkin

springcloud其它基礎(chǔ)依賴包引入這里省略,直接模擬場(chǎng)景。

會(huì)員服務(wù):zipkin_member

訂單服務(wù):zipkin_order

消息服務(wù):zipkin_msg

過程:會(huì)員服務(wù)調(diào)用訂單服務(wù),訂單服務(wù)調(diào)用消息服務(wù)。

1)、引入依賴
<!-- zipkin -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
2)、application.yml配置

注意事項(xiàng):

a)、加上服務(wù)名,RestTemplate調(diào)用時(shí)會(huì)用到;

b)、加上zipkin服務(wù)端地址;

c)、加上probability采集率設(shè)置,默認(rèn)0.1,測(cè)試環(huán)境改為1.0保證每次都采集,生產(chǎn)環(huán)境適當(dāng)抽樣即可。(因?yàn)?0000個(gè)請(qǐng)求抽樣1000個(gè)也能發(fā)現(xiàn)問題了,沒必要全部都采集)

222.png
3)、引入RestTemplate

這里restTemplate主要用來(lái)進(jìn)行接口調(diào)用查看鏈路追蹤是否生效

@Component
public class RestTemplateConfig {
    
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
4)、controller調(diào)用

會(huì)員調(diào)用訂單

333.png

訂單調(diào)用消息

444.png

消息處理具體業(yè)務(wù)

555.png
5)、查看效果

啟動(dòng)Zipkin服務(wù)端,訪問:http://127.0.0.1:9411

666.png

執(zhí)行controller接口

777.png

查看鏈路追蹤,可以看到,接口調(diào)用的鏈路已經(jīng)在zipkin顯現(xiàn)了。

888.png
999.png


3、zipkin整合RabbitMQ異步采集

springboot2.0之后,官方不再推薦使用自建的zipkin server,而是直接使用編譯好的zipkin.jar來(lái)給我們使用。

zipkin.jar中的yml配置可以參考:https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml

1)、指定RabbitMQ為服務(wù)器

啟動(dòng)zipkin服務(wù)時(shí)指定rabbitmq為服務(wù)器即可,得先啟動(dòng)rabbitmq服務(wù)器。

java -jar zipkin.jar --zipkin.collector.rabbitmq.addresses=192.168.239.132

啟動(dòng)之后,可以發(fā)現(xiàn)rabbitmq中會(huì)自動(dòng)新增一個(gè)zipkin隊(duì)列,表示綁定成功。

1010.png
2)、引入中間依賴

給每個(gè)微服務(wù)引入stream和rabbitmq的中間件依賴

<!-- 引入和rabbitmq的中間依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
3)、yml配置

修改每個(gè)微服務(wù)的application.yml,加上rabbitmq的配置。

rabbitmq: 
    host: 192.168.239.132
    port: 5672
    username: guest
    password: guest
4)、啟動(dòng)和調(diào)用

啟動(dòng)微服務(wù),執(zhí)行調(diào)用。

1111.png
5)、MQ是否收到消息

看rabbitmq是否有收消息,隊(duì)列有反應(yīng)說明rabbitmq收到消息了。

1212png.png
6)、Zipkin是否采集信息

看zipkin是否采集了鏈路信息

1313.png
7)、驗(yàn)證積壓消息

關(guān)掉zipkin服務(wù),看消息是否會(huì)積壓在rabbitmq,再啟動(dòng)zipkin服務(wù),看消息是否會(huì)被消費(fèi)并且獲取到鏈路信息。

1414.png

獲取消息查看,發(fā)現(xiàn)獲取到的就是traceId相關(guān)的json數(shù)據(jù),證明整個(gè)過程都是正常的。

1515.png

重新再啟動(dòng)zipkin服務(wù),發(fā)現(xiàn)rabbitmq積壓的消息就被消費(fèi)了。

1616.png

并且也能獲取到鏈路信息

1717.png


4、zipkin使用MySQL存儲(chǔ)

zipkin.jar中的yml配置可以參考,里面有關(guān)于mysql的配置或者其他如elasticsearch的配置:

https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml

這節(jié)我們?cè)谏弦还?jié)MQ的基礎(chǔ)上增加MySQL的啟動(dòng)配置項(xiàng)

1)、指定MySQL

命令看著很長(zhǎng),其實(shí)仔細(xì)看發(fā)現(xiàn)很簡(jiǎn)單,都是見名知義,不必死記硬背。

java -jar zipkin.jar


--zipkin.collector.rabbitmq.addresses=192.168.239.132


--zipkin.storage.type=mysql


--zipkin.storage.mysql.host=127.0.0.1


--zipkin.storage.mysql.port=3306


--zipkin.storage.mysql.username=root


--zipkin.storage.mysql.password=123456


--zipkin.storage.mysql.db=zipkin

2)、創(chuàng)建zipkin數(shù)據(jù)庫(kù)

根據(jù)1中命令配置的信息,創(chuàng)建zipkin數(shù)據(jù)庫(kù),并執(zhí)行語(yǔ)句創(chuàng)建zipkin采集記錄的三張表。

參考官網(wǎng):https://github.com/apache/incubator-zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql

這里我也貼出來(lái) zipkin-mysql.sql

1818.png
CREATE TABLE IF NOT EXISTS zipkin_spans (
  `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
  `trace_id` BIGINT NOT NULL,
  `id` BIGINT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `remote_service_name` VARCHAR(255),
  `parent_id` BIGINT,
  `debug` BIT(1),
  `start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
  `duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query',
  PRIMARY KEY (`trace_id_high`, `trace_id`, `id`)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds';
ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames';
ALTER TABLE zipkin_spans ADD INDEX(`remote_service_name`) COMMENT 'for getTraces and getRemoteServiceNames';
ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';

CREATE TABLE IF NOT EXISTS zipkin_annotations (
  `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
  `trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
  `span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',
  `a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',
  `a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',
  `a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
  `a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
  `endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null',
  `endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',
  `endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',
  `endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null'
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;

ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds';
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';
ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces and autocomplete values';
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces and autocomplete values';
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job';

CREATE TABLE IF NOT EXISTS zipkin_dependencies (
  `day` DATE NOT NULL,
  `parent` VARCHAR(255) NOT NULL,
  `child` VARCHAR(255) NOT NULL,
  `call_count` BIGINT,
  `error_count` BIGINT,
  PRIMARY KEY (`day`, `parent`, `child`)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
3)、效果

啟動(dòng)微服務(wù),執(zhí)行controller請(qǐng)求,看是否成功。

RabbitMQ

1919.png

zipkin

2020.png

MySQL

2121.png


至此,springcloud sleuth + zipkin + rabbitmq + mysql 就全部整合成功了!


總結(jié)

微服務(wù)的治理方案有很多,學(xué)習(xí)方向根據(jù)個(gè)人喜好決定,我的經(jīng)驗(yàn)就是不必盲目跟從這種用于輔助的方案,比如現(xiàn)在有SkyWalking,以后可能還有SkyFlying、SkySwimming。


走向高級(jí)軟件工程師都要有一個(gè)意識(shí),就是在層出不窮的開源框架如雨后春筍般出現(xiàn)的時(shí)候,你得有信心用到哪個(gè)花點(diǎn)時(shí)間就能自己搭建起來(lái),這才是提升自己的最有效方法。


一個(gè)項(xiàng)目使用什么治理方案最重要的絕不是跟風(fēng),而是哪款最適合就用哪款,就像你找女朋友一樣,不單單是找漂亮的,而是找最能一起過日子的,否則就是貌合神離。


分享

本篇實(shí)際上是我8年多工作及學(xué)習(xí)過程中在云筆記中記錄的內(nèi)容之一,其實(shí)還有很多我閑暇之余都做了下整理,有感興趣的朋友可以下載看看,什么時(shí)候用到了翻開說不定就能節(jié)省很多時(shí)間。

鏈接: https://pan.baidu.com/doc/share/flr0QYwZYPYxmWSRPbnJRw-1028798558141759

提取碼: bxaa

資料圖.png



本人原創(chuàng)文章純手打,專注于分享主流技術(shù)及實(shí)際工作經(jīng)驗(yàn),覺得有一滴滴幫助的話就請(qǐng)點(diǎn)個(gè)贊和收藏吧!


更多最新技術(shù)文章可關(guān)注GZH:【Java分享客?!?/p>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容