基于SpringBoot 2.x+Sleuth+Zipkin(Rabbitmq+Mysql)构建链路追踪系统

背景


        无论你的系统是庞大的单应用架构,还是采用的微服务架构,只要是调用过程非常复杂,都会存在如何追踪各个方法或者服务间调用异常如何被开发和运维人员快速定位的问题,为了解决这个问题,你势必需要记录大量的日志。

       举个例子,对于一个大流量的Web应用通常以Stateless方式设计,这样可以更方便的进行水平扩容。但是随着应用实例数量越来越多,我们查询日志就越来越困难。在没有日志系统的情况下,首先我们需要定位到请求的服务器地址,如果每台服务器都部署了多个应用实例,我们则需要去每个应用实例的日志目录下去找日志文件。每个服务可能还会设置日志滚动策略(如:每200M一个文件),还有日志压缩归档策略。

        如此,我们查询一条出错信息就要在茫茫多的日志文件里去找到它,于是使出我们的十八般武艺head less tail grep wc awk count cut,但是如果需要统计最近3天的某个接口的异常次数,或者超时次数。。。。除了上面出现的状况我们还需要考虑:日志量太大如何归档、文本搜索太慢怎么办?

        但是对于故障排查肯定是希望能够快速的进行日志查询、定位、解决问题,对于实时性要求非常高。为了解决这个问题,日志追踪系统应运而生。

概念


        先介绍一个概念:分布式跟踪,或分布式追踪

        电商平台由数以百计的分布式服务构成,每一个请求路由过来后,会经过多个业务系统并留下足迹,并产生对各种Cache或DB的访问,但是这些分散的数据对于问题排查,或是流程优化都帮助有限。对于这么一个跨进程/跨线程的场景,汇总收集并分析海量日志就显得尤为重要。要能做到追踪每个请求的完整调用链路,收集调用链路上每个服务的性能数据,计算性能数据和比对性能指标(SLA),甚至在更远的未来能够再反馈到服务治理中,那么这就是分布式跟踪的目标了。在业界,Twitter 的 zipkin 和淘宝的鹰眼就是类似的系统,它们都起源于 Google Dapper 论文。

        整理一下,Google叫Dapper,淘宝叫鹰眼,Twitter叫ZipKin,京东商城叫Hydra,eBay叫Centralized Activity Logging (CAL),大众点评网叫CAT,其底层实现的追踪逻辑,几乎都是一样的。

分布式追踪系统的设计理念


(1)低侵入性——作为非业务组件,应当尽可能少侵入或者无侵入其他业务系统,对于使用方透明,减少开发人员的负担;

(2)灵活的应用策略——可以(最好随时)决定所收集数据的范围和粒度;

(3)时效性——从数据的收集和产生,到数据计算和处理,再到最终展现,都要求尽可能快;

(4)决策支持——这些数据是否能在决策支持层面发挥作用,特别是从 DevOps 的角度;

(5)可视化才是王道。

Zipkin出场


        在众多的追踪系统中,本文只是对Zipkin的应用做说明。

        最初接触Zipkin,是在《Spring Cloud 微服务实战》这本书中的 Spring Cloud Sleuth章节,按照这个章节写的例子学习下来,踩了无数个坑,弄的我是云里雾里。索性放弃书上的例子,直接看 Zipkin官网(https://zipkin.io)和Spinrg官网中关于Cloud Sleuth章节(https://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.1.2.RELEASE/multi/multi_spring-cloud-sleuth.html),同时查阅了多个网络上的文章,才发现随着Spring boot 2.X的问世,Spring Cloud Sleuth关于Zipkin的实现方式发生了非常大的变化。(在写这篇文章时,Zipkin的版本是V2.14.0)

        Spring Cloud Sleuth 在Spring Boot 1.x时代,是对Zipkin做一个完全整合,不仅实现了以 HTTP 的方式收集跟踪信息,还实现了通过消息中间件来对跟踪信息进行异步收集的封装。就连Zipkin服务器,也做了一层封装。而到了 Spring Boot 2.0 之后 Zipkin 不再推荐我们再自定义 Server 端了,Sleuth专注于对Dapper 中的算法进行封装,spring-cloud-starter-zipkin 只是对Zipkin客户端的封装,对于Sleuth在工程中如何使用,Spring官网上是这样写的:

\bullet Only Sleuth (log correlation):如果你只想使用Sleuth功能,而不想与Zipkin做集成的话,那么你只需要引入spring-cloud-starter-sleuth就可以了。我觉得,这种方式,对于普通使用者是很少会这样用的。是否是给那些牛到自己开发追踪服务的人准备的?谁知道呢!

\bullet Sleuth with Zipkin via HTTP :不重复发明轮子,是本人的一贯主张。如果你想使用Sleuth并通过HTTP方式集成ZipkinServer,你只需要引入spring-cloud-starter-zipkin 就可以了。你可能会问:spring-cloud-starter-sleuth不需要引入了吗? 我的回答是:需要,但它会被spring-cloud-starter-zipkin间接依赖而自动引入的。

\bullet Sleuth with Zipkin over RabbitMQ or Kafka :最后一种使用方式是,如果你不想通过HTPP方式集成ZipkinServer,而是通过RabbitMQ或者Kafka这些消息中间件做异步消息处理的话(笔者推荐这种用法),你除了需要引入spring-cloud-starter-zipkin,还需要引入spring-rabbit(本文以Rabbit为例)。还有一点就是:如果使用了消息中间件传递消息,那么Zipkin的服务端也需要做相应的配置,才能监听处理消息。

RabbitMQ相关参数配置


spring:

  rabbitmq:

    host: 10.10.10.10

    port: 5672

    username: guest

    password: guest

同时,在启动Zipkin服务端的时候,添加以上相同的Rabiit配置

D:\>java -jar zipkin.jar --zipkin.collector.rabbitmq.addresses=10.10.10.10 

端口如果不写默认是5672,用户名密码也是采用的默认值,如果你的配置不是采用默认值,需要维护相应参数。

启动服务


启动集成了Sleuth的服务和Zipkin 服务端,进行访问带多级调用的服务(省略具体操作),打开Zipkin的UI界面http://localhost:9411/zipkin/  ,如下图:

可以看到,刚才的调用链已经可以查询到了。点击某条记录,进入调用详细页面。

可以看到每个服务的调用时间,时长,是否异常等信息。这样,你就可以快速定位那些响应时间超长的请求或者发生异常的请求。

存储


Zipkin最初是为在Cassandra上存储数据而构建的,因为Cassandra是可扩展的,有一个灵活的模式,并且在Twitter中广泛使用。然而,我们使这个组件可插拔。除了Cassandra之外,Zipkin的存储还支持ElasticSearch和MySQL。

要想把记录的信息存储到Mysqls,你需要在启动Zipkin Server的时候添加如下的参数:

D:\>java -jar zipkin.jar --zipkin.collector.rabbitmq.addresses=10.10.10.10 --STORAGE_TYPE=mysql --MYSQL_DB=zipkin --MYSQL_HOST=10.10.1.10 --MYSQL_TCP_PORT=3306 --MYSQL_USER=root --MYSQL_PASS=123456

并且,要确保在zipkin库下,已经存在了需要用到的表。建表语句需要与Zipkin Server的版本相对应,避免未知错误:

CREATETABLEIFNOTEXISTSzipkin_spans (

`trace_id_high`BIGINTNOTNULLDEFAULT0COMMENT'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',

`trace_id`BIGINTNOTNULL,

`id`BIGINTNOTNULL,

`name`VARCHAR(255)NOTNULL,

`remote_service_name`VARCHAR(255),

`parent_id`BIGINT,

`debug`BIT(1),

`start_ts`BIGINTCOMMENT'Span.timestamp(): epoch micros used for endTs query and to implement TTL',

`duration`BIGINTCOMMENT'Span.duration(): micros used for minDuration and maxDuration query',

PRIMARYKEY(`trace_id_high`,`trace_id`,`id`)

) ENGINE=InnoDB ROW_FORMAT=COMPRESSEDCHARACTERSET=utf8 COLLATE utf8_general_ci;

ALTERTABLEzipkin_spans ADD INDEX(`trace_id_high`,`trace_id`) COMMENT'for getTracesByIds';

ALTERTABLEzipkin_spans ADD INDEX(`name`) COMMENT'for getTraces and getSpanNames';

ALTERTABLEzipkin_spans ADD INDEX(`remote_service_name`) COMMENT'for getTraces and getRemoteServiceNames';

ALTERTABLEzipkin_spans ADD INDEX(`start_ts`) COMMENT'for getTraces ordering and range';

CREATETABLEIFNOTEXISTSzipkin_annotations (

`trace_id_high`BIGINTNOTNULLDEFAULT0COMMENT'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',

`trace_id`BIGINTNOTNULLCOMMENT'coincides with zipkin_spans.trace_id',

`span_id`BIGINTNOTNULLCOMMENT'coincides with zipkin_spans.id',

`a_key`VARCHAR(255)NOTNULLCOMMENT'BinaryAnnotation.key or Annotation.value if type == -1',

`a_value`BLOB COMMENT'BinaryAnnotation.value(), which must be smaller than 64KB',

`a_type`INTNOTNULLCOMMENT'BinaryAnnotation.type() or -1 if Annotation',

`a_timestamp`BIGINTCOMMENT'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',

`endpoint_ipv4`INTCOMMENT'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`SMALLINTCOMMENT'Null when Binary/Annotation.endpoint is null',

`endpoint_service_name`VARCHAR(255) COMMENT'Null when Binary/Annotation.endpoint is null'

) ENGINE=InnoDB ROW_FORMAT=COMPRESSEDCHARACTERSET=utf8 COLLATE utf8_general_ci;

ALTERTABLEzipkin_annotations ADD UNIQUEKEY(`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`) COMMENT'Ignore insert on duplicate';

ALTERTABLEzipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`,`span_id`) COMMENT'for joining with zipkin_spans';

ALTERTABLEzipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`) COMMENT'for getTraces/ByIds';

ALTERTABLEzipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT'for getTraces and getServiceNames';

ALTERTABLEzipkin_annotations ADD INDEX(`a_type`) COMMENT'for getTraces and autocomplete values';

ALTERTABLEzipkin_annotations ADD INDEX(`a_key`) COMMENT'for getTraces and autocomplete values';

ALTERTABLEzipkin_annotations ADD INDEX(`trace_id`,`span_id`,`a_key`) COMMENT'for dependencies job';

CREATETABLEIFNOTEXISTSzipkin_dependencies (

`day`DATENOTNULL,

`parent`VARCHAR(255)NOTNULL,

`child`VARCHAR(255)NOTNULL,

`call_count`BIGINT,

`error_count`BIGINT,

PRIMARYKEY(`day`,`parent`,`child`)

) ENGINE=InnoDB ROW_FORMAT=COMPRESSEDCHARACTERSET=utf8 COLLATE utf8_general_ci;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容