提交 eaa16b43 authored 作者: 陈泽健's avatar 陈泽健

Merge remote-tracking branch 'origin/develop' into develop

......@@ -77,7 +77,7 @@ start_service() {
nohup "./$(basename "$script_path")" > startup.log 2>&1 &
# 等待一小段时间,让进程有机会启动
sleep 3
sleep 600
# 再次检查进程是否启动成功
if is_process_running "$service_name"; then
......
#!/bin/bash
echo "==============================================="
echo " Linux 已删除但仍被占用文件排查工具 (内核直读版)"
echo "==============================================="
echo -e "\n🔍 正在扫描被删除但仍被进程占用的文件...\n"
total_size=0
found_count=0
# 遍历所有进程的 fd 目录
for fd_path in /proc/[0-9]*/fd/*; do
# 检查是否为符号链接且指向已删除文件
if [ -L "$fd_path" ] && ls -l "$fd_path" 2>/dev/null | grep -q "(deleted)"; then
# 提取 PID 和 FD
pid=$(echo "$fd_path" | cut -d'/' -f3)
fd=$(echo "$fd_path" | cut -d'/' -f5)
# 获取原始文件路径
target_file=$(readlink "$fd_path")
# 获取进程名
if [ -f "/proc/$pid/comm" ]; then
proc_name=$(cat "/proc/$pid/comm")
else
proc_name="unknown"
fi
# 获取文件大小 (通过 stat 命令获取该 fd 对应的大小)
# 注意:对于已删除文件,直接 stat fd 路径是获取该文件大小最准确的方法
size_bytes=$(stat -L -c %s "$fd_path" 2>/dev/null || echo 0)
if [ "$size_bytes" -gt 0 ] || [[ "$target_file" == *"$TARGET_KEY"* ]]; then
found_count=$((found_count + 1))
total_size=$((total_size + size_bytes))
size_mb=$(echo "scale=2; $size_bytes / 1024 / 1024" | bc)
echo "--------------------------------------------------"
printf "进程: %-15s | PID: %-8s | FD: %-5s\n" "$proc_name" "$pid" "$fd"
printf "占用: %-10s MB | 文件: %s\n" "$size_mb" "$target_file"
fi
fi
done
if [ "$found_count" -eq 0 ]; then
echo "✅ 未发现被占用的已删除文件,磁盘空间正常。"
else
total_mb=$(echo "scale=2; $total_size / 1024 / 1024" | bc)
total_gb=$(echo "scale=2; $total_size / 1024 / 1024 / 1024" | bc)
echo "=================================================="
printf "总共被删除但未释放的空间:%.2f MB (%.2f GB)\n" "$total_mb" "$total_gb"
echo "=================================================="
fi
echo -e "\n📌 处理建议:"
echo "1) 重启占用文件的进程即可释放空间(推荐)"
echo "2) 或执行: kill -9 <PID>"
echo "3) 若为日志文件,建议检查日志轮转策略(如 logrotate 是否配置了 copytruncate)"
echo -e "\n🎉 扫描完成。\n"
......@@ -3,7 +3,7 @@
# ================= 配置区域 =================
TARGET_KEY="ubains-INFO-AND-ERROR"
MIN_SIZE=$((1024*1024*1024)) # 1GB (单位:字节)
LOG_FILE="$(dirname "$0")/auto_clean_deleted_ubains.log"
LOG_FILE="/var/log/scripts/auto_clean_deleted_ubains.log"
MAX_LOG_SIZE=$((5*1024*1024)) # 5MB 日志大小限制
LOG_RETENTION_DAYS=7 # 日志保留天数
CONTAINER_NAME="ujava2" # 容器名称
......@@ -24,7 +24,8 @@ rotate_logs() {
log "日志文件超过 5MB,已自动轮转。"
fi
fi
find "$(dirname "$0")" -name "auto_clean_deleted_ubains.log.*" -mtime +$LOG_RETENTION_DAYS -exec rm -f {} \;
# 修改为在日志文件所在目录查找备份文件
find "$(dirname "$LOG_FILE")" -name "auto_clean_deleted_ubains.log.*" -mtime +$LOG_RETENTION_DAYS -exec rm -f {} \;
}
rotate_logs
......
......@@ -105,7 +105,7 @@ start_service() {
nohup "./$(basename "$script_path")" > startup.log 2>&1 &
# 等待一小段时间,让进程有机会启动
sleep 3
sleep 600
# 再次检查进程是否启动成功
if is_process_running "$service_name"; then
......
#!/bin/bash
#===============================================================================
# 脚本名称:monitor_external_api_services.sh
# 功能描述:外部 API 服务监测与自愈脚本 (严格精确匹配版)
# 版本:V2.1
# 创建日期:2026-03-05
#
# 核心策略:
# 1. Java Jar 包:精确匹配命令行中包含特定 Jar 文件名的 Java 进程。
# 2. 普通进程:严格使用 pgrep -x 进行全名匹配,拒绝模糊搜索。
# 3. 启动验证:轮询检测,确保进程真正拉起。
#
# 使用方法:
# chmod +x monitor_external_api_services.sh
# */5 * * * * /opt/scripts/monitor_external_api_services.sh >> /var/log/cron_monitor.log 2>&1
#===============================================================================
# --- 配置区域 ---
set -euo pipefail
# 日志配置
LOG_DIR="/var/log/scripts"
LOG_FILE="${LOG_DIR}/monitor_external_api_services.log"
# 监控参数
STARTUP_TIMEOUT=600 # 最大等待启动时间 (秒)
POLL_INTERVAL=3 # 状态轮询间隔 (秒)
STOP_WAIT_TIME=30 # 停止残留进程的等待时间 (秒)
# 定义要监控的服务
# 格式: "进程标识:目录路径:启动脚本路径"
# 注意:
# - 对于 Jar 包,'进程标识' 必须是 Jar 文件的完整名称 (如 app-1.0.jar)
# - 对于普通程序,'进程标识' 必须是准确的进程名 (如 nginx, malan)
SERVICES=(
"ubains-meeting-api-1.0-SNAPSHOT.jar:/var/www/java/external-meeting-api:/var/www/java/external-meeting-api/run.sh"
"malan:/var/www/malan:/var/www/malan/run.sh"
)
# --- 函数定义 ---
log_message() {
local level="$1"
local message="$2"
local ts
ts=$(date '+%Y-%m-%d %H:%M:%S')
[ ! -d "$LOG_DIR" ] && mkdir -p "$LOG_DIR" 2>/dev/null || true
echo "${ts} [${level}] ${message}" >> "$LOG_FILE"
if [[ "$level" == "ERROR" || "$level" == "FATAL" ]]; then
echo "${ts} [${level}] ${message}" >&2
fi
}
# 获取进程 PID (严格模式)
get_process_pid() {
local identifier="$1"
local pid=""
if [[ "$identifier" == *.jar ]]; then
# 【Java 策略】
# 必须匹配到 'java' 命令且命令行参数中包含该具体的 jar 文件名
# 使用 -f 是因为 java 进程的 cmdline 包含 jar 路径,但我们要确保 jar 名完全匹配
# 这里的正则确保 jar 文件名前后有边界 (空格或结束符),防止部分匹配
pid=$(pgrep -f "java.*${identifier}" | head -n 1)
else
# 【普通进程策略】
# 严格使用 -x (exact match),只匹配进程名完全等于 identifier 的进程
# 绝不进行模糊搜索
pid=$(pgrep -x "$identifier" | head -n 1)
fi
echo "$pid"
}
# 检查进程是否存在
is_process_running() {
local identifier="$1"
local pid
pid=$(get_process_pid "$identifier")
[ -n "$pid" ]
}
# 清理残留进程
cleanup_stale_process() {
local identifier="$1"
local pid
pid=$(get_process_pid "$identifier")
if [ -n "$pid" ]; then
log_message "WARN" "发现残留进程 '${identifier}' (PID: ${pid}),正在清理..."
# 尝试优雅停止
kill "$pid" 2>/dev/null || true
local count=0
while kill -0 "$pid" 2>/dev/null && [ $count -lt $STOP_WAIT_TIME ]; do
sleep 1
((count++))
done
# 强制杀死
if kill -0 "$pid" 2>/dev/null; then
log_message "WARN" "进程未响应,强制杀死 (PID: ${pid})"
kill -9 "$pid" 2>/dev/null || true
sleep 1
fi
log_message "INFO" "残留进程已清理完毕。"
fi
}
# 启动服务并验证
start_service() {
local name="$1"
local dir="$2"
local script="$3"
log_message "INFO" ">>> 开始启动服务: ${name}"
# 1. 环境校验
if [ ! -d "$dir" ]; then
log_message "ERROR" "启动失败:目录不存在 -> ${dir}"
return 1
fi
if [ ! -x "$script" ]; then
log_message "ERROR" "启动失败:脚本不可执行 -> ${script}"
return 1
fi
# 2. 清理可能占用的旧进程
cleanup_stale_process "$name"
# 3. 执行启动
cd "$dir" || { log_message "ERROR" "无法切换目录: ${dir}"; return 1; }
local startup_log="${dir}/startup_last.log"
# 使用 setsid 独立运行
setsid "$script" > "$startup_log" 2>&1 &
log_message "INFO" "启动命令已发送,进入状态轮询 (最多 ${STARTUP_TIMEOUT}s)..."
# 4. 轮询验证 (严格匹配)
local elapsed=0
while [ $elapsed -lt $STARTUP_TIMEOUT ]; do
sleep $POLL_INTERVAL
elapsed=$((elapsed + POLL_INTERVAL))
if is_process_running "$name"; then
local running_pid
running_pid=$(get_process_pid "$name")
log_message "INFO" "✅ 服务 '${name}' 启动成功 (PID: ${running_pid})"
return 0
fi
done
log_message "ERROR" "❌ 服务 '${name}' 启动超时!请检查日志: ${startup_log}"
return 1
}
# --- 主逻辑 ---
main() {
log_message "INFO" "========== 监控周期开始 =========="
for entry in "${SERVICES[@]}"; do
IFS=':' read -r identifier work_dir start_script <<< "$entry"
# 去除空格
identifier=$(echo "$identifier" | xargs)
work_dir=$(echo "$work_dir" | xargs)
start_script=$(echo "$start_script" | xargs)
[ -z "$identifier" ] && continue
log_message "DEBUG" "检测目标: ${identifier}"
if is_process_running "$identifier"; then
local pid
pid=$(get_process_pid "$identifier")
log_message "INFO" "正常: ${identifier} (PID: ${pid})"
else
log_message "WARN" "异常: ${identifier} 未运行,触发自愈..."
if ! start_service "$identifier" "$work_dir" "$start_script"; then
log_message "ERROR" "自愈失败: ${identifier},等待下一周期。"
# TODO: 此处可集成钉钉/邮件报警
fi
fi
done
log_message "INFO" "========== 监控周期结束 =========="
}
main || log_message "FATAL" "脚本执行异常退出"
\ No newline at end of file
......@@ -5,6 +5,8 @@
- **脚本存放目录**:`/opt/scripts/`
- **日志文件目录**:`/var/log/scripts/`
- **日志文件命名规则**:`脚本名.log`
- **MySQL备份目录**:`/opt/mysql/YYYYMMDD/`
- **Nginx日志备份目录**:`/opt/nginx/logs/`
## 二、部署步骤
......@@ -18,6 +20,13 @@
3. **创建日志目录**(如果不存在):
```bash
sudo mkdir -p /var/log/scripts/
sudo chown $(whoami):$(whoami) /var/log/scripts/
```
4. **创建备份目录**(如不存在):
```bash
sudo mkdir -p /opt/mysql /opt/nginx/logs
sudo chown $(whoami):$(whoami) /opt/mysql /opt/nginx/logs
```
## 三、定时任务配置
......@@ -76,92 +85,280 @@ crontab -e
## 四、脚本功能详解
### 数据库相关脚本
- **backup_mysql_databases.sh**: MySQL数据库备份脚本
- 备份容器:umysql
- 备份数据库:10个核心业务数据库
- 特色功能:容器内临时目录处理、PID防冲突、自动清理
- **backup_mysql_logs.sh**: MySQL日志备份脚本
- 备份类型:.log, .slow, error.log等日志文件
- 特色功能:权限保存恢复、自动压缩、保留原始文件
#### backup_mysql_databases.sh - MySQL数据库备份脚本
- **功能描述**:备份umysql容器内指定的10个核心业务数据库
- **备份数据库列表**:
- devops, devops_voice, huazhao2, nacos_mysql, offline
- ubains, wifi, voice, ubains_nacos_config, ubains_sso
- **特色功能**:
- 容器内临时目录处理(带PID防冲突)
- 自动创建日期目录结构
- 30天自动清理过期备份
- 容器密码自动获取
- 完整的日志记录机制
#### backup_mysql_logs.sh - MySQL日志备份脚本
- **功能描述**:备份MySQL各种日志文件,包括慢查询日志和错误日志
- **备份文件类型**:.log, .slow, error.log等日志文件
- **特色功能**:
- 权限保存和恢复机制
- 自动压缩备份文件
- 保留原始日志文件
- 30天自动清理策略
### 服务监测脚本
- **monitor_emqx_service.sh**: EMQX消息队列服务监测
- 监测维度:容器状态、进程存在性、服务可用性
- 恢复机制:容器重启、服务状态验证
- **monitor_mysql_service.sh**: MySQL数据库服务监测
- 监测维度:容器运行、连接测试、SQL执行验证
- 恢复机制:容器重启、密码获取、功能验证
- **monitor_redis_service.sh**: Redis缓存服务监测
- 监测维度:容器状态、认证检查、PING响应
- 恢复机制:密码认证、数据清理、容器重启
- **monitor_external_api_services.sh**: 外部API服务监测
- 监测服务:meeting-api、malan服务
- 监测方式:进程检查、目录验证、脚本执行
- **monitor_inner_api_services.sh**: 内部API服务监测
- 监测对象:平台API、容器内服务、6060端口
- 特色功能:IP自动获取、容器模糊匹配、分级恢复
#### monitor_emqx_service.sh - EMQX消息队列服务监测
- **监测维度**:
- uemqx容器运行状态检查
- 容器内EMQX进程存在性验证
- EMQX服务可用性检测(使用emqx_ctl status命令)
- **恢复机制**:
- 容器未运行时自动重启
- 服务状态异常时重启容器
- 重启后验证服务恢复情况
- **特色功能**:
- 多层次状态检查
- 精确的服务状态识别
- 自动化的恢复流程
#### monitor_mysql_service.sh - MySQL数据库服务监测
- **监测维度**:
- umysql容器运行状态
- MySQL连接可用性测试
- SQL执行能力验证
- **恢复机制**:
- 容器未运行时自动重启
- 密码自动获取和验证
- 功能完整性测试
- **特色功能**:
- 容器密码动态获取
- 多层次健康检查
- 完整的功能验证
#### monitor_redis_service.sh - Redis缓存服务监测
- **监测维度**:
- uredis容器运行状态
- Redis连接和认证状态检查
- PING命令响应验证
- **恢复机制**:
- 无密码和有密码双重测试
- 容器重启和数据清理
- 重启失败时的数据目录清理重试
- **重要配置**:
```
REDIS_PASSWORD="dNrprU&2S" # Redis认证密码
```
- **特色功能**:
- 支持有密码/无密码环境
- 渐进式恢复策略
- 数据目录清理机制
#### monitor_external_api_services.sh - 外部API服务监测
- **监测服务**:
- ubains-meeting-api服务
- malan服务
- **监测方式**:
- 进程存在性检查
- 服务目录存在性验证
- 启动脚本执行状态
- **恢复机制**:
- 服务缺失时自动启动
- 脚本执行失败时重试
#### monitor_inner_api_services.sh - 内部API服务监测
- **监测对象**:
- 平台API可用性(自动获取服务器IP)
- 容器内meeting2.0服务(支持ujava*模糊匹配)
- 宿主机6060端口malan服务
- **特色功能**:
- IP地址自动发现
- 容器名称模糊匹配(ujava2/ujava3/ujava6等)
- 分级恢复策略
- 调试模式支持
- **重要配置**:
```
CONTAINER_NAME="ujava2" # 支持模糊匹配
MALAN_DIR="/var/www/malan" # Malan服务目录
MALAN_PORT="6060" # Malan服务端口
DEBUG_MODE="true" # 调试模式开关
```
### 系统维护脚本
- **backup_nginx_logs.sh**: Nginx日志备份脚本
- 处理文件:access.log, error.log
- 特色功能:日志轮转、Nginx信号通知、权限保持
- **cleanup_deleted_files.sh**: 已删除文件清理脚本
- 处理对象:被进程占用的已删除文件
- 处理方式:SIGHUP信号释放、避免强制kill
## 五、注意事项
#### backup_nginx_logs.sh - Nginx日志备份脚本
- **处理文件**:access.log, error.log
- **特色功能**:
- 日志轮转和压缩
- Nginx信号通知(USR1)重新打开日志
- 权限保持机制
- 自动清理过期备份
#### cleanup_deleted_files.sh - 已删除文件清理脚本
- **处理对象**:被进程占用的已删除文件
- **处理方式**:SIGHUP信号释放文件句柄
- **安全机制**:避免强制kill进程,温和释放资源
#### clean_deleted_ubains_v2.sh - 预定系统专属文件清理脚本
- **特殊功能**:
- 专门处理ubains相关的已删除大文件(>1GB)
- 关键字匹配:"ubains-INFO-AND-ERROR"
- 内核直读方式扫描
- 日志轮转和大小限制(5MB)
- 7天日志保留策略
- **重要配置**:
```
TARGET_KEY="ubains-INFO-AND-ERROR" # 匹配关键字
MIN_SIZE=$((1024*1024*1024)) # 1GB最小尺寸
MAX_LOG_SIZE=$((5*1024*1024)) # 5MB日志大小限制
LOG_RETENTION_DAYS=7 # 日志保留天数
```
## 五、配置参数说明
### 全局配置参数
| 参数名 | 默认值 | 说明 |
|--------|--------|------|
| LOG_FILE | /var/log/scripts/脚本名.log | 日志文件路径 |
| RETENTION_DAYS | 30 | 备份文件保留天数 |
| CONTAINER_NAME | 各脚本不同 | 目标容器名称 |
### 服务特定配置
| 脚本 | 容器名 | 特殊配置 | 说明 |
|------|--------|----------|------|
| backup_mysql_databases.sh | umysql | DB_USER="root" | 数据库用户名 |
| monitor_emqx_service.sh | uemqx | - | EMQX消息队列容器 |
| monitor_mysql_service.sh | umysql | - | MySQL数据库容器 |
| monitor_redis_service.sh | uredis | REDIS_PASSWORD="dNrprU&2S" | Redis认证密码 |
| monitor_inner_api_services.sh | ujava* | DEBUG_MODE="true" | 调试模式开关 |
## 六、注意事项
1. **日志输出**:所有脚本已在内部实现日志输出功能,无需在 crontab 中重定向输出
2. **权限要求**:某些脚本可能需要特定权限才能正常运行,确保脚本具有足够的权限访问所需资源
2. **权限要求**:
- 脚本执行用户需要docker执行权限
- 日志目录需要写入权限
- 备份目录需要读写权限
- 部分脚本可能需要sudo权限
3. **服务依赖**:确保相关服务(如 Docker、Nginx、MySQL 等)在执行脚本前处于运行状态
3. **服务依赖**:
- 确保Docker服务正常运行
- 相关容器(umysql、uemqx、uredis、ujava*)需要预先创建
- Nginx服务需要配置相应的日志路径
4. **监控日志**:定期检查 `/var/log/scripts/` 目录下的日志文件,确认各脚本正常运行
4. **监控日志**:
- 定期检查 `/var/log/scripts/` 目录下的日志文件
- 关注脚本执行时间和错误信息
- 监控备份文件生成情况
5. **备份保留**:日志和备份文件会保留30天,如需调整保留时间请修改脚本中的 RETENTION_DAYS 参数
5. **备份保留策略**:
- 数据库备份:保留30天
- 日志备份:保留30天
- 清理脚本日志:保留7天
- 可通过修改脚本中的RETENTION_DAYS参数调整
6. **密码管理**:Redis脚本中包含硬编码密码,请根据实际情况修改
6. **密码安全管理**:
- Redis密码在monitor_redis_service.sh中硬编码
- 建议定期更换密码并在脚本中同步更新
- 考虑使用环境变量或加密存储替代硬编码
7. **容器名称**:支持容器名称模糊匹配(ujava*, uemqx, umysql, uredis)
7. **容器名称适配**:
- 支持容器名称模糊匹配(ujava*)
- 脚本会自动查找匹配的容器实例
- 可根据实际环境修改CONTAINER_NAME配置
## 六、故障排查
8. **系统资源监控**:
- 定期检查磁盘空间使用情况
- 监控内存和CPU使用率
- 注意大文件清理对系统性能的影响
## 七、故障排查
### 常见问题诊断
1. **检查脚本权限**:
```bash
ls -la /opt/scripts/
# 确保所有脚本都有执行权限
```
2. **检查定时任务是否生效**:
```bash
crontab -l
# 确认定时任务已正确添加
```
3. **查看日志文件**:
3. **查看实时日志**:
```bash
tail -f /var/log/scripts/脚本名.log
# 实时监控脚本执行情况
```
4. **手动执行脚本测试**:
```bash
/opt/scripts/脚本名.sh
# 验证脚本功能是否正常
```
5. **检查日志目录权限**:
```bash
ls -ld /var/log/scripts/
# 确保当前用户有写入权限
```
## 七、维护建议
6. **检查容器状态**:
```bash
docker ps | grep -E "(umysql|uemqx|uredis|ujava)"
# 确认相关容器正在运行
```
7. **检查备份目录**:
```bash
ls -la /opt/mysql/
ls -la /opt/nginx/logs/
# 确认备份文件正常生成
```
1. **定期检查**:建议每日检查关键服务监测脚本的执行情况
2. **备份验证**:定期验证备份文件的完整性和可恢复性
3. **日志清理**:监控日志文件大小,避免磁盘空间不足
4. **性能监控**:关注脚本执行时间和系统资源消耗
5. **版本更新**:及时更新脚本以适应系统变更
### 错误处理指南
| 错误类型 | 可能原因 | 解决方案 |
|----------|----------|----------|
| 权限拒绝 | 用户无docker权限 | 将用户添加到docker组或使用sudo |
| 容器未找到 | 容器名称不匹配 | 检查并修改CONTAINER_NAME配置 |
| 连接失败 | 服务未启动或密码错误 | 检查服务状态和认证配置 |
| 磁盘空间不足 | 备份文件过多 | 清理旧备份或增加磁盘空间 |
| 脚本执行超时 | 系统负载过高 | 调整定时任务执行时间间隔 |
## 八、维护建议
1. **定期检查**:
- 每日检查关键服务监测脚本的执行情况
- 每周审查备份文件完整性和可用性
- 每月评估系统资源使用情况
2. **备份验证**:
- 定期验证备份文件的完整性和可恢复性
- 测试关键数据的恢复流程
- 建立备份恢复的标准操作程序
3. **日志管理**:
- 监控日志文件大小,避免磁盘空间不足
- 定期分析日志中的错误和警告信息
- 建立日志分析和报警机制
4. **性能优化**:
- 关注脚本执行时间和系统资源消耗
- 根据系统负载调整定时任务执行频率
- 优化大文件处理和清理策略
5. **安全更新**:
- 及时更新脚本以适应系统变更
- 定期审查和更新密码配置
- 加强日志文件的访问控制
6. **文档维护**:
- 保持配置说明文档与实际脚本同步更新
- 记录系统变更和配置调整历史
- 建立完善的运维知识库
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论