导读:
分布式链路追踪作为解决分布式应用可观测问题的重要技术,得物全链路追踪(简称Trace2.0)基于OpenTelemetry提供的可观测标准方案实现新一代的一站式全链路观测诊断平台,并通过全量采集Trace帮助业务提高故障诊断、性能优化、架构治理的效率。
全量采集Trace数据(日增数百TB 、数千亿条Span数据)并以较低的成本保证数据的实时处理与高效查询,对Trace2.0后端整体的可观测性解决方案提出了极高的要求。本文将详细介绍Trace2.0背后的架构设计、尾部采样和冷热存储方案,以及我们是如何通过自建存储实现进一步的降本增效(存储成本下降66%)。
全链路追踪Trace2.0从数据接入侧、计算、存储到查询整体模块架构如上图所示。这里说一下各组件的核心能力:
得物早期的全链路追踪方案出于对存储成本的考虑,在客户端设置了1%的采样率,导致研发排查问题时经常查询不到想看的Trace链路。那么Trace2.0为了解决这个问题,就不能仅仅只是简单地将客户端的采样率调整为100%,而是需要在客户端全量采集Trace数据的同时,合理地控制Trace存储成本。且从实践经验来看,Trace数据的价值分布是不均匀的,随着时间的推移Trace的数据价值是急速降低的。
全量存储Trace数据不仅会造成巨大的成本浪费,还会显著地影响整条数据处理链路的性能以及稳定性。所以,如果我们能够只保存那些有价值、大概率会被用户实际查询的Trace,就能取得成本与收益的平衡。那什么是有价值的Trace呢?根据日常排查经验,我们发现业务研发主要关心以下四类优先级高场景:
在这个背景下,并结合业界的实践经验,落地Trace2.0的过程中设计了尾部采样&冷热分层存储方案,方案如下:
整体处理流程如下:
接下来再介绍一下尾部采样中Bloom Filter的设计细节,如下图所示:
整体处理流程如下:
综上所述,Trace2.0仅使用了较少的资源就完成了尾部采样和冷热分层存储。既为公司节约了成本,又保存了几乎所有「有价值」Trace,解决了业务研发日常排查时查询不到想看的Trace的问题。
Trace2.0建设初期采用了SLS专为OpenTelemetry定制的Trace方案 【1】,提供了Trace查询、调用分析、拓扑分析等功能,如下图所示:
SLS-Trace主要处理流程如下:
随着Trace2.0在公司内部全面铺开,SLS的存储成本压力变得越来越大,为了响应公司“利用技术手段实现降本提效”的号召,我们决定自建存储。
目前业内比较流行的全链路追踪开源项目(SkyWalking、Pinpoint、Jaeger等)采用的存储大都是基于ES或者HBase实现的。而近几年新兴的开源全链路追踪开源项目(Uptrace【3】、Signoz【4】等)采用的存储大都是基于ClickHouse实现的,同时将Span数据清洗出来的指标数据也存储在ClickHouse中。且ClickHouse的物化视图(很好用)也很好地解决了指标数据降采样(DownSampling)的问题。最终经过一番调研,我们决定基于ClickHouse来自建新的存储解决方案。整体架构图如下:
整体处理流程如下:
计算&持久化SpanMetrics数据:OTel Storage会根据Span的Service、SpanName、Host、StatusCode等属性统计并生成「30秒」粒度的总调用次数、总耗时、最大耗时、最小耗时、分位线等指标数据,并写入到SpanMetrics表;
-- span_metrics_10m_mv
CREATE MATERIALIZED VIEW IF NOT EXISTS '{database}'.span_metrics_10m_mv_local
on cluster '{cluster}'
TO '{database}'.span_metrics_10m_local
AS
SELECT 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 timeMin
FROM '{database}'.span_metrics_30s_local as a
GROUP BY a.serviceName, a.spanName, a.kind, a.statusCode,
toStartOfTenMinutes(a.timeBucket);
ClickHouse写入细节
ClickHouse使用Distributed引擎实现了Distributed(分布式)表机制,可以在所有分片(本地表)上建立视图,实现分布式查询。并且Distributed表自身不会存储任何数据,它会通过读取或写入其他远端节点的表来进行数据处理。SpanData表创建语句如下所示:
-- span_data
CREATE 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 = MergeTree
ORDER BY (traceID,startTime,spanID)
PARTITION BY toStartOfTenMinutes(startTime)
TTL toDate(startTime) + INTERVAL '{TTL}' HOUR;
-- span_data_distributed
CREATE 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 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方案 释放Trace的价值-SLS OpenTelemetry新功能直击痛点-阿里云开发者社区
【2】SLS-Trace Contrib https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/alibabacloudlogserviceexporter
【3】Uptrace Distributed Traces, Logs & Errors (tracing, monitoring, observability, APM)
【4】Signoz Open source APM | SigNoz
【5】Uptrace Schema设计https://github.com/uptrace/uptrace/tree/v0.2.16/pkg/bunapp/migrations
本篇是《得物云原生全链路追踪Trace2.0》系列开篇,更多内容请关注“得物技术”公众号。
得物云原生全链路追踪Trace2.0架构实践
得物云原生全链路追踪Trace2.0产品篇
得物云原生全链路追踪Trace2.0采集篇
得物云原生全链路追踪Trace2.0数据挖掘篇
*文/南风
@得物技术公众号