Perfetto数据流架构故障分析:带你研究 trace 为何丢失

在系统工程师的日常工作中,最苦恼的事情之一就是分析问题所依赖的可观测性数据出现了错误。“这该死的玩意儿又出错了!” 在面对新工具出现的新问题时,工程师们在愤懑之余免不了怀念旧时的荣光:那时的调试工具设计精巧,API 简明易用,如老伙计般地可靠。

然而随着新系统、新编程语言和新编程框架的不断发展,可观测性工具也在不断地推陈出新,"good old days" 早已一去不复返了。可观测性领域的技术虽并未产生大的革新,但是工程师们在观测数据的采集方式和分析方式上做了大量的工作,Perfetto 就是 Android 领域的后起之秀之一。

Perfetto 为自己标榜了开源、稳定且高效的跨领域系统跟踪和分析平台这一头衔,也为其自身的架构设计指出了明确的目标。在这篇文章我们暂且放下“观测工具”们自身的发展历史不谈,谈谈其数据编码与传输(后文简称 Data Flow)的架构设计,并从这个角度解释其可能存在数据丢失的诸多原因,并提出相应的解决(或者规避)建议。

Note:对 Perfetto 架构不感兴趣的伙伴可以直接跳转至 PART 4 章节,获得减少 Perfetto 使用故障的具体建议。

前言 - 数据传输系统的设计理念  

如何将数据从一侧搬至另一侧的基本设计理念从来都不是秘密,这就如同我们在现实生活中订购产品送到家的过程。

通常我们在使用这类服务的时候只需要考虑 3 方面的因素:

  • WHAT:订阅什么产品

  • WHEN:什么时候收到

  • WHERE:在什么地点收货

除此之外的诸多细节我们统统都不关心,我们提供了必要的信息来描述需求,供应商、物流公司设法为我们解决过程中需要处理的诸多麻烦事儿。

大多数时候机制都是运转良好的:商品总是供应充足,快递总能按时到家,很难遇到意外的情况发生,我们不需要操心整个过程是如何完成的。但是当错误的事情开始发生时(例如产品没有送到家,或是收到了错误的产品),我们就会陷入一种沮丧的情绪中:我们知道有问题,但是不知道该找谁的麻烦。这种沮丧的情绪就如同工程师遇到了不太合作的系统可观测工具,此时人类的情感是共同的。

为什么 trace 会漏掉了我们关注的时间发生的系统状态?为什么 Perfetto UI 上的 trace event 会层层叠叠地延伸至屏幕的两端?造成这一切的根源都来自于不同程度的“权衡利弊”。    

毕竟可使用的资源总归是有限的,而在系统里有不止一个生产者、物流和消费者,任何一方都有可能成为瓶颈。“物流公司”的运输可能会延迟后丢失,“产品供应商”也可能会爆单,来自消费者的需求也可能不足。只要我们设法触达了这套系统的中的诸多瓶颈,那么权衡利弊的策略就会在各个环节发生。

ca20866d7cab0f7028aa20f3dac8b64d.png

在生产者 & 运输者 & 消费者 组成的一个供销系统下,每一方都会为了自身效率的最大化而添加很多非必要的中间环节。例如:物流公司可能会为货物增设中转站,以提前备货来缓解消费者的需求旺盛使得某些货品的物流压力骤增。

PART 1 - 基本理念:生产者,消费者,以及 IPC 通讯  

现在让我们将目光拉回到 Perfetto 本身。我们已经知道了 Perfetto 希望成为一个拥抱开源、支持跨平台跨领域的系统跟踪和分析框架,那么在这个框架下生产者、消费者和 “物流公司” 分别有哪些?从官方提供的示意图中我们可以窥知一二:    

396b849f851a2f6d93afb44bea746b8e.png

  •  数据生产者:如图绿色框所示。生产者可以是多个进程,且每个进程可以同时供给不同的数据类型。

  • 数据消费者:如图黄色框所示。在一个数据跟踪会话中只存在一个消费者进程。对于 Perfetto 来说,Traced 只能算是一个代理消费者。代理消费者仅仅将数据放置在自己的 Buffer 中,并可以与真正的消费者协商数据的处理方式:是定期读取 buffer 数据做持久化存储?还是将数据重定向至新的 IPC 通道?

  • 数据传输:如图蓝色框所示。数据传输分为信号传递和数据交换两个过程,发生在生产者进程和消费者进程之间。

Perfetto 的跨平台数据跟踪能力,是以 Data source 的 ABI/API 协议来定义的。无论是 Chrome 浏览器内核,还是 Android 或 Chrome OS 操作系统,都可以在遵循这套协议的基础上将自己注册为 Perfetto 的数据生产者。

以 Linux ftrace 为例:Perfetto 在 Android 操作系统中如何将 ftrace 作为其数据源?从上图灰色框部分可以看到 ftrace 在每个 CPU core 中已有对应的 ring buffer,在兼容已有 ftrace 框架的基础上,Android 系统启动了 traced_probes 进程来定期读取 ftrace buffer 数据并将其序列化为 perfetto 支持的二进制格式。由于 traced_probes 在启动阶段已经注册为了 Perfetto 的 Data source,因此消费端在启动一个跟踪会话时只需要告知 Perfetto 订阅 linux.ftrace 这个数据源即可。    

PART 2 - 权衡利弊:观测开销 vs 传输可靠性  

可观测工具的使用是有成本的。如下表展示了在前台随机启动应用 60 秒的过程中,相关可观测工具进程的 CPU task 运行时间的统计:

process_name

pid

uid

cpu_time_ms

cpu_time_perccent

/system/bin/traced_probes

2376

9999

11013.04

2.294383

/system/bin/logd

1034

1036

6801.802

1.417042

logcat

3756

0

4545.653

0.947011

/system/bin/traced

2386

9999

2064.368

0.430077

/apex/com.android.os.statsd/bin/statsd

1506

1066

1124.588

0.234289

logcat

7330

[NULL]

11.8526

0.002469

从上表数据可知,无论是 trace 相关的进程(tracd, tracd_probes)还是 log 的进程(logd, logcat)或是 metrics 采集进程(statsd)都会引入一定的性能开销。随着需要记录或存储的数据流量越来越大,工具本身可能引入的开销也逐渐膨胀。

我们希望观测工具所带来的 “观察者效应” 能够尽可能地消除。除了约束数据的生产者生产数据的速度,观测工具还会绞劲脑汁地优化观测数据的 data flow 中所有可能引入系统负载的代码流程。

Perfetto 采用了共享内存 Buffer 的方式来减少跨进程的数据拷贝所带来开销,并采用 buffer 的分区写入方案实现了生产者在并行生产数据时的数据同步开销。

Central Buffer 映射  

如 PART 1 所述,Perfetto 为 trace 会话设置了一个代理的数据消费者,这个代理消费者位于 Traced 进程内,负责将生产者产生的数据拷贝至独立的 Central Buffer 中。Central Buffer 需要设置合适的大小,以缓冲特定生产者发送的数据包。    

buffer 与 生产者可以建立明确的映射关系:               
eaf640278d22532f14e350c04197d5e1.png

权衡利弊 1:生产者生产数据的速度是有差异的,因此依照数据生产的吞吐率来为其映射合适的 Central Buffer 可以保证 buffer 的填充速率相对一致:生产较快的数据源使用更大的 Central Buffer,而生产较慢的数据源应当映射到一个更小的 Central Buffer。同时对于更 “重要” 的生产者生产的数据,最好也为其设置独立的 Central Buffer,以免受到其它生产者的干扰。

生产速度不一致的数据生产者如果不进行 buffer 隔离,可能会出现互相挤兑现象。假使我们仅仅分配一个 Buffer 供 A,B,C 三个生产者共用,在预期的状态下,Buffer 按照 RING BUFFER 模式进行数据的存储和覆写,如下图所示:               
c639625be56241314d6656c473921c76.png                
此时三位生产者生产数据的频率和数据的大小近似,在 Buffer Size 的限制窗口内我们可以观测到来自三个生产者的数据。               
当生产者 A 的数据包大小或生产速度突然加快时,RING BUFFER 模式将会挤占 buffer 中记录的来自其它生产者的数据包并使其快速丢失,如下图:               

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OPPO内核工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值