当前位置: 首页 > ds >正文

linux 环境服务发生文件句柄泄漏导致服务不可用

问题描述:

        服务调用远程rest接口 报错,发生too many open files 异常,系统句柄资源耗尽,导致服务不可用。

  

排查经过:

        1、针对报错代码进行本地构建,构造异常,并进行压测。问题未复现

        2、经过讨论分析,问题发生根因为:句柄资源耗尽,那么必然存在进程持续消耗句柄资源,且不进行释放。

        3、因此,开始排查服务进程句柄信息 

# 统计进程句柄总数
lsof -p <PID> | wc -l 
# 统计进程目录句柄总数  若持续增加则存在泄漏
lsof -p <PID> | grep DIR  
# 统计进程delete文件删除句柄总数  若持续增加则存在泄漏
lsof -p <PID> | grep delete

 通过统计观察各个进程的句柄总数,分析查找到问题根源

原因最终确认:

问题代码:loadDirectory函数加载指定目录下所有文件,并返回Path列表。Files.list函数为安全关闭文件句柄,导致该方法频繁调用时未释放目录句柄资源。导致系统句柄资源耗尽

    public static List<Path> loadDirectory(String fileDirectory) {try {final Path pathDirectory = Path.of(fileDirectory);if (Files.isDirectory(pathDirectory)) {return Files.list(pathDirectory).collect(Collectors.toList());} else {throw new NotDirectoryException(fileDirectory);}} catch (IOException e) {log.error("file write error:", e);}return new ArrayList<>(0);}

问题修复 :使用try-resource-with 方式主动关闭资源

public static List<Path> loadDirectory(String fileDirectory) throws CheckingException {try (Stream<Path> stream = Files.list(Paths.get(fileDirectory))) {return stream.collect(Collectors.toList());} catch (IOException e) {log.error("fileDirectory is not directory:", e);throw new CheckingException("can not load directory:" + fileDirectory);}}

问题复盘:创建系统句柄监控,进程句柄如果超过300,则进行告警,超过1000,则提示高危进程

#!/bin/bash
# 高效进程句柄监控脚本 v2.0
THRESHOLD=300       # 单个进程句柄阈值
HIGH_THRESHOLD=2000  # 高危进程阈值
INTERVAL=20          # 监控间隔(秒)
LOG_DIR="logs"
LOG_FILE="${LOG_DIR}/handle_monitor_$(date +%Y%m%d).log"
MAX_LOG_DAYS=30      # 日志保留天数# 创建日志目录
mkdir -p ${LOG_DIR}# 清理旧日志
find ${LOG_DIR} -name "handle_monitor_*.log" -mtime +${MAX_LOG_DAYS} -delete# 日志函数
log() {echo "$(date "+%Y-%m-%d %H:%M:%S") $1" >> ${LOG_FILE}
}# 获取进程FD数量的高效方法
get_fd_count() {local pid=$1if [ -d /proc/$pid/fd ]; thenecho $(ls -1 /proc/$pid/fd 2>/dev/null | wc -l)elseecho 0fi
}# 主监控循环
while true; dolog "===== 开始监控 ====="total_warning=0# 高效获取所有PIDpids=$(find /proc -maxdepth 1 -type d -name '[0-9]*' -printf "%f\n" 2>/dev/null)# 遍历PIDfor pid in $pids; dofd_count=$(get_fd_count $pid)if [[ $fd_count -ge $THRESHOLD ]]; thenproc_name=$(ps -p $pid -o comm= 2>/dev/null || echo "未知进程")log "警告: PID $pid ($proc_name) - $fd_count 个文件描述符"((total_warning++))# 高危进程详细记录if [[ $fd_count -ge $HIGH_THRESHOLD ]]; thenlog "高危进程详情:"lsof -p $pid +c 0 2>/dev/null | head -50 >> ${LOG_FILE}log "(仅显示前50个FD,完整列表请单独检查)"fifidone# 系统级统计sys_stats=$(cat /proc/sys/fs/file-nr 2>/dev/null)log "系统FD统计: ${sys_stats:-无法获取}"log "警告进程总数: $total_warning"log "===== 监控结束 ====="sleep $INTERVAL
done

       使用说明

使用说明:
  1. 保存为 fd_monitor.sh
  2. 赋予执行权限:chmod +x fd_monitor.sh
  3. 后台运行:nohup ./fd_monitor.sh &
  4. 查看日志:tail -f logs/handle_monitor_xxx.log
http://www.xdnf.cn/news/16170.html

相关文章:

  • 基于网络爬虫的在线医疗咨询数据爬取与医疗服务分析系统,技术采用django+朴素贝叶斯算法+boostrap+echart可视化
  • CS231n-2017 Lecture5卷积神经网络笔记
  • 【世纪龙科技】电动汽车原理与构造-汽车专业数字课程资源
  • 33、基于JDK17的GC调优策略
  • haproxy七层均衡
  • CanOpen--SDO 数据帧分析
  • Hugging Face 模型的缓存和直接下载有什么区别?
  • 【C++】第十八节—一文万字详解 | map和set的使用
  • 7.22 Java基础 | I/O流【下】
  • 小米视觉算法面试30问全景精解
  • HCIA/IP(一二章)笔记
  • Redis 初识
  • vcs门级仿真(后仿真)指南
  • Linux研学-Tomcat安装
  • 深入解析Hadoop中的Region分裂与合并机制
  • [pdf epub]《软件方法》电子书202507更新下载
  • 如何安装没有install.exe的mysql数据库文件
  • C# 析构函数
  • 虚幻5入门教程:如何在虚幻5中创建一个C++的Plugin
  • Zabbix 6.0+ 使用官方模板监控 Redis 数据库的完整配置指南
  • Linux 内核不能直接访问物理地址,必须通过虚拟地址访问。
  • Java+Vue构建的固定资产内控管理系统,融合移动端便捷与后台管理强大功能,模块完备,提供全量源码,轻松实现资产智能管控
  • 【uboot/kernel1】启动流程,环境变量,内存,initramfs
  • 构建智能视频中枢--多路RTSP转RTMP推送模块在轨道交通与工业应用中的技术方案探究
  • 知识库搭建之Meilisearch‘s 搜索引擎 测评-东方仙盟测评师
  • 二分查找-852.山峰数组的峰顶索引-力扣(LeetCode)
  • 【coze扣子】第1篇:coze快速入门
  • 【Spring AI 0基础教程】1、基础篇 环境搭建 - 智能天气预报助手
  • csp基础知识——递推
  • OpenCV快速入门之CV宝典