运维问题排查笔记:磁盘、Java进程与SQL执行流程

一、磁盘空间满但未释放问题

现象

df -h 显示磁盘使用率100%

du -sh * 查看目录占用与df结果不匹配

文件已被删除但空间未释放

根本原因

文件被进程占用,即使执行rm删除,只要进程仍持有文件句柄,磁盘空间就不会释放。

排查步骤

bash

1. 查找被删除但仍被占用的文件

bash 复制代码
lsof | grep deleted

或更精确的查询

bash 复制代码
lsof +L1  # 显示链接数小于1的文件

2. 查看具体进程信息

bash 复制代码
lsof | grep deleted | awk '{print $1,$2,$NF}' | sort | uniq

3. 确认文件大小和进程

bash 复制代码
ls -lh /proc/<PID>/fd/ | grep deleted

4. 查看哪些进程占用最多

bash 复制代码
lsof | grep deleted | awk '{print $2}' | sort | uniq -c | sort -rn

解决方案

方法一:优雅重启相关服务

bash 复制代码
# 找到占用文件的进程
PID=$(lsof | grep deleted | head -1 | awk '{print $2}')
bash 复制代码
# 查看是什么服务
ps aux | grep $PID
bash 复制代码
# 根据服务类型重启(如nginx, mysql, java应用等)
systemctl restart service_name

bash 复制代码
service service_name restart

方法二:清理进程句柄(谨慎使用)

bash 复制代码
# 方式1: 向进程发送信号,让其重新打开日志文件
kill -HUP <PID>
bash 复制代码
# 方式2: 清空文件内容(如果确定文件可清理)
cat /dev/null > /proc/<PID>/fd/<FD_NUM>
bash 复制代码
# 方式3: 强制结束进程(最后手段)
kill -9 <PID>

预防措施

日志轮转配置

bash 复制代码
# logrotate配置示例
/var/log/application/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 644 root root
    postrotate
        /usr/bin/killall -HUP application_name
    endscript
}

监控告警设置

磁盘使用率>85%触发警告

90%触发紧急告警

使用Prometheus+Alertmanager或Zabbix监控

定期清理脚本

bash 复制代码
#!/bin/bash
# 清理7天前的日志
find /var/log -name "*.log" -type f -mtime +7 -delete
# 清理/tmp目录
find /tmp -type f -atime +1 -delete

二、Java进程CPU占用超100%

现象

top命令显示Java进程CPU使用率>100%(多核系统)

系统响应缓慢,可能有线程死锁或频繁GC

排查流程

步骤1:定位高CPU线程

bash 复制代码
# 查看Java进程PID
top -c | grep java
ps aux | grep java
bash 复制代码
# 查看该进程的所有线程
top -H -p <PID>
bash 复制代码
# 或
ps -eLf | grep <PID> | head -20

步骤2:转换线程ID

将十进制的线程ID转为十六进制(用于jstack)

bash 复制代码
printf "%x\n" <线程ID>

步骤3:获取线程堆栈

使用jstack获取线程堆栈

bash 复制代码
jstack <PID> > jstack_$(date +%Y%m%d_%H%M%S).log

或直接查找特定线程

bash 复制代码
jstack <PID> | grep -A 10 <十六进制线程ID>

步骤4:分析GC情况

查看GC状态

bash 复制代码
jstat -gcutil <PID> 1000 5

开启GC日志(JVM参数)

bash 复制代码
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc.log

常见问题及解决方案

  1. 线程死锁
    特征:

多个线程长期处于BLOCKED状态

线程等待同一个锁

排查:

bash 复制代码
jstack <PID> | grep -A 5 "BLOCKED"

或直接检测死锁

bash 复制代码
jstack <PID> | grep -i deadlock

解决:

检查同步代码块

使用ReentrantLock替代synchronized

设置锁超时时间

  1. 频繁GC
    特征:
    CPU使用率周期性飙升
    jstat显示频繁的Full GC

排查:

bash 复制代码
# 查看堆内存使用
jmap -heap <PID>

# 生成堆转储(生产环境慎用)
jmap -dump:format=b,file=heapdump.hprof <PID>

解决:

JVM调优参数示例

bash 复制代码
-Xms4g -Xmx4g  # 设置相同避免动态调整
-XX:+UseG1GC   # 使用G1垃圾收集器
-XX:MaxGCPauseMillis=200  # 目标暂停时间
-XX:InitiatingHeapOccupancyPercent=45  # G1触发混合GC的堆占用率
  1. 无限循环/递归
    特征:
    单个线程持续高CPU
    堆栈显示重复的方法调用

解决:

检查算法逻辑

添加循环终止条件

设置递归深度限制

工具推荐

Arthas(阿里开源的Java诊断工具)

bash 复制代码
# 安装运行
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

常用命令

bash 复制代码
dashboard    # 实时监控面板
thread       # 查看线程信息
thread -n 3  # 查看最忙的3个线程
jad          # 反编译类
watch        # 方法执行监控
VisualVM(图形化监控)
JProfiler(商业性能分析工具)

三、Update语句执行全流程

SQL执行架构概览

客户端请求 → 连接层 → SQL层 → 存储引擎层 → 磁盘

详细执行流程

阶段1:连接层(Connector)

功能:

客户端连接管理

身份认证

连接池维护

关键组件:

线程池(Thread Pool)

连接限制(max_connections)

超时设置(wait_timeout)

阶段2:SQL层(SQL Layer)

步骤1:查询解析

sql

-- 原始SQL

UPDATE users SET status = 'active' WHERE id = 100;

-- 解析为抽象语法树(AST)

UpdateStmt

├── Table: users

├── SetClause: status = 'active'

└── WhereClause: id = 100

步骤2:查询优化

基于规则的优化:

条件化简

外连接转内连接

子查询优化

基于成本的优化:

选择最佳索引

连接顺序优化

访问路径选择

步骤3:执行计划生成

bash 复制代码
-- EXPLAIN查看执行计划
EXPLAIN UPDATE users SET status = 'active' WHERE id = 100;

-- 输出示例:
-- id: 1
-- select_type: UPDATE
-- type: const
-- key: PRIMARY
-- rows: 1
-- Extra: Using where

阶段3:存储引擎层(Storage Engine)

InnoDB引擎Update流程

bash 复制代码
开始事务 → 读取数据页 → 写undo log → 修改数据 → 写redo log → 提交事务
详细步骤:
事务开始
获取事务ID
设置事务隔离级别
数据读取

或使用pt-query-digest

总结对比表

问题类型 关键命令 解决思路 预防措施

磁盘未释放 lsof | grep deleted 重启持有文件的服务 配置日志轮转,监控磁盘

Java高CPU top -H, jstack 分析线程堆栈,优化GC 代码review,JVM调优

SQL执行慢 EXPLAIN, SHOW PROCESSLIST 优化索引,调整配置 定期分析慢查询,监控

快速排查检查清单

磁盘空间紧急处理

df -h 确认磁盘使用率

lsof | grep deleted 查找被占用的文件

确定相关服务并重启

清理临时文件和日志

设置监控告警

Java进程诊断

bash 复制代码
top -H -p <PID> 定位高CPU线程
printf "%x" <TID> 转换线程ID
jstack <PID> \| grep -A 10 <nid> 分析线程堆栈
jstat -gcutil <PID> 检查GC状态

根据分析结果优化代码或JVM参数

SQL优化检查

EXPLAIN 分析执行计划

检查索引使用情况

避免全表扫描和大事务

优化查询语句和表结构

调整数据库配置参数

适用场景:Linux服务器运维、Java应用维护、MySQL数据库管理

注意:生产环境操作前务必在测试环境验证,高危操作建议在业务低峰期进行。

相关推荐
篱笆院的狗2 小时前
Java 中如何创建多线程?
java·开发语言
默 语2 小时前
RAG实战:用Java+向量数据库打造智能问答系统
java·开发语言·数据库
醒过来摸鱼2 小时前
Java Compiler API使用
java·开发语言·python
m0_488777652 小时前
Docker容器技术场景化操作实战及网络模式部署
运维·docker·容器·网络模式
dazhong20122 小时前
Mybatis 敏感数据加解密插件完整实现方案
java·数据库·mybatis
2501_939909052 小时前
Docker
运维·docker·容器
嘻哈baby2 小时前
Linux进程排查实战:strace和lsof救命指南
运维
TDengine (老段)2 小时前
TDengine 在智能制造领域的应用实践
java·大数据·数据库·制造·时序数据库·tdengine·涛思数据
Coder_Boy_2 小时前
基于 MQTT 的单片机与 Java 业务端双向通信全流程
java·单片机·嵌入式硬件