Socket.io Websockets на настроенном TCP-контроллере Amazon Elastic Load Balancer

Я планирую создать группу серверов приложений NodeJS с Socket.io на EC2, и я бы хотел использовать Эластичная балансировка нагрузки, чтобы распределить нагрузку между ними. Я знаю, что ELB не поддерживает Websockets из коробки, но я могу использовать описанную здесь настройку здесь, в сценарии 2.

Как описано в сообщении в блоге, однако, я замечаю, что эта настройка не предлагает никакой близости к сеансу или информации об источнике IP:

Мы не можем иметь Session Affinity или заголовки X-Forward с этой настройкой потому что ELB не анализирует HTTP-сообщения, поэтому его невозможно согласовать файлы cookie, чтобы обеспечить Session Affinity или Inject special Заголовки X-Forward.

Будет ли Socket.io работать в этих условиях? Или есть другой способ иметь набор серверов приложений Socket.io за балансировщиком нагрузки с SSL?

EDIT: Тим Касуэлл говорит об этом уже здесь. Есть ли сообщения, объясняющие, как это установить? Опять здесь нет липкости сеанса, но все, кажется, работает нормально.

Как в стороне, действительно ли нужны липкие сеансы с помощью websockets? Передает ли информация как новые и отдельные запросы или существует только один запрос + соединение, которое перемещает вся информация?

Ответы

Ответ 1

Теперь вы можете использовать новый балансировщик нагрузки приложений, недавно запущенный AWS.

Просто замените ELB (теперь называемый классическим балансировщиком нагрузки) на ALB (балансировщик нагрузки приложения) и включите липкие сеансы.

ALB поддерживает веб-сокеты. Это должно сделать трюк.

https://aws.amazon.com/blogs/aws/new-aws-application-load-balancer/

http://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html

Ответ 2

Socket.io не работает из коробки даже с помощью ELB TCP, поскольку перед обновлением соединения с веб-сайтами он выполняет два HTTP-запроса.

Первое соединение используется для установления протокола, поскольку socket.io поддерживает больше, чем просто веб-порты.

GET /socket.io/1/?t=1360136617252 HTTP/1.1
User-Agent: node-XMLHttpRequest
Accept: */*
Host: localhost:9999
Connection: keep-alive

HTTP/1.1 200 OK
Content-Type: text/plain
Date: Wed, 06 Feb 2013 07:43:37 GMT
Connection: keep-alive
Transfer-Encoding: chunked

47
xX_HbcG1DN_nufWddblv:60:60:websocket,htmlfile,xhr-polling,jsonp-polling
0

Второй запрос используется для фактического обновления соединения:

GET /socket.io/1/websocket/xX_HbcG1DN_nufWddblv HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: MTMtMTM2MDEzNjYxNzMxOA==
Host: localhost:9999

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 249I3zzVp0SzEn0Te2RLp0iS/z0=

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

Данные с сохраненной в памяти информации являются врагом балансировки нагрузки. К счастью, socket.io поддерживает использование Redis для хранения данных. Если вы сообщаете свое redis-соединение с несколькими серверами, они по сути используют сеансы всех клиентов.

Подробнее о настройке Redis см. в странице сокета socket.io.

Ответ 3

Как я упоминал в сообщении, мы используем только ELB для ssl terminate и load-balance в кластере http-proxy-серверов, поддерживающих веб-узлы. ELB напрямую не разговаривает с серверами websocket. Кластер прокси-сервера HTTP обрабатывает поиск правильного сервера socket.io для подключения к обеспечению конфиденциальности сеанса.

Ответ 4

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

Одно из ограничений Socket.io, SockJS и подобных библиотек заключается в том, что они должны постоянно разговаривать с одним и тем же экземпляром сервера. Они отлично работают, когда есть только один экземпляр сервера.

Когда вы масштабируете приложение в облачной среде, балансировщик нагрузки (Nginx в случае Cloud Foundry) возьмет на себя ответственность, и запросы будут отправлены в разные экземпляры, вызывающие разрыв Socket.io.

Чтобы помочь в таких ситуациях, балансировки нагрузки имеют функцию, называемую "липкие сеансы", а также "аффинность сессии". Основная идея заключается в том, что если это свойство установлено, то после первого запроса с балансировкой нагрузки все следующие запросы будут отправляться на один и тот же экземпляр сервера.

В Cloud Foundry, липкие сеансы на основе файлов cookie включены для приложений, которые устанавливают cookie jsessionid.

Примечание. jsessionid - это имя файла cookie, обычно используемое для отслеживания сеансов в приложениях Java/ Spring. Cloud Foundry просто принимает это как липкий файл cookie для всех фреймворков.

Итак, все приложения должны сделать это, чтобы установить файл cookie с именем jsessionid, чтобы сделать работу socket.io.

app.use(cookieParser); app.use(express.session({store: sessionStore, ключ: "jsessionid", секрет: "ваш секрет здесь" }));

Итак, это шаги:

Экспресс устанавливает cookie сеанса с именем jsessionid. Когда socket.io подключается, он использует тот же файл cookie и попадает в балансировщик нагрузки Балансировщик нагрузки всегда направляет его на тот же сервер, на котором был установлен файл cookie. Если вы используете Application Load Balancer, тогда Sticky настройки сеанса находятся на уровне целевой группы.