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

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

......@@ -7,6 +7,8 @@ LOG_FILE="/var/log/scripts/auto_clean_deleted_ubains.log"
MAX_LOG_SIZE=$((5*1024*1024)) # 5MB 日志大小限制
LOG_RETENTION_DAYS=7 # 日志保留天数
CONTAINER_NAME="ujava2" # 容器名称
APP_PATH="/var/www/java/external-meeting-api" # 特定应用路径
APP_START_SCRIPT="${APP_PATH}/run.sh" # 特定应用启动脚本
# ===========================================
# 日志函数
......@@ -24,8 +26,7 @@ rotate_logs() {
log "日志文件超过 5MB,已自动轮转。"
fi
fi
# 修改为在日志文件所在目录查找备份文件
find "$(dirname "$LOG_FILE")" -name "auto_clean_deleted_ubains.log.*" -mtime +$LOG_RETENTION_DAYS -exec rm -f {} \;
find "$(dirname "$0")" -name "auto_clean_deleted_ubains.log.*" -mtime +$LOG_RETENTION_DAYS -exec rm -f {} \;
}
rotate_logs
......@@ -38,6 +39,7 @@ log "==============================================="
FOUND=0
NEED_RESTART=0
NEED_APP_START=0 # 新增:标记是否需要启动特定应用
# 遍历所有进程的 fd 目录,寻找匹配关键字且标记为 deleted 的文件
for fd_path in /proc/[0-9]*/fd/*; do
......@@ -73,6 +75,13 @@ for fd_path in /proc/[0-9]*/fd/*; do
kill -9 "$pid" 2>/dev/null
sleep 1
NEED_RESTART=1
# 获取进程的当前工作目录,判断是否为特定应用
proc_cwd=$(readlink /proc/$pid/cwd 2>/dev/null)
if [ "$proc_cwd" == "$APP_PATH" ]; then
log "检测到被杀死的进程属于特定应用:$APP_PATH,将在容器重启后尝试启动。"
NEED_APP_START=1
fi
else
log "⏩ 文件不足 1GB,跳过。"
fi
......@@ -93,6 +102,17 @@ if [ "$NEED_RESTART" -eq 1 ]; then
else
log "❌ 错误: 未找到 docker 命令,请手动重启容器。"
fi
# 如果需要启动特定应用,则执行启动脚本
if [ "$NEED_APP_START" -eq 1 ]; then
log "➡ 启动特定应用脚本:$APP_START_SCRIPT"
if [ -f "$APP_START_SCRIPT" ]; then
bash "$APP_START_SCRIPT" >> "$LOG_FILE" 2>&1
log "✔ 特定应用启动脚本执行完成。"
else
log "❌ 错误: 未找到特定应用启动脚本:$APP_START_SCRIPT。"
fi
fi
else
log "无需重启 docker 容器。"
fi
......
#!/bin/bash
#===============================================================================
# 脚本名称:cleanup_deleted_files.sh
# 功能描述:清理被进程占用的已删除文件脚本
# 版本:V1.0
# 创建日期:2026-01-27
# 基于文档:_PRD_预定系统_已删除文件清理需求文档.md
#
# 清理对象:
# 1. 使用lsof +L1查找link count为0但仍被进程打开的文件
# 2. 向相关进程发送SIGHUP信号尝试释放文件句柄
# 3. 避免强制kill进程,防止服务中断
# 4. 适用于Nginx、rsyslog等支持reload的服务
#
# 使用方法:
# chmod +x cleanup_deleted_files.sh
# ./cleanup_deleted_files.sh
#
# 定时任务示例:
# 0 4 * * * /opt/scripts/cleanup_deleted_files.sh
#===============================================================================
# clear_deleted_files.sh - 定时清理被进程占用的已删除文件
LOG_FILE="/var/log/scripts/cleanup_deleted_files.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] 开始检查被占用的已删除文件..." >> "$LOG_FILE"
# 使用 lsof +L1 查找 link count 为 0(即已删除)但仍被打开的文件
DELETED_ENTRIES=$(lsof +L1 2>/dev/null | grep -v "COMMAND")
if [ -z "$DELETED_ENTRIES" ]; then
echo "[$DATE] 未发现被占用的已删除文件。" >> "$LOG_FILE"
exit 0
fi
echo "[$DATE] 发现以下被占用的已删除文件:" >> "$LOG_FILE"
echo "$DELETED_ENTRIES" >> "$LOG_FILE"
# 提取唯一 PID 列表
PIDS=$(echo "$DELETED_ENTRIES" | awk 'NR>1 {print $2}' | sort -u)
for PID in $PIDS; do
if ! kill -0 "$PID" 2>/dev/null; then
echo "[$DATE] PID $PID 已不存在,跳过。" >> "$LOG_FILE"
continue
fi
CMD=$(ps -p "$PID" -o comm= 2>/dev/null | tr -d ' ')
echo "[$DATE] 处理进程: PID=$PID, CMD=$CMD" >> "$LOG_FILE"
# 尝试发送 SIGHUP(适用于 Nginx、rsyslog 等支持 reload 的服务)
if kill -0 "$PID" 2>/dev/null; then
echo "[$DATE] 向 PID $PID 发送 SIGHUP 信号..." >> "$LOG_FILE"
kill -HUP "$PID" 2>/dev/null && continue
fi
# 若 SIGHUP 无效或不支持,记录警告(不强制 kill,避免服务中断)
echo "[$DATE] WARNING: 无法通过 SIGHUP 释放 PID $PID 的文件句柄。建议手动处理或配置 logrotate。" >> "$LOG_FILE"
done
echo "[$DATE] 检查完成。" >> "$LOG_FILE"
#!/bin/bash
#===============================================================================
# 脚本名称:monitor_external_api_services.sh
# 功能描述:外部API服务监测与自愈脚本
# 版本:V1.0
# 创建日期:2026-01-27
# 基于文档:_PRD_预定系统_外部API服务需求文档.md
#
# 监测对象:
# 1. ubains-meeting-api-1.0-SNAPSHOT.jar服务
# 2. malan服务
# 3. 宿主机进程运行状态
# 4. 服务目录和启动脚本存在性
#
# 恢复策略:
# 1. 检查进程是否运行(pgrep -f)
# 2. 验证服务目录是否存在
# 3. 检查启动脚本权限
# 4. 异常时自动启动服务
# 5. 启动后验证进程状态
#
# 使用方法:
# chmod +x monitor_external_api_services.sh
# ./monitor_external_api_services.sh
#
# 定时任务示例:
# */5 * * * * /opt/scripts/monitor_external_api_services.sh
#===============================================================================
# --- 配置区域 ---
# 日志文件路径
LOG_FILE="/var/log/scripts/monitor_external_api_services.log"
# 定义要监控的服务及其相关信息
# 格式: "进程名:目录路径:启动脚本路径"
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 message="$1"
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$LOG_FILE"
}
# 检查进程是否运行
is_process_running() {
local process_name="$1"
# 使用 pgrep -f 搜索命令行中包含该名称的进程
# 对于 .jar 文件,通常搜索的是 java -jar ...<jar_name>
# 对于其他程序,搜索其进程名
if [[ "$process_name" == *.jar ]]; then
# 如果是 JAR 文件,搜索 java 进程中包含该 jar 名称的
pgrep -f "java.*$process_name" > /dev/null
else
# 否则直接搜索进程名
pgrep -x "$process_name" > /dev/null
fi
if [ $? -eq 0 ]; then
return 0 # 进程运行中
else
return 1 # 进程未运行
fi
}
# 检查目录是否存在
is_directory_exists() {
local dir_path="$1"
[ -d "$dir_path" ]
}
# 检查启动脚本是否存在且可执行
is_script_executable() {
local script_path="$1"
[ -x "$script_path" ]
}
# 启动服务
start_service() {
local service_name="$1"
local dir_path="$2"
local script_path="$3"
log_message "尝试启动服务 '$service_name'..."
# 切换到服务目录并执行启动脚本
# 使用子shell (cd ...) 以确保不影响当前脚本的工作目录
(
cd "$dir_path" || { log_message "错误: 无法切换到目录 '$dir_path'"; return 1; }
# 检查启动脚本是否存在且可执行
if ! is_script_executable "$script_path"; then
log_message "错误: 启动脚本 '$script_path' 不存在或不可执行。"
return 1
fi
# 执行启动脚本
# 使用 nohup 将进程与终端脱离,使其在后台持续运行
# 输出重定向到 startup.log 或 /dev/null
nohup "./$(basename "$script_path")" > startup.log 2>&1 &
# 等待一小段时间,让进程有机会启动
sleep 600
# 再次检查进程是否启动成功
if is_process_running "$service_name"; then
log_message "服务 '$service_name' 启动成功。"
return 0
else
log_message "错误: 服务 '$service_name' 启动失败。"
return 1
fi
)
}
# --- 主逻辑 ---
# 初始化日志
log_message "=== 服务监控脚本开始执行 ==="
# 遍历所有服务
for service_info in "${SERVICES[@]}"; do
# 解析服务信息
IFS=':' read -r service_name dir_path script_path <<< "$service_info"
# 去除可能的前后空格
service_name=$(echo "$service_name" | xargs)
dir_path=$(echo "$dir_path" | xargs)
script_path=$(echo "$script_path" | xargs)
log_message "检查服务: $service_name (目录: $dir_path, 启动脚本: $script_path)"
# 检查目录是否存在
if ! is_directory_exists "$dir_path"; then
log_message "跳过服务 '$service_name': 目录 '$dir_path' 不存在。"
continue # 跳过当前循环,检查下一个服务
fi
# 检查进程是否运行
if is_process_running "$service_name"; then
log_message "服务 '$service_name' 正在运行。"
else
log_message "服务 '$service_name' 未运行。"
# 尝试启动服务
start_service "$service_name" "$dir_path" "$script_path"
fi
done
log_message "=== 服务监控脚本执行完毕 ==="
#!/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)
# 日志文件路径
LOG_FILE="/var/log/scripts/monitor_external_api_services.log"
# 定义要监控的服务及其相关信息
# 格式: "服务名:目录路径:启动脚本路径"
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"
)
# API 检查配置
API_URL="https://127.0.0.1/exapi/system/v2/login"
API_DATA='{
"account": "test",
"password": "test"
}'
# --- 函数定义 ---
# 记录日志的函数
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
local message="$1"
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$LOG_FILE"
}
# 获取进程 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)
# 检查服务是否正常(通过 API 请求)
is_service_healthy() {
local service_name="$1"
# 使用 curl 发送 POST 请求
# -k: 忽略 SSL 证书检查
# -s: 静默模式
# -o /dev/null: 不输出响应体
# -w "%{http_code}": 只输出 HTTP 状态码
# --max-time 10: 设置超时时间为 10 秒
local http_code=$(curl -k -s -o /dev/null -w "%{http_code}" \
--location --request POST "$API_URL" \
--header 'Content-Type: application/json' \
--data-raw "$API_DATA" \
--max-time 10)
if [ "$http_code" -eq 200 ]; then
return 0 # 服务正常
else
# 【普通进程策略】
# 严格使用 -x (exact match),只匹配进程名完全等于 identifier 的进程
# 绝不进行模糊搜索
pid=$(pgrep -x "$identifier" | head -n 1)
log_message "警告: 服务 '$service_name' 接口返回状态码: $http_code"
return 1 # 服务异常
fi
echo "$pid"
}
# 检查进程是否存在
is_process_running() {
local identifier="$1"
local pid
pid=$(get_process_pid "$identifier")
[ -n "$pid" ]
# 检查目录是否存在
is_directory_exists() {
local dir_path="$1"
[ -d "$dir_path" ]
}
# 清理残留进程
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
# 检查启动脚本是否存在且可执行
is_script_executable() {
local script_path="$1"
[ -x "$script_path" ]
}
# 启动服务并验证
# 启动服务
start_service() {
local name="$1"
local dir="$2"
local script="$3"
log_message "INFO" ">>> 开始启动服务: ${name}"
local service_name="$1"
local dir_path="$2"
local script_path="$3"
# 1. 环境校验
if [ ! -d "$dir" ]; then
log_message "ERROR" "启动失败:目录不存在 -> ${dir}"
return 1
fi
if [ ! -x "$script" ]; then
log_message "ERROR" "启动失败:脚本不可执行 -> ${script}"
return 1
fi
log_message "尝试启动服务 '$service_name'..."
# 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)..."
# 切换到服务目录并执行启动脚本
(
cd "$dir_path" || { log_message "错误: 无法切换到目录 '$dir_path'"; return 1; }
# 检查启动脚本是否存在且可执行
if ! is_script_executable "$script_path"; then
log_message "错误: 启动脚本 '$script_path' 不存在或不可执行。"
return 1
fi
# 4. 轮询验证 (严格匹配)
local elapsed=0
while [ $elapsed -lt $STARTUP_TIMEOUT ]; do
sleep $POLL_INTERVAL
elapsed=$((elapsed + POLL_INTERVAL))
# 执行启动脚本
nohup "./$(basename "$script_path")" > startup.log 2>&1 &
# 等待一段时间,让服务有足够时间启动并响应 API
log_message "等待服务启动 (300秒)..."
sleep 300
if is_process_running "$name"; then
local running_pid
running_pid=$(get_process_pid "$name")
log_message "INFO" "✅ 服务 '${name}' 启动成功 (PID: ${running_pid})"
# 再次检查服务是否正常
if is_service_healthy "$service_name"; then
log_message "服务 '$service_name' 启动并验证成功。"
return 0
else
log_message "错误: 服务 '$service_name' 启动后接口验证仍失败。"
return 1
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}"
# 初始化日志
log_message "=== 服务监控脚本开始执行 (API 检查模式) ==="
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" "========== 监控周期结束 =========="
}
# 遍历所有服务
for service_info in "${SERVICES[@]}"; do
# 解析服务信息
IFS=':' read -r service_name dir_path script_path <<< "$service_info"
# 去除可能的前后空格
service_name=$(echo "$service_name" | xargs)
dir_path=$(echo "$dir_path" | xargs)
script_path=$(echo "$script_path" | xargs)
log_message "检查服务: $service_name"
# 检查目录是否存在
if ! is_directory_exists "$dir_path"; then
log_message "跳过服务 '$service_name': 目录 '$dir_path' 不存在。"
continue
fi
# 检查服务是否正常
if is_service_healthy "$service_name"; then
log_message "服务 '$service_name' 运行正常 (HTTP 200)。"
else
log_message "服务 '$service_name' 响应异常或未运行。"
# 尝试启动服务
start_service "$service_name" "$dir_path" "$script_path"
fi
done
main || log_message "FATAL" "脚本执行异常退出"
\ No newline at end of file
log_message "=== 服务监控脚本执行完毕 ==="
# 预定系统定时任务配置说明
## 一、目录结构说明
- **脚本存放目录**:`/opt/scripts/`
- **日志文件目录**:`/var/log/scripts/`
- **日志文件命名规则**:`脚本名.log`
- **MySQL备份目录**:`/opt/mysql/YYYYMMDD/`
- **Nginx日志备份目录**:`/opt/nginx/logs/`
## 二、部署步骤
1. **上传脚本文件**:将所有定时任务脚本上传至服务器的 `/opt/scripts` 目录下
2. **设置脚本权限**:
```bash
chmod +x /opt/scripts/*.sh
```
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
```
## 三、定时任务配置
执行以下命令编辑 crontab:
```bash
crontab -e
```
添加以下定时任务配置:
```
# ==================== 预定系统定时任务配置 ====================
# 每日凌晨1点备份MySQL数据库
# 功能:备份umysql容器内指定的10个数据库,自动清理30天前的备份
0 1 * * * /opt/scripts/backup_mysql_databases.sh
# 每日凌晨2点备份MySQL日志
# 功能:备份MySQL日志文件(.log/.slow),保留原始权限,自动清理过期备份
0 2 * * * /opt/scripts/backup_mysql_logs.sh
# 每日凌晨3点备份Nginx日志
# 功能:备份Nginx访问日志和错误日志,压缩后清空原文件并通知Nginx重新打开日志
0 3 * * * /opt/scripts/backup_nginx_logs.sh
# 每日凌晨4点检查并清理被占用的已删除文件
# 功能:查找link count为0但仍被进程占用的文件,发送SIGHUP信号释放句柄
# 说明:提供两种清理脚本,分别针对普通文件和预定ubains相关文件,避免误杀进程
0 4 * * * /opt/scripts/cleanup_deleted_files.sh
0 4 * * * /opt/scripts/clean_deleted_ubains_v2.sh
# 每5分钟监测EMQX服务状态
# 功能:检查uemqx容器运行状态、EMQX进程存在性和服务可用性,异常时自动重启
*/5 * * * * /opt/scripts/monitor_emqx_service.sh
# 每5分钟监测外部API服务状态
# 功能:监测ubains-meeting-api和malan服务进程,目录存在性,异常时自动启动
*/5 * * * * /opt/scripts/monitor_external_api_services.sh
# 每5分钟监测内部API服务状态
# 功能:检查平台API可用性、容器内meeting2.0服务和宿主机6060端口malan服务
*/5 * * * * /opt/scripts/monitor_inner_api_services.sh
# 每5分钟监测MySQL服务状态
# 功能:检查umysql容器、MySQL连接可用性和SQL执行能力,异常时自动重启
*/5 * * * * /opt/scripts/monitor_mysql_service.sh
# 每5分钟监测Redis服务状态
# 功能:检查uredis容器、Redis连接和认证状态,支持密码认证,异常时自动重启
*/5 * * * * /opt/scripts/monitor_redis_service.sh
# ==================== 定时任务结束 ====================
```
## 四、脚本功能详解
### 数据库相关脚本
#### 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消息队列服务监测
- **监测维度**:
- 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信号通知(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. **权限要求**:
- 脚本执行用户需要docker执行权限
- 日志目录需要写入权限
- 备份目录需要读写权限
- 部分脚本可能需要sudo权限
3. **服务依赖**:
- 确保Docker服务正常运行
- 相关容器(umysql、uemqx、uredis、ujava*)需要预先创建
- Nginx服务需要配置相应的日志路径
4. **监控日志**:
- 定期检查 `/var/log/scripts/` 目录下的日志文件
- 关注脚本执行时间和错误信息
- 监控备份文件生成情况
5. **备份保留策略**:
- 数据库备份:保留30天
- 日志备份:保留30天
- 清理脚本日志:保留7天
- 可通过修改脚本中的RETENTION_DAYS参数调整
6. **密码安全管理**:
- Redis密码在monitor_redis_service.sh中硬编码
- 建议定期更换密码并在脚本中同步更新
- 考虑使用环境变量或加密存储替代硬编码
7. **容器名称适配**:
- 支持容器名称模糊匹配(ujava*)
- 脚本会自动查找匹配的容器实例
- 可根据实际环境修改CONTAINER_NAME配置
8. **系统资源监控**:
- 定期检查磁盘空间使用情况
- 监控内存和CPU使用率
- 注意大文件清理对系统性能的影响
## 七、故障排查
### 常见问题诊断
1. **检查脚本权限**:
```bash
ls -la /opt/scripts/
# 确保所有脚本都有执行权限
```
2. **检查定时任务是否生效**:
```bash
crontab -l
# 确认定时任务已正确添加
```
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/
# 确认备份文件正常生成
```
### 错误处理指南
| 错误类型 | 可能原因 | 解决方案 |
|----------|----------|----------|
| 权限拒绝 | 用户无docker权限 | 将用户添加到docker组或使用sudo |
| 容器未找到 | 容器名称不匹配 | 检查并修改CONTAINER_NAME配置 |
| 连接失败 | 服务未启动或密码错误 | 检查服务状态和认证配置 |
| 磁盘空间不足 | 备份文件过多 | 清理旧备份或增加磁盘空间 |
| 脚本执行超时 | 系统负载过高 | 调整定时任务执行时间间隔 |
## 八、维护建议
1. **定期检查**:
- 每日检查关键服务监测脚本的执行情况
- 每周审查备份文件完整性和可用性
- 每月评估系统资源使用情况
2. **备份验证**:
- 定期验证备份文件的完整性和可恢复性
- 测试关键数据的恢复流程
- 建立备份恢复的标准操作程序
3. **日志管理**:
- 监控日志文件大小,避免磁盘空间不足
- 定期分析日志中的错误和警告信息
- 建立日志分析和报警机制
4. **性能优化**:
- 关注脚本执行时间和系统资源消耗
- 根据系统负载调整定时任务执行频率
- 优化大文件处理和清理策略
5. **安全更新**:
- 及时更新脚本以适应系统变更
- 定期审查和更新密码配置
- 加强日志文件的访问控制
6. **文档维护**:
- 保持配置说明文档与实际脚本同步更新
- 记录系统变更和配置调整历史
- 建立完善的运维知识库
\ No newline at end of file
# 预定系统定时任务配置说明(x86 架构)
> 版本:V1.0
> 更新日期:2026-03-17
> 适用范围:预定系统 x86 架构全套定时监控与维护脚本
> 部署路径:`/opt/scripts/`
> 日志路径:`/var/log/scripts/`
---
## 📁 脚本文件清单
### 一、服务监控类脚本(每 10 分钟执行)
| 序号 | 脚本名称 | 监控对象 | 日志文件 | 功能描述 |
|-----|---------|---------|---------|---------|
| 1 | `monitor_emqx_service.sh` | EMQX 消息队列 | `/var/log/scripts/monitor_emqx_service.log` | 容器状态 + 进程检查 + 服务验证(emqx_ctl status) |
| 2 | `monitor_mysql_service.sh` | MySQL数据库 | `/var/log/scripts/monitor_mysql_service.log` | 容器状态 + 连接测试 + SQL验证(mysqladmin ping) |
| 3 | `monitor_redis_service.sh` | Redis缓存 | `/var/log/scripts/monitor_redis_service.log` | 容器状态 + 认证识别 + PING验证 |
| 4 | `monitor_external_api_services_v2.sh` | 外部API服务 | `/var/log/scripts/monitor_external_api_services_v2.log` | 进程监控 + 目录验证 + 自动启动 |
| 5 | `monitor_inner_api_services.sh` | 内部API服务 | `/var/log/scripts/monitor_inner_api_services.log` | API检查 + 容器服务 + 端口监控 |
### 二、数据备份类脚本(每日执行)
| 序号 | 脚本名称 | 备份对象 | 日志文件 | 执行时间 | 保留周期 |
|-----|---------|---------|---------|---------|---------|
| 1 | `backup_mysql_databases.sh` | MySQL数据库 | `/var/log/scripts/backup_mysql_databases.log` | 每日 01:00 | 30 天 |
| 2 | `backup_mysql_logs.sh` | MySQL日志 | `/var/log/scripts/backup_mysql_logs.log` | 每日 02:00 | 30 天 |
| 3 | `backup_nginx_logs.sh` | Nginx日志 | `/var/log/scripts/backup_nginx_logs.log` | 每日 03:00 | 30 天 |
### 三、系统维护类脚本(每日执行)
| 序号 | 脚本名称 | 维护对象 | 日志文件 | 执行时间 | 功能描述 |
|-----|---------|---------|---------|---------|---------|
| 1 | `check_deleted_file_ubains.sh` | 已删除的文件 | `/var/log/scripts/check_deleted_file_ubains.log` | 手动触发 | 检测已删除文件 |
| 2 | `auto_clean_deleted_ubains_v3.sh` | 已删除大文件 | `/var/log/scripts/auto_clean_deleted_ubains.log` | 每日 04:00 | 清理>1GB 的 deleted 文件 |
---
## ⚙️ 统一配置规范
### 1. 环境配置
```bash
# 基础环境变量
CONTAINER_NAME="ujava2" # Java 应用容器
APP_PATH="/var/www/java/external-meeting-api" # 应用路径
APP_START_SCRIPT="${APP_PATH}/run.sh" # 应用启动脚本
# 数据库容器
MYSQL_CONTAINER="umysql"
REDIS_CONTAINER="uredis"
EMQX_CONTAINER="uemqx"
# 日志配置
LOG_DIR="/var/log/scripts/" # 统一日志目录
LOG_FORMAT="[YYYY-MM-DD HH:MM:SS] 日志内容"
MAX_LOG_SIZE="5MB" # 日志轮转阈值
LOG_RETENTION_DAYS=7 # 日志保留天数
```
### 2. 监控配置
#### 2.1 EMQX服务监控
```bash
TARGET_KEY="ubains-INFO-AND-ERROR" # 日志关键字
CHECK_INTERVAL="*/10 * * * *" # 每 10 分钟
HEALTH_CHECK="emqx_ctl status" # 健康检查命令
```
#### 2.2 MySQL服务监控
```bash
DB_USER="root" # 数据库用户
CHECK_METHOD="mysqladmin ping" # 连接检查
SQL_TEST="SELECT 1" # SQL 测试语句
```
#### 2.3 Redis服务监控
```bash
AUTH_ENABLED=true # 是否启用认证
CHECK_METHOD="redis-cli ping" # PING 检查
EXPECTED_RESPONSE="PONG" # 期望响应
```
### 3. 备份配置
#### 3.1 MySQL数据库备份
```bash
HOST_BACKUP_DIR="/opt/mysql" # 宿主机备份目录
RETENTION_DAYS=30 # 备份保留 30 天
TARGET_DBS=( # 备份数据库列表
"devops" "devops_voice" "huazhao2"
"nacos_mysql" "offline" "ubains"
"wifi" "voice" "ubains_nacos_config"
"ubains_sso"
)
COMPRESSION="gzip" # 压缩格式
```
#### 3.2 MySQL日志备份
```bash
LOG_PATH="/var/log/mysql" # MySQL日志路径
BACKUP_FORMAT="tar.gz" # 备份格式
CLEAN_OLD_BACKUP=true # 清理旧备份
```
#### 3.3 Nginx日志备份
```bash
NGINX_LOG_PATH="/var/log/nginx" # Nginx日志路径
ROTATE_METHOD="copytruncate" # 轮转方式
COMPRESS_AFTER_ROTATE=true # 轮转后压缩
```
### 4. 清理配置
#### 4.1 已删除文件清理
```bash
MIN_SIZE=$((1024*1024*1024)) # 最小清理尺寸:1GB
TARGET_KEY="ubains-INFO-AND-ERROR" # 匹配关键字
ACTION="kill_process_and_restart" # 处理方式
```
---
## 🕐 Crontab 定时任务配置
### 完整配置示例
```
# 编辑 crontab
crontab -e
# 预定系统定时任务配置
# ============================================
# ========== 服务监控类(每 10 分钟) ==========
*/10 * * * * /opt/scripts/monitor_emqx_service.sh
*/10 * * * * /opt/scripts/monitor_mysql_service.sh
*/10 * * * * /opt/scripts/monitor_redis_service.sh
*/10 * * * * /opt/scripts/monitor_external_api_services_v2.sh
*/10 * * * * /opt/scripts/monitor_inner_api_services.sh
# ========== 数据备份类(每日凌晨) ==========
0 1 * * * /opt/scripts/backup_mysql_databases.sh
0 2 * * * /opt/scripts/backup_mysql_logs.sh
0 3 * * * /opt/scripts/backup_nginx_logs.sh
# ========== 系统维护类(每日凌晨) ==========
0 4 * * * /opt/scripts/auto_clean_deleted_ubains_v3.sh
# ============================================
```
### 执行时间安排图
```
时间轴 (24 小时)
├─ 00:00 - 01:00 → 监控任务(每 10 分钟)
├─ 01:00 - 01:30 → MySQL数据库备份 ★
├─ 01:30 - 02:00 → 监控任务(每 10 分钟)
├─ 02:00 - 02:30 → MySQL日志备份 ★
├─ 02:30 - 03:00 → 监控任务(每 10 分钟)
├─ 03:00 - 03:30 → Nginx日志备份 ★
├─ 03:30 - 04:00 → 监控任务(每 10 分钟)
├─ 04:00 - 04:30 → 已删除文件清理 ★
└─ 04:30 - 24:00 → 监控任务(每 10 分钟)
★ = 重量级任务,错峰执行
```
---
## 🛠️ 部署步骤
### 1. 文件准备
```bash
# 创建脚本目录
sudo mkdir -p /opt/scripts
# 上传所有脚本文件至 /opt/scripts/ 目录
# 或使用 git 克隆
cd /opt/scripts
git clone <repository_url> .
```
### 2. 权限设置
```bash
# 设置所有脚本可执行权限
sudo chmod +x /opt/scripts/*.sh
# 设置日志目录权限
sudo mkdir -p /var/log/scripts
sudo chmod 755 /var/log/scripts
```
### 3. 依赖检查
```bash
# 检查必需命令是否可用
command -v docker >/dev/null 2>&1 && echo "✓ Docker 已安装"
command -v gzip >/dev/null 2>&1 && echo "✓ Gzip 已安装"
command -v mysqladmin >/dev/null 2>&1 && echo "✓ MySQL 客户端已安装"
command -v redis-cli >/dev/null 2>&1 && echo "✓ Redis 客户端已安装"
```
### 4. 定时任务配置
```bash
# 备份现有 crontab
crontab -l > ~/crontab.backup.$(date +%Y%m%d%H%M%S)
# 编辑 crontab
crontab -e
# 粘贴上述定时任务配置并保存
```
### 5. 验证测试
```bash
# 手动执行单个脚本验证
sudo /opt/scripts/monitor_emqx_service.sh
# 查看日志输出
tail -f /var/log/scripts/monitor_emqx_service.log
# 检查 cron 服务状态
sudo systemctl status cron
```
---
## 📊 监控与告警
### 1. 日志监控
```bash
# 实时查看所有脚本日志
tail -f /var/log/scripts/*.log
# 查看错误日志
grep "❌\|ERROR\|错误" /var/log/scripts/*.log
# 统计今日日志量
wc -l /var/log/scripts/*.log
```
### 2. 执行状态检查
```bash
# 检查 cron 任务执行记录
grep CRON /var/log/syslog | grep "/opt/scripts/"
# 查看最近一次执行时间
ls -lt /var/log/scripts/*.log | head -5
```
### 3. 资源使用监控
```bash
# 检查磁盘空间
df -h /opt/mysql
df -h /var/log
# 检查备份文件大小
du -sh /opt/mysql/*
```
### 4. 告警机制建议
```bash
# 添加钉钉通知函数(可选)
dingtalk_notify() {
local message="$1"
curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}"
}
# 在关键错误处调用
if [ 容器启动失败 ]; then
dingtalk_notify "⚠️ 警告:ujava2 容器启动失败,请检查!"
fi
```
---
## 🔧 故障排查
### 常见问题及解决方案
#### 1. 脚本无法执行
```bash
# 检查权限
ls -l /opt/scripts/*.sh
# 解决:添加执行权限
chmod +x /opt/scripts/script_name.sh
```
#### 2. 日志文件无写入
```bash
# 检查日志目录权限
ls -ld /var/log/scripts
# 解决:修改权限
sudo chown -R $USER:$USER /var/log/scripts
```
#### 3. Docker 命令无权限
```bash
# 将用户加入 docker 组
sudo usermod -aG docker $USER
# 重新登录或执行
newgrp docker
```
#### 4. Cron 任务未执行
```bash
# 检查 cron 服务
sudo systemctl status cron
# 启动服务
sudo systemctl start cron
# 设置开机自启
sudo systemctl enable cron
```
#### 5. 备份空间不足
```bash
# 清理过期备份(手动)
find /opt/mysql -name "*.sql.gz" -mtime +30 -delete
# 或调整保留天数(修改脚本配置)
RETENTION_DAYS=15 # 改为 15 天
```
---
## 📈 性能优化建议
### 1. 执行时间优化
- **错峰执行**:备份任务已安排在业务低峰期(凌晨 1-4 点)
- **负载均衡**:避免多个重量级任务同时执行
- **并发控制**:监控类脚本轻量级,可同时执行
### 2. 日志管理优化
```bash
# 添加日志轮转配置(/etc/logrotate.d/scripts)
cat > /etc/logrotate.d/scripts << EOF
/var/log/scripts/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 644 root root
}
EOF
```
### 3. 资源预留
- **内存要求**:≥10G(参考 Java 服务部署规范)
- **磁盘空间**:备份目录预留至少 100GB
- **CPU 核心**:≥4 核(支持并发监控)
---
## 🔐 安全性保障
### 1. 密码安全管理
```bash
# 从环境变量获取敏感信息(推荐)
export MYSQL_ROOT_PASSWORD="your_password"
# 或在脚本中使用 docker exec 获取
docker exec umysql printenv MYSQL_ROOT_PASSWORD
```
### 2. 权限最小化
```bash
# 仅授予必要的操作权限
chmod 755 /opt/scripts/*.sh # 脚本可执行
chmod 644 /var/log/scripts/*.log # 日志只读
chmod 700 /opt/mysql # 备份目录私有
```
### 3. 操作审计
```bash
# 记录所有关键操作
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$(whoami)] [$$] $*" | tee -a "$LOG_FILE"
}
```
---
## 📝 附录
### A. 容器清单
| 容器名 | 服务类型 | 端口 | 说明 |
|-------|---------|------|------|
| ujava2 | Java 应用 | 8080 | 主应用容器 |
| umysql | MySQL | 3306 | 数据库容器 |
| uredis | Redis | 6379 | 缓存容器 |
| uemqx | EMQX | 1883,8083 | 消息队列容器 |
### B. 相关文档
- [_PRD_预定系统定时脚本需求文档概览.md](../../../Docs/PRD/自动化部署脚本/_PRD_预定系统定时脚本需求文档概览.md)
- [_PRD_预定系统_EMQX服务监控需求文档.md](../../../Docs/PRD/自动化部署脚本/_PRD_预定系统_EMQX服务监控需求文档.md)
- [_PRD_预定系统_MySQL服务监控需求文档.md](../../../Docs/PRD/自动化部署脚本/_PRD_预定系统_MySQL服务监控需求文档.md)
- [_PRD_预定系统_Redis服务监控需求文档.md](../../../Docs/PRD/自动化部署脚本/_PRD_预定系统_Redis服务监控需求文档.md)
- [_PRD_预定系统_已删除文件清理需求文档.md](../../../Docs/PRD/自动化部署脚本/_PRD_预定系统_已删除文件清理需求文档.md)
### C. 快速参考卡片
```
# ========== 快速命令参考 ==========
# 1. 手动执行脚本
/opt/scripts/script_name.sh
# 2. 查看实时日志
tail -f /var/log/scripts/script_name.log
# 3. 检查容器状态
docker ps | grep -E "ujava2|umysql|uredis|uemqx"
# 4. 查看 cron 执行记录
grep CRON /var/log/syslog | tail -20
# 5. 检查备份文件
ls -lh /opt/mysql/$(date +%Y%m%d)/
# 6. 紧急重启所有容器
docker restart ujava2 umysql uredis uemqx
# ===================================
```
---
## 📞 技术支持
如遇到问题,请按以下步骤收集信息:
1. **日志文件**`/var/log/scripts/*.log`
2. **容器状态**`docker ps -a`
3. **系统日志**`/var/log/syslog`(cron 相关)
4. **磁盘空间**`df -h`
5. **Cron 配置**`crontab -l`
联系技术支持时请提供以上信息。
---
**文档结束**
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论