Linux下Java服务自动化管理脚本开发指南
1. 为什么需要服务管理脚本在Linux服务器运维和Java服务部署中我们经常遇到这样的场景每次代码更新后都需要手动停止旧服务、重新打包、再启动新版本。当系统由多个微服务组成时这种重复操作会消耗大量时间。更糟糕的是如果遇到服务器意外重启所有服务都需要人工逐个恢复。我曾经维护过一个包含8个Java微服务的电商系统每次发版要重复执行16次启动命令。直到某个深夜紧急修复BUG时因疲劳操作漏掉了一个订单服务导致次日出现严重事故。这次教训让我意识到自动化脚本的必要性。2. 单服务控制脚本实现2.1 基础启动脚本创建一个最基础的Java服务启动脚本start_service.sh#!/bin/bash SERVICE_NAMEorder-service JAR_PATH/opt/apps/${SERVICE_NAME}.jar LOG_PATH/var/log/${SERVICE_NAME}.log nohup java -Xms512m -Xmx1024m -jar ${JAR_PATH} ${LOG_PATH} 21 echo ${SERVICE_NAME} started with PID $!关键点说明nohup保证SSH断开后进程继续运行21将标准错误重定向到标准输出末尾的让服务在后台运行$!获取最后执行的后台进程PID实际使用时要记得给脚本执行权限chmod x start_service.sh2.2 带状态检查的增强版基础版本缺乏状态验证下面增加启动状态检查#!/bin/bash SERVICE_NAMEpayment-service JAR_PATH/opt/apps/${SERVICE_NAME}.jar PID_FILE/var/run/${SERVICE_NAME}.pid # 检查是否已运行 if [ -f ${PID_FILE} ]; then if ps -p $(cat ${PID_FILE}) /dev/null; then echo ${SERVICE_NAME} is already running (PID $(cat ${PID_FILE})) exit 1 else rm -f ${PID_FILE} fi fi # 启动服务 nohup java -Xms512m -Xmx1024m -jar ${JAR_PATH} /dev/null 21 PID$! echo $PID ${PID_FILE} # 验证启动 sleep 5 if ps -p ${PID} /dev/null; then echo ${SERVICE_NAME} started successfully (PID ${PID}) else echo ${SERVICE_NAME} failed to start rm -f ${PID_FILE} exit 1 fi这个版本通过PID文件实现了防止重复启动进程崩溃后自动清理PID文件启动后延迟检查确保服务真正可用3. 多服务批量管理方案3.1 服务清单配置文件首先创建服务配置文件services.list# 格式服务名:JAR路径:启动参数 gateway:/opt/apps/gateway.jar:-Xmx2048m user-service:/opt/apps/user-service.jar:-Xms512m -Xmx1024m product-service:/opt/apps/product-service.jar:-XX:UseG1GC3.2 批量重启脚本实现创建restart_all.sh#!/bin/bash CONFIG_FILEservices.list LOG_DIR/var/log/services mkdir -p ${LOG_DIR} TIMESTAMP$(date %Y%m%d_%H%M%S) while IFS: read -r SERVICE_NAME JAR_PATH JAVA_OPTS; do # 跳过注释和空行 [[ $SERVICE_NAME ~ ^#|^$ ]] continue # 停止旧进程 PID_FILE/var/run/${SERVICE_NAME}.pid if [ -f ${PID_FILE} ]; then kill -9 $(cat ${PID_FILE}) 2/dev/null rm -f ${PID_FILE} echo [${TIMESTAMP}] Stopped ${SERVICE_NAME} fi # 启动新实例 nohup java ${JAVA_OPTS} -jar ${JAR_PATH} ${LOG_DIR}/${SERVICE_NAME}.log 21 PID$! echo $PID ${PID_FILE} echo [${TIMESTAMP}] Started ${SERVICE_NAME} (PID ${PID}) done ${CONFIG_FILE}3.3 进阶功能扩展增加健康检查与邮件通知#!/bin/bash # ...前面部分同上... # 健康检查函数 check_health() { local PORT$1 local TIMEOUT10 local START_TIME$(date %s) while ! nc -z localhost ${PORT}; do sleep 1 if [ $(($(date %s) - START_TIME)) -gt ${TIMEOUT} ]; then return 1 fi done return 0 } # 服务端口映射 declare -A PORTS( [gateway]8080 [user-service]8081 [product-service]8082 ) while IFS: read -r SERVICE_NAME JAR_PATH JAVA_OPTS; do # ...启动部分同上... # 健康检查 if check_health ${PORTS[$SERVICE_NAME]}; then echo [${TIMESTAMP}] ${SERVICE_NAME} health check PASSED else echo [${TIMESTAMP}] ${SERVICE_NAME} health check FAILED | mail -s Service Alert adminexample.com fi done ${CONFIG_FILE}4. 生产环境注意事项4.1 资源隔离与限制为防止单个服务耗尽系统资源建议使用cgroups# 在启动命令前加入 cgcreate -g memory,cpu:/${SERVICE_NAME} echo 100M /sys/fs/cgroup/memory/${SERVICE_NAME}/memory.limit_in_bytes echo 50000 100000 /sys/fs/cgroup/cpu/${SERVICE_NAME}/cpu.cfs_quota_us cgexec -g memory,cpu:${SERVICE_NAME} nohup java ...4.2 日志轮转配置避免日志文件无限增长创建/etc/logrotate.d/java-services/var/log/services/*.log { daily rotate 30 compress missingok notifempty copytruncate }4.3 服务依赖管理对于有启动顺序要求的服务可以这样处理# 在services.list中增加依赖声明 # 格式服务名:JAR路径:启动参数:依赖服务 order-service:/opt/apps/order.jar::user-service,product-service # 在脚本中解析依赖 declare -A DEPENDENCIES declare -A STATUS # 先启动所有无依赖服务 # 然后循环检查依赖条件启动其他服务5. 异常处理与监控5.1 自动崩溃恢复在restart_all.sh基础上增加监控进程#!/bin/bash # 监控模式 if [ $1 --monitor ]; then while true; do for PID_FILE in /var/run/*.pid; do SERVICE_NAME$(basename ${PID_FILE%.*}) if ! ps -p $(cat ${PID_FILE}) /dev/null; then echo [$(date)] ${SERVICE_NAME} crashed, restarting... # 调用原来的启动逻辑 # ... fi done sleep 60 done fi5.2 集成Prometheus监控在Java启动参数中添加JAVA_OPTS$JAVA_OPTS -javaagent:/opt/prometheus/jmx_prometheus_javaagent.jar8083:/etc/prometheus/config.yml对应的Prometheus配置scrape_configs: - job_name: java-services static_configs: - targets: [host1:8083, host1:8084]6. 实际应用案例在某跨境电商平台的生产环境中我们使用这套脚本管理12个核心服务。通过以下优化显著提升了稳定性启动时间从人工操作的15分钟缩短到45秒服务崩溃后平均恢复时间从23分钟降低到1分钟以内通过资源限制防止了3次内存泄漏导致的全系统崩溃关键改进点包括为每个服务添加了启动超时控制实现了服务间的启动顺序控制增加了磁盘空间不足的预防检查集成了企业微信告警通知# 磁盘检查示例 check_disk() { local THRESHOLD90 local USAGE$(df / | awk NR2 {print $5} | tr -d %) if [ ${USAGE} -gt ${THRESHOLD} ]; then send_alert Disk usage ${USAGE}% exceeds threshold return 1 fi return 0 }