介绍
分布式链路追踪(Distributed tracing),就是将一次分布式请求还原成调用链路,进行日志记录,性能监控并将一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上、每隔服务节点的请求状态等等。
思路:
Sleuth
概念
- Span:基本工作单元,例如,在一个新建的span中发送一个RPC等同于发送一个回应请求给RPC,span通过一个64位ID唯一标识,trace以另一个64位ID表示,span还有其他数据信息,比如摘要、时间戳事件、关键值注释、span的ID、以及进度ID(通常是IP地址),span在不断的启动和停止,同时记录了时间信息,当你创建了一个span,你必须在未来某个时刻停止他。
- Trace:一系列spans组成一个树状结构,例如,如果你正在跑一个分布式大数据工程,你可能需要创建一个trace。
简介
Spring Cloud Sleuth主要的功能就是在分布式系统中提供解决方案,并且兼容支持zipkin,你只需要在pom文件中引入相应依赖即可。
引入Sleuth
(1)引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>RELEASE</version>
</dependency>
(2)配置文件
logging:
level:
root: INFO
org.springframework.web.servlet.DispatcherServlet: DEBUG
org.springframework.cloud.sleuth: DEBUG
(3)运行
我这里的调用顺序是,gateway网关 ------ 服务消费者 ----- 服务提供者
结果会出现一系列日志,日志大致内容:
2020-03-26 11:17:39.081 DEBUG [consumer-service,79b2673a3eba9ab8,89d5a1d7d78cd946,false] 12376 --- [nio-9002-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
我们看到
[consumer-service,79b2673a3eba9ab8,89d5a1d7d78cd946,false]
第一个参数(consumer-service)是本机的服务名称
第二个参数(79b2673a3eba9ab8)是trace的ID
第三个参数(89d5a1d7d78cd946)是span的ID
Zipkin
介绍
Zipkin是Twitter的一个开源项目,它基于Google Dapper实现,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。处理面向开发的API接口之外,它也提供了方便的UI组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。Zipkin提供了可插拔数据存储方式:In-Memory、Mysql、Cassandra以及Elasticsearch
Zipkin的基础架构有四个核心组件构成:
- Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为Zipkin内部处理的Span格式,以支持后续的存储、分析、展示等功能。
- Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储到内存中,我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。
- RESTful API:API组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或者外接系统访问以实现监控等。
- Web UI:UI组件,基于API组件实现的上层应用。通过UI组件用户可以方便而又直观地查询和分析跟踪信息。
部署
- 下载jar包
https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/ - 启动
java -jar zipkin-server-2.12.9-exec.jar - 访问
localhost:9411
整合到springcloud
- 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>RELEASE</version>
</dependency>
- 配置文件
spring:
zipkin:
base-url: http://localhost:9411/
sender:
type: web #数据的传输方式,以http的形式向http形式向server端发送
sleuth:
sampler:
probability: 1 #采样比,100%收集信息
在浏览器上多访问几次这个链路,然后到zipkin后台查看数据信息:
链路数据持久化
- 准备mysql数据库和表(zipkin提供)
CREATE DATABASE `zipkin`;
USE 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`);
- 修改server的启动参数
java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1(数据库ip) --MYSQL_TCP_PORT=3306(数据库端口) --MYSQL_USER=root(数据库用户) --MYSQL_PASS=root(数据库密码) --MYSQL_DB=zipkin(数据库名称)
优化数据采集过程
通过使用消息中间件(Rabbitmq)优化
- 准备rabbitmq服务器
rabbitmq的下载和安装参考:
https://www.jianshu.com/p/3874a446a1e0 - 修改zipkin客户端,将消息以rabbit的形式发送到mq服务器
(1)添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
(2)修改配置文件
spring:
#zipkin配置(使用rabbitmq采集数据)
zipkin:
#base-url: http://localhost:9411/
sender:
#type: web #数据的传输方式,以http的形式向http形式向server端发送
type: rabbit #向rabbitmq中发送消息
sleuth:
sampler:
probability: 1 #采样比,100%收集信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
listener: #配置重试策略
direct:
retry:
enabled: true
simple:
retry:
enabled: true
- 修改zipkin服务端,从rabbit中拉取消息
java -jar zipkin-server-2.12.9-exec.jar --RABBIT_ADDRESSES=127.0.0.1:5672