Sleuth & zipkin
分布式鍊路追蹤(Distributed Tracing),就是将一次分布式請求還原成調用鍊路,進行日志記錄,性能監控并将 一次分布式請求的調用情況集中展示。比如各個服務節點上的耗時、請求具體到達哪台機器上、每個服務節點的請求狀态等等。
Sleuth
Spring Cloud Sleuth 主要功能就是在分布式系統中提供追蹤解決方案,并且相容支援了 zipkin,你隻需要在pom檔案中引入相應的依賴即可。
- Span:基本工作單元,例如,在一個建立的span中發送一個RPC等同于發送一個回應請求給RPC,span通過一個64位ID唯一辨別,trace以另一個64位ID表示,span還有其他資料資訊,比如摘要、時間戳事件、關鍵值注釋(tags)、span的ID、以及進度ID(通常是IP位址)span在不斷的啟動和停止,同時記錄了時間資訊,當你建立了一個span,你必須在未來的某個時刻停止它。
-
Trace:一系列spans組成的一個樹狀結構,例如,如果你正在跑一個分布式大資料工程,你可能
需要建立一個trace。
- Annotation:用來及時記錄一個事件的存在,一些核心annotations用來定義一個請求的開始和結束
- cs - Client Sent -用戶端發起一個請求,這個annotion描述了這個span的開始
- sr - Server Received -服務端獲得請求并準備開始處理它,如果将其sr減去cs時間戳便可得到網絡延遲
- ss - Server Sent -注解表明請求處理的完成(當請求傳回用戶端),如果ss減去sr時間戳便可得到服務端需要的處理請求時間
- cr - Client Received -表明span的結束,用戶端成功接收到服務端的回複,如果cr減去cs時間戳便可得到用戶端從服務端擷取回複的所有所需時間
- 配置依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency>
- 配置檔案application.yml
需要收集日志的微服務(本項目就是gateway服務,product服務,service服務)都需要添加如上的配置和依賴pom檔案。啟動微服務,調用之後,我們可以在對應微服務的控制台觀察到sleuth的日志輸出。logging: level: root: INFO org.springframework.web.servlet.DispatcherServlet: DEBUG org.springframework.cloud.sleuth: DEBUG
// gateway控制台列印的 DEBUG [api-gateway-server,79ff7de257120731,79ff7de257120731,true] 8928 --- [ctor-http-nio-2...... // service-order控制台列印的 DEBUG [service-order, 79ff7de257120731, df75b5eaaa9c99b0,true] 2944 --- [nio-9002-exec-6] ...... // service-product控制台列印的 DEBUG [service-product, 79ff7de257120731, c891708ade291c9f,true] 8324 --- [nio-9001-exec-2]......
可以看到,上面都是DEBUG開頭,中括号裡第一個參數是服務名,第二個是TraceId(同一個調用鍊的id是相同的),後面跟着的是SpanId,依次調用有一個全局的TraceId,将調用鍊路串起來。仔細分析每個微服務的日志,不難看出請求的具體過程。
控制台檢視不夠清晰,Zipkin可以将日志聚合,并進行可視化展示和全文檢索。
ZipKin
主要由 4 個核心元件構成:
- Collector:收集器元件,它主要用于處理從外部系統發送過來的跟蹤資訊,将這些資訊轉換為Zipkin 内部處理的 Span 格式,以支援後續的存儲、分析、展示等功能。
- Storage:存儲元件,它主要對處理收集器接收到的跟蹤資訊,預設會将這些資訊存儲在記憶體中,我們也可以修改此存儲政策,通過使用其他存儲元件将跟蹤資訊存儲到資料庫中。
- RESTful API:API 元件,它主要用來提供外部通路接口。比如給用戶端展示跟蹤資訊,或是外接系統通路以實作監控等。
- Web UI:UI 元件,基于 API 元件實作的上層應用。通過 UI 元件使用者可以友善而有直覺地查詢和分析跟蹤資訊。
Zipkin 分為兩端,一個是 Zipkin 服務端,一個是 Zipkin 用戶端,用戶端也就是微服務的應用。
用戶端會配置服務端的 URL 位址,一旦發生服務間的調用的時候,會被配置在微服務裡面的 Sleuth 的監聽器監聽,并生成相應的 Trace 和 Span 資訊發送給服務端。
發送的方式主要有兩種,一種是 HTTP 封包的方式,還有一種是消息總線的方式如 RabbitMQ。
不論哪種方式,我們都需要:
- 一個 Eureka 服務注冊中心。
- 一個 Zipkin 服務端。
- 多個微服務,這些微服務中配置Zipkin 用戶端。
-
下載下傳zipkin server(服務端)的啟動jar包
下載下傳位址:https://search.maven.org/search?q=a:zipkin-server
選擇版本,一定要選擇exec.jar進行下載下傳(40-60M大小)【建議2.12.9】**
下載下傳下來後,在cmd指令行輸入
java -jar zipkin-server-2.12.9-exec.jar
啟動 Zipkin Server
【其中的2.12.9是你下載下傳的jar包版本,記得更改】
啟動參數配置官方文檔:https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml
浏覽器輸入http://localhost:9411進入Zipkin Server的管理背景
- 在需要記錄日志的微服務導入依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
- 修改application.yml (需要收集日志的微服務)
spring: zipkin: base-url: http://127.0.0.1:9411/ #zipkin server的請求位址 sender: type: web #請求方式,預設以http的方式向zipkin server發送追蹤資料 sleuth: sampler: probability: 1.0 #采樣的百分比,可以設定0-1的小數,比如設定0.1就是隻收集1/10的資料
重新整理http://localhost:9411 可以看到請求的鍊路,及響應時長等。
這是通過web方式進行檢視,鍊路資料儲存在記憶體中,重新開機zipkin服務資料會消失。
持久化zipkin資料,存儲在mysql資料庫中
- 準備mysql庫及表
CREATE DATABASE /*!32312 IF NOT EXISTS*/`zipkin` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `zipkin`;
/*Table structure for table `zipkin_annotations` */
DROP TABLE IF EXISTS `zipkin_annotations`;
CREATE TABLE `zipkin_annotations` (
`trace_id_high` bigint(20) NOT NULL DEFAULT '0' COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
`trace_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
`span_id` bigint(20) 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(11) NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
`a_timestamp` bigint(20) DEFAULT NULL COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
`endpoint_ipv4` int(11) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null',
`endpoint_ipv6` binary(16) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',
`endpoint_port` smallint(6) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null',
`endpoint_service_name` varchar(255) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null',
UNIQUE KEY `trace_id_high` (`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`) COMMENT 'Ignore insert on duplicate',
KEY `trace_id_high_2` (`trace_id_high`,`trace_id`,`span_id`) COMMENT 'for joining with zipkin_spans',
KEY `trace_id_high_3` (`trace_id_high`,`trace_id`) COMMENT 'for getTraces/ByIds',
KEY `endpoint_service_name` (`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames',
KEY `a_type` (`a_type`) COMMENT 'for getTraces',
KEY `a_key` (`a_key`) COMMENT 'for getTraces',
KEY `trace_id` (`trace_id`,`span_id`,`a_key`) COMMENT 'for dependencies job'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;
/*Data for the table `zipkin_annotations` */
/*Table structure for table `zipkin_dependencies` */
DROP TABLE IF EXISTS `zipkin_dependencies`;
CREATE TABLE `zipkin_dependencies` (
`day` date NOT NULL,
`parent` varchar(255) NOT NULL,
`child` varchar(255) NOT NULL,
`call_count` bigint(20) DEFAULT NULL,
UNIQUE KEY `day` (`day`,`parent`,`child`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;
/*Data for the table `zipkin_dependencies` */
/*Table structure for table `zipkin_spans` */
DROP TABLE IF EXISTS `zipkin_spans`;
CREATE TABLE `zipkin_spans` (
`trace_id_high` bigint(20) NOT NULL DEFAULT '0' COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
`trace_id` bigint(20) NOT NULL,
`id` bigint(20) NOT NULL,
`name` varchar(255) NOT NULL,
`parent_id` bigint(20) DEFAULT NULL,
`debug` bit(1) DEFAULT NULL,
`start_ts` bigint(20) DEFAULT NULL COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
`duration` bigint(20) DEFAULT NULL COMMENT 'Span.duration(): micros used for minDuration and maxDuration query',
UNIQUE KEY `trace_id_high` (`trace_id_high`,`trace_id`,`id`) COMMENT 'ignore insert on duplicate',
KEY `trace_id_high_2` (`trace_id_high`,`trace_id`,`id`) COMMENT 'for joining with zipkin_annotations',
KEY `trace_id_high_3` (`trace_id_high`,`trace_id`) COMMENT 'for getTracesByIds',
KEY `name` (`name`) COMMENT 'for getTraces and getSpanNames',
KEY `start_ts` (`start_ts`) COMMENT 'for getTraces ordering and range'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;
/*Data for the table `zipkin_spans` */
/*!40101 SET [email protected]_SQL_MODE */;
/*!40014 SET [email protected]_FOREIGN_KEY_CHECKS */;
/*!40014 SET [email protected]_UNIQUE_CHECKS */;
/*!40111 SET [email protected]_SQL_NOTES */;
-
修改server啟動指令
官方文檔 :https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml
cmd啟動指令:
java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=111111
上面的指令記得修改mysql的登陸密碼。
啟動之後,自動連接配接資料庫,資料儲存在mysql中,重新開機也支援檢視之前資料。
使用消息中間件RabbitMQ收集資料
Zipkin用戶端和Server之間是使用HTTP請求的方式進行通信(即同步的請求方式)影響響應效率。Zipkin支援與rabbitMQ整合完成異步消息傳輸。
-
準備RabbitMQ
安裝RabbitMQ ,可檢視部落格https://blog.csdn.net/qq_43220949/article/details/113134782
輸入指令 進行啟動:
浏覽器輸入http://localhost:15672,預設密碼賬号都是rabbitmq-server.bat
guest
-
修改zipkin服務端從rabbit拉取消息
重新啟動zipkin服務端,指令為:
(RabbitMQ的TCP端口為5672,web管理工具端口為15672)java -jar zipkin-server-2.12.9-exec.jar --RABBIT_ADDRESSES=127.0.0.1:5672
-
修改zipkin用戶端,将消息以rabbit形式發送到mq伺服器
a. 依賴
給需要給RabbitMQ發送請求的服務都配置上依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-zipkin</artifactId> </dependency> <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> </dependency>
b. 修改application.yml
給需要給RabbitMQ發送請求的服務都修改application.yml,然後重新開機服務。
- 修改zipkin的配置
- 添加rabbitmq
spring: zipkin: #base-url: http://127.0.0.1:9411/ #zipkin server的請求位址 sender: type: rabbit #type: web #請求方式,預設以http的方式向zipkin server發送追蹤資料 sleuth: sampler: probability: 1.0 #采樣的百分比 rabbitmq: host: localhost port: 5672 username: guest password: guest listener: # 這裡配置了重試政策 direct: retry: enabled: true simple: retry: enabled: true
當ZipkinServer不可用時(比如關閉、網絡不通等),追蹤資訊不會丢失,因為這些資訊會儲存在Rabbitmq伺服器上,直到Zipkin伺服器可用時,再從Rabbitmq中取出這段時間的資訊。
rabbitmq配置好後:sleuth來收集鍊路資料,傳輸到rabbitmq,zipkin從rabbitmq讀取資料。
order服務通路路徑:http://localhost:8080/order/buy/1
product服務通路路徑:http://localhost:8080/order/buy/1
order服務和product服務除了springcloud-zuul項目中,其他項目路徑不變。
eureka通路路徑;http://localhost:9000/
rabbitmq通路路徑:http://localhost:15672/#/
zipkin通路路徑:http://localhost:9411
項目源碼:https://gitee.com/hxmkd/spring-cloud/tree/master/study_springcloud9_sleuth&zipkin