SpringCloud集成sleuth和zipkin實(shí)現(xiàn)微服務(wù)鏈路追蹤的實(shí)戰(zhàn)分享
技術(shù)積累
spring cloud sleuth介紹
Sleuth是Spring cloud的分布式跟蹤解決方案。
1.span(跨度),基本工作單元。一次鏈路調(diào)用,創(chuàng)建一個(gè)span,span用一個(gè)64位id唯一標(biāo)識(shí)。包括:id,描述,時(shí)間戳事件,spanld,span父id.span被啟動(dòng)和停止時(shí),記錄了時(shí)間信息,初始化span叫:rootspan,它的span id和trace id相等。
2.trace(跟蹤),一組共享"root span”的span組成的樹狀結(jié)構(gòu)稱為 trace,trace也有一個(gè)64位ID,trace中所有span共享一個(gè)trace id。類似于一顆 span 樹。
3.annotation (標(biāo)簽),annotation用來記錄事件的存在,其中,核心annotation用來定義請(qǐng)求的開始和結(jié)束CS(Client Send客戶端發(fā)起請(qǐng)求)??蛻舳税l(fā)起請(qǐng)求描述了span開始,
SR(Server Received服務(wù)端接到請(qǐng)求)。服務(wù)端獲得請(qǐng)求并準(zhǔn)備處理它。SR-CS=網(wǎng)絡(luò)延遲SS(Server Send服務(wù)器端處理完成,并將結(jié)果發(fā)送給客戶端)。表示服務(wù)器完成請(qǐng)求處理,響應(yīng)客戶端時(shí)。SS-SR=服務(wù)器處理請(qǐng)求的時(shí)間,
CR(Client Received 客戶端接受服務(wù)端信息)。span結(jié)束的標(biāo)識(shí)??蛻舳私邮盏椒?wù)器的響應(yīng)。CR-CS=客戶端發(fā)出請(qǐng)求到服務(wù)器響應(yīng)的總時(shí)間。
其實(shí)數(shù)據(jù)結(jié)構(gòu)是一顆樹,從root span 開始。
工具定位
Spring Cloud Sleuth是一個(gè)用于Spring Cloud應(yīng)用程序的分布式追蹤工具,它主要專注于在服務(wù)間傳播追蹤信息。
主要功能
傳播追蹤上下文:在服務(wù)調(diào)用間傳遞Trace ID和Span ID,確保整個(gè)請(qǐng)求鏈路的追蹤信息保持一致。
集成日志框架:修改日志框架的配置,使得日志記錄中包含Trace和Span的ID。
與Spring Cloud生態(tài)集成:與Spring Cloud的其他組件(如Ribbon、Hystrix、Zuul等)無縫集成。
依賴性:Sleuth是為Spring Cloud應(yīng)用程序設(shè)計(jì)的,它依賴于Spring框架和Spring Boot。
zipkin介紹
Zipkin是一款開源的分布式實(shí)時(shí)數(shù)據(jù)追蹤系統(tǒng)(Distributed Tracking System),基于 Google Dapper的論文設(shè)計(jì)而來,由 Twitter 公司開發(fā)貢獻(xiàn)。其主要功能是聚集來自各個(gè)異構(gòu)系統(tǒng)的實(shí)時(shí)監(jiān)控?cái)?shù)據(jù)。
工具定位
Zipkin是一個(gè)分布式追蹤系統(tǒng),它提供了追蹤數(shù)據(jù)的收集、存儲(chǔ)、查找和展示功能。
主要功能
收集追蹤數(shù)據(jù):Zipkin通過其客戶端庫(kù)(如Brave)收集追蹤數(shù)據(jù)。
存儲(chǔ)追蹤數(shù)據(jù):支持多種存儲(chǔ)方案,如內(nèi)存、MySQL、Cassandra、Elasticsearch等。
查詢和展示:提供Web界面,用于查詢追蹤數(shù)據(jù),并以可視化的方式展示服務(wù)間的調(diào)用關(guān)系和延遲。
獨(dú)立性:Zipkin可以獨(dú)立于任何應(yīng)用程序或框架運(yùn)行,并且可以與多種編程語(yǔ)言和框架集成。
zipkin 官網(wǎng)
https://zipkin.io/pages/quickstart.html
Zipkin與Sleuth的協(xié)作
數(shù)據(jù)收集:Sleuth負(fù)責(zé)在Spring Cloud應(yīng)用程序中生成和傳播追蹤數(shù)據(jù),而Zipkin負(fù)責(zé)收集這些數(shù)據(jù)。
數(shù)據(jù)展示:Sleuth生成的追蹤數(shù)據(jù)可以通過Zipkin的Web界面進(jìn)行查詢和展示。
集成:在Spring Cloud應(yīng)用程序中,Sleuth通常與Zipkin一起使用,Sleuth負(fù)責(zé)追蹤信息的生成和傳播,Zipkin負(fù)責(zé)存儲(chǔ)和展示。
SpringCloud多模塊搭建
多模塊微服務(wù)項(xiàng)目結(jié)構(gòu)
新增父項(xiàng)目來管理微服務(wù)各個(gè)模塊
#父模塊pom必須聲明
pom
新增子模塊
Zipkin Server部署
由于springcloud F版本不支持自定義zipkin server,故我們采用docker鏡像進(jìn)行部署zipkin server。
docker pull 鏡像
docker pull openzipkin/zipkin:latest
啟動(dòng)zipkin server
未持久化(內(nèi)存):
docker run --name zipkin-server -d --restart=always -p 9411:9411 openzipkin/zipkin:latest
http://127.0.0.1:9411/zipkin/
持久化到MySQL5:
docker run --name zipkin-server-mysql -d --restart=always -p 19411:9411 -e MYSQL_USER=root -e MYSQL_PASS=12345678 -e MYSQL_HOST=127.0.0.1 -e STORAGE_TYPE=mysql -e MYSQL_DB=zipkin -e MYSQL_TCP_PORT=13306 openzipkin/zipkin:3.3
mysql DD語(yǔ)句如下:
https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql -- -- Copyright The OpenZipkin Authors -- SPDX-License-Identifier: Apache-2.0 -- 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;
持久化到ES:
docker run --name zipkin-server-es -d -p 19411:9411 --restart=always -e STORAGE_TYPE=elasticsearch -e ES_HOSTS=127.0.0.1:9200 openzipkin/zipkin:latest
JAR運(yùn)行:
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=12345678
我們測(cè)試選擇不持久化
docker run -d -p 9411:9411 --name zipkinServer --restart=always openzipkin/zipkin
3、啟動(dòng)完成
SpringCloud 接入 Sleuth 與 Zipkin
pom引入依賴 (springboot2.6+)
<properties> <spring-cloud.version>2021.0.5</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> <version>3.1.10</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> <version>3.1.10</version> </dependency> </dependencies>
appilication.yml配置修改
spring: zipkin: #zipkin服務(wù)所在地址 base-url: http://127.0.0.1:9411/ sender: type: web #使用http的方式傳輸數(shù)據(jù) #配置采樣百分比 sleuth: sampler: probability: 1 # 將采樣比例設(shè)置為 1.0,也就是全部都需要。默認(rèn)是0.1也就是10%,一般情況下,10%就夠用了 ##打開debug日志 logging: level: org.springframework.web.servlet.DispatcherServlet: Debug
type=web也就是通過 HTTP 的方式發(fā)送數(shù)據(jù)到 Zipkin 。
如果請(qǐng)求量比較大,這種方式其實(shí)性能是比較低的,一般情況下我們都是通過消息中間件來發(fā)送,比如 RabbitMQ 。如果日志數(shù)據(jù)量比較大,一般推薦擁有更高吞吐量的 Kafka 來進(jìn)行日志推送。這種方式就是讓服務(wù)將 Sleuth 收集的日志推給 MQ ,讓 Zipkin 去監(jiān)控 MQ 的信息,通過 MQ 的隊(duì)列獲取到服務(wù)的信息。這樣就提高了性能。
而日志的存儲(chǔ)則可以采用mysql、 Elasticsearch 對(duì)數(shù)據(jù)進(jìn)行持久化,這樣可以保證 Zipkin 重啟后,鏈路信息不會(huì)丟失。
增加測(cè)試鏈路代碼
鏈路為:
user-service --> order-service --> finance-service
user-service增加請(qǐng)求入口getOrderAmount:
/** * 計(jì)算訂單金額 * @param orderId * @author senfel * @date 2024/12/9 18:25 * @return java.lang.String */ @RequestMapping("/getOrderAmount") public String getOrderAmount(@RequestParam(name = "orderId") String orderId) { return orderService.getOrderAmount(orderId); }
user-service增加feign調(diào)用order-service:
/** * FeeService * @author senfel * @version 1.0 * @date 2024/12/9 18:02 */ @FeignClient(name = "order-service",fallback = OrderServiceFallback.class) public interface getOrderAmount { /** * 獲取訂單金額 * @param orderId * @author senfel * @date 2024/12/9 18:06 * @return java.lang.String */ @RequestMapping(value = "/order/getOrderAmount",method = RequestMethod.GET) String getOrderAmount(@RequestParam(name = "orderId") String orderId); }
order-service增加調(diào)用入口getOrderAmount:
/** * 獲取訂單金額 * @param orderId * @author senfel * @date 2024/12/9 18:06 * @return java.lang.String */ @RequestMapping(value = "/getOrderAmount",method = RequestMethod.GET) public String getOrderAmount(@RequestParam(name = "orderId") String orderId){ return financeService.getFee(orderId); }
order-service增加feign調(diào)用finance-service:
/** * FinanceService * @author senfel * @version 1.0 * @date 2024/12/9 18:10 */ @FeignClient(name = "finance-service",fallback = FinanceServiceFallback.class) public interface FinanceService { /** * 獲取費(fèi)用 * @param orderId * @author senfel * @date 2024/12/9 18:12 * @return java.lang.String */ @RequestMapping(value = "/finance/getFee",method = RequestMethod.GET) String getFee(@RequestParam(name = "orderId") String orderId); }
finance-service增加請(qǐng)求入口getFee:
/** * 獲取費(fèi)用 * @param orderId * @author senfel * @date 2024/12/9 18:12 * @return java.lang.String */ @RequestMapping(value = "/getFee",method = RequestMethod.GET) public String getFee(@RequestParam(name = "orderId") String orderId) { return "100"; }
調(diào)用微服務(wù)進(jìn)行驗(yàn)證
啟動(dòng)微服務(wù)調(diào)用getOrderAmount()
進(jìn)入zipkin界面查看請(qǐng)求調(diào)用鏈路和各個(gè)階段耗時(shí)
至此,我們已經(jīng)完微服務(wù)鏈路追蹤實(shí)戰(zhàn).。
以上就是SpringCloud集成sleuth和zipkin實(shí)現(xiàn)微服務(wù)鏈路追蹤的實(shí)戰(zhàn)分享的詳細(xì)內(nèi)容,更多關(guān)于SpringCloud sleuth和zipkin鏈路追蹤的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot前后端傳輸加密設(shè)計(jì)實(shí)現(xiàn)方案
這篇文章主要給大家介紹了關(guān)于SpringBoot前后端傳輸加密設(shè)計(jì)實(shí)現(xiàn)方案的相關(guān)資料,包括數(shù)據(jù)加密方案、解密傳輸數(shù)據(jù)實(shí)現(xiàn)方案和響應(yīng)數(shù)據(jù)加密實(shí)現(xiàn)方案,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-11-11Java實(shí)現(xiàn)對(duì)象按照其屬性排序的兩種方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)對(duì)象按照其屬性排序的兩種方法,結(jié)合實(shí)例形式詳細(xì)分析了Java對(duì)象按照其屬性排序的兩種實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-05-05解決idea更新maven倉(cāng)庫(kù)的圖文教程
這篇文章主要介紹了解決idea更新maven倉(cāng)庫(kù)的圖文教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01解決Java調(diào)用BAT批處理不彈出cmd窗口的方法分析
本篇文章是對(duì)Java調(diào)用BAT批處理不彈出cmd窗口的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05詳解Java中LinkedStack鏈棧的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Java中LinkedStack鏈棧的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下2022-11-11超簡(jiǎn)單的java獲取鼠標(biāo)點(diǎn)擊位置坐標(biāo)的實(shí)例(鼠標(biāo)在Jframe上的坐標(biāo))
在Java窗體Jframe上獲取鼠標(biāo)點(diǎn)擊的坐標(biāo),其中使用了匿名內(nèi)部類,實(shí)例代碼非常簡(jiǎn)單易懂,大家可以學(xué)習(xí)一下2018-03-03