Pull to refresh

Настройка Elastic Beanstalk для повышения отказоустойчивости и автоматического масштабирования

Level of difficultyMedium
Reading time6 min
Views822

Всем привет! Сегодняшняя статья, как вы увидели в заголовке, посвящена настройке Elastic Beanstalk, а конкретно - балансировщика AWS и количества инстансов TagretGroup в зависимости от нужных нам условий.

Введение в Elastic Beanstalk

pic 0. Elastic Beans
pic 0. Elastic Beans

Elastic Beanstalk представляет собой высокоуровневую сервисную платформу, которая автоматизирует развертывание приложений в облаке. EB автоматически настраивает необходимую инфраструктуру и ресурсы, такие как экземпляры EC2 (виртуальные серверы), группы безопасности, объекты S3 для хранения файлов версии приложения, базы данных RDS, балансировщики нагрузки Elastic Load Balancing и многое другое, чтобы обеспечить запуск приложения с минимальными затратами времени и усилий со стороны разработчика.

Ключевыми компонентами Elastic Beanstalk являются:

  1. Приложение (Application) является основной единицей. Сначала вы создаете приложение, которое служит контейнером для ваших версий и окружений.

  2. Окружение (Environment) представляет собой версию приложения, которая развертывается на конкретной инфраструктуре AWS и служит выполнения определенной роли, например, тестового или продакшн окружения.

Ресурсы, с которыми мы будем иметь дело:

  • EC2 (Elastic Compute Cloud) - это виртуальные серверы, которые можно арендовать в облаке AWS для запуска приложений.

  • Target Group - это концепция, используемая в AWS для управления трафиком на уровне приложений. Target Group позволяют указать куда именно должен быть направлен трафик, поступающий на балансировщик нагрузки (Load Balancer). Каждая Target Group ассоциирована с определёнными ресурсами, например с EC2 либо лямбда-функциями.

  • Auto Scaling Groups дают возможность автоматического масштабирования количества экземпляров EC2 в ответ на изменения нагрузки/возникновения других факторов

После небольшого описания EB, приступим к теме статьи.

Вступление и проблемы

pic 1. EB Environment Events
pic 1. EB Environment Events

Наше приложение было запущено на одном экземпляре c5.xlarge и все status checks от AWS выдавали "Success", машина была в состоянии "Running", однако приложение не отвечало. Посмотрев логи сервера, мы поняли, что проблема крылась в перезапуске IIS (эта процедура стандартная - обычно это происходит каждые 29 часов, но также можно настроить период индивидуально).

Однако выяснилось, что сервер перезапустился только через 4 (!) минуты. В контексте нашего приложения 4 минуты неработоспособности веб-сервера недопустимо.

К сожалению, такого рода падения сервера мы не смогли определить с помощью системы мониторинга NewRelic. Всё что мы получили из его логов - что сервер не отвечал на запросы, факты увеличения времени отклика и пр. показатели.

Поэтому в итоге мы решили использовать стандартные фичи ElasticBeanstalk для того чтобы повысить отказоустойчивость нашего приложения. И тут возникли следующие мысли - следует не только заменять неработающие инстансы, но и при большой нагрузке увеличивать их число, либо уменьшать при малой.

Elastic Beanstalk

EB не заточен под работу с одной машиной, поэтому после разговора с заказчиком мы сделали такой сэтап:

  • 2x c5.large (c5.large стоит ровно в 2 раза дешевле, чем c5.xlarge)

  • если в течении 5 минут нагрузка на процессор >80%, мы добавляем еще одни инстанс

  • если в течении 5 минут нагрузка на процессор <40%, мы убираем один инстанс

pic 2. configuration
pic 2. configuration
Конфигурация
Resources:
  AWSEBAutoScalingGroup:
    Type: "AWS::AutoScaling::AutoScalingGroup"
    Properties:
      MinSize: 2
      MaxSize: 3
      
  AWSEBCloudwatchAlarmHigh:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      EvaluationPeriods: 1 
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Period: 300
      Statistic: Average
      ComparisonOperator: GreaterThanOrEqualToThreshold
      Threshold: 80
      Unit: Percent
      AlarmActions:
        - Ref: "AWSEBAutoScalingScaleUpPolicy"
        
  AWSEBCloudwatchAlarmLow:
    Type: "AWS::CloudWatch::Alarm"
    Properties:
      EvaluationPeriods: 1
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Period: 300
      Statistic: Average
      ComparisonOperator: LessThanOrEqualToThreshold
      Threshold: 40
      Unit: Percent
      AlarmActions:
        - Ref: "AWSEBAutoScalingScaleDownPolicy"
        
  AWSEBAutoScalingScaleUpPolicy:
    Type: "AWS::AutoScaling::ScalingPolicy"
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName:
        Ref: "AWSEBAutoScalingGroup"
      Cooldown: 360
      ScalingAdjustment: 1

Главная проблема такого решения в том, что оно не будет работать как задумано - по умолчанию AWS считает, что если все Status Check на инстансе проходят, то на него можно пускать траффик. Что неверно для нашего кейса - нам нужно добавить к этим проверкам наш собственный HealthCheck, установленный в .NET приложении.

Начнем!

Конфигурация

Для конфигурации нам понадобиться Environment ID и вот эти вкладки в сайдбаре EC2:

pic 3. EC2 Sidebar
pic 3. EC2 Sidebar

Пойдем по порядку:

1) Target Groups

Здесь нам нужно в соответствием с нашими критериями uptime'а задать конфигурацию TG.
Для нашем случае мы посчитали достаточным обнаружение unhealthy машины через 1 минуту:

3 запроса каждые 15 секунд + таймауты (5 сек) = 1 минута

pic 4. Tagret Group health check settings
pic 4. Tagret Group health check settings

Также во вкладке Attributes есть важный параметр - Deregistration delay. Когда инсанc перестает отвечать по /hc, то он должен быть заменен за время, указанное в этом параметре:

pic 5. TG Deregistration Delay
pic 5. TG Deregistration Delay
Конфигурация
Resources:
  AWSEBV2LoadBalancerTargetGroup:
    Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
    Properties:
      HealthCheckIntervalSeconds: 15
      HealthCheckPath: /hc
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 5
      UnhealthyThresholdCount: 3
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: '20'

2) Auto Scaling Groups

2.1 Enable HealthChecks & Set grace period

Самый важный параметр, без которого все конфигурации выше не будут применены:

pic. 6
pic. 6

Чтобы добавить проверку по ELB, нужно нажать на "Turn on Elastic Load Balancing health checks" и установить Health check grace period.

Health check grace period - это время ожидания, в течение которого AWS не будет предпринимать никаких действий по удалению или замене только что созданных (или запущенных) инстансов в рамках Auto Scaling Group, даже если они не проходят health check.

Например, мы только запустили своё новое приложение и ему нужно некоторое время, чтобы полностью загрузиться и начать работать правильно. Если бы AWS сразу же начинал проверять, работает ли оно как надо, и при этом видел, что что-то не так (потому что приложению просто еще нужно время, чтобы завершить все процессы запуска), то AWS маркировал бы его как unhealthy и попытаться перезапустить его или создать новый экземпляр.

pic. 7
pic. 7

Подбор оптимального grace period - задача не самая тривиальная. Мы просто замерили сколько в среднем времени нужно новому приложению, чтобы оно начало отдавать 200-е запросы. Для нашего приложения это менее 8 минут, поэтому мы выставили с запасом значение 500 секунд.

Следует учитывать разные факторы, которые могут увеличить время загрузки приложения - миграции БД или крупные обновления приложения. В таких случаях потребуется увеличить grace period вручную

Конфигурация
Resources:
  AWSEBAutoScalingGroup:
    Type: "AWS::AutoScaling::AutoScalingGroup"
    Properties:
      HealthCheckType: ELB
      HealthCheckGracePeriod: 500

2.2 Instance maintenance policy

Также нам нужно разрешить ELB превышать лимит в N инстансов в случае, если один из них не отвечает, но еще не удален из EB. То есть мы хотим разрешить превентивно добавлять 1 инстанс, пока происходит удаление нерабочего. В итоге мы будем одномоментно иметь на 1 инстанс больше, чем разрешено в EB. Для этого в Auto Scaling Group выбираем параметр "Instance maintenance policy" и устанавливаем для него значение Launch before terminating:

pic 8. ASG Instance maintenance policy (example for 2 instances)
pic 8. ASG Instance maintenance policy (example for 2 instances)

Эксперимент

Давайте проверим, как будет вести себя балансировщик, если мы целенаправленно остановим наше приложение на одном инстансе (например командой Stop-Service)

Немного изменим нашу конфигурация для эксперимента - максимальное количество инстансов сделаем равным 2, оставив такие же параметры CPU:

pic 9. Demo configuration
pic 9. Demo configuration

Cтоит упомянуть, что в нашем кейсе также настроен Blue/Green Deployment, но его конфигурация выходит за рамки этой статьи.

Видим рабочие инстансы:

pic 10. Running instances
pic 10. Running instances

Останавливаем сервис на одном из них:

pic 11. Stopping the service
pic 11. Stopping the service

В течении одной минуты (по нашим настройкам TargetGroups) мы увидим следующую картину:

pic 12. Severe Status
pic 12. Severe Status

Инстанс закономерно не прошел HealthCheck и в теперь весь траффик идет на единственный оставшийся инстанс.

И в тоже время (как мы помним, в течении 20 секунд) стартует запуск нового инстанса, даже пока предыдущий не удалён! В результате мы видим 3 инстанса (конечно, рабочих инстансов всегда будет всего 2):

pic 13. 3 Instances
pic 13. 3 Instances

После удаления нерабочего инстанса наша система возвращается в стабильное состояние из двух рабочих машин.

Что можно увидеть и в EB Envorinment Events:

pic 14. Final EB Envorinment Events
pic 14. Final EB Envorinment Events

Заключение

На этом всё, надеемся что описание нашего кейса сэкономило вам немало времени и вы узнали больше о настройке Elastic Beanstalk в AWS.


Tags:
Hubs:
Total votes 2: ↑2 and ↓0+2
Comments0

Articles