

业务指标采集影响系统性能问题排查
source link: https://blog.csdn.net/renfufei/article/details/125598603
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

背景:
- 规则引擎 + 图结构的执行逻辑
- Datadog 指标监控系统
- 多组 Kafka 集群
1. 现象描述
业务处理逻辑比较重, 执行代码的效率上不去, 系统吞吐量不足。
部署了N个Docker节点(8C8G), CPU使用率80~90%, 每秒吞吐量总计只有2万左右,远远小于生产者的速度。
2. 原因分析
经过排查,发现2个瓶颈点:
- 并行流:
parallelStream()
; - 指标采集: Micrometer的
Timed
注解, 以及StatsDClient#time()
方法;
并行流的性能问题:
如果不是纯粹CPU密集型的任务, 并行流默认会使用 ForkJoinPool 来执行, 高并发场景下会导致任务堆积以及阻塞问题。
Timed
注解的问题:
这是早期进行性能调优时, 为了进行指标监控加上的;
根据业务特征, 导致这里每一条数据都会执行几十次方法(图+递归), 恰好大部分方法都标注了 @Timed
注解, 被
StatsDClient指标上报客户端的实现:
public final class NonBlockingStatsDClient{
private final BlockingQueue<String> queue;
// ... ...
// final int queueSize = Integer.MAX_VALUE
// queue = new LinkedBlockingQueue<String>(queueSize);
private void send(final String message) {
queue.offer(message);
}
}
LinkedBlockingQueue 之类的阻塞队列, 高并发时可能会发生一些问题, 比如 锁争抢, 队列过大等等.
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
if (count.get() == capacity)
return false;
final int c;
final Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
if (count.get() == capacity)
return false;
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
}
3. 解决办法
- 将并行流改成普通流, 或者取消流:
/*
taskIdList.parallelStream().forEach(taskId -> {
*/
taskIdList.forEach(taskId -> {
// ... ...
});
需要提高并发度可以采用自定义线程池处理;
- 取消 TimedAspect, 让
@Timed
注解失效:
/*
@Bean
public TimedAspect timedAspect(MeterRegistry reg) {
return new TimedAspect(reg);
}
*/
- 屏蔽部分无效指标
private static StatsDClient statsDClient;
public static void recordTime(String aspectPrefix, long usedMillisecond, String... tags) {
if(usedMillisecond < 1L){
return;
}
statsDClient.time(aspectPrefix + ".time", usedMillisecond, tags == null ? EMPTY_TAG : tags);
}
根据业务特征, 小于1ms的指标, 直接抛弃;
这个阈值看具体业务来确定, 也可以在业务代码中按批次进行聚合与上报, 减小指标系统压力;
4. 优化效果
重新发版之后, 每秒总吞吐量达到了 80 万左右, 基本跟上生产者的速度;
CPU使用率也降低到30~40%左右;
至此, 本次优化基本完成, 后续需要在提高并发度的同时防止背压问题。
早期进行性能优化时, 追踪了详细的业务指标监控信息。 当然,业务复杂度也在持续上升, 等到吞吐量达到一定阶段时, 指标采集的部分又形成了新的瓶颈点, 根据需求, 去除不必要的指标采集之后, 性能得到了大幅度提升。
当然, 在特定的系统容量下, 性能满足业务的需求即可, 调优成果很多时候还是不稳定的产出,有时候得靠一点经验。
知识储备:
有些任务你可以不做、做不到、暂时没资格做,比如有价值的事都被上司和前辈分摊了。
但你不能一直不懂、不会做。
如果你不懂、不会, 还不学习,那么就永远跟机会无缘。
通过看书和网络进行积累, 大致明白和了解,那么日常工作中起码可以争取到一些机会,慢慢的机会就越来越多。
Recommend
-
31
今天谈下业务系统性能问题分析诊断和性能优化方面的内容。这篇文章重点还是谈已经上线的业务系统后续出现性能问题后的问题诊断和优化重点。...
-
5
高效采集数据,帮助应用业务增长 - HMS Core - OSCHINA - 中文开源技术交流社区 ...
-
5
一文详解|云原生下的指标与日志采集 - Erda技术团队的个人空间 - OSCHINA - 中文开源技术交流社区 导读:众所周知,对于一个云原生 PaaS 平台而言,在页面上查看日志与指标是最为基础的功能。...
-
7
Prometheus监控Kubernetes系列3——业务指标采集 · Service Mesh|服务网格中文社区 由于容器化和微服务的大力发展,Kubernetes基本已经统一了容器管理方案,当我们使用Kubernetes来进行容器化管理的时候,全面监控Ku...
-
13
使用 Vmagent 代替 Prometheus 采集监控指标-51CTO.COM 使用 Vmagent 代替 Prometheus 采集监控指标 作者:阳明 2022-05-12 08:01:26 我们以抓取 Kubernetes 集群指标为例说明如何使用...
-
6
分布式的概念存在年头有点久了,在正式进入我们《分布式专栏》之前,感觉有必要来聊一聊,什么是分布式,分布式特点是什么,它又有哪些问题,在了解完这个概念之后,再去看它的架构设计,理论奠基可能帮助会更大。本文将从三个方面来讲述一下我理解的"分布式...
-
9
Grafana Mimir:支持乱序的指标采集 译自:New in Grafana Mimir: Int...
-
3
使用coroot-pg-agent采集pg指标 精选 原创 coroot-pg-agent 和 postgres_exporter 的不同之处在于, coroot-pg-agent 主要是根据 ...
-
3
在当今数字时代,软件系统在我们的生活和工作中发挥着越来越重要的作用。我们需要确保这些系统能够在高负载、高并发的情况下稳定运行,为用户提供良好的体验。为了实现这一目标,我们需要关注系统性能监控指标,洞察系统运行的关键脉搏。本文将从指标分类、指标详细...
-
7
采集Java程序JVM信息 创建 Spring Boot Application 应用程序# 进行
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK