TT Lab
开始
学习 学习路径 课程

OTCA — OpenTelemetry 认证助理

订单只有 6 笔,仪表盘却画出了 9 笔

在 TT Lab 中继续学习

目标

用真实的 OpenTelemetry Python SDK,依次测量 reader 的 temporality、默认直方图边界、通过视图(View)修改边界与属性以及丢弃指标的方法、异步 Instrument 的上报方式,最后把三个视图组装进同一个 MeterProvider。

为什么重要

同一个 Counter,按累积(cumulative)发送还是按增量(delta)发送,后端需要解读的含义并不相同。把两者混着读,订单会被计算两次;把以秒为单位的值放进为毫秒设计的默认边界,直方图会挤进同一个桶,分位数就失去意义。客户 ID 这类属性会增加数据点数量,推高成本。不修改埋点代码,而是通过 SDK 配置(reader、视图)来纠正这些问题,正是 API 与 SDK 分离的原因。

已准备的环境

/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py init 会在 /root/otca-metrics/ 中放入 shop.py(按固定顺序记录订单、购物车、结算耗时和调试指标)与 pipeline.py(需要填写的七个函数)。/opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show N 会用你的 pipeline.py,基于 lab-dev 镜像中的 OpenTelemetry Python SDK 1.44.0(/opt/otel-lab)组装 MeterProvider,并输出 shop 记录之后两次采集到的数据点。不使用网络、Collector 和 API key。评分器会用同一个 SDK 重新运行你的函数,对照行为与你填写的数字。务必用 /opt/otel-lab/bin/python 运行。

步骤

  1. 用 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py init 生成材料。把 /root/otca-metrics/pipeline.py 的 reader_cumulative() 改为返回默认的 InMemoryMetricReader 后,运行 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 1。shop.py 会记录 3 笔订单并采集,再记录 3 笔订单并再次采集。在 /root/otca-metrics/01-cumulative.txt 中写入 first=、second=(orders 合计)。
  2. 把 reader_delta() 改为返回仅对Counter以 DELTA 请求的 reader,然后运行 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 2。在 /root/otca-metrics/02-delta.txt 中写入 first=、second= 以及 double_counted=(把第 1 步的两个累积值误当作增量相加时,仪表板会画出的合计)。
  3. 修改 reader_all_delta(),让它对 Counter、UpDownCounter、Histogram、ObservableCounter 全部以 DELTA 请求,然后运行 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 3。在 /root/otca-metrics/03-updown.txt 中写入 cumulative_second=(用 reader_delta 看到的 cart.items 第二个值)与 delta_second=(用 reader_all_delta 看到的值)。
  4. 用 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 4 查看没有视图时采集到的 checkout.duration(单位 s,值为 0.2、0.35、0.8、1.4)的直方图。在 /root/otca-metrics/04-default-buckets.txt 中写入 boundaries=(默认边界的个数)、nonzero_bucket_index=(有值的桶的位置,从 0 开始)、nonzero_bucket_count=。
  5. 修改 views_buckets(),让它返回只对 checkout.duration 应用边界 0.25、0.5、1、2 的 View 列表。把 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 5 结果中各桶的个数,以 bucket_counts=(逗号分隔,最后一项是大于 2 的部分)的形式写入 /root/otca-metrics/05-view-buckets.txt。其他指标必须保持不变。
  6. 修改 views_cardinality(),让它返回把 orders 的属性键只保留为 route 的 View 列表。查看 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 6,并在 /root/otca-metrics/06-view-attributes.txt 中写入 points_before=(没有视图时第一次采集的 orders 数据点数)、points_after=、checkout_sum=(挂上视图后第一次采集的 /checkout 值)。
  7. 在 register_async(meter, source) 中,让 queue.processed 用 ObservableCounter 观测 source.processed(),让 queue.depth 用 ObservableGauge 观测 source.depth()。查看 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 7(使用 reader_all_delta),并在 /root/otca-metrics/07-async.txt 中写入 processed_delta_second=、depth_second=。source 每次调用会依次返回 processed 10、25 和 depth 7、4。
  8. 修改 provider(reader),让它返回带有所收到的 reader 和三个视图的 MeterProvider,三个视图分别是第 5 步的桶、第 6 步的属性精简,以及丢弃 debug.cache.lookups 的 DropAggregation。评分器会用 reader_all_delta() 采集两次,同时检查 orders(按 route 的增量)、checkout.duration(新边界)、cart.items 以及被丢弃的 debug 指标。先用 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 8 查看。

参考

采集两次,3 之后是 6

用 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py init 生成材料。把 /root/otca-metrics/pipeline.py 的 reader_cumulative() 改为返回默认的 InMemoryMetricReader 后,运行 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 1。shop.py 会记录 3 笔订单并采集,再记录 3 笔订单并再次采集。在 /root/otca-metrics/01-cumulative.txt 中写入 first=、second=(orders 合计)。

如果 reader 没有单独请求 temporality,SDK 会发送从启动时刻起的累积值。

按增量接收,以及混着读时会怎样

把 reader_delta() 改为返回仅对Counter以 DELTA 请求的 reader,然后运行 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 2。在 /root/otca-metrics/02-delta.txt 中写入 first=、second= 以及 double_counted=(把第 1 步的两个累积值误当作增量相加时,仪表板会画出的合计)。

preferred_temporality 是从 Instrument 类映射到 temporality 的字典。把累积值相加,前面的区间会被计算两次。

UpDownCounter 必须单独请求

修改 reader_all_delta(),让它对 Counter、UpDownCounter、Histogram、ObservableCounter 全部以 DELTA 请求,然后运行 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 3。在 /root/otca-metrics/03-updown.txt 中写入 cumulative_second=(用 reader_delta 看到的 cart.items 第二个值)与 delta_second=(用 reader_all_delta 看到的值)。

reader_delta 只改了 Counter。购物车依次记录 +5、-2,然后是 +1。

以秒为单位的值挤进了一个桶

用 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 4 查看没有视图时采集到的 checkout.duration(单位 s,值为 0.2、0.35、0.8、1.4)的直方图。在 /root/otca-metrics/04-default-buckets.txt 中写入 boundaries=(默认边界的个数)、nonzero_bucket_index=(有值的桶的位置,从 0 开始)、nonzero_bucket_count=。

SDK 的默认边界是按毫秒级延迟设计的。请看第一个边界和第二个边界。

用视图修改边界

修改 views_buckets(),让它返回只对 checkout.duration 应用边界 0.25、0.5、1、2 的 View 列表。把 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 5 结果中各桶的个数,以 bucket_counts=(逗号分隔,最后一项是大于 2 的部分)的形式写入 /root/otca-metrics/05-view-buckets.txt。其他指标必须保持不变。

View 通过 instrument_name 选择对象,通过 aggregation 修改聚合方式。不选择对象时,会作用于所有 Instrument。

丢掉客户 ID,数据点就会减少

修改 views_cardinality(),让它返回把 orders 的属性键只保留为 route 的 View 列表。查看 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 6,并在 /root/otca-metrics/06-view-attributes.txt 中写入 points_before=(没有视图时第一次采集的 orders 数据点数)、points_after=、checkout_sum=(挂上视图后第一次采集的 /checkout 值)。

每种属性组合对应一个数据点。只选择要保留的键,其余键不同的测量就会被合并,而合计保持不变。

异步计数器上报的是累积值

在 register_async(meter, source) 中,让 queue.processed 用 ObservableCounter 观测 source.processed(),让 queue.depth 用 ObservableGauge 观测 source.depth()。查看 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 7(使用 reader_all_delta),并在 /root/otca-metrics/07-async.txt 中写入 processed_delta_second=、depth_second=。source 每次调用会依次返回 processed 10、25 和 depth 7、4。

异步计数器的回调返回的是到目前为止的累积绝对值。增量由 SDK 按与上一次观测的差值计算。Gauge 不做累加。

三个视图放进同一个 provider

修改 provider(reader),让它返回带有所收到的 reader 和三个视图的 MeterProvider,三个视图分别是第 5 步的桶、第 6 步的属性精简,以及丢弃 debug.cache.lookups 的 DropAggregation。评分器会用 reader_all_delta() 采集两次,同时检查 orders(按 route 的增量)、checkout.duration(新边界)、cart.items 以及被丢弃的 debug 指标。先用 /opt/otel-lab/bin/python /opt/fixtures/otca_metrics_lab.py show 8 查看。

视图在创建 MeterProvider 时传入。一个 Instrument 匹配多个视图时会产生多个流,所以要为每个视图缩小对象范围。