新功能:SLS支持持续性能数据采集与监控

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 降本增效的背景下,提升资源利用率变得更加重要,SLS 新功能持续性能数据采集与监控助力开发者突破性能瓶颈,定位系统顽疾。

遇事不慌,先问ChatGPT

小王所在的公司最近在做降本增效,要求上半年每个人的微服务接口性能提升至少30%。小王思虑很久也没想到优化点,于是开始向ChatGPT寻求帮助,提问“如何定位性能问题”,ChatGPT 给出了3个答案。

第二个与第三个答案是本质同样使用时间模块记录程序函数的运行时时间,而这对于开发者来说,这可能是最为熟悉的方式,如下所示,使用4条Log 来定位性能瓶颈出现的性能范围,但这对于线上服务来说,不断地Log定位方式也意味着不断地重启,风险是可能带来不断地业务损失,但是更坏的一个问题是如果线上产生死锁等问题,重启也意味着”案发现场“的丢失,这也为下次问题的再次出现埋下隐患。

2023-03-17 15:55:01 [INF] outer function start
2023-03-17 15:55:10 [INF] inner function start
2023-03-17 15:55:13 [INF] inner function end
2023-03-17 15:55:30 [INF] outer function end

而ChatGPT 的首推答案也指出可以使用性能分析工具来帮助开发者定位瓶颈问题,随着软件工程的演进,性能分析工具的地位也愈加上升,对于一些新出现的编程语言,如Golang,性能诊断已经成为语言标准库的一部分。

什么是性能采集?

对于前端开发者来说,Chrome 浏览器中的性能分析可能是最为直观的性能采集,下图中Chrom记录加载网页每个事件的时间戳和持续时间,包括JavaScript函数执行、网络请求和渲染过程等。而这些数据也为前端开发者寻找网页性能瓶颈与定位优化点提供了依据。

以下内容将介绍常见的CPU 与内存 性能采集的基本原理,了解为什么性能采集是“统计值”而不是精确值。

CPU 性能采集基本原理

以CPU 性能Perf采集为例,如下图所示,实线代表某单核CPU 的持续运行所经过的时间,而pid/func1、pid/func2 以及pid/func3 表示在此段运行时间内此单核所经过的函数,当每隔一段时间产生一个中断(箭头处),此单核CPU必然执行于某一具体的函数。对于下图来说,可以产生如下统计结果,根据命中率计算可知,在采集时间段内pid/fun3花费了此核CPU的62.5%。对于一般的程序CPU 中断的间隔一般为100ns,从上述基本原理可知,当CPU 采样时间越大,中断间隔忽略的函数越多,因此CPU 性能采集是统计结果,可能存在误差。

函数

中断命中次数

占用CPU比率

pid/fun1

1

6.25%

pid/fun2

5

31.25%

pid/fun3

10

62.5%

内存性能采集基本原理

与 CPU 性能采集原理不同的是,内存性能数据因为要拿到具体的分配数量,因此内存性能采集的通常做法是将工具集成到内存的分配器中,当语言进行内存分配时,拿到当前的函数调用栈,最终将样本聚合,便可推算出函数的内存分配了。以下代码为GO语言的内置Profiling行为,当开启Profling后,每次功能mallocgc 分配512K大小内存,便触发一次profilealloc函数记录分配行为。

func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
    ...
    if rate := MemProfileRate; rate > 0 {
     // Note cache c only valid while m acquired; see #47302
     if rate != 1 && size < c.nextSample {
      c.nextSample -= size
  } else {
      profilealloc(mp, x, size)
  }
 }
    ...
}
func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
    c := getMCache()
    if c == nil {
     throw("profilealloc called without a P or outside bootstrapping")
 }
    c.nextSample = nextSample()
    mProf_Malloc(x, size)
}

如下图所示,实线代表某单核CPU 的持续运行所经过的时间,而pid/func1、pid/func2 以及pid/func3 表示在此段运行时间内此单核所经过的函数,每个箭头处表示一次内存分配,但由于默认512K记录一次分配行为,因此可以产生如下统计结果,第一次与第二次malloc行为因为分配不满足512K记录大小规则,因此跳该过记录,如将MemProfileRate设置为1,可以完全精确的记录每一个函数的内存分配,但是性能开销带来的成本是巨大的,因此内存性能采集也同样是统计结果,可能存在误差,因此Profling程序一般并不是采用上述512K的固定值进行,而是以512K为平均值的指数分布中随机取一个值,降低误差影响。

函数

分配次数

pid/fun1

1

pid/fun2

1

pid/fun3

2

为什么需要持续性能分析?

性能采集带给开发者分析程序性能的工具,开发者可以清楚的了解性能采集时刻的CPU 或内存的分布,通过分析这些数据,开发者可以快速定位程序性能瓶颈问题。但现实情况可能更加复杂,应用的部署结构已经从单体结构走向微服务结构,并且随着云化浪潮,部署也存在着多云、多Region、多架构机器等诸多行为。因此宏观的角度分析服务的性能变得更加重要,这也就意味着性能采集多了一个新的维度“时间”,当有了时间维度,性能采集便成为了持续的性能分析,这也意味着分析从单体分析变成了高纬度的对比分析,也让以下场景的性能分析成为了可能。

场景

性能采集

持续性能分析

对比某服务测试环境与生产环境的性能差异

N

Y

对比某服务版本1.0 与版本2.0 性能差异

N

Y

对比某服务在Arm 服务器与Amd 服务器性能差异

N

Y

对比某服务在北京地域与杭州地域服务的性能差异

N

Y

......

SLS 持续性能数据采集与分析

SLS 持续性能分析为开发者提供开放、一站式性能持续分析平台,目前已经对于Pyroscope 开源SDK 或Agent 完全兼容,后续SLS 持续性能分析会持续拓展接入兼容性,如支持对原生Golang Profile接口的采集或对Datadog Profling SDK 等接入的兼容。

性能数据存在着不同的协议,如pprof、JFR、Tire 等,不同协议对性能数据的承载能力不同,如Tire 协议一般仅承载CPU 性能数据,而pprof 可承载cpu、memory、mutex、goroutines 等多种性能数据,下文将使用基于pprof 协议的Go 语言样例介绍SLS持续分析的功能。

类型

Go

Java

NodeJs

Python

CPU时间

分配堆

争用

线程

实际时间

数据探索

在SLS 持续性能分析的数据查询界面,开发者可以选择关注服务性能类别与时间后,整个数据查询探索界面会通过火焰图与表格两种方式显示性能数据,下图展示了Go的一个demo 程序在CPU性能分析下的样例。但对于持续性能分析更重要的是价值是更高维度的数据探索,因此SLS 持续性能分析支持通过动态标签组合满足开发者对性能数据的高纬度探索需求,如下图所示的性能查询条件为进行sls-mall 集群下、test环境、version1版本的性能分析。

对于持续性能分析,时间维度的加入也就意味着可以进行更多的性能数据的对比,在在SLS 持续性能分析探索界面,开发者可以轻松的选择对比性能的时间范围,通过火焰图或者表格方式进行数据探索,如下图为对比Go Demo 程序过去一小时性能与当前性能的差异,通过灰色颜色可以快速得知,服务性能没有明显变化。

  • 灰色: 代表性能性能相近
  • 红色:代表性能下降,颜色越深代表性能下降越严重
  • 蓝色:代表性能提升,颜色约深代表性能上升越多

当然性能对比界面也同样支持利用动态标签组合的方式满足满足开发者对性能数据更高的对比需求,如下图展示了相同服务不同版本的性能差异。

优化案例

小王公司待优化的服务为一个gRPC服务,在限定资源(CPU限制为250m核,内存限制为50M),小王使用日志方式打印了压测下此服务待优化接口性能,发现QPS 仅仅在30左右。

CPU 优化

  1. 定位问题

小王将此服务接入了SLS 持续性能分析发现有一个内部库函数regexp.MatchString消耗了应用程序的大量CPU性能。

  1. 分析问题

小王发现此程序的业务逻辑为计算存储文件行包含输入字符串的数量,使用regexp.MatchString进行匹配,但此行为并未涉及复杂的正则提取,字符串包含操作已经可以满足业务需求,且相比于正则匹配,字符串匹配的算法复杂度更低,因此小王进行了下面的优化。

  1. 性能对比

小王将此优化版本标记版本为version2,通过SLS 持续性能对比界面分析此次"小" 改动的带来的性能差异,下图展示了 version :1version:2(CPU 优化后)的差别,浅蓝色代表部分优化,深蓝色代表全部优化,小王发现经过对正则表达式的优化,上层函数耗时竟然下降77.29%。

  1. 验证优化

小王再次打开自己最初打印的QPS 统计日志,发现同等资源条件下,程序10次平均QPS 提升到1399左右,接口性能得到接近40倍的性能提升,小王出色的完成了公司提出的降本增效任务。

内存优化

  1. 定位问题

小王出色的完成了公司降本增效的认为后,公司领导很高兴,提出能不能把程序的内存也优化一下。小王公司的程序为Go程序,GO的内存性能指标分为alloc_objectsalloc_spaceinuse_objects以及inuse_spacealloc_*指标为从程序启动到目前分配的大小或数量,可以帮助定位频繁分配对象的方法,降低Go程序GC 压力,inuse_* 方法是内存中存在的对象大小或数量,可以帮助定位内存泄漏等问题。小王继续通过SLS 持续性能分析来分析上述4类指标。小王通过对不同指标的查看,发现服务alloc_space指标存在异常,大量内存分配行为都存在于标准库strings.split函数。

  1. 分析问题

小王通过对业务逻辑的梳理,基本逻辑为从本地文件读取文件全量数据,之后按行进行切割,接着与输入进行字符串进行匹配比较,按行切割时存在大量小字符串分配,通过slice 偏移量截取字符串对比,可以避免大量小字符串的分配与释放,因此小王进行了如下优化。

  1. 性能对比

小王将此优化版本标记版本为version3,通过SLS 持续性能对比界面分析此次改动的带来的内存性能差异,下图展示了 version :3version:2(CPU 优化后)的差别,浅蓝色代表部分优化,深蓝色代表全部优化,小王发现经过对本次字符串优化,核心函数空间分配下降59.46%。

小王推测内存分配空间的减少也就意味对象分配时间与GC 时间的减少,因此推测本次优化可能还会带来性能的提升,因此继续使用CPU性能对比查看CPU 性能的变化,小王发现CPU 性能确实得到了19.71%的性能提升。

  1. 验证优化

小王再次打开自己的QPS 统计日志,发现同等资源条件下,验证第二次性能优化的结果,程序10次平均QPS 提升到1840左右,性能再次获得了30%的提升。

优化回顾

上述案例中小王的2次优化,第一次是对正则的优化,第二次是对字符串使用的优化,都是对标准库的使用优化,这样的问题可能也潜藏在每一位开发者的程序中,通过SLS持续性能分析的查询、聚合、对比能力,可以快速的定位应用程序潜藏的顽疾。

展望

SLS性能持续分析基于开放的接入生态与持续性能分析的理念所构建(开放接入部分已在iLogtail开源),基于SLS 性能持续分析,将为广大开发者提供开箱即用、一站式的的性能观测体验,助力开发者轻松面对多云、多Region、多版本、微服务等场景下的性能分析需求,目前已经发布部分地域, 欢迎大家试用与交流。在后续的版本中,我们将为开发者提供更为便捷、丰富的性能监控接入渠道,更强大的性能分析体验。

  • 更多开源Agent与SDK 兼容,如Datadog 等。
  • 更多无需集成SDK 的接入方式,如Golang下的主动抓取采集等。
  • 在交互分析上,提供更便捷、性能更高的迷你图划线对比。
  • ...

参考文档

Linux下做性能分析:perf

Google-Wide Profiling: A Continuous Profiling Infrastructure for Data Centers

Profiling concepts bookmark_border

What is continuous profiling?

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
7天前
|
存储 调度 C++
16 倍性能提升,成本降低 98%! 解读 SLS 向量索引架构升级改造
大规模数据如何进行语义检索? 当前 SLS 已经支持一站式的语义检索功能,能够用于 RAG、Memory、语义聚类、多模态数据等各种场景的应用。本文分享了 SLS 在语义检索功能上,对模型推理和部署、构建流水线等流程的优化,最终带给用户更高性能和更低成本的针对大规模数据的语义索引功能。
|
1月前
|
Prometheus 监控 Cloud Native
基于docker搭建监控系统&日志收集
Prometheus 是一款由 SoundCloud 开发的开源监控报警系统及时序数据库(TSDB),支持多维数据模型和灵活查询语言,适用于大规模集群监控。它通过 HTTP 拉取数据,支持服务发现、多种图表展示(如 Grafana),并可结合 Loki 实现日志聚合。本文介绍其架构、部署及与 Docker 集成的监控方案。
295 122
基于docker搭建监控系统&日志收集
|
1月前
|
Prometheus 监控 Java
日志收集和Spring 微服务监控的最佳实践
在微服务架构中,日志记录与监控对系统稳定性、问题排查和性能优化至关重要。本文介绍了在 Spring 微服务中实现高效日志记录与监控的最佳实践,涵盖日志级别选择、结构化日志、集中记录、服务ID跟踪、上下文信息添加、日志轮转,以及使用 Spring Boot Actuator、Micrometer、Prometheus、Grafana、ELK 堆栈等工具进行监控与可视化。通过这些方法,可提升系统的可观测性与运维效率。
197 1
日志收集和Spring 微服务监控的最佳实践
|
1月前
|
存储 缓存 监控
用 C++ 红黑树给公司电脑监控软件的日志快速排序的方法
本文介绍基于C++红黑树算法实现公司监控电脑软件的日志高效管理,利用其自平衡特性提升日志排序、检索与动态更新效率,并结合实际场景提出优化方向,增强系统性能与稳定性。
65 4
|
6月前
|
监控 测试技术 Go
告别传统Log追踪!GOAT如何用HTTP接口重塑代码监控
本文介绍了GOAT(Golang Application Tracing)工具的使用方法,通过一个Echo问答服务实例,详细展示了代码埋点与追踪技术的应用。内容涵盖初始化配置、自动埋点、手动调整埋点、数据监控及清理埋点等核心功能。GOAT适用于灰度发布、功能验证、性能分析、Bug排查和代码重构等场景,助力Go项目质量保障与平稳发布。工具以轻量高效的特点,为开发团队提供数据支持,优化决策流程。
403 89
|
9月前
|
存储 运维 监控
日志服务SLS焕新升级:卓越性能、高效成本、极致稳定与智能化
日志服务SLS焕新升级,涵盖卓越性能、高效成本、极致稳定与智能化。新功能特性包括Project回收站、ELasticsearch兼容方案及全链路数据处理能力提升。通过扫描计算模式和数据加工优化,实现更好的成本效果。案例分析展示了一家国内顶级车企如何通过日志服务实现跨云、跨地域的全链路数据处理,大幅提升问题处理效率。
231 9
|
6月前
|
消息中间件 运维 监控
智能运维,由你定义:SAE自定义日志与监控解决方案
通过引入 Sidecar 容器的技术,SAE 为用户提供了更强大的自定义日志与监控解决方案,帮助用户轻松实现日志采集、监控指标收集等功能。未来,SAE 将会支持 istio 多租场景,帮助用户更高效地部署和管理服务网格。
491 52
|
7月前
|
数据采集 运维 监控
数据采集监控与告警:错误重试、日志分析与自动化运维
本文探讨了数据采集技术从“简单采集”到自动化运维的演进。传统方式因反爬策略和网络波动常导致数据丢失,而引入错误重试、日志分析与自动化告警机制可显著提升系统稳定性与时效性。正方强调健全监控体系的重要性,反方则担忧复杂化带来的成本与安全风险。未来,结合AI与大数据技术,数据采集将向智能化、全自动方向发展,实现动态调整与智能识别反爬策略,降低人工干预需求。附带的Python示例展示了如何通过代理IP、重试策略及日志记录实现高效的数据采集程序。
350 7
数据采集监控与告警:错误重试、日志分析与自动化运维
|
7月前
|
存储 监控 算法
基于 PHP 语言的滑动窗口频率统计算法在公司局域网监控电脑日志分析中的应用研究
在当代企业网络架构中,公司局域网监控电脑系统需实时处理海量终端设备产生的连接日志。每台设备平均每分钟生成 3 至 5 条网络请求记录,这对监控系统的数据处理能力提出了极高要求。传统关系型数据库在应对这种高频写入场景时,性能往往难以令人满意。故而,引入特定的内存数据结构与优化算法成为必然选择。
179 3
|
7月前
|
消息中间件 运维 监控
智能运维,由你定义:SAE自定义日志与监控解决方案
SAE(Serverless应用引擎)是阿里云推出的全托管PaaS平台,致力于简化微服务应用开发与管理。为满足用户对可观测性和运维能力的更高需求,SAE引入Sidecar容器技术,实现日志采集、监控指标收集等功能扩展,且无需修改主应用代码。通过共享资源模式和独立资源模式,SAE平衡了资源灵活性与隔离性。同时,提供全链路运维能力,确保应用稳定性。未来,SAE将持续优化,支持更多场景,助力用户高效用云。