导读:
分布式链路追踪作为解决分布式应用可观测问题的重要技术,得物全链路追踪(简称Trace2.0)基于OpenTelemetry提供的可观测规范计划实现新一代的一站式全链路观测诊断平台,并通过全量采集Trace帮忙业务进步故障诊断、性能优化、架构治理的效率。
全量采集Trace数据(日增数百TB 、数千亿条Span数据)并以较低的老本保证数据的实时处理与高效查问,对Trace2.0后端整体的可观测性解决方案提出了极高的要求。本文将具体介绍Trace2.0背地的架构设计、尾部采样和冷热存储计划,以及咱们是如何通过自建存储实现进一步的降本增效(存储老本降落66%)。
1. 整体架构设计
全链路追踪Trace2.0从数据接入侧、计算、存储到查问整体模块架构如上图所示。这里说一下各组件的外围能力:
- 客户端&数据采集:集成并定制OpenTelemetry提供的多语言SDK(Agent),生成对立格局的可观测数据。
- 管制立体Control Plane:对立的配置核心向数据采集侧下发各类动静配置发并实时失效;反对向各采集器下发动静配置并实时失效,反对利用按实例数灰度接入,并提供出入参收集动静开关、性能分析动静开关、流量染色动静配置、客户端版本治理等。
- 数据收集服务OTel Server:数据收集器OTel Server兼容OpenTelemetry Protocol(OTLP)协定,提供gRPC和HTTP两种形式接管采集器发送的可观测数据。
剖析计算&存储OTel Storage:计算侧除了根底的实时检索能力外,还提供了场景化的数据分析计算次要包含:
- 存储Trace数据:数据分为两段,一段是索引字段,包含TraceID、ServiceName、SpanName、StatusCode、Duration和起止工夫等根本信息,用于高级检索;另一段是明细数据(源数据,蕴含所有的Span数据)
- 计算SpanMetrics数据:聚合计算Service、SpanName、Host、StatusCode、Env、Region等维度的执行总次数、总耗时、最大耗时、最小耗时、分位线等数据;
- 业务单号关联Trace:电商场景下局部研发多以订单号、履约单号、汇金单号作为排障的输出,因而和业务研发约定非凡埋点规定后--在Span的Tag里增加一个非凡字段"bizOrderId={理论单号}"--便将这个Tag作为ClickHouse的索引字段;从而实现业务链路到全链路Trace造成一个残缺的排障链路;
- Redis热点数据统计:在客户端侧扩大调用Redis时入参和出参SpanTag埋点,以便统Redis命中率、大Key、高频写、慢调用等指标数据;
- MySQL热点数据统计:依照SQL指纹统计调用次数、慢SQL次数以及关联的接口名。
2. 尾部采样&冷热存储
得物晚期的全链路追踪计划出于对存储老本的思考,在客户端设置了1%的采样率,导致研发排查问题时常常查问不到想看的Trace链路。那么Trace2.0为了解决这个问题,就不能仅仅只是简略地将客户端的采样率调整为100%,而是须要在客户端全量采集Trace数据的同时,正当地管制Trace存储老本。且从实践经验来看,Trace数据的价值散布是不平均的,随着工夫的推移Trace的数据价值是急速升高的。
全量存储Trace数据不仅会造成微小的老本节约,还会显著地影响整条数据处理链路的性能以及稳定性。所以,如果咱们可能只保留那些有价值、大概率会被用户理论查问的Trace,就能获得老本与收益的均衡。那什么是有价值的Trace呢?依据日常排查教训,咱们发现业务研发次要关怀以下四类优先级高场景:
- 在调用链上呈现了异样ERROR;
- 在调用链上呈现了大于「200ms」的数据库调用;
- 整个调用链耗时超过「1s」;
- 业务场景的调用链,比方通过订单号关联的调用链。
在这个背景下,并联合业界的实践经验,落地Trace2.0的过程中设计了尾部采样&冷热分层存储计划,计划如下:
- 「3天」内的Trace数据全量保留,定义为热数据。
- 基于Kafka提早生产+Bloom Filter尾部采样的数据(错、慢、自定义采样规定、以及默认惯例0.1%采样数据)保留「30天」,定义为冷数据。
整体解决流程如下:
- OTel Server数据收集&采样规定:将客户端采集器上报的全量Trace数据实时写入Kafka中,并把满足采样规定(上述定义的场景)的Span数据对应的TraceID记录到Bloom Filter中;
- OTel Storage长久化热数据:实时生产Kafka中数据,并全量长久化到ClickHouse热集群中;
- OTel Storage长久化冷数据:订阅上游OTel Server的Bloom Filter,提早生产Kafka中的数据,将TraceID在Bloom Filter中可能存在的Span数据长久化到ClickHouse冷集群中;延迟时间配置的30分钟,尽量保障一个Trace下的Span残缺保留。
- TraceID点查: Trace2.0自定义了TraceID的生成规定;在生成TraceID时,会把以后工夫戳秒数的16进制编码后果(占8个字节)作为TraceID的一部分。查问时只须要解码TraceId中的工夫戳,即可晓得应该查问热集群还是冷集群。
接下来再介绍一下尾部采样中Bloom Filter的设计细节,如下图所示:
整体解决流程如下:
- OTel Server会将满足采样规定的Span数据对应的TraceID,依据TraceID中的工夫戳写入到对应工夫戳的Bloom Filter中;
- Bloom Filter会按十分钟粒度(可依据理论的数据量并联合BloomFilter的误算率和样本大小计算内存耗费并调整)进行分片,十分钟过后将Bloom Filter进行序列化并写入到ClickHouse存储中;
- OTel Storage生产侧拉取Bloom Filter数据(留神:同一个工夫窗口,每一个OTel Server节点都会生成一个BloomFilter)并进行合并Merge(缩小Bloom Filter的内存占用并进步Bloom Filter的查问效率)。
综上所述,Trace2.0仅应用了较少的资源就实现了尾部采样和冷热分层存储。既为公司节约了老本,又保留了简直所有「有价值」Trace,解决了业务研发日常排查时查问不到想看的Trace的问题。
3. 自建存储&降本增效
3.1 基于SLS-Trace的解决方案
Trace2.0建设初期采纳了SLS专为OpenTelemetry定制的Trace计划 【1】,提供了Trace查问、调用剖析、拓扑剖析等性能,如下图所示:
SLS-Trace次要解决流程如下:
- 利用OpenTelemetry Collector aliyunlogserverexporter【2】将Trace数据写入到SLS-Trace Logstore中;
- SLS-Trace通过默认提供的Scheduled SQL工作定时聚合Trace数据并生成相应的Span指标与利用、接口粒度的拓扑指标等数据。
随着Trace2.0在公司外部全面铺开,SLS的存储老本压力变得越来越大,为了响应公司“利用技术手段实现降本提效”的号召,咱们决定自建存储。
3.2 基于ClickHouse的解决方案
目前业内比拟风行的全链路追踪开源我的项目(SkyWalking、Pinpoint、Jaeger等)采纳的存储大都是基于ES或者HBase实现的。而近几年新兴的开源全链路追踪开源我的项目(Uptrace【3】、Signoz【4】等)采纳的存储大都是基于ClickHouse实现的,同时将Span数据荡涤进去的指标数据也存储在ClickHouse中。且ClickHouse的物化视图(很好用)也很好地解决了指标数据降采样(DownSampling)的问题。最终通过一番调研,咱们决定基于ClickHouse来自建新的存储解决方案。整体架构图如下:
整体解决流程如下:
- Trace索引&明细数据:OTel Storage会将基于Span原始数据构建的索引数据写入到SpanIndex表中,将Span原始明细数据写入到SpanData表中(相干表设计能够参考Uptrace【5】);
计算&长久化SpanMetrics数据:OTel Storage会依据Span的Service、SpanName、Host、StatusCode等属性统计并生成「30秒」粒度的总调用次数、总耗时、最大耗时、最小耗时、分位线等指标数据,并写入到SpanMetrics表;
- 指标DownSampling性能:利用ClickHouse的物化视图将「秒级」指标聚合成「分钟级」指标,再将「分钟级」指标聚合成「小时级」指标;从而实现多精度的指标以满足不同工夫范畴的查问需要;
-- span_metrics_10m_mvCREATE MATERIALIZED VIEW IF NOT EXISTS '{database}'.span_metrics_10m_mv_local on cluster '{cluster}' TO '{database}'.span_metrics_10m_localASSELECT a.serviceName as serviceName, a.spanName as spanName, a.kind as kind, a.statusCode as statusCode, toStartOfTenMinutes(a.timeBucket) as timeBucket, sum(a.count) as count, sum(a.timeSum) as timeSum, max(a.timeMax) as timeMax, min(a.timeMin) as timeMinFROM '{database}'.span_metrics_30s_local as aGROUP BY a.serviceName, a.spanName, a.kind, a.statusCode, toStartOfTenMinutes(a.timeBucket);
- 元数据(上下游拓扑数据):OTel Storage依据Span属性中的上下游关系(须要在客户端埋相干属性),将拓扑依赖关系写入到图数据库Nebula中。
ClickHouse写入细节
ClickHouse应用Distributed引擎实现了Distributed(分布式)表机制,能够在所有分片(本地表)上建设视图,实现分布式查问。并且Distributed表本身不会存储任何数据,它会通过读取或写入其余远端节点的表来进行数据处理。SpanData表创立语句如下所示:
-- span_dataCREATE TABLE IF NOT EXISTS '{database}'.span_data_local ON CLUSTER '{cluster}'( traceID FixedString(32), spanID FixedString(16), startTime DateTime64(6 ) Codec (Delta, Default), body String CODEC (ZSTD(3))) ENGINE = MergeTreeORDER BY (traceID,startTime,spanID)PARTITION BY toStartOfTenMinutes(startTime)TTL toDate(startTime) + INTERVAL '{TTL}' HOUR;-- span_data_distributedCREATE TABLE IF NOT EXISTS '{database}'.span_data_all ON CLUSTER '{cluster}'as '{database}'.span_data_local ENGINE = Distributed('{cluster}', '{database}', span_data_local, xxHash64(concat(traceID,spanID,toString(toDateTime(startTime,6)))));
整体写入流程比较简单(留神:防止应用分布式表),如下所示:
- 定时获取ClickHouse集群节点;
- 通过Hash函数抉择对应的ClickHouse节点,而后批量写ClickHouse的本地表。
上线成果
全链路追踪是一个典型的写多读少的场景,因而咱们采纳了ClickHouse ZSTD压缩算法对数据进行了压缩,压缩后的压缩比高达12,成果十分好。目前ClickHouse冷热集群各应用数十台16C64G ESSD机器,单机写入速度25w/s(ClickHouse写入的行数)。相比于初期的阿里云SLS-Trace计划,存储老本降落66%,查问速度也从800+ms降落至490+ms。
下一步布局
目前Trace2.0将Span的原始明细数据也存储在了ClickHouse中,导致ClickHouse的磁盘使用率会有些偏高,后续思考将Span明细数据先写入HDFS/OSS等块存储设备中,ClickHouse来记录每个Span在块存储中的offset,从而进一步升高ClickHouse的存储老本。
对于咱们:
得物监控团队提供一站式的可观测性平台,负责链路追踪、时序数据库、日志零碎,包含自定义大盘、利用大盘、业务监控、智能告警、AIOPS等排障剖析。
欢送对可观测性/监控/告警/AIOPS 等畛域感兴趣的同学退出咱们。
援用
【1】SLS-Trace计划 https://developer.aliyun.com/...
【2】SLS-Trace Contrib https://github.com/open-telem...
【3】Uptrace https://uptrace.dev/
【4】Signoz https://signoz.io/
【5】Uptrace Schema设计https://github.com/uptrace/up...
本篇是《得物云原生全链路追踪Trace2.0》系列开篇,更多内容请关注“得物技术”公众号。
得物云原生全链路追踪Trace2.0架构实际
得物云原生全链路追踪Trace2.0产品篇
得物云原生全链路追踪Trace2.0采集篇
得物云原生全链路追踪Trace2.0数据挖掘篇
*文/南风
@得物技术公众号