一、概念

1.1 链路追踪

用户->网关->A->B->C->D

分布式系统中一次调用会非常的复杂。我们需要更好的发现问题,定位问题是在哪个微服务中出现的。分析在各个定义节点的耗时确认性能瓶颈等。

分布式链路追踪,就是将一次分布式请求还原成调用链路,进行日志记录,性能监控并将 一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。

1.2 各种系统

目前业界比较流行的链路追踪系统如:Twitter的Zipkin,阿里的鹰眼,美团的Mtrace,大众点评的
cat等,大部分都是基于google发表的Dapper。Dapper阐述了分布式系统,特别是微服务架构中链路
追踪的概念、数据表示、埋点、传递、收集、存储与展示等技术细节。

二、重要概念

trace 整个调用链路

完整的一次调用,比如用户A->网关->B->C 可以定义为 traceid:1

span 最小的工作单元(链路中的一个节点的调用)

用户A->网关 spanid:1

网关->B spanid:2

B->C spanid:3

三、实现(sleuth+zipkin)

sleuth

1.概念

Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案,并且兼容支持了 zipkin,你只
需要在pom文件中引入相应的依赖即可。

2.依赖和配置
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
logging:
  level:
    root: INFO
    org.springframework.web.servlet.DispatcherServlet: DEBUG
    org.springframework.cloud.sleuth: DEBUG

zipkin

1.概念

Zipkin 是 Twitter 的一个开源项目,它基于 Google Dapper 实现,它致力于收集服务的定时数据,以
解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。 我们可以使用它来收集各个服务
器上请求链路的跟踪数据,并通过它提供的 REST API 接口来辅助我们查询跟踪数据以实现对分布式系
统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。除了面向开发
的 API 接口之外,它也提供了方便的 UI 组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比
如:可以查询某段时间内各用户请求的处理时间等。 Zipkin 提供了可插拔数据存储方式:InMemory、MySql、Cassandra 以及 Elasticsearch。

主要是收集链路追踪的日志然后进行存储展示等功能

2.zipkin架构图

Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为

Zipkin 内部处理的 Span 格式,以支持后续的存储、分析、展示等功能。

Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,

我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。

RESTful API:API 组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接

系统访问以实现监控等。

Web UI:UI 组件,基于 API 组件实现的上层应用。通过 UI 组件用户可以方便而有直观地查询和

分析跟踪信息。
在这里插入图片描述
每个被追踪的微服务作为zipkin客户端,收集数据处理数据的是zipkin的服务端

2.使用
Zipkin Server

从spring boot 2.0开始,官方就不再支持使用自建Zipkin Server的方式进行服务链路追踪,而是直接提
供了编译好的 jar 包来给我们使用。可以从官方网站下载先下载Zipkin的web UI,我们这里下载的是
zipkin-server-2.12.9-exec.jar

启动命令

在命令行输入 java -jar zipkin-server-2.12.9-exec.jar 启动 Zipkin Server

默认Zipkin Server的请求端口为 9411

下载地址

https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml

Zipkin Client

依赖

        <dependency>
           <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
spring:
  zipkin:
    base-url: http://127.0.0.1:9411/ #zipkin server的请求地址
    sender:
      type: web #请求方式,默认以http的方式向zipkin server发送追踪数据
  sleuth:
    sampler:
      probability: 1.0 #采样的百分比 生产环境中不用1.0

问题和优化

问题

1.http请求和fegin调用的时候,会出现问题(源码级别)

2.放入内存中,关闭了就没了

优化

使用rabbitmq发生和接收日志

Server

启动 Zipkin Server时指定rabbitmq地址和用户密码信息

java -jar zipkin-server-2.12.9-exec.jar --RABBIT_ADDRESSES=127.0.0.1:5672 --RABBIT_USER=guest --RABBIT_PASSWORD=guest

java -jar zipkin-server-2.12.9-exec.jar --RABBIT_ADDRESSES=192.168.200.128:5672 --RABBIT_USER=guest --RABBIT_PASSWORD=guest

Client

依赖

<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>

配置rabbitmq相关信息

spring:
  zipkin:
    base-url: http://127.0.0.1:9411/ #zipkin server的请求地址
    sender:
      type: rabbit #请求方式,默认以http的方式向zipkin server发送追踪数据
  rabbitmq:
    host: 192.168.200.128 #自己rabbitmq的ip地址
    port: 5672
    username: guest 
    password: guest
    listener:
      direct:
        retry:
          enabled: true
      simple:
        retry:
          enabled: true

数据存储到mysql

创建数据库表

创建数据库zipkin 然后执行下面的sql

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  
 ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE
utf8_general_ci;  
ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);

启动 Zipkin Server时指定mysql相关信息

只吧数据存储到mysql的启动命令,里面没有配置rabbit的信息

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
STORAGE_TYPE : 存储类型
MYSQL_HOST: mysql主机地址
MYSQL_TCP_PORT:mysql端口
MYSQL_DB: mysql数据库名称
MYSQL_USER:mysql用户名
MYSQL_PASS :mysql密码

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=root --RABBIT_ADDRESSES=192.168.200.128:5672 --RABBIT_USER=guest --RABBIT_PASSWORD=guest

更多推荐