在linux服务器上平滑发布(蓝绿发布)java项目,不影响现有业务运行
具体操作
- 使用nginx作为负载均衡,配置upstream(注意修改项目名)
upstream 项目名 {
server localhost:7008 max_fails=3 fail_timeout=30s;
server localhost:7009 max_fails=3 fail_timeout=30s;
}
- 启动命令(注意修改jar位置及端口号),后修改为
start.sh
并开放权限
#!/bin/sh
RESOURCE_NAME=你的jar具体位置
#默认端口号
DEFAULT_PORT=7008
#另一端口号
ALTERNATE_PORT=7009
STARTUP_TIMEOUT=60 # 等待新服务启动的超时时间(秒)
CHECK_INTERVAL=2 # 检查间隔时间(秒)
check_port() {
netstat -tuln | grep ":$1 " > /dev/null
return $?
}
start_app() {
PORT=$1
nohup java -Xms256m -Xmx512m -jar $RESOURCE_NAME --spring.profiles.active=prod --server.port=$PORT > nohup_$PORT.out 2>&1 &
echo $! > tpid_$PORT
echo "应用程序启动成功,使用端口 $PORT"
}
wait_for_startup() {
PORT=$1
TIMEOUT=$2
INTERVAL=$3
START_TIME=$(date +%s)
while [ $(($(date +%s) - $START_TIME)) -lt $TIMEOUT ]; do
check_port $PORT
if [ $? -eq 0 ]; then
echo "端口 $PORT 的应用程序已启动"
return 0
fi
echo "等待端口 $PORT 的应用程序启动..."
sleep $INTERVAL
done
echo "等待超时,端口 $PORT 的应用程序未启动"
return 1
}
stop_app() {
PORT=$1
tpid=$(ps -ef | grep $RESOURCE_NAME | grep $PORT | grep -v grep | grep -v kill | awk '{print $2}')
if [ -n "$tpid" ]; then
echo "停止进程,端口 $PORT, PID: $tpid..."
kill -15 $tpid
sleep 5
tpid=$(ps -ef | grep $RESOURCE_NAME | grep $PORT | grep -v grep | grep -v kill | awk '{print $2}')
if [ -n "$tpid" ]; then
echo "强制终止进程,PID: $tpid..."
kill -9 $tpid
else
echo "进程停止成功!"
fi
else
echo "未找到端口 $PORT 的进程停止。"
fi
}
# 检查默认端口是否被占用
check_port $DEFAULT_PORT
if [ $? -eq 0 ]; then
echo "端口 $DEFAULT_PORT 已被占用,使用端口 $ALTERNATE_PORT 启动应用程序"
start_app $ALTERNATE_PORT
if wait_for_startup $ALTERNATE_PORT $STARTUP_TIMEOUT $CHECK_INTERVAL; then
echo "停止使用端口 $DEFAULT_PORT 的应用程序"
stop_app $DEFAULT_PORT
else
echo "备用端口的应用程序启动失败,保持原服务运行"
fi
else
echo "端口 $DEFAULT_PORT 未被占用,使用该端口启动应用程序"
start_app $DEFAULT_PORT
if wait_for_startup $DEFAULT_PORT $STARTUP_TIMEOUT $CHECK_INTERVAL; then
echo "停止使用端口 $ALTERNATE_PORT 的应用程序"
stop_app $ALTERNATE_PORT
else
echo "默认端口的应用程序启动失败,保持备用服务运行"
fi
fi
echo "服务切换完成!"
说明:
启动应用程序:start_app 函数启动应用程序,并指定使用的端口。
等待应用程序完全启动:
wait_for_startup 函数会在指定的超时时间内轮询检查指定端口是否已经开始监听(应用程序是否已完全启动)。
这个函数会每 CHECK_INTERVAL 秒检查一次端口,直到超过 STARTUP_TIMEOUT 秒。
停止旧的应用程序:只有在新的应用程序完全启动后,才会停止旧的应用程序。
超时处理:如果在指定时间内新服务未能启动,将会输出相应的信息,并保留原服务继续运行。
使用说明:
STARTUP_TIMEOUT:等待新服务启动的最大时间(秒)。
CHECK_INTERVAL:检查新服务是否启动的间隔时间(秒)。