#!/bin/bash # 多实例启动脚本 # 使用方法: ./start-multi-instance.sh [start|stop|restart|status] [instance_name] # 实例名称: 9900, 9901, 9902, 9903, all # 配置变量 JAR_NAME="ruoyi-admin.jar" JAVA_OPTS="-Xms8192m -Xmx8192m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1024m" JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai" JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=200" JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=logs/" # 实例配置 declare -A INSTANCES INSTANCES[9900]="prod-9900" INSTANCES[9901]="prod-9901" INSTANCES[9902]="prod-9902" INSTANCES[9903]="prod-9903" # 日志目录 LOG_DIR="logs" mkdir -p $LOG_DIR # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # 打印带颜色的消息 print_message() { local color=$1 local message=$2 echo -e "${color}${message}${NC}" } # 检查JAR文件是否存在 check_jar() { if [ ! -f "$JAR_NAME" ]; then print_message $RED "错误: $JAR_NAME 文件不存在!" print_message $YELLOW "请确保在正确的目录下运行此脚本,或先执行 mvn clean package -Pprod 编译项目" exit 1 fi } # 启动单个实例 start_instance() { local port=$1 local profile=$2 local pid_file="logs/ruoyi-admin-${port}.pid" local log_file="logs/ruoyi-admin-${port}.log" # 检查是否已经运行 if [ -f "$pid_file" ]; then local pid=$(cat "$pid_file") if ps -p $pid > /dev/null 2>&1; then print_message $YELLOW "实例 $port 已经在运行中 (PID: $pid)" return else # PID文件存在但进程不存在,清理PID文件 rm -f "$pid_file" fi fi print_message $GREEN "正在启动实例 $port (配置文件: $profile)..." # 启动应用 nohup java $JAVA_OPTS \ -Dspring.profiles.active=prod,$profile \ -Dserver.port=$port \ -jar $JAR_NAME \ > "$log_file" 2>&1 & local new_pid=$! echo $new_pid > "$pid_file" # 等待启动 sleep 3 # 检查启动状态 if ps -p $new_pid > /dev/null 2>&1; then print_message $GREEN "实例 $port 启动成功 (PID: $new_pid)" print_message $GREEN "访问地址: http://localhost:$port" print_message $GREEN "日志文件: $log_file" else print_message $RED "实例 $port 启动失败,请检查日志文件: $log_file" rm -f "$pid_file" fi } # 停止单个实例 stop_instance() { local port=$1 local pid_file="logs/ruoyi-admin-${port}.pid" if [ -f "$pid_file" ]; then local pid=$(cat "$pid_file") if ps -p $pid > /dev/null 2>&1; then print_message $YELLOW "正在停止实例 $port (PID: $pid)..." kill $pid # 等待进程结束 local count=0 while ps -p $pid > /dev/null 2>&1 && [ $count -lt 30 ]; do sleep 1 count=$((count + 1)) done # 强制杀死进程 if ps -p $pid > /dev/null 2>&1; then print_message $YELLOW "强制停止实例 $port..." kill -9 $pid fi rm -f "$pid_file" print_message $GREEN "实例 $port 已停止" else print_message $YELLOW "实例 $port 未运行" rm -f "$pid_file" fi else print_message $YELLOW "实例 $port 未运行" fi } # 重启单个实例 restart_instance() { local port=$1 print_message $YELLOW "重启实例 $port..." stop_instance $port sleep 2 start_instance $port ${INSTANCES[$port]} } # 查看实例状态 status_instance() { local port=$1 local pid_file="logs/ruoyi-admin-${port}.pid" if [ -f "$pid_file" ]; then local pid=$(cat "$pid_file") if ps -p $pid > /dev/null 2>&1; then local memory=$(ps -o rss= -p $pid | awk '{print $1/1024 " MB"}') local uptime=$(ps -o etime= -p $pid) print_message $GREEN "实例 $port: 运行中 (PID: $pid, 内存: $memory, 运行时间: $uptime)" else print_message $RED "实例 $port: 异常 (PID文件存在但进程不存在)" rm -f "$pid_file" fi else print_message $YELLOW "实例 $port: 未运行" fi } # 启动所有实例 start_all() { print_message $GREEN "启动所有实例..." for port in "${!INSTANCES[@]}"; do start_instance $port ${INSTANCES[$port]} sleep 2 done } # 停止所有实例 stop_all() { print_message $YELLOW "停止所有实例..." for port in "${!INSTANCES[@]}"; do stop_instance $port done } # 重启所有实例 restart_all() { print_message $YELLOW "重启所有实例..." stop_all sleep 3 start_all } # 查看所有实例状态 status_all() { print_message $GREEN "所有实例状态:" for port in "${!INSTANCES[@]}"; do status_instance $port done } # 显示帮助信息 show_help() { echo "多实例启动脚本使用方法:" echo " $0 [命令] [实例名称]" echo "" echo "命令:" echo " start 启动实例" echo " stop 停止实例" echo " restart 重启实例" echo " status 查看实例状态" echo "" echo "实例名称:" echo " 9900 启动9900端口实例" echo " 9901 启动9901端口实例" echo " 9902 启动9902端口实例" echo " 9903 启动9903端口实例" echo " all 操作所有实例" echo "" echo "示例:" echo " $0 start 9900 # 启动9900端口实例" echo " $0 start all # 启动所有实例" echo " $0 stop 9900 # 停止9900端口实例" echo " $0 status all # 查看所有实例状态" echo " $0 restart all # 重启所有实例" } # 主函数 main() { local action=$1 local instance=$2 # 检查参数 if [ -z "$action" ]; then show_help exit 1 fi # 检查JAR文件 check_jar case $action in start) if [ "$instance" = "all" ]; then start_all elif [ -n "${INSTANCES[$instance]}" ]; then start_instance $instance ${INSTANCES[$instance]} else print_message $RED "无效的实例名称: $instance" show_help exit 1 fi ;; stop) if [ "$instance" = "all" ]; then stop_all elif [ -n "${INSTANCES[$instance]}" ]; then stop_instance $instance else print_message $RED "无效的实例名称: $instance" show_help exit 1 fi ;; restart) if [ "$instance" = "all" ]; then restart_all elif [ -n "${INSTANCES[$instance]}" ]; then restart_instance $instance else print_message $RED "无效的实例名称: $instance" show_help exit 1 fi ;; status) if [ "$instance" = "all" ]; then status_all elif [ -n "${INSTANCES[$instance]}" ]; then status_instance $instance else print_message $RED "无效的实例名称: $instance" show_help exit 1 fi ;; *) print_message $RED "无效的命令: $action" show_help exit 1 ;; esac } # 执行主函数 main "$@"