如何用AI技术降噪? QCon 广州“音视频架构实践”专场给你答案! 了解详情
写点什么

Observability 之深度讲解采样 Sampling 场景和落地案例(上)

  • 2022 年 7 月 13 日
  • 本文字数:6248 字

    阅读完需:约 20 分钟

Observability 之深度讲解采样 Sampling 场景和落地案例(上)

采样的知识背景

回顾可观测系统解决的主要问题


系统的调用链信息 Traces、Metrics、Logs 串联后,开发者基于调用链进行系统行为分析。

常见的使用场景可以分为以下几类:

异常检测


异常检测指的是定位和排查一些引发系统异常行为的请求,通常这些请求的出现频率很低。尽管异常事件被采样的概率很低,但它的信息熵大,能给到开发者更多细节信息。这些细节可能体现在:慢请求、慢查询、循环调用未设上限、存在错误级别日志、未覆盖测试的问题逻辑分支等等。如果调用链追踪系统能主动为开发者发现异常问题,将使得风险隐患提前暴露,并被扼杀在摇篮中。

健康度分析


健康度分析指的是分析业务系统健康度,分析粒度可能包括单个接口、单个服务、多个服务等等;分析范围可能是单个请求或多个请求;分析角度可能包括埋点指标、依赖关系、流量大小等等。分析反映系统主要流程的健康状态,一些配置的改动,如存储节点修改、客户端日志上报频率,都可能反馈到系统稳态。健康度关键点

1. 可用性


首先,将业务系统的运行状态分为“可用”和“不可用”两个状态。若业务系统或其支撑服务不可用,则健康度直接 0 分甚至负分。


其次,业务系统关联的网络、中间件、数据库的运维状态分为“可用”和“不可用”两个状态。如存在“不可用”状态,则根据关键点重要等级权重计算业务系统健康度。


再次,业务系统底层的硬件设备,也存在“可用”和“不可用”两个状态,考虑到当前服务均使用高可用模式,所以会存在服务“可用”但支持的硬件出现“不可用”情况。

2. 性能


性能指标更关注于业务系统,包含:响应时间(可以再细分到:响应时间(宏观);加载速度(微观,各个服务)),可以通过控制性能健康度权重值调节业务系统健康度。


稳态性能分析:定位和排查系统稳态中的性能问题,这些问题的起因通常与异常检测类似,只是其影响尚不足以触发报警。


服务依赖分析:构建接口级别的依赖关系图,节点通常为接口或服务,边通常为接口或服务的调用关系,边的权重则为流量。构建方式可以分为离线构建和在线构建,对应的就是静态关系图和动态关系图。这些信息可以以基础 API 的方式提供给上游应用使用,如 APM。

资源归因


资源归因解答的主要问题是:“谁该为我的服务成本买单?” 它需要将资源消耗或占用与请求方关联,资源归因也是成本分析的基础。

负载建模


负载建模主要指分析和推测系统的行为表现,该场景解答的问题通常可以表述为 “如果出现 XX 变化,系统整体或关键链路状态会发生什么改变” 。


常见应用如容量预估、全链路压测、混沌测试等等。

采样角色在调用链系统架构的位置


从调用链系统架构设计看,采样处理几乎每个阶段都在。


采样


采样分成两种部署模式:客户端采样、服务端采样,有的系统客户端、服务器同时采样。


实践中无论从计算和存储资源成本消耗上分析,还是从具体使用场景出发,都不一定需要收集所有埋点数据。因此许多调用链追踪系统会要求按照一定的策略上报数据,目的是取得成本与收益之间的平衡,提高投入产出比。

上报


数据可以从服务实例中直接发送到处理中心,或经由同一宿主机上的 agent 代理上报。使用 agent 上报的好处之一在于一些计算操作可以在 agent 中统一处理,一些逻辑如压缩、过滤、配置变更等可以集中到 agent 中实现,服务只需要实现很薄的一层埋点、采样逻辑即可,这也能使得调用链追踪方案对业务服务本身的影响降到最低;使用 agent 上报的另一好处是数据处理服务的发现机制对服务本身透明。因此在每台宿主机上部署 agent 是许多调用链追踪系统的推荐部署方案。


Kubernetes,Istio 上报也是类似 Agent 原理:SideCar、DaemonSet 的模式,思路类似。

收集中心


调用链数据上报到中心节点,通常称后者为收集器 (Collector),由收集器完成必要的后处理,如数据过滤、数据标记、尾部采样、数据建模等等,最后批量写到不同的存储服务中,并建立必要的索引。

存储/索引、可扩展性


调用链追踪系统需要处理的数据与全站的请求总量正相关。假如全站所有请求平均要经过 10 个服务处理,那么调用链追踪系统将需要承担全站请求总量 10 倍压力,如果不做任何采样,一方面系统存储压力成指数增长,服务器成本非常高。另一方面链路系统其架构设计上要求具备可扩展性。

采样的常见场景


  1. 分布式系统,微服务系统存在调用链比较深情况,让一个 Trace 产生指数的比例 Span,链路数据量巨大。


  1. 服务 TPS 很高,高并发的情况,全量采集给公司系统整体带来两方面压力:


  • 因数据上报造成的每个业务服务的网络 I/O 压力

  • 因数据采集、分析造成的调用链追踪服务的计算和存储压力。


采样主要为了干三件事:


  • 节约服务器资源,数据存储成本;

  • 高并发带来链路采集的性能瓶颈,讲请求量指数级降低可以指数级减少性能问题困难度;

  • 异常检测、链路故障排查更聚焦,采样不只是减小传送,有可能甚至增加采样样本;

采样的好处


这里,我举两个案例给大家一个参考,说实在,这也只是我平时随便留意的一小部分。

伴鱼案例

2020 年,我们不断收到业务研发的反馈:能不能全量采集 trace?这促使我们开始重新思考如何改进调用链追踪系统。我们做了一个简单的容量预估:目前 Jaeger 每天写入 ES 的数据量接近 100GB/天,如果要全量采集 trace 数据,保守假设平均每个 HTTP API 服务的总 QPS 为 100,那么完整存下全量数据需要 10TB/天;乐观假设 100 名服务器研发每人每天查看 1 条 trace,每条 trace 的平均大小为 1KB,则整体信噪比千万分之一。可以看出,这件事情本身的 ROI 很低,考虑到未来业务会持续增长,存储这些数据的价值也会继续降低,因此全量采集的方案被放弃。退一步想:全量采集真的是本质需求吗?实际上并非如此,我们想要的其实是「有意思」的 trace 全采,「没意思」的 trace 不采。

货拉拉

2.0 架构虽然能满足高吞吐量,但是也存在存储成本浪费的问题。其实从实践经验看,我们会发现 80~90%的 Trace 数据都是无价值的、无意义的数据,或者说是用户不关心的。那么用户关心哪些数据呢?关心链路中错、慢的请求以及部分核心服务的请求。那么我们是不是可以通过某些方式,把这些有价值的数据给过滤采样出来从而降低整体存储成本?在这个背景下,我们进行 3.0 的改造,实现了差异化的完成链路采样,保证 1H 以内的数据全量保存,我定义它为热数据,而一小时以外的数据,只保留错、慢、核心服务请求 Trace,定义为冷数据,这样就将整体的存储成本降低了 60%。

原文链接: https://www.sohu.com/a/531709613_411876

字节跳动

由于字节整体线上流量非常大,微服务数目众多,不同微服务的性能敏感度、成本敏感度和数据需求各有不同,例如有些服务涉及敏感数据,必须有非常完整的追踪数据;有些服务性能高度敏感,需要优先控制采样数最小化 Overhead;测试泳道、小流量灰度或者线上问题追查等场景会需要不同的采样策略;常规流量和发生异常的流量也需要不同的采样策略。

原文链接:https://blog.csdn.net/ByteDanceTech/article/details/122076591

采样的主要方案



 主要分三类:


  • 头部连贯采样:Head-based coherent sampling,从图中,采样决策 Sampling decision 从请求一开始做出了哪些初始节点需要采样的决定。头部采样是没有做预判的逻辑,从一开始选择性采集少量数据。但是,如果错误发生在没采集的节点,它无法采集到异常链路;

  • 单元采样:Unitary sampling;

  • 尾部连贯采样:Tail-based coherent sampling,尾部采样,是 Agent 在采集完整个服务链路,准备将采集数据上报时,根据一定的策略做选择性上报。比如下面的过程。



某个请求出问题开发者需要查看完整调用链信息,因此需要连贯采样。又由于问题请求的发生是小概率事件,只能通过尾部连贯采样来保证数据都能被捕获。


所以,业界普遍都选择尾部采样的方式。

主流开源和商业系统的采样实现

SkyWalking


它采样机制主要在 Agent 端支持 Head-based Sampling:能够支持简单的采样百分比 Sampling Rate,允许 forceSampleErrorSegment:错误链路强制采样。


Skywalking 做了 Slow SQL Sampling:分布式系统中,数据库非常常用,往往也是性能问题常出的中间件。


对 SQL 慢查询的采样在链路调用中一个重要的点,Skywalking 也做了支持。

https://skywalking.apache.org/docs/main/v8.5.0/en/setup/backend/slow-db-statement/

Jaeger

采样策略: 头部连贯采样,目前 Jaeger 支持三种采样方式:


  • Const:要么全采样,要么不采样;

  • Probabilistic:按固定概率采样;

  • Rate Limiting:限流采样,即保证每个进程每隔一段时间最多采 k 个;


除了 Agent 配置外,Jaeger 还支持远程动态调整采样方式,但调整的选择范围仍然必须为上面三种之一。为了防止一些调用量小的请求因为出现概率低而无法获得调用链信息,Jaeger 团队也提出了适应性采样 (Adaptive Sampling) ,但这个提议从 2017 年至今仍然未有推进。


限流采样适用范围有限,比如伴鱼案例:伴鱼的生产环境中使用的是限流采样策略:每个进程每秒最多采 1 条 trace。这种策略虽然很节省资源,但其缺点在一次次线上问题排查中逐渐暴露:一个进程中包含多个接口:不论按固定概率采样还是限流采样,都会导致小流量接口一直采集不到调用链数据而饿死 (starving)线上服务出错是小概率事件,导致出错的请求被采中的概率更小,就导致采到的调用链信息量不大,引发问题的调用链却丢失的问题,可以参考这篇内容

OpenTelemetry

支持尾部连贯采样


OpenTelemetry 收集器引入尾部连贯采样的支持。

https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/tailsamplingprocessor


OpenTelemetry 尾部连贯采样提供的策略也是非常丰富,下面常用一些策略:

  1. 常见的百分比采样 Latency: Sample based on the duration of the trace.

  2. 基于 Metric 指标范围的采样过滤:在你只想采集一些超过监控阈值的异常链路时候很有用

  • numeric_attribute: Sample based on number attributes

  • probabilistic: Sample a percentage of traces. Read a comparison with the Probabilistic Sampling Processor.

  1. 专门提供给 API 状态码定义采样,这个场景:异常特殊采样

  • status_code: Sample based upon the status code (OK, ERROR or UNSET)

  1. 基于标签匹配的采样过滤,这个场景:URL 采样过滤,某些特定自定义监控采样过滤,非常灵活,

  2. 给专门的应用服务和节点打标签的采样:很多业务监控会用上

  • string_attribute: Sample based on string attributes value matches, both exact and regex value matches are supported

  • rate_limiting: Sample based on rate

  1. 限流采样: 不详细说了


OpenTelemetry 还支持多种采样规则混合搭配方式:它把一种策略叫做 Policy。你可以根据自身系统,定制化一套完整的采样方案。比如下面,是 Collector 收集中心定义的一套完整的采集方案:


processors:  tail_sampling:    decision_wait: 10s    num_traces: 100    expected_new_traces_per_sec: 10    policies:      [          {            name: test-policy-2,            type: latency,            latency: {threshold_ms: 5000}          },          {            name: test-policy-3,            type: numeric_attribute,            numeric_attribute: {key: key1, min_value: 50, max_value: 100}          },          {            name: test-policy-4,            type: probabilistic,            probabilistic: {sampling_percentage: 10}          },          {            name: test-policy-5,            type: status_code,            status_code: {status_codes: [ERROR, UNSET]}          },          {            name: test-policy-6,            type: string_attribute,            string_attribute: {key: key2, values: [value1, value2]}          },          {            name: test-policy-7,            type: string_attribute,            string_attribute: {key: key2, values: [value1, val*], enabled_regex_matching: true, cache_max_size: 10}          }        ]
复制代码

OpenTelemetry 尾部采样实例


我们做一个简单异常链路采集的例子:Github 我放上了案例,大家可以自行下载体验

https://github.com/laziobird/otel-collector-java/

我们看看对于的效果,在没有开启异常采样前:



 所有链路都采集上报到 Jaeger 做链路数据分析,当我们开启了一个采集策略配置,对应 otel-collector-config.yaml 简单配置一个 Policy:


processors:batch:tail_sampling:policies:[  {    name: test-policy-5,    type: status_code,    status_code: {status_codes: [ERROR]}  }]service:extensions: [pprof,health_check]pipelines:traces:receivers: [otlp]processors: [tail_sampling]exporters: [jaeger]
复制代码


看看加了异常 Sampling 结果:



看到了吧,只有异常链路被上报了!

Datadog


默认 Agent 也有头部采样,同时支持尾部采样。


Datadog 做全链路追踪的可观测,同时支持了 RUM、APM 前后端的采样。

https://docs.datadoghq.com/tracing/trace_ingestion/mechanisms/?tab=environmentvariables#head-based-sampling


在 APM 侧,做了基于 Tag 尾部采样

https://docs.datadoghq.com/serverless/distributed_tracing/

Tail-based sampling and fully customizable tag-based retention filters.


它做了一个采样 Trace 的权重等级,通过权重区分采样还是不采样。

PRIORITY SAMPLINGThe sampler can set the priority to the following values:Datadog::Tracing::Sampling::Ext::Priority::AUTO_REJECT: the sampler automatically decided to reject the trace.Datadog::Tracing::Sampling::Ext::Priority::AUTO_KEEP: the sampler automatically decided to keep the trace.
复制代码

染色采样


刚才根据权重采样,是采样一种常见模式,我们可以归类染色采样的范畴:当我们针对特殊场景、服务进行针对性分析时,可以给他们打上特殊标签 Tag 进行全量采集。


我们简单看看染色采样的案例:


  1. 腾讯云的自定义采样:

介绍出处: https://cloud.tencent.com/document/product/1463/66104


采样模式的案例分享和简单讲解

尾部连贯采样 VS 头部连贯采样


收钱吧一开始头部连贯采样,后面也是考虑尾部采样:

由于我们目前采样的是头采样(Head-Based Sampling)方案,一旦在链路中间的服务发生抛出异常且这条链路没有被采样,那么就会出现有错误日志和报警,但链路追踪系统无法查询到这条链路的情况,这给开发排查问题带来很大的阻碍。


伴鱼最早采用 Jaeger,默认头部连贯采样的限流采样,后面开始使用 OpenTelemetry 一个原因,也是采样支持尾部采样:

伴鱼的生产环境中使用的是限流采样策略:每个进程每秒最多采 1 条 trace。这种策略虽然很节省资源,但其缺点在一次次线上问题排查中逐渐暴露:

一个进程中包含多个接口:不论按固定概率采样还是限流采样,都会导致小流量接口一直采集不到调用链数据而饿死 (starving)

线上服务出错是小概率事件,导致出错的请求被采中的概率更小,就导致采到的调用链信息量不大,引发问题的调用链却丢失的问题


字节跳动、货拉拉,OpenTelemetry 都有分享尾部采样案例,这里我不一一列举了。最后,还推荐 Oy LM Ericsson Ab 芬兰公司 (母公司爱立信)的核心开发 G KIBRIA SHUVO 分享尾部连贯采样的完整一本书介绍,里面也有 OpenTelemetry 在尾部采样的应用实现。

Tail Based Sampling Framework for Distributed Tracing Using Stream Processing



英文原版下载链接

https://kth.diva-portal.org/smash/get/diva2:1621787/FULLTEXT01.pdf

 

2022 年 7 月 13 日 14:232169

评论

发布
暂无评论
发现更多内容

「云智公开课」百度沧海·存储

「云智公开课」百度沧海·存储

Observability 之深度讲解采样 Sampling 场景和落地案例(上)_语言 & 开发_蒋志伟_InfoQ精选文章