Настройка автоскейлинга серверов веб-приложения

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка автоскейлинга серверов веб-приложения
Сложная
~3-5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Настройка автоскейлинга серверов веб-приложения

Автоскейлинг автоматически добавляет серверы при росте нагрузки и убирает их в периоды затишья. Главная цель — не переплачивать за простаивающие мощности и не терять запросы при пиках трафика.

Метрики для скейлинга

Правильный выбор метрики определяет качество автоскейлинга:

Метрика Когда использовать Порог
CPU Utilization CPU-intensive приложения 60–70%
Request Count (RPS) Stateless HTTP-сервисы по бизнес-тесту
Memory Utilization Memory-intensive 70–80%
Queue Depth (SQS/RabbitMQ) Worker-процессы 100–500 сообщений
Custom metric (p95 latency) Latency-sensitive API 200–500 мс

CPU-метрика запаздывает — сервер сначала тормозит, потом скейлится. RPS-метрика реагирует быстрее. Для типичного веб-приложения комбинируют CPU + Request Count.

AWS Auto Scaling Group

Самый распространённый сценарий — EC2 ASG с Application Load Balancer.

# Terraform: Launch Template + ASG
resource "aws_launch_template" "app" {
  name_prefix   = "myapp-"
  image_id      = data.aws_ami.ubuntu.id
  instance_type = "t3.medium"

  user_data = base64encode(<<-EOF
    #!/bin/bash
    cd /var/www/myapp
    git pull origin main
    systemctl restart php8.3-fpm
    systemctl reload nginx
  EOF
  )

  network_interfaces {
    associate_public_ip_address = false
    security_groups             = [aws_security_group.app.id]
  }

  iam_instance_profile {
    name = aws_iam_instance_profile.app.name
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "app" {
  name                = "myapp-asg"
  vpc_zone_identifier = aws_subnet.private[*].id
  target_group_arns   = [aws_lb_target_group.app.arn]
  health_check_type   = "ELB"
  health_check_grace_period = 300

  min_size         = 2
  max_size         = 20
  desired_capacity = 2

  launch_template {
    id      = aws_launch_template.app.id
    version = "$Latest"
  }

  instance_refresh {
    strategy = "Rolling"
    preferences {
      min_healthy_percentage = 50
    }
  }

  tag {
    key                 = "Name"
    value               = "myapp-app"
    propagate_at_launch = true
  }
}

# Target Tracking Policy: CPU
resource "aws_autoscaling_policy" "cpu" {
  name                   = "myapp-cpu-tracking"
  autoscaling_group_name = aws_autoscaling_group.app.name
  policy_type            = "TargetTrackingScaling"

  target_tracking_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ASGAverageCPUUtilization"
    }
    target_value       = 65.0
    scale_in_cooldown  = 300
    scale_out_cooldown = 60
  }
}

# Target Tracking Policy: ALB Request Count per Target
resource "aws_autoscaling_policy" "rps" {
  name                   = "myapp-rps-tracking"
  autoscaling_group_name = aws_autoscaling_group.app.name
  policy_type            = "TargetTrackingScaling"

  target_tracking_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ALBRequestCountPerTarget"
      resource_label         = "${aws_lb.main.arn_suffix}/${aws_lb_target_group.app.arn_suffix}"
    }
    target_value = 1000.0  # запросов на инстанс
  }
}

ECS Fargate Auto Scaling

Для контейнерных приложений ECS Fargate проще — нет EC2, только задачи.

resource "aws_appautoscaling_target" "ecs" {
  max_capacity       = 50
  min_capacity       = 2
  resource_id        = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.app.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

resource "aws_appautoscaling_policy" "ecs_cpu" {
  name               = "myapp-ecs-cpu"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.ecs.resource_id
  scalable_dimension = aws_appautoscaling_target.ecs.scalable_dimension
  service_namespace  = aws_appautoscaling_target.ecs.service_namespace

  target_tracking_scaling_policy_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageCPUUtilization"
    }
    target_value       = 60.0
    scale_in_cooldown  = 300
    scale_out_cooldown = 30
  }
}

# Scale by SQS queue depth (worker service)
resource "aws_appautoscaling_policy" "ecs_sqs" {
  name               = "myapp-worker-sqs"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.worker.resource_id
  scalable_dimension = aws_appautoscaling_target.worker.scalable_dimension
  service_namespace  = aws_appautoscaling_target.worker.service_namespace

  target_tracking_scaling_policy_configuration {
    customized_metric_specification {
      metric_name = "ApproximateNumberOfMessagesNotVisible"
      namespace   = "AWS/SQS"
      statistic   = "Sum"
      dimensions {
        name  = "QueueName"
        value = aws_sqs_queue.jobs.name
      }
    }
    target_value = 100.0  # сообщений на задачу
  }
}

Kubernetes HPA и KEDA

Kubernetes Horizontal Pod Autoscaler работает с CPU и Memory из коробки. KEDA (Kubernetes Event-Driven Autoscaling) добавляет внешние метрики: SQS, RabbitMQ, Kafka, Prometheus.

# HPA по CPU + Memory
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
  namespace: myapp
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp-web
  minReplicas: 2
  maxReplicas: 50
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 65
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 75
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 30
      policies:
        - type: Pods
          value: 4
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 25
          periodSeconds: 60
# KEDA ScaledObject — RabbitMQ queue
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: myapp-worker-scaler
  namespace: myapp
spec:
  scaleTargetRef:
    name: myapp-worker
  minReplicaCount: 1
  maxReplicaCount: 30
  pollingInterval: 10
  cooldownPeriod: 60
  triggers:
    - type: rabbitmq
      metadata:
        host: amqp://rabbitmq.myapp.svc.cluster.local
        queueName: email-queue
        mode: QueueLength
        value: "50"     # 50 сообщений на под

Scheduled Scaling

Для предсказуемых пиков (ночная рассылка, распродажи по расписанию) добавляют scheduled actions.

import boto3
from datetime import datetime, timezone

client = boto3.client('application-autoscaling', region_name='eu-west-1')

# Масштабирование вверх перед пиком (пятница 18:00 UTC)
client.put_scheduled_action(
    ServiceNamespace='ecs',
    ResourceId='service/myapp-cluster/myapp-web',
    ScalableDimension='ecs:service:DesiredCount',
    ScheduledActionName='scale-up-friday-evening',
    Schedule='cron(0 18 ? * FRI *)',
    ScalableTargetAction={
        'MinCapacity': 10,
        'MaxCapacity': 50,
    }
)

# Возврат к нормальному режиму (воскресенье 22:00 UTC)
client.put_scheduled_action(
    ServiceNamespace='ecs',
    ResourceId='service/myapp-cluster/myapp-web',
    ScalableDimension='ecs:service:DesiredCount',
    ScheduledActionName='scale-down-sunday-night',
    Schedule='cron(0 22 ? * SUN *)',
    ScalableTargetAction={
        'MinCapacity': 2,
        'MaxCapacity': 20,
    }
)

Warm Pool для EC2

Warm Pool держит инстансы в состоянии Stopped или Running (без трафика), чтобы скейлинг занимал секунды, а не минуты.

resource "aws_autoscaling_group" "app" {
  # ... основная конфигурация

  warm_pool {
    pool_state                  = "Stopped"  # экономия: инстансы остановлены
    min_size                    = 2
    max_group_prepared_capacity = 5

    instance_reuse_policy {
      reuse_on_scale_in = true
    }
  }
}

Graceful Shutdown

При scale-in инстанс получает сигнал завершения. Приложение должно успеть завершить текущие запросы.

// Node.js Express
const server = app.listen(3000);

process.on('SIGTERM', () => {
  console.log('SIGTERM received, shutting down gracefully');

  server.close(() => {
    console.log('HTTP server closed');
    process.exit(0);
  });

  // Принудительное завершение через 30 секунд
  setTimeout(() => {
    console.error('Forced shutdown');
    process.exit(1);
  }, 30000);
});
// PHP-FPM: pm.process_idle_timeout = 10s
// nginx upstream: proxy_read_timeout 60s
// ASG: lifecycle hook + heartbeat timeout

Lifecycle hook в AWS позволяет выполнить команды до реального завершения инстанса:

# Lambda-функция на lifecycle hook (TERMINATING:WAIT)
# 1. Снять инстанс с балансировщика (ALB делает автоматически)
# 2. Дождаться завершения активных соединений
# 3. aws autoscaling complete-lifecycle-action --lifecycle-action-result CONTINUE

Мониторинг автоскейлинга

# CloudWatch алерты
- Metric: GroupDesiredCapacity > 15 → Slack alert (неожиданный рост)
- Metric: GroupInServiceInstances < 2 → PagerDuty (мало инстансов)
- Metric: WarmPoolMinSize не выполняется → проверить бюджет

Grafana дашборд: aws_autoscaling_group_desired_capacity, aws_autoscaling_group_in_service_instances, aws_alb_request_count в разрезе target group.

Типичные проблемы

Thrashing — постоянное добавление/удаление инстансов из-за короткого cooldown. Решение: увеличить scale_in_cooldown до 300–600 секунд, добавить stabilizationWindowSeconds в HPA.

Медленный старт приложения — инстанс создан, но трафик идёт до готовности. Решение: health check grace period + readiness probe + Warm Pool.

Дорогой scale-in — удаление инстанса с незавершёнными фоновыми задачами. Решение: lifecycle hook + drain очереди перед CONTINUE.

Неправильная метрика — CPU 20%, но приложение тормозит из-за I/O wait. Решение: custom metric (p95 latency через CloudWatch Contributor Insights или Prometheus).

Срок реализации

Конфигурация Срок
EC2 ASG + ALB + CPU scaling 2–3 дня
ECS Fargate + target tracking 1–2 дня
Kubernetes HPA 1 день
KEDA + внешние метрики 2–3 дня
Scheduled scaling + Warm Pool +1–2 дня