【十】 分布式链路追踪技术 Sleuth + Zipkin

在微服务架构下,⼀次请求少则经过三四次服务调⽤完成,多则跨越几十个甚⾄是上百个服务节点。那么问题接踵而来:
1)如何动态展示服务的调用链路?(比如A服务调用了哪些其他的服务—依赖关系)
2)如何分析服务调⽤链路中的瓶颈节点并对其进⾏调优?(比如A—>B—>C,C服务处理时间特别长)
3)如何快速进⾏服务链路的故障发现?
这就是分布式链路追踪技术存在的目的和意义

本质:记录日志

⼀个请求链路,⼀条链路通过TraceId唯⼀标识,span标识发起的请求信息,各span通过parrentId关联起来
Trace:服务追踪的追踪单元是从客户发起请求(request)抵达被追踪系统的边界开始,到被追踪系统向客户返回响应(response)为⽌的过程

Trace ID:为了实现请求跟踪,当请求发送到分布式系统的⼊⼝端点时,只需要服务跟踪框架为该请求创建⼀个唯⼀的跟踪标识Trace ID,同时在分布式系统内部流转的时候,框架失踪保持该唯⼀标识,直到返回给请求⽅⼀个Trace由⼀个或者多个Span组成,每⼀个Span都有⼀个SpanId,Span中会记录TraceId

ParentId,指向了另外⼀个Span的SpanId,表明父子关系,其实本质表达了依赖关系

Span ID:为了统计各处理单元的时间延迟,当请求到达各个服务组件时,也是通过⼀个唯⼀标识SpanID来标记它的开始,具体过程以及结束。对每⼀个Span来说,它必须有开始和结束两个节点,通过记录开始Span和结束Span的时间戳,就能统计出该Span的时间延迟,除了时间戳记录之外,它还可以包含⼀些其他元数据,⽐如时间名称、请求信息等。每⼀个Span都会有⼀个唯⼀跟踪标识 Span ID,若⼲个有序的 span 就组成了⼀个 trace。

Span可以认为是⼀个⽇志数据结构,在⼀些特殊的时机点会记录了⼀些日志信息,比如有时间戳、
spanId、TraceId,parentIde等,Span中也抽象出了另外⼀个概念,叫做事件,核心事件如下

  • CS :client send/start 客户端/消费者发出⼀个请求,描述的是⼀个span开始
  • SR: server received/start 服务端/⽣产者接收请求 SR-CS属于请求发送的⽹络延迟
  • SS: server send/finish 服务端/⽣产者发送应答 SS-SR属于服务端消耗时间
  • CR:client received/finished 客户端/消费者接收应答 CR-SS表示回复需要的时间(响应的⽹络延 迟)

Spring Cloud Sleuth (追踪服务框架)可以追踪服务之间的调⽤,Sleuth可以记录⼀个服务请求经过哪些服务、服务处理时长等,根据这些,我们能够理清各微服务间的调⽤关系及进行问题追踪分析。

  • 耗时分析:通过 Sleuth 了解采样请求的耗时,分析服务性能问题(哪些服务调用比较耗时)

  • 链路优化:发现频繁调用的服务,针对性优化等

  • Sleuth就是通过记录日志的方式来记录踪迹数据的

服务构建

Sleuth+ Zipkin

  1. 每⼀个需要被追踪踪迹的微服务⼯程都引⼊依赖坐标
    在这里插入图片描述
  <dependency>
     <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-sleuth</artifactId>
 </dependency>
      
  1. 每⼀个微服务都修改application.yml配置⽂件,添加日志级别
#分布式链路追踪
logging:
  level:
    org.springframework.web.servlet.DispatcherServlet: debug
    org.springframework.cloud.sleuth: debug
  1. 启动服务观察控制台
    在这里插入图片描述

结合 Zipkin 展示追踪数据

Zipkin 包括Zipkin Server和 Zipkin Client两部分,Zipkin Server是⼀个单独的服务,Zipkin Client就是
具体的微服务。

  1. Zipkin Server 构建(在m-parent下新建moudle)
    在这里插入图片描述
    2.依赖
 <!--zipkin-server的依赖坐标-->
		        <dependency>
		            <groupId>io.zipkin.java</groupId>
		            <artifactId>zipkin-server</artifactId>
		            <version>2.12.3</version>
		            <exclusions>
		                <!--排除掉log4j2的传递依赖,避免和springboot依赖的⽇志组件冲突-->
		                <exclusion>
		                    <groupId>org.springframework.boot</groupId>
		                    <artifactId>spring-boot-starter-log4j2</artifactId>
		                </exclusion>
		            </exclusions>
		        </dependency>
		        <!--zipkin-server ui界⾯依赖坐标-->
		        <dependency>
		            <groupId>io.zipkin.java</groupId>
		            <artifactId>zipkin-autoconfigure-ui</artifactId>
		            <version>2.12.3</version>
		        </dependency>
  1. 启动类
@SpringBootApplication
@EnableZipkinServer //开启ZipkinServer
public class MCloudZipkinServer9411 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(MCloudZipkinServer9411.class,args);
    }
}
  1. 配置
server:
  port: 9411

management:
  metrics:
    web:
      server:
        auto-time-requests: false #关闭自动检测
  1. Zipkin Client 构建(在具体微服务中修改)
  • pom中添加 zipkin 依赖
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
  • application.yml 中添加对zipkin server的引⽤
  # zipkin链路追踪配置
spring:
  zipkin:
    base-url: http://localhost:9411
    sender:
      type: web
  sleuth:
    sampler:
      probability: 1 #采样率 1代表100%全采集,默认0.1 10%
  1. 启动Zipkin Server,并重启以下服务
    在这里插入图片描述
  2. 访问http://localhost:9411/zipkin/
  3. 调用微服务,产生链路信息
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

追踪数据Zipkin持久化到mysql

没有做持久化的,数据服务重启之后数据就消失了。

  1. mysql中创建名称为zipkin的数据库,并执⾏如下sql语句(官⽅提供)
--
-- Copyright 2015-2019 The OpenZipkin Authors
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software distributed under the License
-- is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions and limitations under
-- the License.
--

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;
  1. Zipkin Server,pom⽂件引入相关依赖
 <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-storage-mysql</artifactId>
            <version>2.12.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>
  1. 修改配置⽂件
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/zipkin?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC
    username: root
    password: root
    druid:
      initialSize: 10
      minIdle: 10
      maxActive: 30
      maxWait: 50000
# 指定zipkin持久化介质为mysql
zipkin:
  storage:
    type: mysql
  1. 启动类中注⼊事务管理器
@Bean
public PlatformTransactionManager txManager(DataSource dataSource) {
    
    
 return new DataSourceTransactionManager(dataSource);
}
  1. 启动服务验证持久化

在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u014535922/article/details/130078114