docker–zipkin(分布式链路追踪)实践


文章目录

  • docker--zipkin(分布式链路追踪)实践
  • 前言
  • zipkin架构
  • 启动服务
  • 使用mysql数据库
  • springcloud实践
  • 引入依赖
  • 配置
  • 接口实现
  • 运行
  • 参考


前言

  • 官网:OpenZipkin
  • zipkin是Twitter基于google的分布式监控系统Dapper(论文)的开发源实现,zipkin用于跟踪分布式服务之间的应用数据链路,分析处理延时,帮助我们改进系统的性能和定位故障
  • 搭建 Zipkin 最简单的办法是直接使用 Zipkin 官方的 Docker 镜像。

zipkin架构

docker 使用unzip 解压到当前文件下 docker zipkin_ci

启动服务

  • 启动服务命令如下
#!/bin/sh

docker run -d \
--restart always \
-v /etc/localtime:/etc/localtime:ro \
-p 9411:9411 \
--name zipkin \
openzipkin/zipkin
  • 以上命令即可启动一个zipkin服务,不过数据是放在内存中,一旦重启就数据就消失了,因此这种只适合在测试时使用,生产环境中需要配置持久化,如mysql

使用mysql数据库

  • 如果只是为了测试用,那么以上的服务就够用了,但是一旦到生产环境中,那么数据持久化就非常重要了,官方提供了很多支持,在这里我就用mysql来存储了
  • 如果你已经有了mysql数据库,那么可以直接用现有的mysql进行建库建表
  • 以下方法适用于mysql数据库跟zipkin不在同一台机器上
  • 首先创建数据库zipkin,编码使用utf8
  • 创建数据库后执行以下sql创建表,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',
  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(`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;
  • 创建好数据库后就可以启动zipkin服务了,命令如下
#!/bin/sh

docker run -d \
--restart always \
-v /etc/localtime:/etc/localtime:ro \
-e MYSQL_USER=root \
-e MYSQL_PASS=password \
-e MYSQL_HOST=192.168.0.8 \
-e STORAGE_TYPE=mysql \
-e MYSQL_DB=zipkin \
-e MYSQL_TCP_PORT=3306 \
--net host \
--name zipkin \
openzipkin/zipkin
  • 以上参数需要根据实际情况修改,这里由于使用到数据库,因此网络模式为host;如果使用桥接方式,那么要用link连接到数据库(理论上可行,但自己没测试过,故不做说明)

以上虽然加了共享宿主机的时区,进入到容器内查看date和宿主机也是一样的,但看打印日志的时间还是快了8小时,百思不得其解,望高人指点

springcloud实践

  • 实践环境为:
  • springboot:2.1.3.RELEASE
  • springcloud:Greenwich.SR1
  • gradle:5.2.1

引入依赖

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.cloud:spring-cloud-starter-zipkin'
}
  • spring-cloud-starter-zipkin中已包含了spring-cloud-starter-sleuth与spring-cloud-sleuth-zipkin的依赖,所以使用sleuth-zipkin的SpringCloud项目只需添加spring-cloud-starter-zipkin依赖即可

配置

spring:
  application:
    name: test #在zipkin上显示的服务名,不写则是“default”
  zipkin:
    base-url: http://192.168.25.169:9411/ #zipkin服务的地址
   # sender:
   #   type: web  #网上有人在zipkin上查不到记录,说加上这个即可,但本人亲测不加也是可以查到记录
  sleuth:
    sampler:
      probability: 1.0 #请求的采样率,在测试时为了方便查看可以改为1表示所有请求都记录,但在生产环境中还是建议改为0.1,否则数量太多影响性能

接口实现

  • 在程序中简单实现一个接口
@SpringBootApplication
@RestController
public class SleuthApplication {

    public static void main(String[] args) {
        SpringApplication.run(SleuthApplication.class, args);
    }


    @GetMapping("/test")
    public String abc(){
        return "hello";
    }
}

运行

  • 通过以上两步运行程序即可,此时调用test接口在zipkin服务上并不能马上看到记录,需要等待大约1分钟左右再去刷新

值得注意的是,zipkin的浏览器兼容性还不是很好,在ie和360浏览器上发现显示不了记录,建议使用firefox进行测试,一开始用360浏览器一直看不到记录,害我以为是服务有问题,浪费了大量时间排查
另外,由于时区的问题未解决,因此时间可能要选大一点的才可能查找到