新功能: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?

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
318 3
|
2月前
|
存储 监控 固态存储
如何监控和优化 WAL 日志文件的存储空间使用?
如何监控和优化 WAL 日志文件的存储空间使用?
|
3月前
|
缓存 监控 算法
分析慢日志文件来优化 PHP 脚本的性能
分析慢日志文件来优化 PHP 脚本的性能
|
2月前
|
监控 网络协议 CDN
阿里云国际监控查询流量、用量查询流量与日志统计流量有差异?
阿里云国际监控查询流量、用量查询流量与日志统计流量有差异?
|
3月前
|
运维 Kubernetes 监控
Loki+Promtail+Grafana监控K8s日志
综上,Loki+Promtail+Grafana 监控组合对于在 K8s 环境中优化日志管理至关重要,它不仅提供了强大且易于扩展的日志收集与汇总工具,还有可视化这些日志的能力。通过有效地使用这套工具,可以显著地提高对应用的运维监控能力和故障诊断效率。
384 0
|
4月前
|
SQL 数据库 Java
Hibernate 日志记录竟藏着这些秘密?快来一探究竟,解锁调试与监控最佳实践
【8月更文挑战第31天】在软件开发中,日志记录对调试和监控至关重要。使用持久化框架 Hibernate 时,合理配置日志可帮助理解其内部机制并优化性能。首先,需选择合适的日志框架,如 Log4j 或 Logback,并配置日志级别;理解 Hibernate 的多级日志,如 DEBUG 和 ERROR,以适应不同开发阶段需求;利用 Hibernate 统计功能监测数据库交互情况;记录自定义日志以跟踪业务逻辑;定期审查和清理日志避免占用过多磁盘空间。综上,有效日志记录能显著提升 Hibernate 应用的性能和稳定性。
54 0
|
4月前
|
开发者 前端开发 编解码
Vaadin解锁移动适配新境界:一招制胜,让你的应用征服所有屏幕!
【8月更文挑战第31天】在移动互联网时代,跨平台应用开发备受青睐。作为一款基于Java的Web应用框架,Vaadin凭借其组件化设计和强大的服务器端渲染能力,助力开发者轻松构建多设备适应的Web应用。本文探讨Vaadin与移动设备的适配策略,包括响应式布局、CSS媒体查询、TouchKit插件及服务器端优化,帮助开发者打造美观且实用的移动端体验。通过这些工具和策略的应用,可有效应对屏幕尺寸、分辨率及操作系统的多样性挑战,满足广大移动用户的使用需求。
69 0
|
4月前
|
存储 运维 监控
Entity Framework Core 实现审计日志记录超棒!多种方法助你跟踪数据变化、监控操作,超实用!
【8月更文挑战第31天】在软件开发中,审计日志记录对于跟踪数据变化、监控用户操作及故障排查至关重要。Entity Framework Core (EF Core) 作为强大的对象关系映射框架,提供了多种实现审计日志记录的方法。例如,可以使用 EF Core 的拦截器在数据库操作前后执行自定义逻辑,记录操作类型、时间和执行用户等信息。此外,也可通过在实体类中添加审计属性(如 `CreatedBy`、`CreatedDate` 等),并在保存实体时更新这些属性来记录审计信息。这两种方法都能有效帮助我们追踪数据变更并满足合规性和安全性需求。
114 0
|
4月前
|
存储 JSON 监控
FastAPI日志之谜:如何揭开Web应用监控与调试的面纱?
【8月更文挑战第31天】在现代Web开发中,日志记录对于监控应用状态、诊断问题和了解用户行为至关重要。FastAPI框架提供了强大的日志功能,使开发者能轻松集成日志记录。本文将详细介绍如何在FastAPI中设置和利用日志,包括基础配置、请求响应日志、错误处理和结构化日志等内容,帮助提升应用的可维护性和性能。
183 0
|
4月前
|
消息中间件 Prometheus 监控
Producer的监控与日志记录最佳实践
【8月更文第29天】在分布式系统中,消息队列作为关键组件之一,其稳定性和性能至关重要。生产者(Producer)负责生成并发送消息到消息队列中,因此确保生产者的健康运行是非常重要的。本文将探讨如何为生产者设置监控和日志记录,以跟踪其健康状况和性能指标。
79 0
下一篇
DataWorks