Socket.io: AWS EC2 за ELB всегда печатает ошибку Неожиданный код ответа: 400

Созданный на 30 окт. 2014  ·  66Комментарии  ·  Источник: socketio/socket.io

Привет, ребята -

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

WebSocket connection to 'wss://fakedomain.com/socket.io/?EIO=3&transport=websocket&sid=QH8VmXbiEcp3ZyiLAAAD' failed: Error during WebSocket handshake: Unexpected response code: 400 

Я понимаю ошибку, так как он пытается связаться с балансировщиком нагрузки, а теперь и с экземпляром EC2 (я не очень хорошо разбираюсь в AWS, поэтому не стесняйтесь предлагать помощь в этом!), но я не понимаю, как сделать так, чтобы ошибка не появляется!

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

Я предполагаю, что он возвращается к опросу, который, кажется, работает нормально (у меня подключено соединение с сокетом, и оно срабатывает), но я не хочу запускаться с красной ошибкой в ​​моей консоли.

Заранее спасибо за любой совет, который у вас может быть!

Самый полезный комментарий

Я предполагаю, что вы не используете Elastic Beanstalk (инструкции там будут намного проще).

Перейдите в EC2-> Сеть и безопасность-> Балансировщики нагрузки.

Выберите свой балансировщик нагрузки и перейдите в Listeners. Убедитесь, что для протокола Load Balancer и протокола экземпляра установлено значение TCP для порта 80 и SSL для порта 443, а не HTTP и HTTPS.

Все 66 Комментарий

Кроме того, я установил через Bower, если это имеет значение:

"socket.io-клиент": "~1.1.0",

У вас есть липкое соединение на вашем сервере?

Я предполагаю, что вы не используете Elastic Beanstalk (инструкции там будут намного проще).

Перейдите в EC2-> Сеть и безопасность-> Балансировщики нагрузки.

Выберите свой балансировщик нагрузки и перейдите в Listeners. Убедитесь, что для протокола Load Balancer и протокола экземпляра установлено значение TCP для порта 80 и SSL для порта 443, а не HTTP и HTTPS.

О чувак. Это дельный совет, которого я больше нигде не встречал. попробую утром
и отчитаться. Спасибо!

Ср, 29 октября 2014, 7:48 вечера Вадим Казаков [email protected]
написал:

Я предполагаю, что вы не используете Elastic Beanstalk (инструкции там
быть намного проще).

Перейдите в EC2-> Сеть и безопасность-> Балансировщики нагрузки.

Выберите свой балансировщик нагрузки и перейдите в Listeners. Убедитесь, что оба
Протокол балансировщика и протокол экземпляра установлены на TCP для порта 80 и
SSL для порта 443, а не HTTP и HTTPS.


Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/Automattic/socket.io/issues/1846#issuecomment -61038664
.

Так что, возможно, я ошибаюсь, но наш сайт работает на HTTPS (с нашим SSL-сертификатом). Изменение их на ломает много вещей в будущем. Я проверял X-Forwarded-Proto в своем приложении, чтобы убедиться, что запрос был HTTPS, а если нет, то принудительно перенаправить его. По-видимому, нет заголовка X-Forwarded-Proto с SSL/TCP, и Express сообщает req.secure как ложный (хотя я набрал https).

Предположение?

Не уверен, сокеты используют протокол TCP/SSL, а не HTTP, поэтому вам нужно будет изменить его на TCP/SSL, чтобы веб-сокеты работали. Что касается того, как исправить остальную часть вашего приложения, я понятия не имею.

Спасибо за помощь. Придется делать новую среду и немного возиться. В машине много винтиков!

Возможно ли, чтобы веб-сокеты работали на своих собственных портах? Если да, не могли бы вы связать какую-нибудь документацию? (уверен, что нет, но могу ошибаться)

Они могут работать с любым портом, который вы хотите, просто укажите при подключении порт следующим образом:

io('https://myserver:123');

Я использую Elasticbeanstalk и сталкиваюсь с той же проблемой, у меня не установлен SSL, но я подключен через обычный http.

Привет,
У меня такая же проблема, но я использую SockJS.
мое приложение представляет собой приложение Java Spring 4, работает на машине разработки и
получая ту же ошибку на AWS.
похоже, что заголовок Upgrade кто-то сбрасывает, я вижу это на клиенте.

еще бы найти решение...

Я нахожусь в одной лодке и общаюсь в чате с инженером AWS, и мы оба в тупике. Я подтвердил, что ELB необходимо изменить с HTTP/HTTPS на TCP (или SSL (Secure TCP)), но я все еще часто получаю 400 ошибок. Никогда не было этой проблемы до перехода на кластер с балансировкой нагрузки Elastic Beanstalk.

пожалуйста, попробуйте прокомментировать любой материал промежуточного программного обеспечения app.use (связанный с заголовком/cors), если таковой имеется, или app.get("/", не уверен, какой из них сработал для меня, но опубликуйте свои результаты, пожалуйста.

Обновление: я подтвердил, что это ELB, независимо от того, настроен ли он для трафика HTTP или HTTPS, socket.io не работает. Когда я иду прямо к одному из EC2, все работает отлично.

В приложении то, что я вижу, когда прохожу ELB.
snipimage

Кажется, я решил свою проблему, добавив экземпляр Route53 перед балансировщиком нагрузки.
теперь у меня есть работающий веб-сокет с безопасными соединениями в среде AWS.

Попробуйте добавить Route 53, если это не решит вашу проблему, я буду рад поделиться своей конфигурацией.

@ yoav200 yoav200 думаете, вы могли бы поделиться всей своей конфигурацией того, что заставило вас работать? Т.е. порты на EBS security + протокол (http/tcp), любые .ebextensions, которые вам нужны, и т.д. Я пробовал массу разных вещей, чтобы взломать мои конфиги nginx, чтобы сохранить заголовки обновления и отправить их на узел, но у меня ничего не получилось. . FWIW - вики-страница была бы очень, очень полезна для этого. Единственное, что сработало, — это переход напрямую к моему экземпляру EC2.

Я установил экземпляр Route 53, который управляет моим доменом.
я настроил размещенную зону с записью, которая указывает мой домен непосредственно на балансировщик нагрузки.

балансировщик нагрузки настроен на пересылку запросов к моим экземплярам Tomcat, как показано здесь:
lb-listeners

группа безопасности для ELB довольно стандартна:
lb-security-group

Вы используете nginx? Приходилось ли вам делать что-то особенное в настройке?

Я очень близок к тому, чтобы это заработало, провел почти 8 часов с инженером службы поддержки AWS за последние два дня. Пришлось вырвать nginx из микса, но я очень близок, сокеты работают нормально через ELB через http, завтра я думаю, что смогу справиться с https на стороне сервера, а не на уровне ELB.

Я сообщу о своих выводах.

Я не использую nginx, я всем управляю на Amazon, я также перенес свой домен на Amazon,
однако я перенес свое приложение из размещенной облачной среды, которая использует AWS для своих экземпляров, но управлял нагрузкой с помощью nginx, и у меня не было проблем.

когда их спросили, как это работает для них, они ответили:

мы не используем Amazon Elastic Load Balancer, мы используем собственный уровень балансировки нагрузки NGinx.
Решением может быть использование сервера Nginx или HAProxy вместо ELB и использование группы автомасштабирования с 1 узлом haproxy/nginx для обеспечения высокой доступности компонента.

Да, мне сказали, что HAProxy — это еще один вариант, но я совершенно уверен, что к концу дня он будет работать со следующими сервисами:

  • Эластичный бобовый стебель
  • ELB
  • Группа автоматического масштабирования EC2 (создана EB)
  • РДС
  • ElastiCache

Приложение Node в настоящее время работает со всеми этими службами, но, как я уже сказал, только через HTTP, так что осталось немного сделать, чтобы подготовить производство. Я сообщу о своих выводах/конфигурациях позже.

@niczak, не

Прямо сейчас я пытаюсь подключиться к Socket.IO на своем экземпляре Node в EC2 вместе с Redis от ElastiCache.

Я открыл экземпляр EC2 для публики, а также ответил общедоступным IP-адресом, чтобы я мог легко подключиться к сокету (http://coding-ceo.ghost.io/how-to-run-socket-io-behind -локоть на ладонь/). на моем ELB я использую липкие сеансы (надеясь, что это останется подключенным), однако мой сокет по-прежнему не подключается и выдает мне прекрасную ошибку: соединение закрыто до получения ответа на рукопожатие.

Однако опрос работает нормально, но попытка заставить сокеты и весь путь работать нормально.

Хотелось бы увидеть здесь пример использования, чтобы я мог правильно настроить свой экземпляр (даже если он только на HTTP вместо http и https), поскольку я уже довольно давно ломаю себе голову.

Большое вам спасибо за вашу помощь!

@петрогад

Эй, Пит!

Мои слушатели ELB настолько просты, насколько это возможно (см. изображение), и по умолчанию порт 80 EC2 перенаправляется на 8080 с помощью iptables. С учетом сказанного я могу подключить свой сервер к HTTPS, затем мое приложение узла прослушивает 8080 и обслуживает сам сертификат SSL.

elb

Код узла для обработки сертификатов выглядит следующим образом:

        files = ["COMODOHigh-AssuranceSecureServerCA.crt", "AddTrustExternalCARoot.crt"];
        ca = (function() {
            var _i, _len, _results;
            _results = [];
            for (_i = 0, _len = files.length; _i < _len; _i++) {
                file = files[_i];
                _results.push(fs.readFileSync('/etc/ssl/tcerts/' + file));
            }
            return _results;
            })();

        httpsOptions = {
            ca: ca,
            key: fs.readFileSync('/etc/ssl/tcerts/multidomain.key', 'utf8'),
            cert: fs.readFileSync('/etc/ssl/tcerts/14432575.crt', 'utf8')
        };

        this.serverPort = 8080;
        var httpsServer = https.createServer(httpsOptions, apiInstance);
        httpsServer.listen(this.serverPort);
        startSockets(httpsServer);

Чтобы веб-сокеты работали (без возврата к длительному опросу), мне _пришлось_ отключить межзональную балансировку нагрузки. К сожалению, AWS не претендует на поддержку веб-сокетов через свой ELB, поэтому такие типы «хаков» конфигурации необходимы. Надеюсь, этого будет достаточно, чтобы вы начали работать!

Спасибо @niczak !

Все работает отлично, шел HTTP-трафик, что мешало. Также работает Redis в нескольких экземплярах; последнее, что нужно сделать, это просто работать с reCluster и позволить маршруту tcp придерживаться определенного рабочего процесса.

Вы добились больших успехов в этом? Я использую экспресс, поэтому липкая сессия не работает. Вам повезло с этим?

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

Спасибо @niczak !!

Я наконец-то тоже заработал. Однако помимо настройки
1) Балансировщик нагрузки для использования протокола TCP
2) Балансировщик нагрузки для отключения балансировки нагрузки между зонами.

мне тоже надо поставить
3) Прокси-сервер должен быть «нет» в разделе «Конфигурация программного обеспечения».

screen shot 2015-01-09 at 10 28 56 am

Это отличные новости @aidanbon и @petrogad , ура сокетам на AWS! : +1:

Большое спасибо! Это решило мою проблему с эластичным бобовым стеблем. Имеет смысл удалить прокси nginx

Обновление из моего исходного поста:

Я изменил свой HTTPS на SSL (443 ---> мой пользовательский порт) и оставил HTTP (80 ---> мой пользовательский порт).

У меня есть код, который проверял экспресс !req.secure && X-Forwarded-Proto !=== https, который перенаправляет вас на HTTPS, если вы заходите на порт 80...

ТЕМ НЕ МЕНИЕ

Переход на SSL приводит к тому, что X-Forwarded-Proto возвращается неопределенным... разрывая это соединение. (также кажется, что req.secure может быть устаревшим)

А сейчас:

if (req.get('X-Forwarded-Proto') === 'http') {
            res.redirect('https://' + req.get('Host') + req.url);
        }

кажется, работает отлично, и я больше не получаю ошибку 400 в консоли.

Привет! Я получил это, используя Node, NGINX, SSL и ELB на Elastic Beanstalk, выполнив следующие действия:

Создайте команду контейнера в .ebextensions, чтобы изменить сценарий конфигурации nginx, чтобы включить веб-сокеты прокси:

container_commands:
    00proxy:
        command: sed -i 's/proxy_http_version.*/proxy_http_version\ 1.1\;\n\ \ \ \ \ \ \ \ proxy_set_header\ \ \ \ \ \ \ \ Upgrade\ \ \ \ \ \ \ \ \ \$http_upgrade\;\n\ \ \ \ \ \ \ \ proxy_set_header\ \ \ \ \ \ \ \ Connection\ \ \ \ \ \ \"upgrade\"\;/g' /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf

Установите сертификат SSL на балансировщик нагрузки с помощью веб-консоли Elastic Beanstalk.

Затем перейдите в веб-консоль EC2 и измените балансировщик нагрузки на прослушивание SSL 443 -> TCP 80. Это не сработало, когда я изменил его в веб-консоли EB, мне пришлось сделать это непосредственно в EC2.

Это должно заставить все работать. Мне не нужно было делать какие-либо перенаправления, и мне также удалось заставить работать NGINX.

@ChrisEdson, есть ли что-нибудь еще, что можно включить в пакет, чтобы использовать это решение?
Я попробовал, но развертывание не удалось из-за ошибок. В журнале отображается следующая строка:

/etc/init.conf: Unable to load configuration: No such file or directory

Можете ли вы опубликовать свой код?

Пт, 4 сен 2015 в 1:13 вечера, Treyone [email protected] писал:

@ChrisEdson, есть ли что-нибудь еще, что можно включить в пакет, чтобы использовать это решение?
Я попробовал, но развертывание не удалось из-за ошибок. В журнале отображается следующая строка:

/etc/init.conf: Unable to load configuration: No such file or directory

Ответьте на это письмо напрямую или просмотрите его на GitHub:
https://github.com/socketio/socket.io/issues/1846#issuecomment -137718880

Код приложения представляет собой чрезвычайно простую реализацию socket.io, почти готовый пример использования.
Единственное, что я добавил, это файл .config в .ebextensions, в который я скопировал фрагмент кода, который вы цитировали ранее.
Так что мне особо нечего написать :)

Не волнуйтесь, просто сложно отлаживать без кода или логов. Можешь выложить логи? Вероятно, здесь не уместно торчать, может быть, положить их в корзину для пасты.

Пт, 4 сен 2015 в 3:26 вечера, Treyone [email protected] писал:

Код приложения представляет собой чрезвычайно простую реализацию socket.io, почти готовый пример использования.
Единственное, что я добавил, это файл .config в .ebextensions, в который я скопировал фрагмент кода, который вы цитировали ранее.

Так что мне особо нечего написать :)

Ответьте на это письмо напрямую или просмотрите его на GitHub:
https://github.com/socketio/socket.io/issues/1846#issuecomment -137749890

Хм, я опубликовал свой код с помощью grunt вместо ручной упаковки, и он работает как шарм. Автоматизация должна быть обязательно ;)

Рад слышать это!

Вт, 8 сен 2015 в 3:14 вечера, Treyone [email protected] писал:

Хм, я опубликовал свой код с помощью grunt вместо ручной упаковки, и он работает как шарм. Автоматизация должна быть обязательно ;)

Ответьте на это письмо напрямую или просмотрите его на GitHub:
https://github.com/socketio/socket.io/issues/1846#issuecomment -138572724

Спаси мой день!

Мы также видели эту основную проблему. По сути, поскольку SocketIO отправляет два запроса для установления соединения через веб-сокет, если эти вызовы объединяются между экземплярами, идентификатор сеанса не распознается и рукопожатие завершается неудачно, что приводит к возврату SocketIO к длительному опросу. Это верно независимо от того, используете ли вы ws или wss; предполагается, что вы настроили балансировку нагрузки на уровне 4 (TCP), так как я не смог заставить балансировку нагрузки уровня 7 (HTTP) работать с веб-сокетами.

Исправление будет состоять в том, чтобы включить фиксированные сеансы, чтобы после того, как вызов переходит к экземпляру, балансировщик нагрузки продолжал отправлять эти запросы к тому же экземпляру; однако, если вы используете ELB AWS, они не позволяют использовать закрепленные сеансы для балансировки нагрузки уровня 4.

В итоге мы использовали необработанные веб-сокеты, а не SocketIO, поскольку тогда нет данных сеанса, которые нужно было бы сохранять между вызовами (происходит только один вызов, рукопожатие, и это работает).

Исправление со стороны AWS будет заключаться в том, чтобы каким-то образом использовать липкие сеансы для балансировки нагрузки уровня 4.

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

Потенциальным решением может быть использование Redis для сохранения состояния сеанса во всех экземплярах. Я не проверял это.

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

@aidanbon Я не смог найти Proxy server to be "none" in the Software Configuration section ?

Я просто использую сервер Ubuntu и MeteorJS с развертыванием mup.. не могли бы вы дать мне ссылку ??

Ваше здоровье

@sahanDissanayake Я нашел свой вариант конфигурации прокси-сервера через:

  1. Нажмите «Конфигурация» в интересующей среде.
  2. Нажмите «Конфигурация программного обеспечения» на странице конфигурации.
  3. Раскрывающийся список «Прокси-сервер», как показано на моем предыдущем снимке экрана.

Примечание. Моя среда была подготовлена ​​почти год назад. Не уверен, что панель AWS обновлена ​​для более новых сред. Тем не менее, я все еще вижу этот раскрывающийся список сегодня в своей среде.

@aidanbon Я не использую никаких других сервисов, кроме ec2 .. так что ваши настройки мне не нужны? или мне нужно начать использовать этот прокси-сервер?

Итак, проблема в том, что веб-сокеты моего веб-приложения работают на порту 8080, но НЕ на порту 80.

Это проблема

@lostcolony Спасибо за резюме. Я пришел к такому же выводу. Вы читали этот пост в блоге: https://medium.com/@Philmod/load-balancing-websockets-on-ec2-1da94584a5e9#.hd2ectz8t ? По сути, он говорит, что можно передать уровень 4 (TCP) через экземпляр HAProxy, который затем снимает заголовок PROXY и направляет трафик в нужный экземпляр, используя липкие сеансы. Однако мне не очевидно, как два HAProxy настраивают свой список «бэкэнд» серверов и где он работает, и где работает фактический сервер socket.io. Можете ли вы понять это?

РЕДАКТИРОВАТЬ: я думаю, что я нажал сейчас. Он знает список, потому что у него есть известный набор серверов, и его не волнует автоматическое масштабирование...

Список серверов будет настроен для каждого блока HAproxy. я не знаю как
чтобы это работало с автоматическим масштабированием экземпляров ec2, если вы не написали какой-то
дополнительная инфраструктура для обновления этого списка при появлении нового сервера
онлайн. Socket.io они работают на том же сервере, что и их веб-приложение, поэтому
соединения поступают через Elb, объединяются с экземпляром HAproxy,
Экземпляр(ы) HAproxy гарантирует, что IP-соединения всегда идут к одному и тому же
веб-сервер/сервер приложений, на котором был настроен socket.io.
13 января 2016 г., 2:50, «Феликс Шлиттер» [email protected] написал:

@lostcolony https://github.com/lostcolony Спасибо за резюме. я
пришли к такому же выводу. Вы читали этот пост в блоге:
https://medium.com/@Philmod/load-balancing-websockets-on-ec2-1da94584a5e9#.hd2ectz8t ?
По сути, он говорит, что можно передать уровень 4 (TCP) через
экземпляр HAProxy, который затем снимает заголовок PROXY и маршрутизирует
трафик к нужному экземпляру с помощью закрепленных сессий. Однако это не
мне очевидно, как два HAProxy получают свой список «внутренних» серверов
настроен и где он работает и где работает фактический сервер socket.io.
Можете ли вы понять это?


Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment -171208211
.

@lostcolony Хорошо, я видел интересный проект в отношении автоматического масштабирования на Amazon с использованием HAProxy — по крайней мере, полезный для справки: https://github.com/markcaudill/haproxy-autoscale. Чего я не понимаю, так это зачем использовать ELB перед HAProxy? Должен быть только один экземпляр HAProxy, иначе как вы гарантируете, что ELB отправляет трафик на правильный экземпляр HAProxy? Если только они (экземпляры HAProxy) не использовали общую липкую таблицу каким-то образом с помощью ElastiCache или Redis или чего-то в этом роде? ... Я понимаю, что мы отклоняемся от темы.

Если у вас есть HAProxy, настроенные для маршрутизации соединений на основе IP, вы
может гарантировать, что это закончится в том же экземпляре. То есть, если HAProxy
у всех было одно и то же правило, говорящее, что ip ABCD направлен на первый экземпляр,
то независимо от того, какой HAProxy попал в ELB, он окажется в одном и том же
место. Это то, что происходит в той ссылке, которую вы отправили, они балансируют
через источник, что означает, что экземпляр HAProxy хэширует IP-адрес и использует его для
определить, к какому экземпляру он относится. Несколько HAProxy при условии, что все они
знать об одних и тех же экземплярах, таким образом будет отправлять трафик из одного места в
тот же серверный экземпляр.

В среду, 13 января 2016 г., в 13:19, Феликс Шлиттер, [email protected]
написал:

@lostcolony https://github.com/lostcolony Хорошо, я видел, что
интересный проект в отношении автоматического масштабирования на Amazon с использованием HAProxy -
по крайней мере полезно для справки:
https://github.com/markcaudill/haproxy-autoscale. Чего я не понимаю, так это почему
использовать ELB перед HAProxy? Должен быть только один экземпляр HAProxy,
иначе как бы вы гарантировали, что ELB отправляет трафик вправо
Экземпляр HAProxy? Если только они (экземпляры HAProxy) не имеют общего
липкая таблица каким-то образом с использованием ElastiCache или Redis или что-то в этом роде
линии? ... Я понимаю, что мы отклоняемся от темы.


Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment -171386260
.

@lostcolony Я понимаю, что хэш выводится детерминировано для данного IP-адреса, однако должно быть сопоставление «хэш -> экземпляр». В вашем случае вы говорите, что существует правило, в котором говорится, что «ABCD направлен на первый экземпляр», но разве вы не хотите, чтобы HAProxy сам определял, куда перенаправлять, учитывая список доступных серверов? В конце концов, «ABCD» — это просто IP-адрес какого-то клиента, который заранее не известен.

Правило сопоставления хэша с экземпляром одинаково для всех HAProxy.
экземпляры. То есть ABCD приведет к одному и тому же хэшу независимо от
Экземпляр HAProxy, к которому он попадает, и этот хеш будет отображаться на тот же сервер, нет.
не имеет значения, какой экземпляр HAProxy используется, при условии, что каждый HAProxy знает об
одни и те же экземпляры (и, возможно, в том же порядке/с теми же именами). В
фактические IP-адреса не обязательно должны быть известны заранее, потому что они несущественны.
Любой IP-адрес будет хэшироваться на один и тот же сервер независимо от HAProxy, который он передает.
через.

Для полностью сфальсифицированного примера (HAProxy использует что-то не очень
предсказуемо, я уверен), представьте, что у нас есть три сервера, которые настроены
в порядке server0, server1 и serve2 (фактические детали не имеют значения,
просто есть четкий порядок, неявный в порядке). Каждый HAProxy
экземпляр имеет те же серверы в том же порядке. У них тоже самое
правило, как поступать с входящим IP-адресом. Для этого банального примера
он складывает все четыре части адреса как целые числа (легко расширяемые до
поддержки IPv6, сложите все как шестнадцатеричное по основанию 10) и разделите на 3, возьмите
остаток. Таким образом, IP 123.12.61.24 = (123+12+61+24) % 3 или 1. Таким образом, он маршрутизируется.
на сервер1. Таким образом, независимо от того, в какой экземпляр HAProxy он входит, этот
соединение будет отправлено на server1.

Теперь, если server1 отключается, алгоритм меняется для всех HAProxy.
экземпляры, к которым добавляются все части по модулю 2.

И это обычно работает, если только вы не получите netsplit (или не настроите
экземпляры HAProxy, чтобы иметь другой список серверов). Где видит один HAProxy
3 экземпляра, а другой видит 2. Если это произойдет, вы не можете гарантировать
чтобы достичь того же бэкэнда. И действительно, это может оказаться проблемой. Но
это решение, описанное в ссылке.

В среду, 13 января 2016 г., в 15:51, Феликс Шлиттер, [email protected]
написал:

@lostcolony https://github.com/lostcolony Я понимаю, что хеш
детерминировано для данного IP, однако должно быть сопоставление
из «хэш -> экземпляр». В вашем случае вы говорите, что есть правило, которое
говоря, что «ABCD направлен на первый экземпляр», но разве вы не хотите
HAProxy сам определяет, куда перенаправлять, учитывая список доступных
серверы? В конце концов, «ABCD» — это просто ip какого-то клиента, который не известен
фронт.


Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment -171428465
.

Я обнаружил, что в Elastic Beanstalk, хотя я настроил балансировщик нагрузки на использование TCP и SSL с веб-интерфейсом, когда я напрямую проверил конфигурацию балансировщика нагрузки, он все еще использовал HTTPS для безопасного прослушивателя. Поэтому вам, вероятно, следует проверить в разделе EC2 > Балансировщики нагрузки, что порты настроены так, как они должны быть:

screen shot 2016-03-08 at 16 08 34

Как только это будет отсортировано, добавьте следующее в .ebextensions, и у меня все работает хорошо :)

container_commands:
  01_nginx_static:
    command: |
      sed -i '/\s*proxy_set_header\s*Connection/c \
              proxy_set_header Upgrade $http_upgrade;\
              proxy_set_header Connection "upgrade";\
          ' /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf

Однако это будет работать на 100% только тогда, когда у вас есть только один экземпляр, потому что поддержка закрепленных сеансов не работает через TCP.

@lostcolony , сообщение @williamcoates только что напомнило мне поблагодарить вас за объяснение. Не могу поверить, что я забыл это сделать. Ваше объяснение было чрезвычайно полезным, так что спасибо, что нашли время.

Итак, у меня была та же проблема, и оказалось, что я настроил ECB для использования HTTPS.
Я изменил HTTPS на SSL, и больше не получаю сообщения.
поэтому просто используйте не HTTP/HTTPS, а TCP/SSL

С августа 2016 года вы можете использовать балансировщик нагрузки приложений Amazon (ALB) вместо «классического» ELB. У меня работало «из коробки» со слушателями на HTTP 80 и HTTPS 443.

@trans1t Милый человек, спасибо за информацию! Я должен буду проверить это.

@niczak - я также переключился на ALB для прилипания трафика сокетов. Тем не менее, сначала я столкнулся с конфигурацией ALB Sticky Sessions (поскольку на эту тему не было слишком много документации, по крайней мере, несколько месяцев назад). Наконец-то разобрались. Ключевым моментом является то, что «прилипчивость определяется на уровне целевой группы», поэтому убедитесь, что вы создали целевую группу для обслуживания своего трафика, а затем добавили к ней прилипчивость.

@aidanbon Это фантастическая информация, большое спасибо, что поделились!

Для тех, у кого все еще есть проблема с AWS Application Load Balancer, попробуйте обновить свою политику безопасности, я столкнулся с той же проблемой, хотя она отлично работала в точной настройке для другого веб-сайта, но заметил, что политика безопасности отставала примерно на 1 год. Обновив его на более новый, похоже, проблема решилась.

@michaelmitchell вы что-нибудь изменили или просто обновили без изменений?

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

Однако я узнал, что появление ошибки даже после обновления политики безопасности, вероятно, было связано с тем, что мой сеанс браузера придерживался старой политики безопасности, поэтому я не уверен, действительно ли было необходимо добавление/повторное добавление прослушивателя, но открытие в режиме инкогнито работало нормально, и после закрытие всех моих сеансов Chrome и повторное открытие работали нормально, и с тех пор я их не видел.

Полезно знать, спасибо!

Левен. 31 марта 2017 г., 12:02, Майкл Митчелл, [email protected]
текст:

Я ничего не менял в своем приложении, единственный дополнительный шаг, который я сделал
взять было удалить и повторно добавить прослушиватель HTTPS на ALB, как после
переход на новую политику не сработал.

Однако я узнал, что вижу ошибку даже после обновления безопасности
скорее всего, моя сессия браузера придерживалась старой политики безопасности.
поэтому я не уверен, действительно ли было необходимо добавление/повторное добавление слушателя, но
открытие инкогнито работало нормально, и после закрытия всех моих сеансов Chrome
и повторное открытие работало нормально, и с тех пор я его не видел.


Вы получаете это, потому что вы прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment-290672158 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ADrIi_SXqccWOLUMIWF1IhClGXvKAGMcks5rrM8sgaJpZM4C0swP
.

Кажется, эта ветка стала местом для выяснения проблем с AWS/socket.io —

Моя настройка заключается в том, что клиент делает HTTPS-запрос с данными для соединения socket.io.
Запрос HTTPS должен отвечать файлами cookie, необходимыми для закрепленных сеансов. Проблема в том, что я не могу передать заголовок cookie в соединении socket.io.

Я использую ALB с этими слушателями:
image

Что указывает на целевую группу с липкостью, настроенной следующим образом:
image

Сначала я попал в конечную точку HTTPS:

fetch(`https://${url}/hub/api/spinup/${uuid}`, {
                method: 'GET',
                headers: headers,
            })

затем инициализируйте сокет с помощью

connection = io(`wss://${url}:443/`, {
            path: `/user/${uuid}/spawn`,
        })

Экземпляр, к которому попадает запрос HTTPS, _должен_ быть экземпляром, к которому попадает соединение сокета.

Как только сокет установлен (если он попадает в нужный экземпляр по глупой случайности), он остается там, и все работает хорошо, проблема заключается в том, чтобы веб-сокет попал в ту же конечную точку, что и запрос HTTPS.

Мой первый инстинкт - использовать

connection = io(`wss://${url}:443/`, {
    path: `/user/${uuid}/spawn`,
    extraHeaders: {
        cookie: cookieValueFromFetchResponse
    }
})

Это работает в node , но в браузере cookie является запрещенным заголовком в XMLHTTPRequests, поэтому я не могу его отправить.

Кто-нибудь делал что-то подобное?

Я не делал ничего подобного, но хотя у ALB до сих пор нет маршрутизации на основе заголовков, у них есть маршрутизация на основе хоста. Это очень хакерский подход как таковой, но вы могли бы сделать так, чтобы каждый экземпляр за ALB имел явный путь к нему, о котором экземпляр знает. Когда этот первоначальный HTTP-запрос отправляется, часть ответа включает путь, и соединение для веб-сокета включает этот путь. То есть, HTTP-запрос достигает экземпляра «5» (на основе любых критериев; сгенерированные UUID были бы лучше), возвращает «5» как часть ответа, и веб-сокет открывается для url/5. В ALB есть правило, согласно которому url/5 направляется на экземпляр 5.

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

Подробнее читайте здесь: https://aws.amazon.com/blogs/aws/new-host-based-routing-support-for-aws-application-load-balancers/

Однако я также скажу, что вы, вероятно, захотите просто избегать используемого вами шаблона, если это вообще возможно. Данные, поступающие в HTTP-запросе, должны храниться таким образом, чтобы они были доступны для каждого экземпляра (БД или аналогичного), или они должны быть отправлены через соединение через веб-сокет после его установки. Как бы то ни было, у вас все равно может умереть экземпляр между HTTP-запросом и открытием веб-сокета, и вы можете столкнуться с той же проблемой (хотя и гораздо реже).

@lostcolony спасибо за совет — это определенно стоит попробовать.

HTTP-запрос - это то, что запускает сервер веб-сокетов (на самом деле он находится в контейнере докеров, но он абстрагирован). два запроса должны быть перенаправлены на один и тот же экземпляр, поэтому сервер веб-сокетов существует на экземпляре, который подключается к

с этой строкой помогает сидеть сервер jupyter за локтем.

service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp

на случай, если кто-то придет к этому билету с kubernetes на aws.

Я просто отключаю HTTP2 тогда все в порядке. Вам больше не нужно ничего делать с ELB.

Screen Shot 2019-12-13 at 16 12 49

Привет,
У меня такая же проблема, но я использую SockJS.
мое приложение представляет собой приложение Java Spring 4, работает на машине разработки и
получая ту же ошибку на AWS.
похоже, что заголовок Upgrade кто-то сбрасывает, я вижу это на клиенте.

еще бы найти решение...

Привет @yoav200 ,

СПАСИ МЕНЯ.
Я застрял в той же проблеме. Пожалуйста помоги
Я использую Springboot 2.x и SockJs для веб-сокета.
Я создал приложение tomcat, развернутое в aws,
Эластичный beanstalk с классическим балансировщиком нагрузки

Теперь проблема
Разработчик iOS не может подключиться, он достигает моего бэкэнда, но не работает во время рукопожатия
ниже приведены журналы, которые я получаю как в CLB, так и в ALB.


2019-12-13 15:21:22.662 ОТЛАДКА 27543 --- [nio-8080-exec-2] oswsDispatcherServlet: ПОЛУЧИТЬ "/wtchat/websocket", параметры = {}
2019-12-13 15:21:22.701 DEBUG 27543 --- [nio-8080-exec-2] oswsssWebSocketHandlerMapping : Сопоставлено с org.springframework.web.socket.sockjs.support. SockJsHttpRequestHandler@30c6a17
2019-12-13 15:21:22.714 DEBUG 27543 --- [nio-8080-exec-2] oswssthDefaultSockJsService: обработка запроса на транспорт: GET http://mydomain.com/wtchat/websocket
2019-12-13 15:21:22.716 ОШИБКА 27543 --- [nio-8080-exec-2] cwcMyHandshakeHandler: рукопожатие не удалось из-за недопустимого заголовка обновления: null

2019-12-13 15:21:22.717 ОТЛАДКА 27543 --- [nio-8080-exec-2] oswsDispatcherServlet: выполнено 400 BAD_REQUEST

Я последовал тому, что вы сказали
image
image

создал набор записей в Route 53, который напрямую указывает на балансировщик нагрузки.

После этого я также получаю ту же ошибку, что и выше.

Что еще мне нужно сделать?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги