🃏 Continuous Profiling 持续分析漫谈
date
Apr 12, 2023
slug
continuous-profiling
status
Published
tags
tech
observability
profiling
summary
漫谈就是什么都谈,又好像什么都没谈
type
Post
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fba3bcfdb-70e8-4f32-a43c-e73e766b6d71%2Fpersona5.jpeg%3Fid%3D8a63738b-bb03-4053-aecc-722d21296f4e%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DD8d3b731EHnkkwNNZM5dmh7JacsMI6dKTg0T_y9_FVw?table=block&id=8a63738b-bb03-4053-aecc-722d21296f4e&cache=v2)
What ?Profiling vs Continuous Profiling来龙去脉Why ?开源方案Pyroscope语言支持存储优化总结ParcaeBPF AgentMeta Sample 分离存储总结Phlare水平扩展分级存储总结Pixie商业软件Datadog Continuous Profiler可以细粒度控制 function 展示内容Only My Code 可以聚焦于用户代码对比图表直观清晰常用的数据聚合快捷入口Elastic Profiler?方案选型对抗赛推 vs 拉存算分离 vs 存算一体块存储 vs 对象存储eBPF vs Native Language Toolspprof vs OT总结
What ?
Profiling vs Continuous Profiling
相信各位开发老司机都给自己的程序“号过脉”,所以对于 Profiling 一定不陌生,在这里我还是搬一下 Profiling 的定义:
Profiling 是一种性能分析工具,用于确定程序或系统中哪些部分消耗了最多的资源(例如 CPU、内存、磁盘和网络)。它可以帮助开发人员找到性能瓶颈并改进代码。
而 Continuous Profiling 就是在这个基础上,增加一个“持续”,也就是在生产环境里定期跑 Profiling 并将数据上报。
通常开发者手动跑 Profiling 往往是发现了线上代码性能瓶颈后,用工具尝试复现瓶颈,而 Continuous 最大的优势就是:持续意味着贯穿整个程序的完整生命周期,不会漏掉任何一个历史上产生过的异常,能直接从数据中找到“现场”,而不是尝试复现。
用一个非常直观的比较就能迅速理解二者的差异:如果 Profiling 最有代表性展示方式是火焰图的话,那么 Continuous Profiling 的表现形式就是带有时序功能的火焰图,你可以在拖动展示、对比不同时刻的火焰图,找到代码在时间维度上的性能变迁。
![一个典型的例子](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F63089862-ccda-4eda-bc70-c6b6b63e3f29%2FUntitled.png%3Fid%3D12cfaf12-fa40-49b5-99e8-333b9af2abac%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DNvBa_nkVgWio-aDctkBY41TwiBbNYPKnafLXnv4t39E?table=block&id=12cfaf12-fa40-49b5-99e8-333b9af2abac&cache=v2)
来龙
Continuous Profiling 这个概念最早出自 Google 2010 年的研究文章: Google-Wide Profiling 。它虽然没有直接输出可用的工具,但是却给这个理念“打了样”:以较低的开销(~0.01% Overhead) 换取了大量对生产有用的代码状态数据,并且通过类 SQL 的方式查询以定位问题。
去脉
转眼到了十多年后,这期间有不少开源或商业软件涌现,但 OpenTelemetry 的加入给了 Continuous Profiling 领域一个确定的未来。
"Four pillars"
在 Monitoring, Logging, Tracing 三大支柱的工具链逐渐完善后,Profiling 将成为可观测领域新的支柱。
Why ?
借用 OT Profiling Vision 里列举的一些场景:
- 跟踪应用程序的资源利用情况,以了解代码更改、硬件配置更改和临时环境问题如何影响性能
- 理解哪些代码负责消耗资源(例如 CPU、内存、磁盘、网络)
- 为在生产中运行的一组服务规划资源分配
- 比较不同代码版本的配置文件,了解代码如何随时间改进或退化
- 在生产中检测经常使用的和“死”代码
- 将跟踪跨度分解为代码级粒度(例如函数调用和代码行),以了解该特定单元的性能
简而言之,Continue Profiling 可以帮助开发者掌握代码的“持续生产状态”。对于 DevOps 团队而言,它应该是 CD 后进行持续分析的一部分。
![CI → CD → CP](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fd7c357f0-60a3-4143-99d7-8bb5e48c4d3c%2Fci_cd_cp.png%3Fid%3D43e2167d-aba8-4f9f-adee-c2a1df9e27be%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3Dr-gEIswWSzBY4AE65an2HWBVgSqYpNjNNFSnbBt6BJc?table=block&id=43e2167d-aba8-4f9f-adee-c2a1df9e27be&cache=v2)
开源方案
Pyroscope
![架构图](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fcbb841eb-f3d2-4eb5-96d9-dbd145229387%2FUntitled.png%3Fid%3Da80d3ca9-d6bf-432d-8af5-b230ce8e316e%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DblnbYH7TUSsF6rdPuvRn45M6J9F0SHgvEqby4WQi-HI?table=block&id=a80d3ca9-d6bf-432d-8af5-b230ce8e316e&cache=v2)
Pyroscope 项目算是这个领域中最热门的种子选手了。相较于其他几个项目有这么几个显著的优势:
- UI 清晰美观,功能齐全,可以从官方提供的 demo 窥见一二
- 支持的语言广泛
- 对存储有着额外的优化
下面会针对一些有特点的优势展开说说:
语言支持
上面有提到,Pyroscope 对于 pull 和 push 模型都有着完备的支持,最大的原因就是它针对各个语言的采集工具上都做了适配,并封装成了 SDK:
- Go: pprof
- ruby: rbspy
- python: py-spy
- Java: async-profiler
- php: phpspy
- .NET: dotnet trace
- Rust: pprof-rs
即使部分语言的支持并不完美(例如 Python 不支持 Memory 数据上报),但鉴于其他项目基本都只支持 Go + pprof,在面临多语言环境时,Pyroscope 基本是开源的唯一选择。
存储优化
与其他几个项目还有一个很大的不同,pyroscope 在 profiling 数据的存储上做了额外的优化,开发者专门写了一篇 Blog 介绍了思路。在这里做下简要的介绍并分析。
首先是借助树和字典树,它针对 Profiling 的重复数据做了压缩。
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F9e702fd3-af76-4d02-8c0a-a63492cc01aa%2Fstorage.gif%3Fid%3D9338f096-d165-4d93-8c52-1f62f398c4bd%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3Dqci_qD6HLFyXY390QOTfRFtzq-3G-ocN3Z9aBwUEYE8?table=block&id=9338f096-d165-4d93-8c52-1f62f398c4bd&cache=v2)
其次,为了解决长时间跨度数据的查询延迟问题,利用线段树对数据进行了预合并。
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F933febec-2e5c-44e4-ad8a-d18c952064d6%2Fsegment.gif%3Fid%3D5a0fd51d-fc17-4e8a-b3be-79d680bc26a5%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3Dleyh2NKKh2cLwheLZQS30Z7yL8f_hs1-aLUok_9m8Hc?table=block&id=5a0fd51d-fc17-4e8a-b3be-79d680bc26a5&cache=v2)
虽然和其他项目一样,它的存储逻辑模型基本依照 pprof 定义,得益于这些优化,它在存储空间和读取延迟上都有更好的表现。但也带来了一些其他的问题:
- 为了更容易实现这些优化,存储引擎选择了灵活的 K-V 结构内嵌引擎 BadgerDB,也因此失去了更好的水平扩展能力。
- 在结构落库时需要消耗更多的 CPU 计算,压测时 CPU 更容易出现瓶颈。
总结
Pyroscope 绝对是 Profiling 领域的开源种子选手,它的长板很长(语言支持、存储优化等),同时考虑到最近被 Grafana Labs 收购,原来的短板恰好是 Grafana 团队擅长处理的,相信等待一段时间的发展,Pyroscope 有潜力成为该领域的开源标准答案。
Parca
Parca 项目是由原 Prometheus 团队的开发者开发,带有浓浓的 Prometheus 的味道。相较于其他项目,它也有几个显著的特点:
- Agent 完全采用了 ebpf 作为采集方案
- Profile Meta 和 Profile Sample 使用了两种不同的引擎存储,其中 Sample 存储采用了自研的内嵌列存 FrostDB
eBPF Agent
近几年 eBPF 在云原生、可观测领域讨论度很高,相信紧跟热点的各位读者也是早有耳闻,我在这里就不做多的赘述。Parca 最显著的一个特点就是在 Agent 上完全使用 eBPF 来解决问题。以下是一个简化的处理流程:
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fc0197489-56d8-4b57-8710-f6b517f8fcba%2FPasted_image_20230113174652.png%3Fid%3D2feb672e-1a78-4431-a03f-caa90749554e%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DqsgST7mtXC9vq4kpJk0D1afVxrKXWg5yS7H7w2mbnvs?table=block&id=2feb672e-1a78-4431-a03f-caa90749554e&cache=v2)
在 Profiling 领域,eBPF 的优劣我们会在后面的章节谈到,这里就一笔带过了。
Meta Sample 分离存储
Parca 和其他项目一样,存储的逻辑模型也是依照 pprof 的数据定义,而 pprof 逻辑模型中,按照其不同的特性,可以划分为两类数据:Meta 和 Sample。所谓的分离存储,实际上是讨论:这两类数据是否使用不同的存储引擎。
类型/特性 | 具体内容 | 是否需要计算 | 数据量级 |
Metadata | Function/Mapping/Location 等 | 很少 | 较小 |
Sample | 时序的 Stacktrace | 大量合并计算 | 大 |
由于以上特性,二者的读写需求也不同,所以顺其自然的想法就是将其分成不同的引擎存储。
方式/特性 | 开发便捷性 | 后期存储维护性 | 存储引擎选择空间 |
统一存放 | 高 | 一般 | 一般 |
分离存放 | 较低 | 高 | 高 |
相较于后期的维护性,开发便捷性的损失是一次性且短期的,且不分离的情况是不太方便针对二者特性做针对性优化的。所以 Meta / Sample 分离存储,对于服务的“长治久安”有着更好的积极意义。当然 Parca 目前在 Sample 存储上使用的 FrostDB 还未到可以直接生产的阶段,目前仅是 Parca 专用内嵌引擎。
总结
Parca 项目在 Agent 选择和存储设计上有独到之处,虽然在语言支持上比较少(Go 和有限的 Java),但仍旧可以作为方案设计上的重要参考。
Phlare
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fcb2d83a7-b7b5-4e45-8d72-0ac07fce9042%2FUntitled.png%3Fid%3D246d23eb-b5b3-40fd-b8c5-34f8b2dbffe6%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DsXd0wkIvYG27DKr1q9UEeN2TIzXYx0pA5zdfCNg41sc?table=block&id=246d23eb-b5b3-40fd-b8c5-34f8b2dbffe6&cache=v2)
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F87cd1ef9-8c30-4c64-8e0f-c2c6aa20da27%2FUntitled.png%3Fid%3D727db1ff-238b-48a4-831d-8797ccfa555e%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DH2K4WRmR3zclHG1iomzkixT3dEEIlV2Cao5VXwOES7U?table=block&id=727db1ff-238b-48a4-831d-8797ccfa555e&cache=v2)
Phlare 是 Grafana Labs 出品的 Profiling 产品,随着 Pyroscope 被收购,Phlare 项目很可能会被直接揉碎,合并到 Pyroscope 中去。即便如此,Phlare 项目仍旧有着不少有意思的亮点:
- 支持 monolithic/microservices 两种启动模式,既能满足快速验证,又能在大规模部署中轻易水平扩展
- 数据存储分层,热数据存放在 ingster 的本地块存储中,冷数据发送到远端的对象存储中,总占有成本 TCO 较低(当然是存储空间的,没有考量到对象存储发送带来的带宽成本)
水平扩展
相较于 Parca 和 Pyroscope,Phlare 总算把工程的扩展能力当作重要考量了。要知道前面二者想要水平扩展,无论是想扩展读或者写的能力,都只能将整个进程跑起来,存储走 remote write 的方式,既笨拙又浪费资源,难称优雅。而 Phlare 具备以微服务部署的能力,qureier 和 distrubutor 可以较轻松地水平扩展。
- 在存储上通过一致性哈希解决分片问题
- 通过 Gossip 解决分布式选主问题
为了更好地理解它是如何工作的,以四个 ingester 和一个位于0和9之间的令牌空间为例(来源):
- ingester#1在令牌环中注册令牌
2
- ingester#2在令牌环中注册令牌
4
- ingester#3在令牌环中注册令牌
6
- ingester#4在令牌环中注册令牌
9
当它接收到一个带有 label
{
name
="process_cpu", instance="1.1.1.1"}
的 Profile 数据时,它会将 label 内容进行哈希计算,假如这次计算后的结果是 3
。为了找到对应的 ingester,将会尝试寻找哈希环上 token 值上大于 3
最靠近的一个,即 ingester#2,并认为它将是这份 Profile 的权威数据拥有者。![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fa9b13bb1-7174-46a7-ba2e-98d9804ae94c%2FUntitled.png%3Fid%3D418f8f28-c28d-431c-9066-d18a902fc56c%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3D0Sb4NLI3WRSYMPui4V05V7dAoPNmivlFDbF_0ucrxfI?table=block&id=418f8f28-c28d-431c-9066-d18a902fc56c&cache=v2)
此时, Ingester 的副本数设置如果是 3 个,在 ingester#2 被选主后,将继续向后寻找接下来的两个实例,即 ingester#3 & ingester#4,并将数据复制分摊到他们的存储中,以保证数据能够均匀地被复制成多副本来保证高可用。
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fa86cc56a-1126-4d9d-984c-3d1ebd31c01a%2FUntitled.png%3Fid%3Db63c5b80-3d2d-4699-8fd3-fc48ed2674f0%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3D_7mqZ46BeB0FeCIQ4sFKcWssgPeDwBDjiHSxcBjxcOE?table=block&id=b63c5b80-3d2d-4699-8fd3-fc48ed2674f0&cache=v2)
分级存储
phlare 的存储流程较为复杂,主要分成了三个部分:
- head block,ingester 模块获取到数据后不会立即写入到长期存储中,而是首先放在内存
- 当 head block 大小超限或者超时,会将这些数据写到 ingester 本地磁盘
- 内存和磁盘的数据都将会周期上报到 Long term storage
这样做的好处显而易见:
- 最热的数据将在内存中被访问,速度最快
- 大量的冷数据放到了对象存储,成本更低
但也有些问题,就像上面
read path
中表述的,对象存储中冷数据的读取问题会存在延迟问题,后面在对象存储和块存储的对比环节会稍微展开。总结
Phlare 相较于 Parca 和 Pyroscope 增加了更多工程上的探索,它比后两者都更容易在大集群中部署和扩展,但它只支持 pprof Http 端点数据拉取,仅有 Go 能够被较好的支持,这也成了它没法被大规模采用的最大障碍。在 Pyroscope 被收购后,Phlare 的这些工程特点也许会被整合到前者里去,就让我们继续关注接下来会发生什么吧。
Pixie
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F04cb20ca-0d39-4887-90b1-b156b1c5e266%2FPasted_image_20230106143708.png%3Fid%3Ddf187fd9-c3d6-4b68-803f-e7015fb83b79%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DOEFWzTJUDXW07E4lytvPXXCQPgAxOJ-cqAMLgwxANHY?table=block&id=df187fd9-c3d6-4b68-803f-e7015fb83b79&cache=v2)
pixie 实际上并不是一个 Profiling 专用软件,而是一个 K8S 应用的观测工具。除了 Profiling 以外,它还包括了Service 映射、集群资源、应用流量等能力。我们这里仅关注它的 Continuous Profiling 能力。
相较于以上其他开源软件,它又有一些不同的特点:
- PxL,用于查询 SQL 不再是 PromQL like 而是 Python 风格
- 与 K8S 集群绑定较强,不适合部署在物理机的服务
- 底层使用 eBPF 采集数据,编译型语言支持更好
- 仅限于 CPU Profiling
由于它在 Profiling 领域着墨不多,功能也相对简单,这里就不做过多展开了。
商业软件
Datadog Continuous Profiler
Datadog 作为可观测的商业 SaaS 产品巨头,推出的 Profiler 产品质量非常高,由于它的闭源性,我们很难分析它具体的技术架构,仅从它产品表现来窥见一二。
以下是一些 Datadog 有别于开源产品的亮眼功能。
可以细粒度控制 function 展示内容
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F4c5de3f5-8b9f-4027-bd50-bab3528a30fe%2FPasted_image_20230209155039.png%3Fid%3D82534873-9a04-4914-904a-996da3771045%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DF2YGPrmWsxIzpCpTW4EwR6pc9CCqJ-UvL_C7j9XdwXo?table=block&id=82534873-9a04-4914-904a-996da3771045&cache=v2)
Only My Code 可以聚焦于用户代码
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F6ed74e04-7843-405b-91cf-8e46321f2378%2FPasted_image_20230209153132.png%3Fid%3D61cbf1cb-4dee-4af1-a1a9-02731bdc2aca%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DVEkaNh3jpDkgZt9mk-jxWuRAj4nzvDk6oClsPBXVV4M?table=block&id=61cbf1cb-4dee-4af1-a1a9-02731bdc2aca&cache=v2)
聚焦前
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F40bd239c-c278-41f1-b81f-07659d949145%2FPasted_image_20230209161309.png%3Fid%3Ddf84be5a-4757-4ff1-a968-281d27c40e08%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DUf5fhPYaS6dAfXY5bGvT1sNUxgoqP2iIW751-XGLgDU?table=block&id=df84be5a-4757-4ff1-a968-281d27c40e08&cache=v2)
聚焦后
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fe9f62ef1-da7f-4ee0-a7c0-a384c94cf72f%2FPasted_image_20230209161312.png%3Fid%3Dce4525d4-8926-4332-98c9-80382af68fae%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DR9pfyAeTwBjKIWMQ_6wsd3Bm2wBBD1gl0XK9wy6hUBw?table=block&id=ce4525d4-8926-4332-98c9-80382af68fae&cache=v2)
对比图表直观清晰
对比视图,通过颜色能够清晰获取不同时间的代码内存申请的异同。火焰图表现:
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fa0575373-99e8-42b4-afcf-0dd78c65b4b1%2FPasted_image_20230209162221.png%3Fid%3De357cd64-c9ea-4f5c-89f2-15397a2b2ad1%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DMhnTkEYEBWQZiicvSMF_Z9uG73mDkC0Z1cQypvPDmvE?table=block&id=e357cd64-c9ea-4f5c-89f2-15397a2b2ad1&cache=v2)
表格表现:
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F82b8c0ac-0516-4a8b-b09b-b0bf1fa7650a%2FPasted_image_20230209162359.png%3Fid%3D3461c9b1-1c57-4bec-91b3-44d2aee67f7e%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DqKqErsrK7qcDnq3i8cD6iY-fnJzw9u0nZIRQYNhvFsU?table=block&id=3461c9b1-1c57-4bec-91b3-44d2aee67f7e&cache=v2)
常用的数据聚合快捷入口
在 CPU 数据上,已经根据不同纬度提供了聚合计算快捷入口。
![notion image](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2F6b7742fe-f526-4231-b30a-158b52a32c2f%2FPasted_image_20230209161756.png%3Fid%3Dd6be32ce-df58-4312-ab16-bc40d0a7a85d%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DvXaBP6IPAahE3tLaNz9Ak1QbcgrJ-ugntd9xq5gKQZ4?table=block&id=d6be32ce-df58-4312-ab16-bc40d0a7a85d&cache=v2)
Elastic Profiler?
实话实说,实际上在本文写成的时候,笔者尚未体验过 Elastic Profiler ,这里就暂不置评,留空日后补充。
方案选型对抗赛
推 vs 拉
在可观测领域,数据获取的方向一直是热议的话题,Profiling 也不例外。以下是概要性的对比:
对比特性 | pull | push |
配置方式 | 原生中心化配置 | 端上配置,通过配置中心支持中心化 |
监控对象发现 | 依赖服务发现机制 | 由应用、Agent自主上报,无需服务发现模块 |
部署方式 | 应用暴露端口,接入服务发现,原生支持Pull协议 | 1. Agent 统一代理抓取 2. 应用主动推送到监控系统 |
指标获取灵活性 | On Demand按需获取 | 被动接受,需要一些过滤器额外支持 |
应用耦合性 | 应用与监控系统解耦,应用无需关心对端地址、错误处理等 | 与应用代码耦合 |
安全性保证 | 工作量大,需要保证应用暴露端口的安全性,容易被DDos攻击或者出现数据泄露 | 难度低,ingest 接口交互一般都有鉴权控制 |
与 Prometheus 稍有不同的是,Continuous Profiling 基本不存在短任务数据上报的场景——既然都是 Continuous 了,那肯定不短,所以 pull 场景中最大的短板——难以适配短任务——基本不存在了。同时,由于 Go 语言是该领域的绝对“第一公民”,其标准库就支持的 pprof 模块能够以极低的开发成本添加 pprof HTTP 端点,所以三大开源软件在 pull 方向的支持上都是完备的,而 push 方向除了 pyroscope,其他项目均有不同程度的“残缺”。考虑到 OT 和其他语言工具转换 pprof 的进度,这种“重 pull 轻 push” 的现象仍将在 Profiling 领域持续一段时间。
存算分离 vs 存算一体
Profiling 项目最大的技术难点就是如何处理存储,这也是可观测领域一直以来的重点。其中存算分离和存算一体的选择,决定了存储引擎乃至整个产品的形态。
在我们上面分享的几个开源产品中,它们无一例外都选择了内嵌式——也就是存算一体的方式,无论是性能较好、灵活度较高、但缺少水平扩容的 BadgerDB,还是列存 FrostDB,存取逻辑都是和计算进程绑定在一起。
在我看来,产品的服务形态是存算分离与否的决定性因素。
服务形态/存储类型 | 选择存算一体(内嵌存储引擎) | 选择存算分离(分布式存储服务) |
OSS | ● 少依赖,易部署 👍
● 针对性优化灵活 👍 | ● 额外依赖,数据优化灵活度低 👎 |
SaaS | ● 扩展、灾备方案不完善 👎 | ● 将状态向存储侧转移,组件复杂度相对低 👍
● 针对性优化难度稍高 👎 |
总而言之,产品的服务形态将很大程度上决定存储的模式。如果是偏向于 OSS 分发,选内嵌存储,如果是以 SaaS 服务为主,选专用的分布式 DBMS。当然,从具体的工程实现来说,完全可以在存储上加一个可插拔的抽象层,以适配不同的服务形态,类似这里的讨论。
块存储 vs 对象存储
在存储领域,块存储和对象存储都是非常常见的方式。
块存储(Block Storage)是将存储数据分为固定大小的块进行存储,适合于需要低延迟、高性能、高可用的场景,如数据库、虚拟机、容器等。块存储一般使用本地存储或网络存储,操作系统可以使用块设备访问。缺点在于扩展性差、价格相较于对象存储更贵,不适合存储海量数据。
对象存储(Object Storage)则是将数据存储为对象,每个对象都有唯一的标识符(URI),将数据分散到多个节点上,通过分布式算法实现高可用和容错,适合于海量数据存储和分布式存储。缺点在于读写性能较差,不适合要求低延迟和高性能的场景。
在实际 Profiling 场景下,通常会有两部分数据:
- 近期需要频繁访问的短期热数据
- 可能会存在较长时间的冷数据
从原理上来说,热、冷数据应该分别存放到块存储和对象存储中,类似上面提到的 Phlare 方案,而不是一股脑放到块存储(Pyroscope OSS 的做法)或者全部放到对象存储(好像也没人这么做)。
即使 Phlare 的方案看起来很合理,但它依旧是内嵌型存储,目前还没有一个比较成熟的分布式 DBMS 支持这样的特性。Pyroscope 在其云服务中也放弃了原来的内嵌式 K-V 存储,而转向了借用 Parquet 的分布式存储 Tempo 方案(来自其 blog),在保证后端存储针对性优化的同时,利用类似 Thanos objstore 的方案实现了利用对象存储的扩展能力,遗憾的是尚未将这部分代码开源,也无法研究其内部细节了。
eBPF vs Native Language Tools
Profier 是 Profiling 数据来源的基础,上述不少产品中都采用了 eBPF 作为采集方案,那么是否只要使用了 eBPF 就代表着开销更小、数据更全呢?并不全是,Pyroscope 的这篇 blog 给了我们一个比较客观的对比。首先从数据来源的层级来看,可以将 Profiler 分为两类:
- 用户态: 流行的性能分析工具,如pprof,async-profiler,rbspy,py-spy,pprof-rs,dotnet-trace等,都在这个层面上运行。
- 内核态: 基于 eBPF 的各种 Profiler 封装和 Linux perf 工具可以从内核获取整个系统的堆栈跟踪
由于数据来源的层级不同,它们各有长短。
对于用户态的工具而言:
- 可以非常灵活的标记用户的应用代码(例如 标记 spans, controllers, functions)👍
- 能够分析代码的各个特定部分(例如 Lambda 函数、测试套件、脚本)👍
- 有着更容易分析其他类型数据的能力(例如内存、goroutines)👍
- 本地开发十分便捷,容易使用 👍
- 复杂,如果一个系统是多语言的,很难获取一个全局视图 👎
- 对于基建元信息的标识能力有限(例如 Kubernetes) 👎
对于内核态的工具而言:
- 非常容易就能获取到跨语言的全局视图 👍
- 很容易对基建元信息进行标识能力有限(例如 Kubernetes Pods) 👍
- 所有语言在符号化上都是一致的 👍
- 对 Linux 内核版本有要求 👎
- 用户层级的代码比较难标记 👎
- 内存、goroutines 很难获取对应数据 👎
- 开发者想在本地开发比较困难 👎
- 解释器型的语言获取的信息较为有限 👎
简单来说,这两种方案的方向是反的:自下而上和自上而下,它们的数据信息理应做到互相补充,现阶段仅有 Pyroscope 对它做了有限的整合优化,需要进一步关注进展。
pprof vs OT
pprof 本身是一个开源的性能分析工具套件,它可以抓取并组装 CPU、内存、goroutine 等性能数据,并且通过配套的工具可以生成各种可视化视图,例如火焰图、调用图等。
同时 pprof 也定义了相关的 Profile 数据格式,以 Protocol Buffers 呈现。它由一系列的记录 Sample 组成:包含了函数调用堆栈以及相应的计数器值。
以下讨论的 pprof 指的是其代表的数据格式。
可以通过它的文本表达示例或者下面这张图理解其中的关联关系(除了 Stacktrace 是额外抽象出来的中间表)
![基本对齐 pprof 模型的列存数据表,来自 Phlare](https://www.notion.so/image/https%3A%2F%2Ffile.notion.so%2Ff%2Ff%2Fb0a64676-90b9-4734-9c63-2d704ee573b6%2Fa436eddf-7b62-4cff-b8ed-d0b14037d1ca%2FUntitled.png%3Fid%3D5e17dafb-13e4-4533-b6ad-eb6703c1e3e1%26table%3Dblock%26spaceId%3Db0a64676-90b9-4734-9c63-2d704ee573b6%26expirationTimestamp%3D1713952800000%26signature%3DJRdH2YK6EGpPWw4mYfd2FMSOomkc5OMMrtwXhcOGbLo?table=block&id=5e17dafb-13e4-4533-b6ad-eb6703c1e3e1&cache=v2)
pprof 在设计上是跨语言的,它理应成为一个跨语言标准,但受限于历史的进程,大多数语言的采集工具比它的历史更久,各种工具和采集链已经较为成熟,所以,除了 Go 语言有着极好的 pprof 支持,其他语言都没有成熟的 pprof 格式转换方案(例如 Python 虽然有,但缺乏维护)。这中间的沟壑既给了 Pyroscope 较多的对接工作量,也给 OT 的标准化留足了空间。
Open Telemetry 预期将 Profiling 格式做一个标准化,包括了非常多的工作内容:
- 尽可能多兼容各种 Profiling 格式
- 应尽可能高效地传输分析数据,并且制定一个无损的 Profiling 模型,重点在于解析、转码(与其他格式之间的转换)和分析的效率上
- 应该可以清晰地映射到标准数据模型(例如 collapsed、pprof、JFR 等)
- 应该包含表示其他 OT Signal 之间关系的机制(例如 span 中的调用链)
- 对于已经流行的 Profiler,保持尽可能小的转换开销
OT 的愿景是非常美好的,但从可观察的进展来说,并不是非常顺利,至少距离上一次有效的更新已经过了几个月了。所以,现阶段在没有 OT 标准化格式之前,pprof 仍旧是 Profiling 数据格式为数不多的选择。
总结
Continuous Profiling 是一个不新不旧的领域,有着不大不小的市场,伴随着可观测领域常见的问题。在 OT 标准化前,Pyroscope 算是领先了一个身位,但各产品仍处于百舸争流的阶段,需要 Continuous Focusing 。