概述
在前面:微服務呼叫鏈追蹤中心搭建 一文中我們利用Zipkin搭建了一個微服務呼叫鏈的追蹤中心,並且模擬了微服務呼叫的實驗場景。利用Zipkin的庫Brave,我們可以收集一個客戶端請求從發出到被響應 經歷了哪些元件、哪些微服務、請求總時長、每個元件所花時長 等資訊。
本文將講述如何利用Zipkin對Mysql資料庫的呼叫進行追蹤,這裡同樣藉助OpenZipkin庫Brave來完成。
注: 本文首發於 My 公眾號 CodeSheep ,可 長按 或 掃描 下面的 小心心 來訂閱 ↓ ↓ ↓
擴充套件ZipkinTool元件
ZipkinTool是在《微服務呼叫鏈追蹤中心搭建》一文中編寫的與Zipkin通訊的工具元件,利用其追蹤微服務呼叫鏈的,現在我們想追蹤Mysql資料庫呼叫鏈的話,可以擴充套件一下其功能。
- pom.xml新增依賴:
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-mysql</artifactId>
<version>4.0.6</version>
</dependency>
複製程式碼
- 在ZipkinConfiguration類中新增MySQLStatementInterceptorManagementBean
@Bean
public MySQLStatementInterceptorManagementBean mySQLStatementInterceptorManagementBean() {
return new MySQLStatementInterceptorManagementBean(brave().clientTracer());
}
複製程式碼
新增Mysql資料庫訪問的微服務
依然繼承前文:《微服務呼叫鏈追蹤中心搭建》,我們改造一下文中的ServiceC這個微服務,在其中新增與Mysql資料庫的互動。
- pom.xml中新增JDBC和Mysql依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
複製程式碼
- application.properties中新增Mysql連線的配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://你的Mysql服務所在IP:3307/test?useSSL=false\
&statementInterceptors=com.github.kristofa.brave.mysql.MySQLStatementInterceptor\
&zipkinServiceName=mysqlService
spring.datasource.username=root
spring.datasource.password=XXXXXX
複製程式碼
- Controller中新增JdbcTemplate訪問資料庫的程式碼
@GetMapping("/mysqltest”)
public String mysqlTest() {
String name = jdbcTemplate.queryForObject( "SELECT name FROM user WHERE id = 1", String.class );
return "Welcome " + name;
}
複製程式碼
啟動Mysql資料庫服務
1. 啟動Mysql容器
docker run -d -p 3307:3306 \
-v ~/mysql/data:/var/lib/mysql \
-v ~/mysql/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=XXXXXX \
--name mysql mysql
複製程式碼
2. 再啟動一個Mysql容器,接入其中做一些設定
- 首先進入mysql命令列
docker run -it --rm \
--link mysql:mysql mysql \
mysql -hmysql -u root -p
複製程式碼
- 接下來建立資料庫zipkin: 用於存放Zipkin所收集的資料
CREATE DATABASE `zipkin`
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,
`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’
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT 'ignore insert on duplicate’;
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT 'for joining with zipkin_annotations’;
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(`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’;
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces’;
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
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);
複製程式碼
這裡建立了三個資料表。
該Sql檔案可以從以下連結獲得:https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql/src/main/resources/mysql.sql
Sql指令碼執行完成後,可以看到zipkin相關的三個表已經建成:
- 建立資料庫test:用作測試資料庫
CREATE DATABASE `test`
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL auto_increment,
`name` varchar(100) DEFAULT NULL ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET = utf8;
insert into user values (1,”hansonwang99”)
複製程式碼
這裡插入了一條資料用於實驗。
啟動zipkin服務
docker run -d -p 9411:9411 \
--link mysql:mysql \
-e STORAGE_TYPE=mysql \
-e MYSQL_HOST=mysql \
-e MYSQL_TCP_PORT=3306 \
-e MYSQL_DB=zipkin \
-e MYSQL_USER=root \
-e MYSQL_PASS=XXXXXX \
--name zipkin openzipkin/zipkin
複製程式碼
啟動Mysql資料庫訪問的微服務(即ServiceC)
在瀏覽器中輸入:localhost:8883/mysqltest,如果看到以下輸出,就可以證明資料庫呼叫操作已經成功了!
Zipkin追蹤資料庫呼叫實際實驗
- **瀏覽器輸入:**http://localhost:9411/zipkin/
開啟Zipkin Web UI,點選服務名下拉選單能看見已經成功識別了Mysql資料庫呼叫服務
- 選中mysqlservice後,點選Find Traces
可以看到 首次查詢 Mysql的呼叫鏈追蹤資訊,有很多
隨便點開某一個檢視:
- **接下來瀏覽器中再次輸入:**localhost:8883/mysqltest
目的是再次觸發Mysql的呼叫,然後再次Find Traces,可以看到追蹤資料類似下圖:包含兩次Mysql的query動作:
點開第一個query檢視,其實際上是在 嘗試連線Mysql資料庫
點開第二個query檢視,發現這裡才是 實際查詢業務
從圖形化介面上可以清楚地知道每個階段的詳細步驟與耗時,因此可以用來分析哪個SQL語句執行相對較慢。
後記
本文實驗所用原始碼已經開源,需要的話請 自取。
作者更多的SpringBt實踐文章在此:
- Spring Boot應用監控實戰
- SpringBoot應用部署於外接Tomcat容器
- ElasticSearch搜尋引擎在SpringBt中的實踐
- 初探Kotlin+SpringBoot聯合程式設計
- Spring Boot日誌框架實踐
- SpringBoot優雅編碼之:Lombok加持
如果有興趣,也可以抽點時間看看作者一些關於容器化、微服務化方面的文章:
- 利用K8S技術棧打造個人私有云 連載文章
- 從一份配置清單詳解Nginx伺服器配置
- Docker容器視覺化監控中心搭建
- 利用ELK搭建Docker容器化應用日誌中心
- RPC框架實踐之:Apache Thrift
- RPC框架實踐之:Google gRPC
- 微服務呼叫鏈追蹤中心搭建
- Docker容器跨主機通訊
- Docker Swarm叢集初探
- 高效編寫Dockerfile的幾條準則