Zipkin链路追踪

2023-11-13

Zipkin链路追踪技术分享

  1. 什么是Zipkin

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

扩展:Google Dapper是什么?

        Dapper是谷歌内部使用的分布式链路追踪系统,虽然没有开源,但是Google在其2010年发布的一篇论文中对其进行了详细的介绍。可以说,Dapper是链路追踪领域的始祖,其提出的概念和理念一致影响着后来所有的分布式系统链路追踪系统,包括阿里的鹰眼系统,大众点评的cat系统,Twitter的Zipkin以及开源的Jaeger等等。

  1. 设计初衷及应用场景

        现代的大型应用系统一般是复杂的分布式系统,他们由许多的软件模块构成,这些软件模块可能由不同的团队用不同的编程语言编写而成,因此那些传统的用于理解系统行为,分析性能问题的工具,在这种复杂环境下变得失效。

  1. Zipkin的核心组件
  1. Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为 Zipkin 内部处理的 Span 格式,以支持后续的存储、分析、展示等功能。
  2. Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中, 我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。
  3. RESTful API:API 组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接 系统访问以实现监控等。
  4. Web UI:UI 组件,基于 API 组件实现的上层应用。通过 UI 组件用户可以方便而有直观地查询和 分析跟踪信息。

Zipkin 分为两端,一个是 Zipkin 服务端,一个是 Zipkin 客户端,客户端也就是微服务的应用。

  1. Zipkin中的术语
  • Span:基本工作单元,
  • 那么Span中都有什么呢?

{

      "traceId": "bd7a977555f6b982",(标记一次请求的跟踪,相关的Spans都有相同的traceId)

      "name": "get-traces",(span的名称,一般是接口方法的名称)

      "id": "ebf33e1a81dc6f71",(Span的id)

      "parentId": "bd7a977555f6b982",(上一个span的id)

      "timestamp": 1458702548478000,(开始的时间戳,微秒级)

      "duration": 354374,(持续时间,微秒级)

      "annotations": [

        {

          "endpoint": {

            "serviceName": "zipkin-query",

            "ipv4": "192.168.1.2",

            "port": 9411

          },

          "timestamp": 1458702548786000,

          "value": "cs"

        }

      ],

      "binaryAnnotations": [(二进制注释,旨在提供有关RPC的额外信息)

        {

          "key": "lc",

          "value": "JDBCSpanStore",

          "endpoint": {

            "serviceName": "zipkin-query",

            "ipv4": "192.168.1.2",

            "port": 9411

          }

        }

      ]

}                 

如下图:

    刚发起调用时traceId和spanId是一致,parentId不存在。         被调用者的traceId和调用者的traceId时一致的,被调用者会产生自己的spanId,并且被调用者的parentId是调用者的spanId

  • Trace(追溯):一系列spans组成的一个树状结构,例如,如果你正在跑一个分布式大数据工程,你可能需要创建一个trace。
  • Annotation:用来及时记录一个事件的存在,一些核心annotations用来定义一个请求的开始和结束 
    • cs - Client Sent -客户端发起一个请求,这个annotion描述了这个span的开始
    • sr - Server Received -服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳便可得到网络延迟
    • ss - Server Sent -注解表明请求处理的完成(当请求返回客户端),如果ss减去sr时间戳便可得到服务端需要的处理请求时间
    • cr - Client Received -表明span的结束,客户端成功接收到服务端的回复,如果cr减去cs时间戳便可得到客户端从服务端获取回复的所有所需时间 

下面一张大图能够清晰展示其中的关系和事件

        Reporter:将数据发送到Zipkin的仪器化应用程序中的组件;有三个主要的传输方式:HTTP, Kafka和Scribe

        然后才是上面提到的Zipkin客户端的收集器等

  1. 安装与使用

官方提供了多种安装方式

官网: Quickstart · OpenZipkin

一.docker安装启动

docker run -d -p 9411:9411 openzipkin/zipkin

  • jar包启动(jdk1.8以上,默认端口9411)

java -jar zipkin-server-2.24.0-exec.jar

 

        如果端口被占用,也可切换端口 java -jar zipkin-server-2.24.0-exec.jar --server.port=8080

启动之后我们就可以直接通过路径访问Zipkin的页面

  • 如何使用

        通过jar方式,已经把Zipkin服务器启动了,下面需要启动客户端,

         客户端:服务的生产者及服务的调用者:

        服务的生产者、调用者是相对的,两者之间可以互相调用,即可以同时作为生产者和调用者,两者都是Eureka Client;

        两者都要注册到注册中心上,这样才可以相互可见,才能通过服务名来调用指定服务,才能使用Feign或RestTemplate+Ribbon来达到负载均衡

两者都要注册到Zipkin服务器上,这样Zipkin才能追踪服务的调用链路

1.准备

        准备两个项目:op-aouth和op-basic,在basic项目中调用查询人员基本信息接口通过Feign,再调用aouth中的服务

  1. 服务中的配置

添加mvn

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-zipkin</artifactId>

</dependency>

添加配置

spring.zipkin.base-url=http://localhost:9411

spring.sleuth.sampler.percentage=1

注:base-url不配置的话,是默认向9411端口注册的

 

  1. 启动服务

        启动顺序:注册中心(可选)->Zipkin服务器->服务生产者及调用者(op-aouth和op-basic)

        顺利启动后,就可在Zipkin的web页面看到注册进来的服务

这是我们就可以调用一个接口,对接口进行追踪

        我们可以看到,这个接口整个的链路,以及每一步所使用的时间,就可以有针对性代码优化

  1. 更改通信方式

        Zipkin默认是http的通信方式,在发生问题的,就可能造成数据丢失,生产环境一般是需要添加MQ来辅助

        Zipkin是支持MQ的,从jar中就可以看出

 

zipkin.jar中的yml配置可以参考:        https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml

也可指定MQ的地址

java -jar zipkin-server-2.24.0-exec.jar --zipkin.collector.rabbitmq.addresses=192.168.8.215:5672

MQ访问页面:192.168.8.215:15672

客户端也配置上MQ

spring.zipkin.sender.type=rabbit

spring.zipkin.rabbitmq.addresses=192.168.8.215

 

加了MQ之后,通信过程如下图所示

可以看到如下效果:

        当ZipkinServer不可用时(比如关闭、网络不通等),追踪信息不会丢失,因为这些信息会保存在Rabbitmq服务器上,直到Zipkin服务器可用时,再从Rabbitmq中取出这段时间的信息

看一下效果

 

  1. Zipkin数据持久化

        这时候我们看到的所有数据,都是存在内存中,在实际生产中,数据肯定是要进行持久化的

        所以,前面也说到,Zipkin支持多种数据库,下面以mysql为例

        命令看着很长,其实仔细看发现很简单,都是见名知义,不必死记硬背。

java -jar zipkin-server-2.24.0-exec.jar --zipkin.collector.rabbitmq.addresses=192.168.8.215:5672 --zipkin.storage.type=mysql --zipkin.storage.mysql.host=192.168.8.21 --zipkin.storage.mysql.port=3306 --zipkin.storage.mysql.username=***** --zipkin.storage.mysql.password=****** --zipkin.storage.mysql.db=op_basic

还需要创建一下几张表

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;

下面看看效果

6配置参数含义

https://www.dandelioncloud.cn/article/details/1592875941275815938

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Zipkin链路追踪 的相关文章

  • 菜单未显示在应用程序中

    由于某种原因 我的操作菜单在我的 Android Studio 应用程序中消失了 我正在按照教程学习如何创建 Android 应用程序 但最终遇到了这个问题 我正在使用 atm 的教程 http www raywenderlich com
  • 如果测试用例失败,Selenium Web 驱动程序无法关闭 Firefox 实例

    我各位 我正在使用 junit 和 selenium web 驱动程序 2 28 问题是 如果我运行成功的测试用例 Web 驱动器能够关闭 Firefox 实例 但是当测试用例失败时 Selenium Web 驱动器无法关闭 Firefox
  • 如何使用 FileChannel 将一个文件的内容附加到另一个文件的末尾?

    File a txt好像 ABC File d txt好像 DEF 我正在尝试将 DEF 附加到 ABC 所以a txt好像 ABC DEF 我尝试过的方法总是完全覆盖第一个条目 所以我总是最终得到 DEF 这是我尝试过的两种方法 File
  • ElasticBeanstalk Java,Spring 活动配置文件

    我正在尝试通过 AWS ElasticBeanstalk 启动 spring boot jar 一切正常 配置文件为 默认 有谁知道如何为 java ElasticBeanstalk 应用程序 不是 tomcat 设置活动配置文件 spri
  • Java程序中的数组奇怪的行为[重复]

    这个问题在这里已经有答案了 我遇到了这个 Java 程序及其以意想不到的方式运行 以下程序计算 int 数组中元素对之间的差异 import java util public class SetTest public static void
  • Android Studio 在编译时未检测到支持库

    由于 Android Studio 将成为 Android 开发的默认 IDE 因此我决定将现有项目迁移到 Android studio 中 项目结构似乎不同 我的项目中的文件夹层次结构如下 Complete Project gt idea
  • CXF Swagger2功能添加安全定义

    我想使用 org apache cxf jaxrs swagger Swagger2Feature 将安全定义添加到我的其余服务中 但是我看不到任何相关方法或任何有关如何执行此操作的资源 下面是我想使用 swagger2feature 生成
  • 在数据流模板中调用 waitUntilFinish() 后可以运行代码吗?

    我有一个批处理 Apache Beam 作业 它从 GCS 获取文件作为输入 我的目标是根据执行后管道的状态将文件移动到两个 GCS 存储桶之一 如果管道执行成功 则将文件移动到存储桶 A 否则 如果管道在执行过程中出现任何未处理的异常 则
  • java中删除字符串中的特殊字符?

    如何删除字符串中除 之外的特殊字符 现在我用 replaceAll w s 它删除了所有特殊字符 但我想保留 谁能告诉我我该怎么办 Use replaceAll w s 我所做的是将下划线和连字符添加到正则表达式中 我添加了一个 连字符之前
  • HDFS:使用 Java / Scala API 移动多个文件

    我需要使用 Java Scala 程序移动 HDFS 中对应于给定正则表达式的多个文件 例如 我必须移动所有名称为 xml从文件夹a到文件夹b 使用 shell 命令我可以使用以下命令 bin hdfs dfs mv a xml b 我可以
  • 使用替换字符串中多个单词的最有效方法[重复]

    这个问题在这里已经有答案了 此刻我正在做 Example line replaceAll replaceAll cat dog replaceAll football rugby 我觉得那很丑 不确定有更好的方法吗 也许循环遍历哈希图 ED
  • 请求位置更新参数

    这就是 requestLocationUpdates 的样子 我使用它的方式 requestLocationUpdates String provider long minTime float minDistance LocationLis
  • 迁移到 java 17 后有关“每个进程的内存映射”和 JVM 崩溃的 GC 警告

    我们正在将 java 8 应用程序迁移到 java 17 并将 GC 从G1GC to ZGC 我们的应用程序作为容器运行 这两个基础映像之间的唯一区别是 java 的版本 例如对于 java 17 版本 FROM ubuntu 20 04
  • Java中未绑定通配符泛型的用途和要点是什么?

    我不明白未绑定通配符泛型有什么用 具有上限的绑定通配符泛型 stuff for Object item stuff System out println item Since PrintStream println 可以处理所有引用类型 通
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • 如何在 Maven 中显示消息

    如何在 Maven 中显示消息 在ant中 我们确实有 echo 来显示消息 但是在maven中 我该怎么做呢 您可以使用 antrun 插件
  • com.jcraft.jsch.JSchException:身份验证失败

    当我从本地磁盘上传文件到远程服务器时 出现这样的异常 com jcraft jsch JSchException Auth fail at org apache tools ant taskdefs optional ssh Scp exe
  • JAVA - 如何从扫描仪读取文件中检测到“\n”字符

    第一次海报 我在读取文本文件的扫描仪中读取返回字符时遇到问题 正在读取的文本文件如下所示 test txt start 2 0 30 30 1 1 90 30 0 test txt end 第一行 2 表示两个点 第二行 位置索引 0 xp
  • java8 Collectors.toMap() 限制?

    我正在尝试使用java8Collectors toMap on a Stream of ZipEntry 这可能不是最好的想法 因为在处理过程中可能会发生异常 但我想这应该是可能的 我现在收到一个我不明白的编译错误 我猜是类型推理引擎 这是
  • Jackson 将单个项目反序列化到列表中

    我正在尝试使用一项服务 该服务为我提供了一个带有数组字段的实体 id 23233 items name item 1 name item 2 但是 当数组包含单个项目时 将返回该项目本身 而不是包含一个元素的数组 id 43567 item

随机推荐