Bash管理兄弟进程池:如何避免重复启动相同应用与数据库对
重复实例检测实现方案
推荐使用flock内核文件锁方案,是比PID文件、ps进程检索更可靠的实现,完全规避PID文件残留、进程PID复用、命令行模糊匹配误判等边缘问题。
方案核心逻辑
每个应用+数据库的配对对应一个独立的锁文件,由内核持有锁的状态:
- 进程正常/异常退出时,锁会被内核自动释放,无需手动清理
- 只有持有锁的进程可以正常启动,重复尝试加锁会直接失败
脚本实现示例
#!/bin/bash # 参数校验 if [ $# -lt 2 ]; then echo "用法: $0 <应用名> <数据库名>" exit 1 fi APP_NAME="$1" DB_NAME="$2" # 锁目录配置,可自行修改为有权限访问的路径,比如~/.runserver_lock LOCK_DIR="/var/run/runserver" mkdir -p "${LOCK_DIR}" LOCK_FILE="${LOCK_DIR}/${APP_NAME}_${DB_NAME}.lock" # 尝试对锁文件加非阻塞排他锁 exec 9>"${LOCK_FILE}" if ! flock -n 9; then echo "错误:应用 ${APP_NAME} + 数据库 ${DB_NAME} 的配对实例已经在运行" exit 1 fi # ------------ 以下为你原有服务启动逻辑 ------------ echo "启动服务实例:应用=${APP_NAME},数据库=${DB_NAME}" # 示例:你的Web服务启动命令 # exec /opt/webserver/bin/start --app "${APP_NAME}" --db "${DB_NAME}"
注意事项
- 如果你的Web服务需要后台运行,不要让脚本启动完直接退出,否则锁会随着脚本进程退出自动释放。可以将服务改为前台运行,或者用
flock 9 -c "你的服务启动命令 &"的形式持有锁到服务进程退出。 - 锁目录需要保证执行脚本的用户有读写权限,普通用户使用可以将路径改为用户目录下的路径,避免权限报错。
备选方案:进程特征匹配
如果环境不允许使用flock,可以采用正则精准匹配进程的方案:
# 检索匹配当前应用+数据库配对的进程 EXIST_PID=$(pgrep -f "runserver\.sh.*${APP_NAME}\s+${DB_NAME}([[:space:]]|$)") if [ -n "${EXIST_PID}" ] && kill -0 "${EXIST_PID}" 2>/dev/null; then echo "错误:应用 ${APP_NAME} + 数据库 ${DB_NAME} 的配对实例已经在运行" exit 1 fi
该方案需要注意正则写得足够精准,避免不同应用、数据库名出现前缀匹配导致的误判。
内容的提问来源于stack exchange,提问作者user5507535
相关产品推荐
相关产品推荐

