SpringBoot集成ZipKin实现链路跟踪_springboot zipkin_八五年的湘哥的博客-程序员秘密

技术标签: SSM&开源组件  spring boot  java  zipkin  后端  链路跟踪  

SpringBoot集成ZipKin实现链路跟踪

1、我们要做什么

​ 当我们的服务器成千上万,当我们的模块上万成千,当我们的调用链路复杂如蜘蛛网时,我们突然发现一个小小的性能问题却不能快速定位到点!千万不要以为自己是神,当年那个觉得ELK日志分析系统多余的程序员已经被老板祭天!

​ 废话有点多,今天我们要做的一件事非常简单,如何在一个多层调用的接口里快速查看它们的网络拓扑图并得到监控数据!

2、我们要注意什么

​ 但凡一个合格的辅助,都不能抢主力的经济,不然会影响主力DPS输出----性能轻损耗

​ 但凡一个合格的辅助,都应该跟随主力的脚步,而不能对主力指手画脚----业务非嵌入

​ 但凡一个合格的辅助,都应该尽可能的实现简单轻负载----架构轻量级

3、zipkin实现原理

​ 流程图:

在这里插入图片描述

​ 流程图包含三个重要信息:

  • Trace

    表示一条调用链路,是整个调用链路串联的唯一标识,将所有Span汇聚起来

  • Span

    通俗的理解就是一次请求信息;它是链路跟踪的基本工作单元,一次链路调用(可以是RPC,DB等没有特定的限制)创建一个span

  • Annotation

    用于定位一个request的开始和结束,cs/sr/ss/cr含有额外的信息,比如说时间点,当这个annotation被记录了,这个RPC也被认为完成了

cs:Client Start,表示客户端发起请求 ;一个span的开始;
cf:Client Finish,表示客户端获取到服务端返回信息;一个span的结束
ss:Server Start,表示服务端收到请求
sf:Server Finish,表示服务端完成处理,并将结果发送给客户端

ss-cs:网络延迟
sf-ss:逻辑处理时间
cf-cs:整个流程时间
  • Collector

    接受或者收集各个应用传输的数据,跟踪一个Http请求的工作流程:

  1. 把当前调用链的Trace信息添加到HTTP Header里面
  2. 记录当前调用的时间戳
  3. 发送HTTP请求,把trace相关的header信息携带上
  4. 调用结束之后,记录当前调用话费的时间
  5. 然后把上面流程产生的 信息汇集成一个span,把这个span信息上传到zipkin的Collector模块
  6. 下一个Http请求继续从第一步开始

4、落地实现

4.1 搭建zipkin server

持久化方式

创建zipkin持久化数据库,当然,也可以不持久化,放内存中,不过我相信您如果不想被老板祭天也不会这么干!

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for zipkin_annotations
-- ----------------------------
DROP TABLE IF EXISTS `zipkin_annotations`;
CREATE TABLE `zipkin_annotations`  (
  `trace_id_high` bigint(20) NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the\r\ntrace uses 128 bit traceIds instead of 64 bit',
  `trace_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
  `span_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.id',
  `a_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'BinaryAnnotation.key or\r\nAnnotation.value if type == -1',
  `a_value` blob NULL COMMENT 'BinaryAnnotation.value(), which must be smaller than\r\n64KB',
  `a_type` int(11) NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
  `a_timestamp` bigint(20) NULL DEFAULT NULL COMMENT 'Used to implement TTL; Annotation.timestamp or\r\nzipkin_spans.timestamp',
  `endpoint_ipv4` int(11) NULL DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null',
  `endpoint_ipv6` binary(16) NULL DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is\r\nnull, or no IPv6 address',
  `endpoint_port` smallint(6) NULL DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is\r\nnull',
  `endpoint_service_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'Null when\r\nBinary/Annotation.endpoint is null',
  UNIQUE INDEX `trace_id_high`(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) USING BTREE COMMENT 'Ignore insert on duplicate',
  INDEX `trace_id_high_2`(`trace_id_high`, `trace_id`, `span_id`) USING BTREE COMMENT 'for joining with zipkin_spans',
  INDEX `trace_id_high_3`(`trace_id_high`, `trace_id`) USING BTREE COMMENT 'for getTraces/ByIds',
  INDEX `endpoint_service_name`(`endpoint_service_name`) USING BTREE COMMENT 'for\r\ngetTraces and getServiceNames',
  INDEX `a_type`(`a_type`) USING BTREE COMMENT 'for getTraces and\r\nautocomplete values',
  INDEX `a_key`(`a_key`) USING BTREE COMMENT 'for getTraces and\r\nautocomplete values',
  INDEX `trace_id`(`trace_id`, `span_id`, `a_key`) USING BTREE COMMENT 'for dependencies job'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPRESSED;

-- ----------------------------
-- Table structure for zipkin_spans
-- ----------------------------
DROP TABLE IF EXISTS `zipkin_spans`;
CREATE TABLE `zipkin_spans`  (
  `trace_id_high` bigint(20) NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the\r\ntrace uses 128 bit traceIds instead of 64 bit',
  `trace_id` bigint(20) NOT NULL,
  `id` bigint(20) NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `remote_service_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `parent_id` bigint(20) NULL DEFAULT NULL,
  `debug` bit(1) NULL DEFAULT NULL,
  `start_ts` bigint(20) NULL DEFAULT NULL COMMENT 'Span.timestamp(): epoch micros used for endTs query\r\nand to implement TTL',
  `duration` bigint(20) NULL DEFAULT NULL COMMENT 'Span.duration(): micros used for minDuration and\r\nmaxDuration query',
  PRIMARY KEY (`trace_id_high`, `trace_id`, `id`) USING BTREE,
  INDEX `trace_id_high`(`trace_id_high`, `trace_id`) USING BTREE COMMENT 'for\r\ngetTracesByIds',
  INDEX `name`(`name`) USING BTREE COMMENT 'for getTraces and\r\ngetSpanNames',
  INDEX `remote_service_name`(`remote_service_name`) USING BTREE COMMENT 'for getTraces\r\nand getRemoteServiceNames',
  INDEX `start_ts`(`start_ts`) USING BTREE COMMENT 'for getTraces ordering\r\nand range'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPRESSED;

-- ----------------------------
-- Records of zipkin_annotations
-- ----------------------------
set global innodb_large_prefix=1;
set global innodb_file_format=BARRACUDA;
-- ----------------------------
-- Table structure for zipkin_dependencies
-- ----------------------------
DROP TABLE IF EXISTS `zipkin_dependencies`;
CREATE TABLE `zipkin_dependencies`  (
  `day` date NOT NULL,
  `parent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `child` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `call_count` bigint(20) NULL DEFAULT NULL,
  `error_count` bigint(20) NULL DEFAULT NULL,
  PRIMARY KEY (`day`, `parent`, `child`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPRESSED;

SET FOREIGN_KEY_CHECKS = 1;

部署zipkin server

使用Docker Compose部署zipkin server

 zipkin:
    image: openzipkin/zipkin
    container_name: zipkin
    environment:
      - STORAGE_TYPE=mysql
      # Point the zipkin at the storage backend
      - MYSQL_DB=zipkin
      - MYSQL_USER=root
      - MYSQL_PASS=root
      - MYSQL_HOST=192.168.137.129
      - MYSQL_TCP_PORT=3306
    network_mode: host
    ports:
      # Port used for the Zipkin UI and HTTP Api
      - 9411:9411

配置好数据库,启动docker容器

在这里插入图片描述
通过web浏览器访问如下,表示搭建成功
在这里插入图片描述

4.2 客户端嵌入zipkin跟踪

测试链路

非常简单,四个应用服务,调用深度为三层!

在这里插入图片描述

引入依赖

每个zipkin客户端服务都引入如下依赖:

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
        <dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-sleuth-zipkin</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-sleuth</artifactId>
		</dependency>
	</dependencies>

服务调用代码

  • service1

    package com.paratera.console.linktracking.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    @RequestMapping("/service1")
    public class ZipkinBraveController {
          
    
        @Autowired
        private RestTemplate restTemplate;
    
        @RequestMapping("/test")
        public String service1() throws Exception {
          
            //休眠100ms,模拟业务处理耗时
            Thread.sleep(100);
            //调用service2服务
            ResponseEntity<String> res = restTemplate.getForEntity("http://localhost:8082/service2/test", String.class);
            return res.getBody();
        }
    }
    
  • service2

    package com.paratera.console.linktracking.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    @RequestMapping("/service2")
    public class ZipkinBraveController {
          
    
        @Autowired
        private RestTemplate restTemplate;
    
        @RequestMapping("/test")
        public String service1() throws Exception {
          
            //休眠200ms,模拟业务处理
            Thread.sleep(200);
            //调用service3服务
            ResponseEntity<String> res1 = restTemplate.getForEntity("http://localhost:8083/service3/test", String.class);
            //调用service4服务
            ResponseEntity<String> res2 = restTemplate.getForEntity("http://localhost:8084/service4/test", String.class);
            return res1.getBody()+":"+res2.getBody();
        }
    }
    
  • service3

    package com.paratera.console.linktracking.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/service3")
    public class ZipkinBraveController {
          
    
        @RequestMapping("/test")
        public String service1() throws Exception {
          
            //休眠3s,模拟性能耗点
            Thread.sleep(3000);
            return "service3";
        }
    }
    
  • service4

    package com.paratera.console.linktracking.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/service4")
    public class ZipkinBraveController {
          
    
        @RequestMapping("/test")
        public String service1() throws Exception {
          
            //休眠100ms,模拟业务耗时
            Thread.sleep(100);
            return "service4";
        }
    
    }
    

application.yml配置

spring:
  application:
    name: service1
  zipkin:
    base-url: http://192.168.137.129:9411    #zipkin server 的地址
    sender:
      type: web    #如果ClassPath里没有kafka, active MQ, 默认是web的方式
    sleuth:
      sampler:
        probability: 1.0  #100%取样,生产环境应该低一点,用不着全部取出来
server:
  port: 8081

四个服务工程除了端口不一样,其他都一样,zipkin监控serviceName不做配置,默认会使用Spring Application Name

附RestTemplate实例化代码

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
    
   return new RestTemplate(factory);
}

@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
    
   SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
   factory.setConnectTimeout(5000);
   factory.setReadTimeout(5000);
   return factory;
}

4.3 测试结果

当我们访问http://localhost:8081/service1/test时,会生成一个完整的调用链路json数据,通过4.1搭建的zipkin server UI可以查看详情:

在这里插入图片描述

点击show查看各server请求详情:

在这里插入图片描述

进入service3详情:

在这里插入图片描述

可以自己通过CS,SS,CF,SF计算是网络延迟引起的问题还是逻辑处理引起的性能问题!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/huxiang19851114/article/details/122976149

智能推荐

OpenCV-PyQT项目实战(4)OpenCV 与PyQt的图像转换_基于opencv和pyqt的图像处理_youcans_的博客-程序员秘密

在OpenCV-PyQt的项目中,通常使用OpenCV读写和处理图像,使用PyQt进行显示和交互。但是,OpenCV与PyQt中的图像存储格式不同,需要进行转换。这里有不少坑,小心行驶。

微信Web开发-App前端jssdk获取问题_吴维炜的博客-程序员秘密

本问主要介绍微信网页webapp开发过程中引入微信jssdk的坑1.基本配置毫无疑问,请参照官方文档https://mp.weixin.qq.com/wiki?t=resource/res_main&amp;amp;amp;id=mp1421141115注:一般最容易出现问题的是步骤三2.config配置失败的原因2.1域名不一致官方有错误排查的引导,还是无法解决,那么你问题最可能出现在url...

开发板网线连接虚拟机,虚拟机ens33,没有ip地址(s5pv210)_虚拟机ens33不显示ip_竹东篱的博客-程序员秘密

利用tftp服务器,烧录arm内核,关于tftp服务器的搭建,参考:https://www.cnblogs.com/multimicro/p/9270547.html把tftp服务器搭建后设置虚拟机网络适配器为:桥接模式在虚拟机的编辑 》虚拟网络编辑器 》 桥接到 。 选择你的有线网卡,如果不知道那个选项是有线网卡可以,打开主机上的控制面板》网络共享中心》更改适配器设置》以太网箭头指向的...

[BZOJ 1725][Usaco2006 Nov]Corn Fields牧场的安排:状压DP_牧场的安排ac_BrooksBUAA的博客-程序员秘密

点击这里查看原题用二进制串表示每一行的摆放情况,预处理出各个状态间的转移关系即可。 f[i][j]表示第i行按状态j摆放的方案数。/*User:SmallLanguage:C++Problem No.:1725*/#include<bits/stdc++.h>#define ll long long#define inf 999999999using namespace std;

Android Studio 开发环境搭建 & 配置_android studio环境配置_Wriprin的博客-程序员秘密

前言 开发环境:JDK 开发语言:Java 开发工具 Android Studio JDK 安装配置 HelloWorld AS 默认配置修改 AVD 安装配置

时间单位的换算(秒,毫秒,微秒,纳秒,皮秒)_秒,毫秒,微秒,纳秒,皮秒_lucky_zbaby的博客-程序员秘密

时间单位:  秒(second),时间单位 : s,  毫秒(millisecond),时间单位:ms  微秒(microsecond),时间单位:μs时间换算:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1s【秒】 = 1000ms【毫秒】  1ms【毫秒】 = 1000μs【微秒】   1μs【微秒】 = 1000ns【纳秒】  1ns 【纳秒】= 1000ps【皮秒】1秒(s) = 1000 毫秒(ms) = 1,000,000 微秒(μs) = 1,0

随便推点

多媒体计算机技术2017年四月,2017年4月模拟题-多媒体技术_日本留学秋武老师的博客-程序员秘密

单选题:1、下列四项中属于数字化技术专有特点的是______。A.数字信号不存在衰减和噪音干扰问题B.数字信号在复制和传送过程不会因噪音的积累而产生衰减C.适合数字计算机进行加工和处理D.以上都是答案:D2、以下是关于使用触摸屏的说法,其中正确的是______。A.用手指操作直观﹑方便B.操作简单,无须学习C.交互性好,简化了人机接口D.以上3项全部正确答案:D3、下列说法中,正确的是______...

第四章课后作业_网页第四章课后总裁作业_xyz430771x的博客-程序员秘密

1.使用css制作网页有哪些优势?1.内i容与表现分离2.表现的统一3.丰富的样式4.减少页面的代码量5.运行独立于页面的css2.使用&amp;lt;style&amp;gt;标签和style属性引入cssy 样式有什么不同和相同1.style属性设置css样式的方式仅对当前的HTML标签起作用,这种方式不能使用内容与表现分离&amp;lt;style&amp;gt;这种方式方便在页面中修改样式,但不利于在多页...

Silverlight HttpUtil 封装Post调用_nivana999的博客-程序员秘密

using System;using System.Net;using System.Windows;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Ink;using System.Windows.Input;using System.Windows.M

WebStorm FileWatcher (less 编译生成 css css.map min.css)(js 编译 min.js)_aaw11247的博客-程序员秘密

环境win7 64nodejdk 8工具Webstormnode-lessyuicompressor-2.4.8.jar步骤npm install -g less安装less 自动编译 webstorm (setting-&gt;Tool-&gt;File Watche...

多租户 SaaS 的数据库设计模式,你学废了吗?_saas多租户数据库设计_年少有为2025的博客-程序员秘密

在设计多租户SaaS应用程序时,您必须仔细选择最适合您应用程序需求的租户模型。租户模型确定每个租户的数据如何映射到存储。您选择的租户模式会影响应用程序设计和管理。以后切换到另一个模型有时代价昂贵。关于可选择的租户模型的讨论如下。...

iframe 高度自适应!_michael110的博客-程序员秘密

window.onresize = setFrameSize;                function setFrameSize()        {                        if (document.frames[htmliframe].document.body==null) return;            var frm

推荐文章

热门文章

相关标签