合肥网站建设培训机构,重庆网润集团有限公司,游戏代理哪个平台正规,河南快速网站备案介绍
本项目通过使用 Nginx 和 Java 应用实现了服务实例的动态扩展功能。当健康检查接口的响应时间超过设定阈值时#xff0c;系统会自动新增服务实例以分担负载#xff1b;当负载压力降低时#xff0c;系统会自动减少不必要的实例数#xff0c;从而确保服务的稳定性和高可…介绍
本项目通过使用 Nginx 和 Java 应用实现了服务实例的动态扩展功能。当健康检查接口的响应时间超过设定阈值时系统会自动新增服务实例以分担负载当负载压力降低时系统会自动减少不必要的实例数从而确保服务的稳定性和高可用性。
功能特点
动态扩缩容根据健康检查接口的响应时间动态调整服务实例数量。负载均衡通过 Nginx 配置实现负载均衡支持动态更新后端实例。冷却机制避免频繁的扩缩容操作确保系统的稳定性。日志记录所有扩缩容操作都会被记录到 autoscale.log 文件中便于排查问题。 快速开始
环境要求
操作系统Linux推荐 CentOS 或 Ubuntu软件依赖 JDK 1.8Nginx
安装步骤 安装 Nginx 和 JDK 运行以下命令安装必要的软件并启动相关服务 ./install.sh准备 Java 应用程序 将编译好的 JAR 文件放置在 /root/app.jar 路径下路径可以在 auto_scale.sh 中修改。 启动自动扩缩容脚本 启动 autoscale.sh 脚本进行自动扩缩容 ./auto_scale.sh验证运行状态 查看 Nginx 是否正常运行systemctl status nginx查看日志文件tail -f autoscale.log 自动扩缩容逻辑
配置参数
参数名描述默认值PORT_RANGE可用端口范围8081-9000MIN_INSTANCES最小实例数2MAX_INSTANCES最大实例数10HEALTH_CHECK_URL健康检查接口地址http://localhost/healthRESPONSE_TIME_THRESHOLD响应时间阈值毫秒500COOL_DOWN_TIME冷却时间秒60
扩容触发条件
当健康检查接口的响应时间超过 RESPONSE_TIME_THRESHOLD默认为 500ms时系统会尝试扩容。如果当前实例数已达到 MAX_INSTANCES则不会继续扩容。
缩容触发条件
当前实例数超过 MIN_INSTANCES 且无负载压力时系统会尝试缩容。如果当前实例数已达到 MIN_INSTANCES则不会继续缩容。
冷却机制
在每次扩缩容操作后系统会在 COOL_DOWN_TIME默认为 60秒内暂停任何新的扩缩容操作以避免频繁调整。 日志管理
所有的扩缩容操作日志会被记录到 autoscale.log 文件中。以下是日志示例
2023-10-01 10:00:00 当前实例数2
2023-10-01 10:00:00 当前响应时间600 ms
2023-10-01 10:00:00 扩容启动新实例监听端口 8083
2023-10-01 10:00:00 Nginx 配置已更新新增端口 8083可以通过以下命令实时查看日志
tail -f autoscale.log配置文件说明
autoscale.sh
该脚本实现了自动扩缩容的核心逻辑包括健康检查、扩容、缩容以及 Nginx 配置的动态更新。
install.sh
用于自动化安装 Nginx 和 JDK并配置初始环境。
nginx.conf
Nginx 的配置文件定义了负载均衡规则和健康检查接口。以下是关键部分
upstream backend动态添加服务实例的 IP 和端口。location /将请求转发到后端服务。location /health定义健康检查接口的路径。 常见问题
Q: 扩缩容脚本无法正常运行怎么办
A:
检查是否正确安装了 Nginx 和 JDK。确保 JAR 文件已放置在指定路径。查看 autoscale.log 文件中的错误信息。
Q: 如何调整扩缩容参数
A: 编辑 autoscale.sh 文件修改以下参数
PORT_RANGE调整可用端口范围。MIN_INSTANCES 和 MAX_INSTANCES设置最小和最大实例数。RESPONSE_TIME_THRESHOLD调整健康检查的响应时间阈值。COOL_DOWN_TIME调整冷却时间。
Q: 如何测试健康检查接口
A: 使用以下命令测试健康检查接口的响应时间
curl -o /dev/null -s -w %{time_total}\n http://localhost/health未来改进方向
支持多节点部署目前仅支持单机环境下的扩缩容后续可以扩展为支持多节点的集群环境。集成监控系统将扩缩容日志集成到 Prometheus 或 Grafana 中提供更直观的监控界面。动态调整阈值根据历史数据动态调整扩缩容的触发条件提升智能化水平。
源码下载 服务自动添加实例工具 核心脚本 script/auto_scale.sh #!/bin/bash# 配置参数
PORT_RANGE8081-9000 # 端口范围
START_PORT$(echo $PORT_RANGE | cut -d- -f1)
END_PORT$(echo $PORT_RANGE | cut -d- -f2)MIN_INSTANCES2 # 最小实例数
MAX_INSTANCES10 # 最大实例数
HEALTH_CHECK_URLhttp://localhost/health # 拨测接口
RESPONSE_TIME_THRESHOLD500 # 响应时间阈值毫秒
COOL_DOWN_TIME60 # 冷却时间60秒
JAR_PATH/root/app.jar # JAR 包路径# 全局变量
CURRENT_INSTANCE_COUNT0
LAST_ACTION_TIME0# 端口映射文件路径
PORT_MAPPING_FILE$(pwd)/app_port_mapping.txt# 初始化端口映射文件
if [ ! -f $PORT_MAPPING_FILE ]; thentouch $PORT_MAPPING_FILE
fi# 获取当前实例数
get_instance_count() {CURRENT_INSTANCE_COUNT$(pgrep -f java -jar $JAR_PATH | wc -l)
}# 检查是否在冷却时间内
is_in_cool_down() {local current_time$(date %s)if ((current_time - LAST_ACTION_TIME COOL_DOWN_TIME)); thenreturn 0 # 在冷却时间内elsereturn 1 # 不在冷却时间内fi
}# 扩容
scale_up() {if ((CURRENT_INSTANCE_COUNT MAX_INSTANCES)); thenecho $(date) 达到最大实例数无法扩容 autoscale.logreturnfi# 查找下一个可用端口local portfor port in $(seq $START_PORT $END_PORT); doif ! grep -q :$port $PORT_MAPPING_FILE; thenbreakfidoneif [ -z $port ]; thenecho $(date) 无可用地址范围内的端口 autoscale.logreturnfi# 启动新实例nohup java -jar $JAR_PATH --server.port$port app_$port.log 21 local pid$!# 记录 PID 和端口到映射文件echo $pid:$port $PORT_MAPPING_FILEecho $(date) 扩容启动新实例监听端口 $portPID $pid autoscale.log# 更新 Nginx 配置update_nginx_config# 记录最后操作时间LAST_ACTION_TIME$(date %s)
}# 获取端口函数
get_port_by_pid() {local pid$1local port$(lsof -Pn -p $pid | grep LISTEN | awk {print $9} | grep -oE :[0-9] | cut -d: -f2)echo $port
}# 缩容
scale_down() {if ((CURRENT_INSTANCE_COUNT MIN_INSTANCES)); thenecho $(date) 达到最小实例数无法缩容 autoscale.logreturnfi# 获取最后一个实例的 PID 和端口last_line$(tail -n 1 $PORT_MAPPING_FILE)if [ -z $last_line ]; thenecho $(date) 映射文件为空无法缩容 autoscale.logreturnfilast_pid$(echo $last_line | cut -d: -f1)last_port$(echo $last_line | cut -d: -f2)# 停止实例kill $last_pid 2/dev/nullsed -i $d $PORT_MAPPING_FILE # 删除最后一行记录echo $(date) 缩容停止实例端口 $last_portPID $last_pid autoscale.log# 更新 Nginx 配置update_nginx_config# 记录最后操作时间LAST_ACTION_TIME$(date %s)
}# 更新 Nginx 配置
update_nginx_config() {# 获取所有正在运行的实例的端口local ports()while IFS: read -r pid port; doif kill -0 $pid 2/dev/null; thenports(127.0.0.1:$port)else# 如果进程已不存在清理映射文件sed -i /^$pid:$port$/d $PORT_MAPPING_FILEfidone $PORT_MAPPING_FILE# 如果没有找到任何端口退出if [ ${#ports[]} -eq 0 ]; thenecho $(date) 没有可用的端口跳过 Nginx 配置更新 autoscale.logreturnfi# 动态生成 upstream 配置local upstream_configupstream backend {\nfor p in ${ports[]}; doupstream_config server $p;\ndoneupstream_config}\n# 替换 nginx.conf 中的 upstream 部分sed -i /upstream backend {/,/}/d /etc/nginx/nginx.confsed -i /http {/a\\$upstream_config /etc/nginx/nginx.conf# 重新启动 Nginxsystemctl restart nginxecho $(date) Nginx 配置已更新$(echo ${ports[]}) autoscale.log
}# 检查健康状态
check_health() {# 发起请求并获取响应时间和状态码local response$(curl -o /dev/null -s -w %{http_code} %{time_total} $HEALTH_CHECK_URL)local http_code$(echo $response | awk {print $1})local response_time$(echo $response | awk {print $2})# 将响应时间转换为毫秒response_time$(echo $response_time * 1000 | bc) # 转换为毫秒echo $(date) 当前响应时间$response_time ms, HTTP 状态码$http_code autoscale.log# 检查 HTTP 状态码是否为 2xxif [ $http_code -lt 200 ] || [ $http_code -ge 300 ]; thenecho $(date) 服务不健康HTTP 状态码为 $http_code autoscale.logif is_in_cool_down; thenecho $(date) 冷却中跳过扩容 autoscale.logelsescale_upfireturnfi# 使用 bc 进行浮点数比较检查响应时间是否超过阈值if [ $(echo $response_time $RESPONSE_TIME_THRESHOLD | bc) -eq 1 ]; thenecho $(date) 响应时间超过阈值 ($RESPONSE_TIME_THRESHOLD ms) autoscale.logif is_in_cool_down; thenecho $(date) 冷却中跳过扩容 autoscale.logelsescale_upfifi
}# 清理函数
cleanup() {echo $(date) 开始清理... autoscale.log# 杀掉所有由该脚本启动的 Java 进程pids$(pgrep -f java -jar $JAR_PATH)if [ -n $pids ]; thenecho $(date) 正在杀掉 Java 进程: $pids autoscale.logkill $pidsfi# 删除端口映射文件rm -f $PORT_MAPPING_FILEecho $(date) 删除端口映射文件 autoscale.log# 还原 Nginx 配置NGINX_CONF_PATH/etc/nginx/nginx.confCUSTOM_NGINX_CONF_PATH$(pwd)/nginx.confif [ -f $CUSTOM_NGINX_CONF_PATH ]; thencp $CUSTOM_NGINX_CONF_PATH $NGINX_CONF_PATHecho $(date) Nginx 配置已还原 autoscale.logelseecho 未找到自定义的 Nginx 配置文件请确保 nginx.conf 存在于当前目录 autoscale.logexit 1fi# 关闭 Nginxsystemctl stop nginxecho $(date) 清理完成 autoscale.logexit 0
}# 捕获 SIGTERM 和 SIGINT 信号
trap cleanup SIGTERM SIGINT# 主循环
while true; doget_instance_countecho $(date) 当前实例数$CURRENT_INSTANCE_COUNT autoscale.log# 如果实例数小于最小值启动新实例if ((CURRENT_INSTANCE_COUNT MIN_INSTANCES)); thenecho $(date) 实例数低于最小值启动新实例 autoscale.logwhile ((CURRENT_INSTANCE_COUNT MIN_INSTANCES)); doscale_upget_instance_countdone# 扩容完成后等待一段时间例如60秒echo $(date) 扩容完成等待 $COOL_DOWN_TIME 秒后再触发健康检查 autoscale.logsleep $COOL_DOWN_TIMEficheck_health# 检查是否需要缩容if ((CURRENT_INSTANCE_COUNT MIN_INSTANCES)); thenif is_in_cool_down; thenecho $(date) 冷却中跳过缩容 autoscale.logelsescale_downfifi# 动态更新 Nginx 配置update_nginx_configsleep 10 # 每10秒检查一次
done script/install.sh #!/bin/bash# 安装 Nginx
echo 正在安装 Nginx...
if yum install -y nginx; thenecho Nginx 安装成功
elseecho Nginx 安装失败请检查系统环境exit 1
fi# 替换默认的 Nginx 配置文件为自定义的配置文件
echo 正在替换 Nginx 配置文件...
NGINX_CONF_PATH/etc/nginx/nginx.conf
CUSTOM_NGINX_CONF_PATH$(pwd)/nginx.conf # 假设当前目录下有 nginx.conf 文件if [ -f $CUSTOM_NGINX_CONF_PATH ]; thencp $CUSTOM_NGINX_CONF_PATH $NGINX_CONF_PATHecho Nginx 配置文件替换成功
elseecho 未找到自定义的 Nginx 配置文件请确保 nginx.conf 存在于当前目录exit 1
fiecho 正在安装 jdk...
if yum install -y java-1.8.0-openjdk-devel.x86_64; thenecho jdk 安装成功
elseecho jdk 安装失败请检查系统环境exit 1
fi# 提示用户完成安装
echo 安装完成请确保 JAR 包位于指定路径并正确运行。 script/nginx.conf worker_processes 1;events {worker_connections 1024;
}http {upstream backend {# 动态添加服务实例的 IP 和端口}server {listen 80;location / {proxy_pass http://backend;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}# 健康检查接口location /health {proxy_pass http://backend/health;}}
}