You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写bash脚本基于SQS队列负载实现EC2实例自动扩缩容

问题1:仅用bash脚本实现自动扩缩容的可行性

完全可以实现,不需要依赖CloudWatch和Auto Scaling Groups。你只需要找一个固定运行的环境(比如本地机器、一台长期运行的轻量EC2)跑控制脚本即可,核心逻辑如下:

  • 每15秒调用aws sqs get-queue-attributes接口拉取目标队列的ApproximateNumberOfMessages指标,用你给出的公式计算需要的总实例数
  • 调用aws ec2 describe-instances接口过滤出你提前打了统一业务标签的运行中EC2实例,统计当前运行数N
  • 计算差值:差值为正则创建对应数量的实例,差值为负则销毁对应数量的多余实例
  • 整个逻辑放入死循环,每次循环结束执行sleep 15即可

这里给出核心控制脚本的参考实现:

# 自定义配置项
QUEUE_URL="替换为你的SQS队列URL"
WORKER_TAG="Key=sqs-worker,Value=business"
AMI_ID="替换为你使用的AMI ID,推荐用预装了aws-cli的Amazon Linux 2/2023的公共AMI"
INSTANCE_TYPE="t2.micro"
IAM_PROFILE_NAME="替换为你提前创建的有权限访问SQS的IAM实例配置文件名"
USER_DATA_PATH="./worker_process.sh" # 替换为你的实例消息处理脚本路径

while true; do
  # 获取队列待处理消息数
  MSG_COUNT=$(aws sqs get-queue-attributes \
    --queue-url "$QUEUE_URL" \
    --attribute-names ApproximateNumberOfMessages \
    --query 'Attributes.ApproximateNumberOfMessages' \
    --output text)
  # 计算期望实例数,整数除法向上取整
  DESIRED_COUNT=$(( (MSG_COUNT + 9) / 10 ))
  # 统计当前运行的worker实例数
  RUNNING_COUNT=$(aws ec2 describe-instances \
    --filters "Name=tag:$WORKER_TAG" "Name=instance-state-name,Values=running" \
    --query 'Reservations[*].Instances[*].InstanceId' \
    --output text | wc -w)
  # 计算扩缩容差值
  DIFF=$(( DESIRED_COUNT - RUNNING_COUNT ))

  if [ $DIFF -gt 0 ]; then
    # 批量创建不足的实例
    aws ec2 run-instances \
      --image-id "$AMI_ID" \
      --instance-type "$INSTANCE_TYPE" \
      --iam-instance-profile Name="$IAM_PROFILE_NAME" \
      --tag-specifications "ResourceType=instance,Tags=[{$WORKER_TAG}]" \
      --count $DIFF \
      --user-data "file://$USER_DATA_PATH"
    echo "完成扩容:新增$DIFF个worker实例"
  elif [ $DIFF -lt 0 ]; then
    # 销毁多余实例,优先销毁启动时间最早的实例
    TERMINATE_NUM=$(( -DIFF ))
    TERMINATE_IDS=$(aws ec2 describe-instances \
      --filters "Name=tag:$WORKER_TAG" "Name=instance-state-name,Values=running" \
      --query "sort_by(Reservations[*].Instances[], &LaunchTime)[:$TERMINATE_NUM].InstanceId" \
      --output text)
    aws ec2 terminate-instances --instance-ids $TERMINATE_IDS
    echo "完成缩容:销毁$TERMINATE_NUM个多余worker实例"
  fi
  sleep 15
done
问题2:创建可直接处理SQS消息的EC2实例最简方案

不需要额外配置私有VPC和安全组,用AWS默认VPC的默认配置即可满足需求,默认安全组本来就放通了所有出方向流量,默认VPC的EC2可以直接访问公网SQS端点。你只需要提前做好1项权限配置即可:

  • 在IAM控制台创建一个EC2类型的实例配置文件(Instance Profile),附加仅允许访问目标SQS队列的权限策略(也可以临时用AmazonSQSFullAccess权限做测试)
  • 创建EC2实例时指定上述实例配置文件,不需要在实例里硬编码AK/SK即可直接调用SQS接口
  • 把消息处理逻辑写入实例的用户数据(UserData),实例启动后会自动执行该逻辑,直接拉取SQS消息处理即可

这里给出实例内消息处理脚本的参考实现:

#!/bin/bash
# 预装依赖(Amazon Linux默认已装aws-cli,若用其他系统需要自行安装)
yum install -y jq aws-cli
QUEUE_URL="替换为你的SQS队列URL"

while true; do
  # 长轮询拉取消息,最多等20秒
  MESSAGE=$(aws sqs receive-message \
    --queue-url "$QUEUE_URL" \
    --max-number-of-messages 1 \
    --wait-time-seconds 20)
  # 没拉到消息就继续循环
  [ -z "$MESSAGE" ] && continue

  # 解析消息内容和删除凭证
  MSG_BODY=$(echo "$MESSAGE" | jq -r '.Messages[0].Body')
  RECEIPT_HANDLE=$(echo "$MESSAGE" | jq -r '.Messages[0].ReceiptHandle')

  # 这里替换为你自己的业务处理逻辑
  echo "处理消息内容:$MSG_BODY"

  # 处理完成后删除队列中的消息
  aws sqs delete-message --queue-url "$QUEUE_URL" --receipt-handle "$RECEIPT_HANDLE"
done

内容的提问来源于stack exchange,提问作者Doraemon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 05:06:08