惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
Help Net Security
Help Net Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
博客园_首页
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MongoDB | Blog
MongoDB | Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
LINUX DO - 最新话题
PCI Perspectives
PCI Perspectives
博客园 - 三生石上(FineUI控件)
V2EX - 技术
V2EX - 技术
Spread Privacy
Spread Privacy
T
Tor Project blog
量子位
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
小众软件
小众软件
博客园 - 叶小钗
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
H
Help Net Security
Y
Y Combinator Blog
N
News | PayPal Newsroom
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tenable Blog
Scott Helme
Scott Helme
G
GRAHAM CLULEY
大猫的无限游戏
大猫的无限游戏
aimingoo的专栏
aimingoo的专栏
IT之家
IT之家
Schneier on Security
Schneier on Security
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
T
Threat Research - Cisco Blogs
博客园 - 司徒正美
Application and Cybersecurity Blog
Application and Cybersecurity Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Attack and Defense Labs
Attack and Defense Labs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
L
LangChain Blog
C
Check Point Blog
Google Online Security Blog
Google Online Security Blog
V
Visual Studio Blog
Latest news
Latest news

叶落阁

叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁 叶落阁
叶落阁
叶落阁 · 2024-10-09 · via 叶落阁

一、背景

最近一年多, job 经常有如下告警, 告警内容如下

尊敬的用户,您关注的监控已触发警报,内容如下,请您关注!

Dear user, the following monitoring alert you are concerned about is triggered, please pay attention!

Summary: [MonitoringID: MOC0000000606595] [Tingyun Alert] [LEMES-PCG-Prod_MajorGc]lemes-job-outbound-executor-idg-lssc-prodJVM每分钟Major GC时间 alert triggered

Notes: [Details:违反规则告警,APM应用实例/lemes-job-outbound-executor-54858fdf5b-dsxrq:0(10.188.138.17),告警级别:严重,JVM每分钟Major GC时间大于阈值(JVM每分钟Major GC时间:2,490ms>阈值:900ms)] [EventID:85882166655658][TriggerTime: 2024-09-30 15:52:00]

由于 job 停一下也没问题, 外加精力在其他任务上, 所以每次都是通过重启来解决问题

二、原因分析

国庆前又发了告警邮件, 觉得这个问题优先级可以提到前面了…

首先根据问题出现的频率分析, 大概是每个 job 运行几个月以上就开始报上面的告警, 根据不同 job 微服务的强度不同, 尤其是 outbound, 大概两个月就开始告警了…

所以基本定位问题为内存泄漏, 比如有框架或者开发的代码存在内存没释放的问题, 如IO流、数据库连接等没关闭的问题

这种问题可以直接对当前的微服务内存进行分析(导出内存快照)

1.我们的微服务是运行在 k8s 上的, 所以首先通过 Rancher 进入出问题的微服务的命令行, 通过如下命令对内存快照进行导出, 因为我们的 /data/logs 目录已经映射到宿主机了, 所以我们可以导出到这个目录

# 找到当前微服务的进程 id
jps
# 假如是9, 我们将其放到最后
jmap -dump:live,format=b,file=/data/logs/lemes-job-outbound-executor/lemes-job-outbound-executor.hprof 9

2.然后我们将导出的 lemes-job-outbound-executor.hprof 文件从宿主机上下载到本地电脑上

3.通过 IDEAProfiler 进行内存分析, 可以在 IDEA→ View → Tool Windows → Profiler

4.然后点击 Open Snapshot , 选择我们刚才下载的文件

Open Snapshot

5.然后点击右边的 Biggest Objects → Calculate retained size and biggest objects 来进行大对象分析

6.发现在 ThreadLocal 中的 ArrayDeque 的占用非常大, 根据 referent 分析, 来自于 DynamicDataSourceContextHolder 中的, 并且查看 elements 中都是数据源的名字

Find biggest objects

DynamicDataSourceContextHolder

7.分析出是关于多数据源框架的问题, 还是要分析出来是使用问题, 还是框架中问题. 我们直接来到上面找到的类 DynamicDataSourceContextHolder, 找到了内存泄漏的变量是存储用于切换数据源的栈, 并且在这个文件中还找到了一句话, 防止内存泄漏,如手动调用了push可调用此方法确保清除

biggest objects

message

8.也就是通过 DynamicDataSourceContextHolder.push(xxx); 切换数据源后, 是需要手动调用 poll() 方法进行移除, 或者在任务执行结束后调用 clear(), 进行清空.

9.查看代码后, 发现 job 中有 DynamicDataSourceContextHolder.push(xxx) 的操作, 却没有移除的方法, 所以定位到了问题.

三、解决问题

根据上一步我们知道了问题出在了没有进行移除操作, 移除操作有两种, 我们去每个执行 push 的地方进行 poll() 移除是比较麻烦的, 也不能避免再有同学漏掉 poll(), 从而导致问题复现.

所以我打算在 job 执行结束后, 统一调用 DynamicDataSourceContextHolder.clear() 来进行清空操作, 问了同事当前 job 框架是没有统一的开始和结束的地方, 但是所以 job 都是实现 SimpleJobexecute 方法来执行的, 所以可以使用切面来统一处理. 代码如下:

package com.lenovo.lemes.job.core.executor.interceptor;
 
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
 
/**
 * 任务拦截器
 * 用于在任务执行前后做一些操作
 *
 * @author Yujie Yang
 * @date 2024/10/8 10:55
 */
@Aspect
@Component
@EnableAspectJAutoProxy
public class JobInterceptor {
 
    // 定义切入点,匹配实现了 SimpleJob 接口的类的 execute 方法
    // 正则解释: Pointcut 由两部分组成, 第一 execution 指明了切入的方法的全路径规则, 第二部分 target 限制了切入的类必须实现 SimpleJob 接口
    @Pointcut("execution(void com.lenovo.lemes.job..jobhandler..*.execute(org.apache.shardingsphere.elasticjob.api.ShardingContext)) && target(org.apache.shardingsphere.elasticjob.simple.job.SimpleJob)")
    public void executeMethodPointcut() {
    }
 
    @After("executeMethodPointcut()")
    public void afterJob(JoinPoint joinPoint) {
        // 在 execute 方法执行完成后清理数据源上下文
        DynamicDataSourceContextHolder.clear();
    }
 
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]