

一些网友都想知道关于性能分析-火焰图概述和一些保时捷718插件相关话题,接下来让小编详细讲解吧!
后台性能分析历史发展
2010年,Google发表了一篇非常重要的论文,名为Google-WideProfiling:AContinuousProfilingInfrastructureforDataCenters[1],提出了一种连续性能分析基础设施,可以对大型服务和集群进行大规模分析。这种新的性能分析方法可以提供准确可靠的性能分析结果,同时保持较低的性能开销。
从那时起,出现了许多商业或开源持续性能分析实现,包括GoogleCloudProfiler[2]和Pyrscope[3]。如今,性能分析已成为可观察性的另一个支柱。
为什么需要性能分析?
可观察性的三个传统支柱,即链接跟踪、指标监控和日志记录,都有共同的局限性。这意味着它们受到性能因素和实现方法的,并且数据往往是通过预先提供的规则和埋点生成的。例如,OpenTelemetry和SkyWalking等开源观测解决方案提供的大多数插件都专注于广泛使用和积极维护的SDK,而插件本身通常只提供关键代码路径的埋点。那么,如果性能瓶颈出现在一段没有被埋没的代码中,那么就很难发现题了。举一些简单的例子,以下场景可能无法识别性能瓶颈
两个连续范围之间的时间间隔变长。
长期运行的Span没有子Span结构。
业界有许多尝试来解决链接跟踪的局限性。
从SkyWalking70开始,社区提出了一种基于链路追踪的性能分析方法,称为TraceProfiling[4]。在最近发布的SkyWalking-Java815版本中,TraceProfiling得到了进一步的改进,并且具有跨线程分析功能[5]。这允许开发人员持续监视特定接口的线程方法堆栈,以推断方法执行需要多长时间。
ElasticAPM支持将JFR采样数据与链路跟踪相结合进行性能分析,称为基于采样的分析器[6]。这是一项实验性功能,目前处于技术预览阶段。
上述方法可以解决一些具体题。但持续性能分析不仅仅如此它可以分析应用程序的调用方法堆栈和CPU使用情况,以及监视对象分配并锁定虚拟机上的争用。此信息对于诊断应用程序性能瓶颈非常重要。
开源社区也有类似的想法,例如SkyWalkingRover提供了基于eBPF的通用性能分析功能,允许开发者对Linux环境下常见的二进制程序进行性能诊断(例如网络性能、CPU上的性能)。允许您这样做。/CPU外部分析等
本文不会涵盖与eBPF相关的性能分析,但将重点关注与该语言相关的正在进行的分析工作。
建筑设计
在介绍设计之前,我们先简单回顾一下一些概念。
JFR:Java飞行记录仪
JFR文件可以简单地理解为事件的集合。JFR文件包含多个事件。通常,一个事件包含此信息。下图是使用JDK原生方法读取
Java:异步分析器
async-profiler[7]是一个低开销的Java采样分析器,它使用虚拟机HotSpot的特殊API来收集堆栈信息和内存分配信息。与大家熟悉的Arthas一样,它可以集成到Java-Agent中并用于收集JFR事件。支持直接创建JFR事件文件或将其转换为SVG格式的火焰图进行输出。
火焰图
FlameGraph是BrendanGregg提出的可视化程序性能分析工具。将堆栈信息转换为可视化图表,以便开发人员可以更好地查看和理解这些信息。
FlameGraph从全局角度看待时间分布,从下到上列出了所有可能造成性能瓶颈的调用堆栈。一般来说,我们应该关注正方形的宽度,它代表调用堆栈在整个采样历史中出现的次数。通常,性能瓶颈出现在大宽度顶部矩形中。了解这一点可以帮助开发者快速找到性能瓶颈。
本节我们主要介绍从创建用户的FlameGraph任务到创建FlameGraph的整个流程。
当用户在Web控制台中创建性能分析作业时,这些作业将持久保存到ElasticSearch等存储中。
根据async-profiler的功能,系统支持创建两种类型的任务
客户端对HTML的分析适合简单的分析场景
服务器端分析JFR适合更复杂的分析场景,例如多种事件类型。用户可以下载JFR在本地进行深入分析。此实现对客户端的性能损失非常小。例如,如果客户端分析堆内存分配,而内存使用率很高,则客户端分析很容易出现OOM。
客户端程序中的Java-Agent程序定期向gRPC接口查询需要执行的任务,获取任务后开始执行。这意味着您可以根据任务使用不同的命令启动async-profiler。发布。作业执行完成后,生成的文件将上传到服务器。
服务器收到文件后,根据不同的文件类型执行不同的逻辑。
当服务器收到客户端分析FlameGraph结果的HTML格式文件时,将其直接存储在对象存储服务中。
当您收到JFR格式的文件时,存储完成后,会读取JFR文件并进行分析,并将得到的树结构存储到ElasticSearch中,以方便后续分析。这一阶段的分析过程将在下一章详细解释。
对于服务器端分析任务,用户可以从Web界面执行分析。此时,服务器从ElasticSearch检索一组预先分析的树,然后将这些数据渲染回前端。系统前端使用pyrscope-flamegraph组件将数据转换成火焰图进行显示。您可以在我们之前的阿里云相关文章[8]中找到更多关于前端显示组件的详细信息。
真实性能分析使用JFR+火焰图优化JFR文件分析
我们使用一个示例来演示如何使用JFR事件和生成的火焰图来优化JFR文件读取和处理。我们使用IDEAProfiler进行性能分析。
初始实现JDK原生JFR阅读器
在系统设计初期,直接使用JDK内置的JFR模块一次性读取文件中的所有事件并依次处理。
该方法在事件量不大时性能正常,单机和端到端测试均未发现题。但是我们在和业务团队对接进行压测的时候,遇到了大量的对象分配事件,这在处理上会带来两个题。
内存使用量非常高,包括读取JFR文件本身的开销以及事件被反序列化并存储在内存中的开销。
分析速度非常慢GC压力、序列化/反序列化、树结构搜索/插入等。
使用火焰图分析该程序,
CPU时间消耗分析
内存分配分析
从图中可以看出,CPU时间消耗和内存分配主要集中在insertStackFrames方法中。方法是将JFR事件的StackTrace序列化成一个ListstackString,然后通过二分查找的方式插入到Tree中以保证排序。
优化尝试批处理
由于上面单次读取分析的事件量非常大,所以我们首先想到的是使用Iterable,利用迭代器的思想,每次批量读取并处理固定数量的事件。1,000。我们的期望是内存的最大使用量将会减少。
随后的测试证实了我们的测。但是,由于我们正在进行批处理,因此在处理过程中总是会打开非常大的文件。结果,分析期间最大内存使用量有所下降,但整体仍维持在较高水平,分析速度并没有明显提升。
在确定JDK默认的JFR阅读器无法满足我们的性能要求后,我们开始寻找替代的处理方法。
参见Pyrscope的JFR解析方法。经过压力测试,pyrscope-io/jfr-parser的内存使用情况和分析速度都不尽如人意[9]。然而,多块处理方法给了我们新的想法。
我正在寻找另一种阅读JFR的方法。
优化使用对象引用和惰性序列化
研究async-profiler的源代码后,我发现它并不包含每个事件的完整StackTrace,而是将所有StackTrace存储在字典中,并且每个事件通过stackTraceId与StackTrace关联。这里的StackTrace并没有完全序列化为Java对象,而是包含对其他对象ID的引用。
公共类StackTrace
从图中可以看到,240万个事件只包含3万个StackTrace,这种低级读取方法可以显着减少内存使用。
优化聚合插入
Pyrscope的处理方式是,在遍历每个事件时,将对应的StackTrace存储为字符串List。
对于性能分析-火焰图概述的相关信息,以及保时捷718插件的详细内容,今天就解到这里了,希望对大家有所帮助。
发表评论