Socket.io: AWS EC2 Behind ELB imprime toujours une erreur Code de réponse inattendu : 400

Créé le 30 oct. 2014  ·  66Commentaires  ·  Source: socketio/socket.io

Salut les gars -

Je n'arrive pas à trouver une solution pour cela, mais lorsque j'exécute mon application derrière un équilibreur de charge, j'obtiens cette erreur sur le client :

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

Je comprends l'erreur, car il essaie de parler à l'équilibreur de charge et maintenant à l'instance EC2 (je ne suis pas très doué avec AWS, alors n'hésitez pas à offrir de l'aide sur celui-ci !), mais ce que je ne comprends pas, c'est comment faire le l'erreur ne s'affiche pas !

J'aimerais résoudre la cause première, mais je suppose que cela implique un serveur socket.io dédié séparé pour gérer toutes les choses en temps réel pour lesquelles je n'ai pas le temps pour le moment, mais quelqu'un pourrait-il m'expliquer la suppression cette erreur?

Je suppose que cela revient à l'interrogation, qui semble fonctionner correctement (j'ai la connexion socket connectée et elle se déclenche) mais je ne veux pas lancer avec une erreur rouge dans ma console.

Merci d'avance pour les conseils que vous pourriez avoir !

Commentaire le plus utile

Je suppose que vous n'utilisez pas Elastic Beanstalk (les instructions seraient beaucoup plus faciles).

Accédez à EC2-> Réseau et sécurité-> Équilibreurs de charge

Sélectionnez votre équilibreur de charge et accédez à Écouteurs. Assurez-vous que le protocole d'équilibrage de charge et le protocole d'instance sont définis sur TCP pour le port 80 et SSL pour le port 443 plutôt que sur HTTP et HTTPS.

Tous les 66 commentaires

De plus, j'ai installé via bower si c'est important:

"socket.io-client": "~1.1.0",

Avez-vous une connexion persistante sur votre serveur ?

Je suppose que vous n'utilisez pas Elastic Beanstalk (les instructions seraient beaucoup plus faciles).

Accédez à EC2-> Réseau et sécurité-> Équilibreurs de charge

Sélectionnez votre équilibreur de charge et accédez à Écouteurs. Assurez-vous que le protocole d'équilibrage de charge et le protocole d'instance sont définis sur TCP pour le port 80 et SSL pour le port 443 plutôt que sur HTTP et HTTPS.

Oh mec. C'est un bon conseil que je n'ai pas vu ailleurs. je vais essayer le matin
et faire rapport. Merci!

Le mer. 29 oct. 2014, 19:48 Vadim Kazakov [email protected]
a écrit:

Je suppose que vous n'utilisez pas Elastic Beanstalk (les instructions
être beaucoup plus facile).

Accédez à EC2-> Réseau et sécurité-> Équilibreurs de charge

Sélectionnez votre équilibreur de charge et accédez à Écouteurs. Assurez-vous que la charge
Le protocole d'équilibrage et le protocole d'instance sont définis sur TCP pour le port 80 et
SSL pour le port 443 plutôt que HTTP et HTTPS.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/Automattic/socket.io/issues/1846#issuecomment-61038664
.

Alors peut-être que je me trompe, mais notre site fonctionne en HTTPS (avec notre cert SSL). Les changer pour casser beaucoup de choses sur toute la ligne. Je vérifiais X-Forwarded-Proto dans mon application pour m'assurer que la requête était HTTPS et sinon, la forçant à être redirigée. Apparemment, il n'y a pas d'en-tête X-Forwarded-Proto avec SSL/TCP et Express signale req.secure comme faux (même si j'ai tapé https).

Suggestion?

Pas sûr, les sockets utilisent le protocole TCP/SSL et non HTTP, vous devrez donc le changer en TCP/SSL pour que les sockets Web fonctionnent. En ce qui concerne la façon de réparer le reste de votre application, je n'en ai aucune idée.

Merci pour l'aide. Je vais devoir créer un nouvel environnement et déconner un peu. Il y a beaucoup de rouages ​​dans la machine !

Est-il possible d'avoir des websockets exécutés sur leurs propres ports ? Si oui, pourriez-vous lier de la documentation? (Je suis presque sûr qu'il n'y en a pas mais je peux me tromper)

Ils peuvent fonctionner sur n'importe quel port que vous voulez, spécifiez simplement quand vous connectez le port comme ceci :

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

J'utilise Elasticbeanstalk et je suis confronté au même problème, je n'ai pas installé SSL mais je suis connecté via http régulier.

Salut,
J'ai le même problème, bien que j'utilise SockJS.
mon application est une application Java Spring 4, fonctionne sur une machine de développement et
obtenir la même erreur sur AWS.
on dirait que l'en-tête de mise à niveau est supprimé par quelqu'un, je peux le voir sur le client.

peut encore trouver une solution...

Je suis dans le même bateau et en discussion en direct avec un ingénieur AWS et nous sommes tous les deux perplexes. J'ai confirmé que l'ELB doit être modifié de HTTP/HTTPS à TCP (ou SSL (Secure TCP)), mais j'obtiens toujours des erreurs 400 fréquentes. Jamais eu ce problème avant de passer au cluster à charge équilibrée Elastic Beanstalk.

s'il vous plaît essayez de commenter n'importe quel truc app.use middleware (lié à l'en-tête/cors) le cas échéant, ou app.get("/", je ne sais pas lequel a fonctionné pour moi, mais publiez vos résultats s'il vous plaît.

Mise à jour : j'ai confirmé qu'il s'agit de l'ELB, qu'il soit configuré pour le trafic HTTP ou HTTPS, socket.io échoue. Quand je vais directement sur l'un des EC2, tout fonctionne très bien.

Ci-joint ce que je vois en passant par l'ELB.
snipimage

J'ai semble avoir résolu mon problème en ajoutant une instance Route53 devant l'équilibreur de charge.
J'ai maintenant un websocket fonctionnel avec des connexions sécurisées dans l'environnement AWS.

Essayez d'ajouter la Route 53, si cela ne résout pas votre problème, je serai heureux de partager ma configuration.

@yoav200 pense que vous pourriez partager toute votre configuration pour savoir ce qui a fait fonctionner les choses pour vous ? C'est-à-dire les ports sur la sécurité EBS + le protocole (http/tcp), toutes les extensions .eb dont vous avez besoin, etc. J'ai essayé une tonne de choses différentes pour pirater mes configurations nginx pour conserver les en-têtes de mise à niveau et les envoyer au nœud, mais rien n'a fonctionné pour moi . FWIW - une page wiki serait vraiment, vraiment utile pour cela. La seule chose qui fonctionnait était d'aller directement à mon instance EC2.

J'ai configuré une instance Route 53 qui gère mon domaine.
J'ai configuré une zone hébergée avec un enregistrement qui pointe mon domaine directement vers l'équilibreur de charge.

l'équilibreur de charge est configuré pour transmettre la demande à mes instances Tomcat, comme indiqué ici :
lb-listeners

le groupe de sécurité pour ELB est assez standard :
lb-security-group

Utilisez-vous nginx ? Avez-vous dû faire quelque chose de spécial au niveau de la configuration ?

Je suis très proche de ce travail, j'ai passé près de 8 heures avec un ingénieur de support AWS au cours des deux derniers jours. J'ai dû extraire nginx du mix mais je suis très proche, les sockets fonctionnent bien via ELB sur http, demain je pense que je pourrai gérer les trucs https côté serveur plutôt qu'au niveau ELB.

Je ferai un retour avec mes découvertes.

Je n'utilise pas nginx, je gère tout sur Amazon, j'ai également déplacé mon domaine sur Amazon,
Cependant, j'ai migré mon application à partir d'un environnement cloud hébergé qui utilise AWS pour leurs instances mais a géré la charge avec nginx et je n'ai eu aucun problème là-bas.

lorsqu'on leur a demandé comment cela fonctionnait pour eux, leur réponse a été :

nous n'utilisons pas Amazon Elastic Load Balancer, nous utilisons notre propre couche d'équilibrage de charge NGinx.
Une solution pourrait être d'utiliser un serveur Nginx ou HAProxy au lieu de l'ELB et d'utiliser un groupe d'autoscaling avec 1 nœud de haproxy/nginx pour assurer la haute disponibilité du composant.

Oui, on m'a dit que HAProxy était une autre option, mais je suis tout à fait certain que je le ferai fonctionner avec les services suivants d'ici la fin de la journée :

  • Haricot élastique
  • ELB
  • Groupe EC2 Autoscaling (créé par EB)
  • RDS
  • ElastiCache

L'application de nœud fonctionne actuellement avec tous ces services, mais comme je l'ai dit, uniquement via HTTP, il ne reste donc pas grand-chose à faire pour préparer la production. Je ferai un rapport avec mes conclusions/configurations plus tard.

@niczak ,

En ce moment, j'essaie de me connecter à Socket.IO sur mon instance Node sur un EC2 en utilisant Redis d'ElastiCache.

J'ai ouvert l'instance EC2 au public et j'ai répondu avec une adresse IP publique afin que je puisse facilement me connecter au socket (http://coding-ceo.ghost.io/how-to-run-socket-io-behind -elb-on-aws/). sur mon ELB, j'utilise des sessions persistantes (en espérant que cela reste connecté), mais ma prise ne se connecte toujours pas et me donne le joli échec: connexion fermée avant de recevoir une réponse de poignée de main.

L'interrogation fonctionne bien, mais en essayant de faire fonctionner correctement les sockets et l'ensemble du chemin.

J'adorerais voir un cas d'utilisation ici afin que je puisse configurer correctement mon instance (même si ce n'est que sur HTTP au lieu de http et https) car je me casse la tête depuis un bon moment maintenant.

Je vous remercie beaucoup pour votre aide!

@petrogad

Salut Pete !

Mes écouteurs ELB sont aussi simples que possible (voir image) et par défaut sur le port EC2, 80 est transféré vers 8080 à l'aide d'iptables. Cela dit, je peux accéder à mon serveur sur HTTPS, puis mon application de nœud écoute sur 8080 et sert le certificat SSL lui-même.

elb

Le code de nœud pour la gestion des certificats est le suivant :

        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);

Pour que les sockets Web fonctionnent (sans revenir à une interrogation longue), j'ai _de_ désactiver l'équilibrage de charge entre zones. Malheureusement, AWS ne prétend pas prendre en charge les sockets Web via leur ELB, ces types de "piratages" de configuration sont donc nécessaires. J'espère que cela sera suffisant pour vous permettre de démarrer!

Merci @niczak !

Tout fonctionne parfaitement, il y avait du trafic HTTP qui gênait les choses. Redis a également fonctionné sur plusieurs instances ; la dernière chose consiste simplement à travailler sur reCluster et à permettre à une route TCP de rester avec un travailleur particulier.

Avez-vous eu beaucoup de succès avec cela? J'utilise express, donc sticky-session n'a pas très bien fonctionné. Avez-vous eu de la chance avec ça?

Merci encore et j'espère qu'une fois tout cela terminé, vous pourrez publier un bon article de blog pour les autres aux prises avec un élément similaire.

Merci @niczak !!

J'ai enfin réussi à faire fonctionner le mien. Cependant, en plus de la configuration
1) Équilibreur de charge pour utiliser le protocole TCP
2) Équilibreur de charge pour désactiver l'équilibrage de charge entre zones

j'ai aussi besoin de régler
3) Le serveur proxy doit être « aucun » dans la section Configuration du logiciel.

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

C'est une excellente nouvelle @aidanbon et @petrogad , huzzah pour les sockets sur AWS ! :+1:

Merci beaucoup! Cela a résolu mon problème avec le haricot élastique. Il est logique de supprimer le proxy nginx

Une mise à jour de mon message d'origine :

J'ai changé mon HTTPS en SSL (443 ---> mon port personnalisé) et j'ai laissé HTTP (80 ---> mon port personnalisé).

J'ai du code qui vérifiait avec express !req.secure && X-Forwarded-Proto !=== https qui vous redirige vers HTTPS si vous entrez sur le port 80...

POURTANT

Le passage à SSL fait que X-Forwarded-Proto revient indéfini... rompant cette connexion. (également req.secure semble être obsolète)

Alors maintenant:

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

semble fonctionner très bien, et je n'obtiens plus l'erreur 400 dans la console.

Bonjour - J'ai réussi à faire fonctionner cela en utilisant Node, NGINX, SSL et un ELB sur Elastic Beanstalk en procédant comme suit :

Créez une commande de conteneur dans .ebextensions pour modifier le script de configuration nginx afin d'inclure les websockets proxy :

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

Installez votre certificat SSL sur l'équilibreur de charge à l'aide de la console Web Elastic Beanstalk.

Allez ensuite dans la console web EC2, et changez le load balancer pour écouter sur SSL 443 -> TCP 80. Cela ne fonctionnait pas quand je l'ai changé dans la console web EB, je devais le faire directement dans EC2.

Cela devrait faire fonctionner tout. Je n'ai eu à faire aucune redirection et j'ai réussi à faire fonctionner NGINX aussi.

@ChrisEdson y a-t-il autre chose à inclure dans le package pour utiliser cette solution ?
Je l'ai essayé mais le déploiement a échoué en raison d'erreurs. Le journal affiche la ligne suivante :

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

Pouvez-vous envoyer votre code?

Le vendredi 4 septembre 2015 à 13 h 13, Treyone [email protected] a écrit :

@ChrisEdson y a-t-il autre chose à inclure dans le package pour utiliser cette solution ?
Je l'ai essayé mais le déploiement a échoué en raison d'erreurs. Le journal affiche la ligne suivante :

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

Répondez directement à cet e-mail ou consultez-le sur GitHub :
https://github.com/socketio/socket.io/issues/1846#issuecomment-137718880

Le code de l'application est une implémentation de socket.io extrêmement basique, presque un exemple d'utilisation prêt à l'emploi.
La seule chose que j'ai ajoutée est le fichier .config dans .ebextensions, dans lequel j'ai copié l'extrait de code que vous avez cité plus tôt.
Donc je n'ai pas grand chose à poster :)

Ne vous inquiétez pas, c'est juste difficile à déboguer sans le code ou les journaux. Pouvez-vous publier les journaux? Probablement pas approprié de rester ici, peut-être les mettre dans un bac à pâte.

Le vendredi 4 septembre 2015 à 15h26, Treyone [email protected] a écrit :

Le code de l'application est une implémentation de socket.io extrêmement basique, presque un exemple d'utilisation prêt à l'emploi.
La seule chose que j'ai ajoutée est le fichier .config dans .ebextensions, dans lequel j'ai copié l'extrait de code que vous avez cité plus tôt.

Donc je n'ai pas grand chose à poster :)

Répondez directement à cet e-mail ou consultez-le sur GitHub :
https://github.com/socketio/socket.io/issues/1846#issuecomment-137749890

Hum, j'ai publié mon code via grunt au lieu d'un emballage manuel et cela fonctionne à merveille. L'automatisation devrait être obligatoire ;)

Content de l'entendre !

Le mardi 8 septembre 2015 à 15h14, Treyone [email protected] a écrit :

Hum, j'ai publié mon code via grunt au lieu d'un emballage manuel et cela fonctionne à merveille. L'automatisation devrait être obligatoire ;)

Répondez directement à cet e-mail ou consultez-le sur GitHub :
https://github.com/socketio/socket.io/issues/1846#issuecomment -138572724

Sauve ma journée !

Nous avons également vu ce problème fondamental. Fondamentalement, étant donné que SocketIO envoie deux requêtes pour établir la connexion Websocket, si ces appels sont fédérés entre les instances, l'ID de session n'est pas reconnu et la négociation échoue, entraînant SocketIO à revenir à une interrogation longue. Cela est vrai que vous utilisiez ou non ws ou wss ; cela suppose que vous avez configuré l'équilibrage de charge au niveau de la couche 4 (TCP), car je n'ai pas pu faire en sorte que l'équilibrage de charge de la couche 7 (HTTP) fonctionne avec les Websockets.

Le correctif serait d'activer les sessions persistantes, de sorte qu'une fois qu'un appel passe à une instance, l'équilibreur de charge continue d'envoyer ces demandes à la même instance ; cependant, si vous utilisez les ELB d'AWS, ils ne vous permettent pas d'utiliser des sessions persistantes pour l'équilibrage de charge de la couche 4.

Ce que nous avons fini par faire, c'est d'utiliser des websockets bruts, plutôt que SocketIO, car il n'y a alors aucune donnée de session qui doit être conservée entre les appels (un seul appel, la poignée de main, a lieu, et cela fonctionne).

Un correctif de la part d'AWS serait d'autoriser l'utilisation de sessions persistantes d'une manière ou d'une autre pour l'équilibrage de charge de la couche 4.

Un correctif de la part de SocketIO serait de faire en sorte que la poignée de main websocket ne nécessite pas le contexte de l'ID de session précédent (je ne connais pas le but ou le cycle de vie autour de cela; je suppose qu'il existe à la fois pour aider à de longs sondages, et pour plus se reconnecter rapidement en cas d'interruption de la connexion ; si le client déterminait qu'une connexion était morte, il pourrait générer une nouvelle session et se reconnecter avec succès, plutôt que de voir le backend refuser la poignée de main parce qu'il croyait qu'une connexion existait déjà).

Une solution potentielle consisterait à utiliser Redis pour conserver l'état de la session dans toutes les instances. Je n'ai pas testé cela.

Une solution de contournement, si votre charge le permet, consiste également à ne garantir qu'une seule instance de nœud par zone de disponibilité et à désactiver l'équilibrage de charge entre zones. De cette façon, tous les appels seront effectués par défaut sur un seul nœud, évitant ce problème.

@aidanbon je n'ai pas trouvé Proxy server to be "none" in the Software Configuration section ?

J'utilise simplement un serveur Ubuntu et MeteorJS avec le déploiement de mup .. pourriez-vous s'il vous plaît me fournir un lien ??

Acclamations

@sahanDissanayake J'ai trouvé mon option de configuration de serveur proxy via :

  1. Cliquez sur "Configuration" dans l'environnement d'intérêt
  2. Cliquez sur "Configuration du logiciel" dans la page de configuration
  3. La liste déroulante "Serveur proxy" comme indiqué dans ma capture d'écran précédente.

Remarque : Mon environnement a été provisionné il y a presque un an. Pas sûr que le panneau AWS ait été mis à jour pour les environnements plus récents. Cependant, je peux toujours voir cette liste déroulante aujourd'hui dans mon environnement.

@aidanbon Je n'utilise pas d'autres services que ec2.. donc vos paramètres ne me concernent pas ? ou dois-je commencer à utiliser ce serveur poxy ?

Donc, le problème que j'ai est que mes websockets d'application Web fonctionnent sur le port 8080, mais PAS sur le port 80.

C'est le problème

@lostcolony Merci pour le résumé. Je suis arrivé à la même conclusion. Avez-vous lu cet article de blog : https://medium.com/@Philmod/load -balancing-websockets-on-ec2-1da94584a5e9#.hd2ectz8t ? Il dit essentiellement que l'on pourrait transmettre la couche 4 (TCP) à une instance HAProxy, qui enlève ensuite l'en-tête PROXY et achemine le trafic vers la bonne instance à l'aide de sessions persistantes. Cependant, je ne vois pas comment les deux HAProxy configurent leur liste de serveurs "backend", où elle s'exécute et où s'exécute le serveur socket.io réel. Pouvez-vous lui donner un sens?

EDIT : Je pense que j'ai cliqué maintenant. Il connaît la liste car il possède un ensemble de serveurs connus et ne se soucie pas de la mise à l'échelle automatique...

La liste de serveurs serait configurée sur chaque boîtier HAproxy. je ne sais pas comment
pour que cela fonctionne avec les instances ec2 à mise à l'échelle automatique, à moins que vous n'ayez écrit
infrastructure supplémentaire pour mettre à jour cette liste lorsqu'un nouveau serveur arrive
en ligne. Socket.io, ils s'exécutent sur le même serveur que leur application Web, donc
les connexions arrivent via l'Elb, sont fédérées à une instance HAproxy,
les instances HAproxy garantissent que les connexions IP vont toujours au même
serveur web/app, où socket.io a été configuré.
Le 13 janvier 2016 à 02h50, "Felix Schlitter" [email protected] a écrit :

@lostcolony https://github.com/lostcolony Merci pour le résumé. je
sont arrivés à la même conclusion. Avez-vous lu cet article de blog :
https://medium.com/@Philmod/load-balancing-websockets-on-ec2-1da94584a5e9#.hd2ectz8t ?
Il dit essentiellement que l'on pourrait transmettre la couche 4 (TCP) à un
Instance HAProxy, qui enlève ensuite l'en-tête PROXY et achemine le
trafic vers la bonne instance à l'aide de sessions persistantes. Cependant, ce n'est pas
évident pour moi comment les deux HAProxy obtiennent leur liste de serveurs "backend"
configuré et où il s'exécute et où s'exécute le serveur socket.io réel.
Pouvez-vous lui donner un sens?

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment -171208211
.

@lostcolony OK, j'ai vu qu'il y avait un projet intéressant concernant la mise à l'échelle automatique sur amazon, en utilisant HAProxy - au moins utile pour référence : https://github.com/markcaudill/haproxy-autoscale. Ce que je ne comprends pas, c'est pourquoi utiliser un ELB devant HAProxy ? Il ne doit y avoir qu'une seule instance HAProxy, sinon, comment garantiriez-vous que l'ELB envoie le trafic à la bonne instance HAProxy ? À moins qu'ils (les instances HAProxy) aient partagé une table collante commune en utilisant d'une manière ou d'une autre ElastiCache ou Redis ou quelque chose du genre ? ... Je me rends compte que nous allons _way_ hors sujet.

Si vous avez configuré les HAProxies pour router les connexions en fonction de l'IP, vous
pourrait garantir que cela finirait dans le même cas. Autrement dit, si les HAProxies
tous avaient la même règle disant que ip ABCD est dirigé vers l'instance un,
alors quel que soit le HAProxy touché par l'ELB, il finirait en même temps
lieu. C'est ce qui se passe dans ce lien que vous avez envoyé, ils s'équilibrent
via la source, ce qui signifie que l'instance HAProxy hache l'adresse IP et l'utilise pour
déterminer à quelle instance il va. Plusieurs HAProxies, à condition qu'ils
connaître les mêmes instances, enverrait ainsi le trafic d'un endroit à
la même instance backend.

Le mercredi 13 janvier 2016 à 13:19, Felix Schlitter [email protected]
a écrit:

@lostcolony https://github.com/lostcolony OK, j'ai vu qu'il y avait un
projet intéressant en ce qui concerne la mise à l'échelle automatique sur amazon, en utilisant HAProxy -
au moins utile pour référence:
https://github.com/markcaudill/haproxy-autoscale. Ce que je ne comprends pas, c'est pourquoi
utiliser un ELB devant HAProxy ? Il ne doit y avoir qu'une seule instance HAProxy,
Sinon, comment garantiriez-vous que l'ELB envoie le trafic vers la droite
Instance HAProxy ? À moins qu'elles (les instances HAProxy) partagent un
table collante en utilisant ElastiCache ou Redis ou quelque chose de ce genre
lignes? ... Je me rends compte que nous allons _way_ hors sujet.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment-171386260
.

@lostcolony Je comprends que le hachage est dérivé de manière déterministe pour une

La règle de mappage du hachage sur une instance est la même pour tous les HAProxy
les instances. C'est-à-dire que ABCD produira le même hachage quel que soit le
instance HAProxy qu'il atteint, et ce hachage sera mappé sur le même serveur, non
importe l'instance HAProxy utilisée, à condition que chaque HAProxy connaisse
les mêmes instances (et éventuellement dans le même ordre/les mêmes noms). le
Les adresses IP réelles n'ont pas besoin d'être connues à l'avance, car elles sont sans importance.
Toute adresse IP sera hachée vers le même serveur quel que soit le HAProxy qu'elle passe
par.

Pour un exemple complètement truqué (HAProxy utilise quelque chose qui n'est pas si
prévisible, j'en suis sûr), imaginez que nous ayons trois serveurs, qui sont configurés
dans l'ordre comme server0, server1 et serve2 (les détails réels n'ont pas d'importance,
juste qu'il y a un ordre clair, implicite est bien). Chaque HAProxy
instance a les mêmes serveurs, dans le même ordre. Ils ont aussi le même
règle sur la façon de traiter une adresse IP entrante. Pour cet exemple banal,
il additionne les quatre parties de l'adresse sous forme d'entiers (facilement extensible à
prend en charge IPv6, additionnez tout en hexadécimal en base 10), et divisez par 3, prenez le
reste. Donc IP 123.12.61.24 = (123+12+61+24) % 3, ou 1. Il est donc routé
au serveur1. Donc, quelle que soit l'instance HAProxy dans laquelle il entre, cela
la connexion sera envoyée au serveur1.

Maintenant, si server1 se déconnecte, l'algorithme change dans tous les HAProxy
instances, à additionner toutes les parties, module 2.

Et cela fonctionne généralement -sauf- si vous obtenez un netsplit (ou configurez le
instances HAProxy pour avoir une liste de serveurs différente). Où un HAProxy voit
3 instances, et une autre en voit 2. Si cela se produit, vous ne pouvez pas être garanti
pour atteindre le même backend. Et en effet, cela peut s'avérer être un problème. Mais
c'est la solution décrite dans le lien.

Le mercredi 13 janvier 2016 à 15h51, Felix Schlitter [email protected]
a écrit:

@lostcolony https://github.com/lostcolony Je comprends que le hachage est
dérivé de manière déterministe pour une adresse IP donnée, cependant, il doit y avoir un mappage
de "hachage -> instance". Dans votre cas, vous dites qu'il y a une règle qui est
disant "ABCD est dirigé vers l'instance un", mais ne voudriez-vous pas
HAProxy pour déterminer lui-même vers où rediriger, étant donné une liste de
les serveurs? Après tout, "ABCD" n'est que l'adresse IP d'un client et n'est pas connue
de face.

-
Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment -171428465
.

J'ai trouvé que sur Elastic Beanstalk, même si j'avais configuré l'équilibreur de charge pour utiliser TCP et SSL avec l'interface Web, lorsque j'ai vérifié directement la configuration de l'équilibreur de charge, il utilisait toujours HTTPS pour l'écouteur sécurisé. Vous devriez donc probablement vérifier dans la section EC2 > Load Balancers que les ports sont configurés comme il se doit :

screen shot 2016-03-08 at 16 08 34

Une fois que cela est trié, ajoutez ce qui suit à .ebextensions et tout fonctionne bien pour moi :)

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

Cela ne fonctionnera toutefois qu'à 100 % lorsque vous n'aurez qu'une seule instance, car la prise en charge des sessions persistantes ne fonctionne pas sur TCP.

@lostcolony , @williamcoates post vient de me rappeler de vous remercier pour l'explication. Je ne peux pas croire que j'ai oublié de le faire. Votre explication a été extrêmement utile, alors merci d'avoir pris le temps.

J'ai donc eu le même problème et il s'est avéré que j'avais configuré la BCE pour utiliser HTTPS.
J'ai changé HTTPS en SSL et je ne reçois plus le message.
donc, n'utilisez pas HTTP/HTTPS mais TCP/SSL

Depuis août 2016, vous pouvez utiliser l'équilibreur de charge d'application (ALB) d'Amazon au lieu de l'ELB "classique". A fonctionné "prêt à l'emploi" pour moi avec des auditeurs sur HTTP 80 et HTTPS 443.

@trans1t Sweet man, merci pour l'info ! Je vais devoir vérifier cela.

@niczak - Je suis également passé à ALB pour la rigidité du trafic de socket. Cependant, j'ai d'abord eu du mal avec la configuration d'ALB Sticky Sessions (car il n'y avait pas trop de doc sur ce sujet ; il y a au moins quelques mois). L'avoir enfin compris. L'essentiel est que « l'adhérence est définie au niveau du groupe cible », alors assurez-vous de créer un groupe cible pour servir votre trafic, puis ajoutez-y de l'adhérence.

@aidanbon C'est une information fantastique, merci beaucoup pour le partage !

Pour toute personne qui rencontre toujours un problème avec AWS Application Load Balancer, essayez de mettre à jour votre politique de sécurité, j'ai rencontré le même problème même si cela fonctionnait parfaitement bien dans la configuration exacte d'un autre site Web, mais j'ai remarqué que la politique de sécurité avait environ 1 an de retard. La mise à jour vers une version plus récente semble avoir résolu le problème.

@michaelmitchell avez-vous changé quelque chose, ou simplement l'avez-vous mis à jour sans modification ?

Je n'ai rien changé dans mon application, la seule étape supplémentaire que j'ai prise a été de supprimer et de rajouter l'écouteur HTTPS sur l'ALB car après le passage à la nouvelle politique ne semblait pas fonctionner.

J'ai appris cependant que voir l'erreur même après la mise à jour de la politique de sécurité était probablement que ma session de navigateur conservait l'ancienne politique de sécurité, donc je ne sais pas si l'ajout / rajout de l'auditeur était vraiment nécessaire, mais l'ouverture incognito a bien fonctionné et après la fermeture de toutes mes sessions Chrome et sa réouverture ont bien fonctionné et je ne l'ai pas vu depuis.

Bon à savoir, merci !

Le ven. 31 mars 2017 à 12:02, Michael Mitchell [email protected] a
écrit :

Je n'ai rien changé dans ma candidature, la seule étape supplémentaire que j'ai faite
take était de supprimer et de rajouter l'écouteur HTTPS sur l'ALB comme après
passer à la nouvelle politique n'a pas semblé fonctionner.

J'ai appris cependant que voir l'erreur même après la mise à jour de la sécurité
la politique était probablement ma session de navigateur conservant l'ancienne politique de sécurité
donc je ne sais pas si ajouter/rajouter l'auditeur était vraiment nécessaire, mais
ouverture incognito cela a bien fonctionné et après avoir fermé toutes mes sessions Chrome
et sa réouverture a bien fonctionné et je ne l'ai pas vu depuis.

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/socketio/socket.io/issues/1846#issuecomment-290672158 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/ADrIi_SXqccWOLUMIWF1IhClGXvKAGMcks5rrM8sgaJpZM4C0swP
.

Il semble que ce fil soit devenu un endroit pour résoudre les problèmes avec AWS/socket.io—

Ma configuration est que le client effectue une requête HTTPS avec des données pour une connexion socket.io.
La requête HTTPS doit répondre avec les cookies nécessaires aux sessions persistantes. Le problème est que je ne parviens pas à transmettre un en-tête cookie dans la connexion socket.io.

J'utilise un ALB avec ces écouteurs :
image

Ce qui pointe vers un groupe cible avec une adhérence configurée comme ceci :
image

J'ai d'abord atteint le point de terminaison HTTPS avec :

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

puis initialisez le socket avec

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

L'instance touchée par la requête HTTPS _doit_ être l'instance touchée par la connexion socket.

Une fois qu'un socket est établi (s'il atteint la bonne instance par hasard), il y reste et les choses fonctionnent bien, le problème consiste à faire en sorte que le websocket atteigne le même point de terminaison que la requête HTTPS.

Mon premier réflexe est d'utiliser

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

Cela fonctionne dans node , mais dans le navigateur, cookie est un en-tête interdit sur XMLHTTPRequests, je ne peux donc pas l'envoyer.

Est-ce que quelqu'un a fait quelque chose de similaire?

Je n'ai pas fait de même, mais, bien que les ALB n'aient toujours pas de routage basé sur les en-têtes, ils ont un routage basé sur l'hôte. C'est extrêmement bidon, en tant que tel, mais vous pouvez faire en sorte que chaque instance derrière l'ALB ait un chemin explicite vers elle, que l'instance connaisse. Lorsque cette requête HTTP initiale est envoyée, une partie de la réponse inclut le chemin et la connexion pour le websocket inclut ce chemin. C'est-à-dire que la requête HTTP atteint l'instance « 5 » (en fonction de n'importe quel critère ; les UUID générés seraient préférables), renvoie « 5 » dans le cadre de la réponse et le websocket est ouvert à l'url/5. L'ALB a une règle selon laquelle l'URL/5 est acheminée vers l'instance 5.

Si vous utilisez l'autoscaling (et que vos instances sont des bovins et non des animaux de compagnie), vous devrez faire en sorte que votre code exécuté sur l'instance modifie les paramètres ALB pour lui acheminer le domaine approprié.

En savoir plus ici : https://aws.amazon.com/blogs/aws/new-host-based-routing-support-for-aws-application-load-balancers/

Je dirai aussi, cependant, que vous voudrez probablement éviter le modèle que vous utilisez si possible. Les données provenant de la requête HTTP doivent être stockées d'une manière accessible à chaque instance (DB ou similaire), ou elles doivent être envoyées via la connexion websocket une fois qu'elle est établie. Dans l'état actuel des choses, vous pouvez toujours avoir une instance qui meurt entre la requête HTTP et l'ouverture du socket Web, et vous pourriez rencontrer le même problème (bien que beaucoup moins souvent)

@lostcolony merci pour les conseils, cela vaut vraiment la peine d'essayer.

la requête http est ce qui déclenche le démarrage du serveur websocket (il se trouve en fait dans un conteneur docker, mais c'est abstrait). les deux requêtes doivent être acheminées vers la même instance afin que le serveur Websocket existe sur l'instance à laquelle est connecté

avec cette ligne, il est utile de placer le serveur jupyter derrière l'elb.

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

au cas où quelqu'un viendrait à ce billet avec kubernetes sur aws.

Je viens de désactiver le HTTP2 alors c'est OK pour moi. Vous n'avez rien d'autre à faire pour ELB.

Screen Shot 2019-12-13 at 16 12 49

Salut,
J'ai le même problème, bien que j'utilise SockJS.
mon application est une application Java Spring 4, fonctionne sur une machine de développement et
obtenir la même erreur sur AWS.
on dirait que l'en-tête de mise à niveau est supprimé par quelqu'un, je peux le voir sur le client.

peut encore trouver une solution...

Salut @yoav200 ,

SAUVE-MOI.
Je suis coincé dans le même problème. S'il vous plaît aider
J'utilise Springboot 2.x et SockJs pour websocket
J'ai créé une application Tomcat déployée dans aws,
Beanstalk élastique avec équilibreur de charge classique

Maintenant, le problème est
Le développeur iOS ne parvient pas à se connecter, il atteint mon backend mais il échoue lors de la poignée de main
ci-dessous sont les journaux que je reçois à la fois dans CLB et ALB


2019-12-13 15:21:22.662 DEBUG 27543 --- [nio-8080-exec-2] oswsDispatcherServlet : GET "/wtchat/websocket", parameters={}
2019-12-13 15:21:22.701 DEBUG 27543 --- [nio-8080-exec-2] oswsssWebSocketHandlerMapping : mappé sur org.springframework.web.socket.sockjs.support. ChaussetteJsHttpRequestHandler@30c6a17
2019-12-13 15:21:22.714 DEBUG 27543 --- [nio-8080-exec-2] oswssthDefaultSockJsService : Traitement de la demande de transport : GET http://mydomain.com/wtchat/websocket
2019-12-13 15:21:22.716 ERREUR 27543 --- [nio-8080-exec-2] cwcMyHandshakeHandler : Échec de la négociation en raison d'un en-tête de mise à niveau invalide : null

2019-12-13 15:21:22.717 DEBUG 27543 --- [nio-8080-exec-2] oswsDispatcherServlet : Terminé 400 BAD_REQUEST

j'ai suivi ce que tu as dit
image
image

a créé un jeu d'enregistrements dans Route 53 qui pointe directement vers l'équilibreur de charge.

Après avoir fait cela, j'obtiens également la même erreur que ci-dessus.

Que dois-je faire d'autre ?

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

varHarrie picture varHarrie  ·  3Commentaires

MyMomSaysIAmSpecial picture MyMomSaysIAmSpecial  ·  4Commentaires

karmac2015 picture karmac2015  ·  3Commentaires

doughsay picture doughsay  ·  4Commentaires

shashuec picture shashuec  ·  4Commentaires