Как реализовать закрепленные сеансы на основе параметров URL в балансировщике нагрузки AWS.
На «лучше». мы склонны раздвигать границы того, что мы знаем, но даже больше того, что возможно, даже когда технология может быть закрыта и официально не поддерживать какую-либо функцию.
Если клиент не попросит об ином, все, что мы создаем, является облачным по дизайну. В то время как «нативное облако» охватывает широкий спектр технологий, мы склонны работать с PaaS, такими как s3, AWS Fargate и т. д., и избегаем работы с обычными виртуальными машинами (мы даже презираем и высмеиваем те, которые это делают). Но бывают случаи, когда его невозможно обойти или он слишком сложен, чтобы его можно было использовать, чтобы результаты в итоге не окупились.
Так было в случае с AWS Elastic Load Balancer (ELB), жестким ограничением, которое было элегантно обойдено благодаря реализации, которую можно воспроизвести для многих вариантов использования.
Прежде чем углубляться, имейте в виду, что эта статья представляет собой не просто учебник о том, как реализовать привязку сеанса на основе параметров URL-адреса, а нестандартный менталитет для подхода к жестким и «невыполнимым» задачам, поэтому без далее давайте погрузимся.
Как официально описано, ELB автоматически распределяет входящий трафик приложений между несколькими целями и виртуальными устройствами в одной или нескольких зонах доступности (AZ). Существует три типа балансировщика нагрузки:
1-Балансировщик нагрузки приложений
2-Балансировщик сетевой нагрузки
3-Балансировщик нагрузки шлюза
В этой статье мы сосредоточимся на балансировщике нагрузки приложений.
Когда вы имеете дело с приложениями без сохранения состояния, готовых конфигураций достаточно для ретрансляции трафика между доступными целями. Хотя в случае видеоконференций или других случаев использования поддержание определенных клиентских отношений с одним сервером или контейнером в течение короткого времени имеет решающее значение, следует использовать закрепленные сеансы. К счастью, AWS поддерживает закрепленные сеансы, как указано на их веб-сайте:
Закрепленные сеансы — это механизм маршрутизации запросов от одного клиента к одной и той же цели. Эластичные балансировщики нагрузки поддерживают закрепленные сеансы. Прилипчивость определяется на уровне целевой группы.
Отлично
НО
Он поддерживает привязку на основе определенного файла cookie и/или времени, но не на основе других атрибутов, например: параметры URL.
Вот с чего начинается путешествие :)
Дело
Нам пришлось интегрировать телеконференции (jitsi) как часть более крупного продукта, который мы разрабатывали, и клиент дал следующие ограничения:
1- Он не должен быть слишком дорогим / разумно масштабироваться в зависимости от использования (учитывая, что его будут использовать 50-200 тысяч конечных пользователей)
2- Он должен поддерживать межплатформенные конференции (Android, iOS, Интернет и т. д.)
3- Он не должен полагаться на третьих лиц
4- Это должно быть настраиваемо
Что касается второго и третьего ограничения, то было ясно, что он должен использовать webrtc, поэтому многие альтернативы были сразу вырезаны.
Поскольку нашим облачным провайдером является AWS, мы взглянули на звуковой сигнал AWS, и в то время он взимал плату за ежемесячных активных пользователей. Это означало, что если клиент будет вести успешный маркетинг, при котором люди по крайней мере один раз попробуют продукт (были пробные пакеты), то затраты будут сумасшедшими, учитывая, что не обязательно все лиды конвертируются в платящих клиентов. Таким образом, это также исключило бы звуковой сигнал AWS. По этой причине нам пришлось удалить все другие услуги SAAS по той же причине, поскольку все они предлагали оплату за ежемесячных активных пользователей (MOA).
Итак, как вы можете догадаться, появился свет в конце туннеля, ПРИВЕТСТВУЙТЕ открытому исходному коду!
Мы изучили jitsi, кросс-платформенную экосистему инструментов с открытым курсом для создания современных возможностей телеконференций, ее можно было настраивать, ее можно было настроить для работы по мере необходимости и интегрировать в наше собственное решение, как в мобильную, так и в веб-версию.
Было коммерческое предложение jitsi как SAAS, но проблема заключалась в том, что он не поддерживал нашу страну, Албанию, и был ужасно дорогим (используя модель MOA)).
Итак, все, что нам нужно было сделать, это настроить автомасштабируемую версию jitsi, чтобы иметь возможность масштабировать столько, сколько необходимо, когда это необходимо, без взимания платы исключительно за количество активных пользователей.
Итак, все, что нам нужно было сделать, это найти в Интернете автомасштабируемую реализацию, и все, верно?
Как сделать решение автоматически масштабируемым?
Есть много способов сделать решение автоматически масштабируемым, один из них — контейнеры.
Только в AWS существует не менее семнадцати способов развертывания контейнерного решения, но вот наиболее, пожалуй, «серьезные» предложения:
1- ECS с экземплярами EC2
2- ECS с AWS Fargate
3- ЭКС (Кубернетес)
4- Лямбда
Теперь, если вы посмотрите на проект jitsi, там есть репозиторий с компоновщиком докеров, и если вы попробуете его на одном сервере, все будет работать нормально и кажется многообещающим, но проблема, которая быстро возникает, — это масштабирование. Ни в одном руководстве в Интернете не было комплексного решения о том, как его реализовать, все, кто его создал, предлагали его на коммерческой основе.
Таким образом, о его развертывании с лямбдой не могло быть и речи, функции не предназначены для видеоконференций.
Kubernetes был невозможен, так как время для внедрения было коротким, в Интернете не было ничего, что мы могли бы легко развернуть, и у команды не было предыдущего опыта в производстве или времени, чтобы привыкнуть к этому, плюс у клиента не было опыта ни в Kubernetes, ни в удалении. это из списка.
Для развертывания в fargate было предпринято слишком много попыток, но, поскольку вы не можете ссылаться на контейнеры внутри fargate с помощью собственного имени хоста, реализовать это в то время было невозможно.
Последний подход заключался в использовании ecs с экземплярами ec2. Так мы и сделали. Давайте погрузимся еще дальше.
Базовый уровень
Вся инфраструктура, которую мы создавали, была написана, а затем развернута в terraform. Поэтому, естественно, мы искали и нашли среду post и GitHub для реализации Auto Scaling.
Все было отлично, слишком хорошо, чтобы быть правдой, мы нашли правильную реализацию автомасштабирования, так что нам оставалось только развернуть ее сразу, а потом настроить под наши нужды, самое сложное было сделано.
Мы быстро развернули его, запустили автомасштабирование и запустили две ВМ, каждая с набором контейнеров. Мы связали его с приложением и интерфейсом, и иногда он работал как надо, а иногда — нет. Иногда люди разговаривали друг с другом, а иногда искали себя в зеркале.
Вскоре стало ясно, что все не так хорошо, как мы думали. Балансировщик нагрузки случайным образом ретранслировал трафик между серверами.
Jitsi работает с комнатами. Два человека, чтобы разговаривать друг с другом, должны находиться в комнате, комната определяется в URL-адресе, например: https://example.com/room_name.
Случилось так, что если два человека присоединялись к одной и той же комнате на разных серверах, они как будто находились на разных серверах.
К счастью, AWS поддерживает фиксированные сеансы, но не на основе параметров URL, а только на основе файлов cookie.
Мы должны были серьезно подумать об этом.
Альтернативные подходы
Альтернативный подход заключался в реализации HA-Proxy, альтернативы с открытым исходным кодом, но реализация ее в собственном облаке была слишком сложной и явно не была изначально связана со всеми другими нативными компонентами, такими как контейнеры и т. д.
Решение
Стало очевидно, что нам нужно найти способ обойти ограничения эластичного балансировщика нагрузки.
Теоретически нам нужен был механизм для перехвата трафика до того, как он достигнет балансировщика нагрузки, добавить нужные куки и перехватить их позже, чтобы сохранить новые куки, сделать это молниеносно быстро, чтобы задержка была незаметной, и сделать это очень экономичным способом. .
Обман ELB
Чтобы выполнить правильную операцию, вам нужно точно знать, как работают липкие сеансы elb на основе файлов cookie.
Поскольку AWS запрашивает у вас только имя вашего файла cookie, если мы перехватим трафик только для того, чтобы поместить значение комнаты в параметр URL внутри заголовков (эмулируя файл cookie) до достижения балансировщика нагрузки, он его обманет.
Лучший способ реализовать это в режиме реального времени — использовать lambda @edge, ведь официальное объяснение AWS выглядит следующим образом:
Lambda@Edge — это функция Amazon CloudFront, позволяющая запускать код ближе к пользователям вашего приложения, что повышает производительность и уменьшает задержку.
Существует четыре типа лямбда @edge, которые вы можете написать, как показано на изображении ниже:
Итак, мы написали легкую лямбду, которая сделает именно это, настроив ее в облаке как запрос зрителя, чтобы он мог управлять ею напрямую. Итак, мы сделали. Так и не получилось :).
Перехитрить ELB
Проблема заключалась в том, что по мере того, как мы погружались еще дальше, ELB при получении файла cookie должен был генерировать несколько новых файлов cookie, он также генерировал некоторые свои собственные файлы cookie с такими ключами, как: «AWSALBAPP-0», «AWSALBAPP-1», «AWSALBAPP-2». «AWSALBAPP-3» и их значения вместе с нашим файлом cookie room_name. Однако проблема заключалась в том, что в нашем случае все остальные файлы cookie были пустыми.
Как выяснилось позже, сервер пришлось настроить так, чтобы куки отражались обратно. Так как jitsi понятия не имел о приходе cookie. Короче говоря, мы создали собственный образ для веб-сервера jitsi и добавили волшебную строку в конфигурацию nginx:
proxy_set_header Cookie $http_cookie;
Это перенаправляло полученные файлы cookie на другой конец.
Наконец, к концу запроса у нас появились специальные файлы cookie ELB.
Поскольку видеозвонок будет происходить между мобильным устройством и другим пользователем веб-сайта, чтобы полностью перехитрить elb, нам нужно было получать новые файлы cookie после каждого запроса с другим лямбда @edge (ответ источника), сохранять их где-нибудь, чтобы в следующем запросе другой пользователь (даже этот) независимо от устройства, чтобы получать одинаковые файлы cookie для данной комнаты.
Каков самый быстрый и дешевый способ безопасно сохранять и извлекать небольшие порции данных в AWS?
Введите ДИНАМОДБ.
DynamoDB — это облачная база данных NoSQL, предлагаемая Amazon. Он предлагает однозначные миллисекунды при чтении и записи.
Таким образом, для каждого запроса лямбда будет получать параметр URL, искать в DynamoDB значение файла cookie для этого имени комнаты, получать его и дополнять запрос, чтобы «содержать» файл cookie.
Затем после этого сервер пересылает файл cookie, другая лямбда получает новые файлы cookie, сгенерированные elb, и сохраняет их в DynamoDB.
Этого было достаточно и достаточно быстро, чтобы сделать весь процесс бесшовным и обойти неотъемлемую проблему мобильных приложений с файлами cookie.
Полировка
Чтобы быть еще быстрее, мы бы сохранили объект с именами комнат и их значениями cookie в корне лямбды, чтобы для последующего запроса ему даже не нужно было обращаться к DynamoDB, а использовать объект как слой кэширования.
Поскольку DynamoDB будет постоянно заполнять файлы cookie, мы использовали Amazon DynamoDB Time-to-Live (TTL), который позволяет автоматически удалять их по истечении определенного периода времени.
Итак, все, что нам оставалось делать, — это смотреть Netflix и отдыхать, пока решение масштабируется, масштабируется, поддерживает сеансы.
Вот и все! Пожалуйста, поделитесь этой записью в блоге, чтобы распространять знания.
Добавьте меня в Linkedin, если статья показалась вам интересной :D