SpringCloud Sleuth主要功能就是在分布式系统中提供追踪解决方案。它大量借用了GoogleDapper的设计, 先来了解一下Sleuth中的术语和相关概念。
- Trace
- 由一组Trace Id 相同的 Span 串联形成一个树状结构。为了实现请求跟踪,当请求到达分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的标识(即TraceId),同时在分布式系统内部流转的时候,框架始终保持传递该唯一值,直到整个请求的返回。那么我们就可以使用该唯一标识将所有的请求串联起来,形成一条完整的请求链路。
- Span
- 代表了一组基本的工作单元。为了统计各处理单元的延迟,当请求到达各个服务组件的时候,也通过一个唯一标识(SpanId)来标记它的开始、具体过程和结束。通过SpanId的开始和结束时间戳,就能统计该span的调用时间,除此之外,我们还可以获取如事件的名称。请求信息等元数据。
- Annotation
- 用它记录一段时间内的事件,内部使用的重要注释:
- cs(Client Send):客户端发出请求,开始一个请求的生命
- sr(Server Received):服务端接受到请求开始进行处理, sr-cs = 网络延迟(服务调用的时间)
- ss(Server Send):服务端处理完毕准备发送到客户端,ss - sr = 服务器上的请求处理时间
- cr(Client Reveived):客户端接受到服务端的响应,请求结束。 cr - sr = 请求的总时间
- 用它记录一段时间内的事件,内部使用的重要注释:
-
我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。
-
除了面向开发的 API 接口之外,它也提供了方便的UI组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。
-
Zipkin 提供了可插拔数据存储方式:In-Memory、MySql、Cassandra 以及 Elasticsearch。但是默认是存储在内存中,这样服务一挂,不就没了,所以还是需要持久化。
-
GitHub 地址:https://github.com/openzipkin/zipkin
-
点击下载最新版本的 jar 包: latest released server
在使用 Spring Boot 2.x 版本后,官方就不推荐自行定制编译了,让我们直接使用编译好的 jar 包.也就是说原来通过@EnableZipkinServer或@EnableZipkinStreamServer的路子,启动SpringBootApplication自建Zipkin Server是不行了
我们可以直接 shift + 鼠标右键,打开 powershell,直接运行 jar 包
# 第一种:(直接启动,不需要持久化) java -jar .zipkin-server-2.23.16-exec.jar # 第二种:(需要持久化,我此处对接的是 MySQL,需要自己手动创建数据库,数据表,下面有对应 SQL 代码) java -jar .zipkin-server-2.23.16-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=192.168.159.133 --MYSQL_TCP_PORT=3306 --MYSQL_USER=liuyunfei --MYSQL_PASS=Lyf123456! --MYSQL_DB=zipkin # 第三种:(Docker 形式启动) docker run -d -p 9411:9411 openzipkin/zipkin # 第四种:(ElasticSearch 形式持久化) java -jar .zipkin-server-2.23.16-exec.jar --STORAGE_TYPE=elasticsearch --ESHOST=localhost:9200
- 此处如果小伙伴想要持久化启动,我提供数据库,数据表创建的 SQL 语句全部内容,一键执行即可
CREATE DATABASE zipkin CHARACTER SET utf8; # DROP 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, `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;
- 然后使用第二个命令执行即可
我是要在网关中添加 链路追踪,大家当然也可以添加到其他的微服务中
- maven 依赖
org.springframework.cloud spring-cloud-starter-sleuth org.springframework.cloud spring-cloud-starter-zipkin
- 修改要添加 链路追踪的 微服务 配置文件
server:
port: 80
# 日志
logging:
level:
org.springframework.web.servlet.DispatcherServlet: DEBUG #一定要开启,否则推送不了日志给zipkin
org.springframework.cloud.sleuth: DEBUG
spring:
application:
name: GatewayDemo
cloud:
gateway:
# 配置路由
routes:
- id: ProductPageDemo
uri: lb://ProductPageDemo
predicates:
# 断言,以 /page/ 开头进行匹配
- Path=/page/**
filters:
# 过滤器,会去除第一级路径然后进行路由
- StripPrefix=1
- id: ProductDemo
uri: lb://ProductDemo
predicates:
# 断言,以 /page/ 开头进行匹配
- Path=/products/**
# 调用链 Sleuth + ZipKin
sleuth:
web:
client:
# 是否启用 webClient
enabled: true
sampler:
probability: 1.0 # 采用比例,默认 0.1 全部采样 1.0
zipkin:
enabled: true
base-url: http://127.0.0.1:9411/ # 指定了Zipkin服务器的地址
# 不注册成一个服务
discoveryClientEnabled: false
sender:
# 数据传输方式,web 表示以 HTTP 报文的形式向服务端发送数据,还有kafka,ACTIVEMQ,rabbit 等
type: web
-
重新启动 网关微服务,然后通过网关微服务访问 ProductPageDemo 微服务
-
访问地址:http://127.0.0.1/page/page/all
-
访问 zipkin 的 web页面:http://127.0.0.1:9411/
-
查看数据库对应的表,看是否有数据生成
上图的消耗时间正好和web上面显示的对应
- 项目运行后台也会有一次访问的记录日志信息
- 引入依赖(消息总线与链路追踪的rabbitmq不冲突,可同时使用)
org.springframework.cloud spring-cloud-starter-sleuth org.springframework.cloud spring-cloud-starter-zipkin org.springframework.cloud spring-cloud-stream-binder-rabbit
- 修改配置文件
# 调用链 Sleuth + ZipKin
sleuth:
web:
client:
# 是否启用 webClient
enabled: true
sampler:
probability: 1.0 # 采用比例,默认 0.1 全部采样 1.0
zipkin:
enabled: true
base-url: http://127.0.0.1:9411/ # 指定了Zipkin服务器的地址
# 不注册成一个服务
discoveryClientEnabled: false
sender:
# 数据传输方式,web 表示以 HTTP报文的形式向服务端发送数据,还有kafka,rabbit等
#type: web
type: rabbit
# RabbitMQ 搭配消息总线 Bus
rabbitmq:
host: 192.168.159.133
port: 5672
username: liuyunfei
password: 123456
- zipkin启动命令如下(既使用rabbitmq做数据传输,又使用MySQL做数据持久化)
java -jar .zipkin-server-2.23.16-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=192.168.159.133 --MYSQL_TCP_PORT=3306 --MYSQL_USER=liuyunfei --MYSQL_PASS=Lyf123456! --MYSQL_DB=zipkin --zipkin.collector.rabbitmq.addresses=192.168.159.133 --zipkin.collector.rabbitmq.username=liuyunfei --zipkin.collector.rabbitmq.password=123456
- 验证此实验中 rabbitmq 是否成功使用,可以查看 rabbitmq客户端是否出现 zipkin 的队列,以及在请求的时候是否有消息的传输记录
我们下载的 jar 包就是一个 服务端,而我们本地的微服务就是一个 客户端,通过 slenth 和 zipkin 就可以对链路的信息进行记录和处理,然后进行持久化存储,展示,分析等功能



