23 January 2012

Балансировщик нагрузки для Amazon EC2 c автомасштабированием

System administration
Sandbox
Многие знают, что Amazon предоставляет возможность автоматически наращивать мощность вашего пула (увеличивать количество виртуальных серверов) в зависимости от нагрузки. Однако я не сумел найти в русскоязычном сегменте сети толкового описания практической реализации такой схемы. Рискну представить на суд общественности итог моих штудий на данную тему.

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


Для всего этого мы подняли виртуальный сервер (EC2 instance в терминологии Amazon, далее я иногда буду использовать и вульгарную кальку с английского — «инстанс»), на котором настроили весь необходимый софт. Важно, чтобы всё было сделано так, чтобы ПО не нуждалось ни в какой дополнительной настройке, и таких одинаковых машин можно было бы запустить столько, сколько необходимо, не вызывая при этом никаких конфликтов, потому что стартует instance из готового зафиксированного слепка. Такой сервер у нас в проекте будет служить множественным front-end, на который и будет балансироваться нагрузка средствами Amazon, при этом база данных у нас хранится отдельно, а контент пользователей (например закачиваемые фотографии и аватары) — вообще на хранилище Amazon S3.

Что ж, считаем что эталонный front-end у нас готов, можем приступать.

Вот как будет выглядеть схема с некоторого отдаления:
image

1. Сначала снимем образ с эталонного instance


Быстрее всего сделать это средствами AWS management console, т.е. через веб-интерфейс. Для этого заходим в пункт меню ELASTIC BLOCK STORE -> Snapshots и делаем новый снимок (snapshot) с тома нашего front-end. Затем, щёлкнув правой кнопкой мыши по получившемуся снимку, выбираем пункт «Create image from snapshot» для получения образа (т.н. AMI) для дальнейшего клонирования. При создании AMI важно указать правильный (тот же, что и в эталонном instance) идентификатор ядра (Kernel ID), иначе есть шанс что AMI просто не будет запускаться.

2. Установим необходимый инструментарий для работы с балансировщиком и автомасштабированием


Собственно, управлять вашей фермой можно абсолютно с любого компьютера, мы выбрали для себя один из серверов с Ubuntu, поэтому привожу примеры настройки именно для этой OS.

2.1. Поставим java (если ещё не установлена) и пропишем переменную окружения JAVA_HOME

apt-get install default-jdk


Добавим в /etc/environment строку (в данном случае)
JAVA_HOME="/usr/lib/jvm/java-6-openjdk"


Далее ставим инструментарий Amazon. Я ставлю его в каталог /opt, и делаю символические ссылки, для облегчения поиска необходимых папок в дальнейшем, но это конечно дело вкуса.

2.2. Поставим инструментарий Amazon для настройки балансировщика

wget http://ec2-downloads.s3.amazonaws.com/ElasticLoadBalancing.zip
unzip ElasticLoadBalancing.zip
mv ElasticLoadBalancing-1.0.15.1 /opt/
ln -s /opt/ElasticLoadBalancing-1.0.15.1 /opt/ELB


Добавляем переменные окружения (я делаю это путём редактирования /etc/environment)
в переменную PATH необходимо добавить пути "/opt/ELB:/opt/ELB/bin"

Добавить туда же переменную AWS_ELB_HOME:
AWS_ELB_HOME="/opt/ELB"


Создать файл /opt/ELB/credential-file, куда прописать ваши AWS credentials (если не знаете что это — см. AWS management console -> Security credentials) в формате:
AWSAccessKeyId=xxx
AWSSecretKey=xxx



chmod 600 /opt/ELB/credential-file


Добавить в /etc/environment переменную AWS_CREDENTIAL_FILE:
AWS_CREDENTIAL_FILE="/opt/ELB/credential-file"


2.3. Поставим инструментарий Amazon для настройки автомасштабирования

wget http://ec2-downloads.s3.amazonaws.com/AutoScaling-2011-01-01.zip
unzip AutoScaling-2011-01-01.zip
mv AutoScaling-1.0.39.0 /opt/
ln -s /opt/AutoScaling-1.0.39.0/ /opt/AS


Добавляем переменные окружения в /etc/environment — в переменную PATH необходимо добавить пути "/opt/AS:/opt/AS/bin"

Добавить туда же переменную AWS_AUTO_SCALING_HOME:
AWS_AUTO_SCALING_HOME="/opt/AS"


2.4. Поставим инструментарий Amazon для настройки мониторинга

wget http://ec2-downloads.s3.amazonaws.com/CloudWatch-2010-08-01.zip
unzip CloudWatch-2010-08-01.zip
mv CloudWatch-1.0.12.1 /opt/
ln -s /opt/CloudWatch-1.0.12.1/ /opt/CW


Добавляем переменные окружения в /etc/environment — в переменную PATH необходимо добавить пути "/opt/CW:/opt/CW/bin"

Добавить туда же переменную AWS_CLOUDWATCH_HOME:
AWS_CLOUDWATCH_HOME="/opt/CW"


2.5. Проверка установленного инструментария

Для проверки переменных, установленных в /etc/environment можно перелогиниться или ещё каким-либо образом перечитать их.
Даём команды:
elb-cmd --help

as-cmd --help

mon-cmd --help

Каждая из них должна выдать справку, либо если были какие-то погрешности при установке — указать на них.

3. Поехали. Собственно настроим балансировщик нагрузки с автомасштабированием


3.1. Создаём балансировщик


elb-create-lb myLB --headers --listener "lb-port=80,instance-port=80,protocol=http" --region us-west-1 --availability-zones us-west-1c


Где myLB — имя нашего балансировщика
--listener «lb-port=80,instance-port=80,protocol=http» — слушаем порт 80, направляем трафик на порт 80 на целевом instance и используем протокол http
--region us-west-1 регион, где будет поднят балансировщик
--availability-zones us-west-1c зона, где будет поднят балансировщик

В ответ мы получим что-то вроде:

DNS_NAME  DNS_NAME
DNS_NAME myLB-108660279.us-west-1.elb.amazonaws.com

Это и есть адрес нашего будущего балансировщика

3.2. Создаём проверочный тест для балансировщика (healthcheck)

Это тест, благодаря которому балансировщик понимает, что целевой инстанс уже плотненько нагружен и переводит трафик на следующий инстанс.
elb-configure-healthcheck myLB --headers --target "HTTP:80/" --interval 30  --timeout 10 --unhealthy-threshold 2 --healthy-threshold 2 --region us-west-1


где myLB — имя нашего балансировщика
--headers — опциональный параметр, включающий вывод названий полей в описании данного healthchek
--target «HTTP:80/» — протокол: порт/URI для проверки
--interval 30 — интервал проверки (проверяем раз в 30 секунд)
--timeout 10 — таймаут, если превышен — инстанс чувствует себя плоховато
--unhealthy-threshold 2 — сколько проверок сделать, прежде чем окончательно убедиться, что инстанс нездоров
--healthy-threshold 2 — сколько проверок сделать, прежде чем окончательно убедиться, что инстанс таки здоров
--region us-west-1 — регион размещения

При удачном выполнении команды получим примерно такой вывод:
HEALTH_CHECK  TARGET  INTERVAL  TIMEOUT  HEALTHY_THRESHOLD  UNHEALTHY_THRESHOLD
HEALTH_CHECK  HTTP:80/index.html  30        10       2                  2


3.3. Создаём конфигурацию для запуска нового инстанса при автомасштабировании

as-create-launch-config myAS --image-id ami-fd015fb8 --kernel aki-9ba0f1de --key ubuntu --group ubuntu-new 	--region us-west-1 --instance-type m1.xlarge


Где myAS — имя конфигурации
--image-id XXX — ID слепка (AMI), созданного на шаге 1
--kernel XXX — Kernel ID для AMI, созданного на шаге 1
--key XXX — название вашего ключа доступа
--group ХХХ — название security group — набора правил брэндмауэра для доступа к данному инстансу
--instance-type XXX — тип запускаемого инстанса
--region us-west-1 — регион

В случае удачного создания конфигурации получаем такой вывод:
OK-Created launch config


3.4. Описываем свойства пула серверов при автомасштабировании, привязываем пул к балансировщику

as-create-auto-scaling-group myASG  --launch-configuration myAS --availability-zones us-west-1c --min-size 1 --max-size 20 --load-balancers myLB  --grace-period 500 --health-check-type ELB --region us-west-1


Где myASG — имя пула
--launch-configuration myAS — имя конфигурации для запуска из предыдущего шага
--min-size 1 — минимальный размер пула
--max-size 20 -максимальный размер пула
--load-balancers myLB — привязка к балансировщику
--grace-period 300 — важный параметр, указывающий, через сколько секунд после старта нового инстанса на него можно подавать нагрузку. У меня например после старта происходит деплой приложения, поэтому этот период довольно большой
--health-check-type ELB — тип healthchek, в нашем случае — Elastic Load Balancer
--region us-west-1 — регион размещения
--availability-zones us-west-1c — зона

3.5. Описываем политику роста пула

as-put-scaling-policy myUp-policy -auto-scaling-group myASG --adjustment=1 --type ChangeInCapacity  --cooldown 300 --region us-west-1


Где myUp-policy — название политики
-auto-scaling-group myASG -название пула серверов, к которому будет относиться политика
--type ChangeInCapacity — тип политики. В данном случае — абсолютное изменение количества серверов пула. Может принимать также значения ExactCapacity (точное значение нового размера пула), PercentChangeInCapacity (процентное относительно текущего значение изменение размера пула).
--adjustment=1 — в данном случае мы прибавляем один сервер к пулу
--cooldown 600 — таймаут перед следующим изменением размера пула. Должно разумно коррелировать с параметром grace-period (как минимум быть не меньше), заданным на предыдущем шаге
--region us-west-1 регион размещения

В ответ мы получаем строку — дескриптор данной политики, примерно такого вида:
arn:aws:autoscaling:us-west-1:033313991904:scalingPolicy:5ae9e75d-4344-4b3f-abb0-c501c7221ecf:autoScalingGroupName/myASG:policyName/myUp-policy


3.6. Привязываем политику роста пула к мониторингу балансировщика

mon-put-metric-alarm MyHighLatAlarm --metric-name  Latency  --comparison-operator  GreaterThanThreshold  --evaluation-periods  1  --namespace  "AWS/ELB"  --period  60  --statistic Average --threshold  80 --alarm-actions arn:aws:autoscaling:us-west-1:033313991904:scalingPolicy:5ae9e75d-4344-4b3f-abb0-c501c7221ecf:autoScalingGroupName/myASG:policyName/myUp-policy --dimensions "LoadBalancerName=myELB"--unit Seconds --region us-west-1


Где MyHighLatAlarm — название привязки
--metric-name Latency — важный параметр. Мы показываем, что измеряем-то собственно задержку на балансировщике. Эта метрика была создана в момент создания балансировщика автоматически. (в чём можно убедится, проверив вывод команды mon-list-metrics).
--comparison-operator GreaterThanThreshold — оператор сравнения, в данном случае «больше порогового значения», может быть также «GreaterThanOrEqualToThreshold», LessThanThreshold" и «LessThanOrEqualToThreshold»
--evaluation-periods 1 — сколько раз проверить метрику, прежде чем сравнивать с порогом
--namespace «AWS/EC2» — пространство имён (обязательный параметр, зачем он — непонятно)
--period 60 период опроса
--statistic Average — как мы меряем порог. В данном случае — по среднему, а может быть также «SampleCount», «Sum», «Minimum», «Maximum»
--threshold 80 — собственно пороговое значение задержки.
--alarm-actions arn:aws:autoscaling:us-west-1:033313991904:scalingPolicy:5ae9e75d-4344-4b3f-abb0-c501c7221ecf:autoScalingGroupName/myASG:policyName/myUp-policy — говорим что по достижению порога срабатывания исполняем политику, описываемую данным дескриптором, которую мы создали на предыдущем шаге.
--dimensions «LoadBalancerName=myLB» — фильтруем алармы по данному признаку.
--unit Seconds — единицы измерения
--region us-west-1 — регион размещения.

Уфф. Теперь у нас есть пул, который будет реагировать на нагрузку, прибавляя по одному серверу. Однако хочется, чтобы пул «сдувался» в ответ на уменьшение нагрузки. Для этого нам надо описать политику уменьшения пула и привязать её к метрике балансировщика. Не буду повторять подробности, вроде бы тут всё ясно из синтаксиса:

3.7. Описываем политику уменьшения пула

as-put-scaling-policy myScaleDown-policy --auto-scaling-group myASG --adjustment=-1 --type ChangeInCapacity  --cooldown 600 --region us-west-1


Получаем дескриптор политики:
arn:aws:autoscaling:us-west-1:033313991904:scalingPolicy:a764b4d4-aff5-4061-ba3a-c35c05ad1d25:autoScalingGroupName/myASG:policyName/myScaleDown-policy


3.8. Привязываем политику уменьшения пула к мониторингу балансировщика

mon-put-metric-alarm MyLowLatAlarm  --comparison-operator  LessThanThreshold --evaluation-periods  1 --metric-name  Latency --namespace  "AWS/EC2"  --period  600  --statistic Average  --threshold  20  --alarm-actions arn:aws:autoscaling:us-west-1:033313991904:scalingPolicy:a764b4d4-aff5-4061-ba3a-c35c05ad1d25:autoScalingGroupName/myASG:policyName/myScaleDown-policy ---dimensions "LoadBalancerName=myLB" --unit Seconds --region us-west-1


4. Обращаемся к балансировщику по имени-отчеству


Здорово. Теперь можно потестировать всё это дело, обращаясь к нашему балансировщику по его публичному DNS имени, полученному на шаге 3.1., в нашем случае — myLB-108660279.us-west-1.elb.amazonaws.com

Амазон советует затем завести запись DNS типа CNAME, показывающую на данное имя для домена вашего сайта:
www.site.com IN CNAME myLB-108660279.us-west-1.elb.amazonaws.com

Тогда можно будет попадать на балансировщик, просто обращаясь к www.site.com

5. Как нам от всего этого избавиться?


Теперь пару слов о том, как разобрать сию конструкцию (когда наиграетесь с тестовой версией например), с тем чтобы она зазря не кушала денежки (пусть и небольшие, но всё же). Это внезапно оказалось нетривиальной задачей, т.к. балансер с масштабированием не давал себя разбирать, постоянно плодя новые инстансы и не давая гасить балансировщик, пока за ним эти самые инстансы висели. Вобщем правильная последовательность действий получилась такая:

получим список наших алармов:
mon-describe-alarms --region us-west-1


Вычистим их по одному:
mon-delete-alarms --region  us-west-1 --alarm-name MyHighLatAlarm
mon-delete-alarms --region  us-west-1 --alarm-name MyLowLatAlarm


Получим список наших политик:
as-describe-policies --region us-west-1


Вычистим их по одной:
as-delete-policy myScaleDown-policy  --auto-scaling-group myASG --region us-west-1
as-delete-policy myUp-policy --auto-scaling-group myASG --region us-west-1


Вот она, хитрость-то. Сначала оказывается надо размер группы выставить в ноль, чтобы инстансы не подрывались:
as-update-auto-scaling-group myASG --min-size 0 --max-size 0 --region us-west-1


Теперь подождём минут пять, пока все инстансы не погаснут и удаляем пул:
as-delete-auto-scaling-group myASG --region us-west-1


Удаляем конфигурацию:
as-delete-launch-config myAS --region us-west-1


Ну и наконец гасим балансировщик:
elb-delete-lb myLB --region us-west-1
Tags:облаковиртуализацияhighloadload balancingautoscaleamazon web servicesamazon ec2балансировка нагрузкиавтомасштабирование
Hubs: System administration
+37
8.9k 216
Comments 9