Socket.io: AWS EC2 hinter ELB druckt immer Fehler Unerwarteter Antwortcode: 400

Erstellt am 30. Okt. 2014  ·  66Kommentare  ·  Quelle: socketio/socket.io

Hallo Leute -

Ich kann keine Lösung dafür finden, aber wenn ich meine App hinter einem Load Balancer ausführe, erhalte ich diese Fehlermeldung auf dem Client:

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

Ich verstehe den Fehler, da er versucht, mit dem Load Balancer und jetzt der EC2-Instance zu kommunizieren (ich bin mit AWS nicht so gut, also können Sie gerne Hilfe anbieten!), aber was ich nicht verstehe, ist, wie man das macht Fehler wird nicht angezeigt!

Ich würde gerne die Ursache beheben, aber ich vermute, es handelt sich um einen separaten dedizierten socket.io-Server, um all die Echtzeit-Sachen zu verarbeiten, für die ich im Moment keine Zeit habe, aber könnte mich jemand bitte durch die Unterdrückung führen? dieser Fehler?

Ich gehe davon aus, dass es auf Polling zurückgreift, was gut zu funktionieren scheint (ich habe die Socket-Verbindung angeschlossen und es wird ausgelöst), aber ich möchte nicht mit einem roten Fehler in meiner Konsole starten.

Vielen Dank im Voraus für jeden Rat, den Sie haben könnten!

Hilfreichster Kommentar

Ich gehe davon aus, dass Sie Elastic Beanstalk nicht verwenden (die Anweisungen dort wären viel einfacher).

Gehen Sie zu EC2->Netzwerk & Sicherheit->Load Balancer

Wählen Sie Ihren Load Balancer aus und gehen Sie zu Listeners. Stellen Sie sicher, dass sowohl das Load Balancer-Protokoll als auch das Instanzprotokoll auf TCP für Port 80 und SSL für Port 443 und nicht auf HTTP und HTTPS eingestellt sind.

Alle 66 Kommentare

Außerdem habe ich über Bower installiert, wenn es darauf ankommt:

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

Haben Sie eine Sticky-Verbindung auf Ihrem Server?

Ich gehe davon aus, dass Sie Elastic Beanstalk nicht verwenden (die Anweisungen dort wären viel einfacher).

Gehen Sie zu EC2->Netzwerk & Sicherheit->Load Balancer

Wählen Sie Ihren Load Balancer aus und gehen Sie zu Listeners. Stellen Sie sicher, dass sowohl das Load Balancer-Protokoll als auch das Instanzprotokoll auf TCP für Port 80 und SSL für Port 443 und nicht auf HTTP und HTTPS eingestellt sind.

Oh Mann. Dies ist ein solider Rat, den ich nirgendwo anders gesehen habe. Ich werde es im AM versuchen
und melde dich zurück. Danke schön!

Am Mi, 29.10.2014, 19:48 Uhr Vadim Kazakov [email protected]
schrieb:

Ich gehe davon aus, dass Sie Elastic Beanstalk nicht verwenden (die Anweisungen dort würden
viel einfacher sein).

Gehen Sie zu EC2->Netzwerk & Sicherheit->Load Balancer

Wählen Sie Ihren Load Balancer aus und gehen Sie zu Listeners. Stellen Sie sicher, dass sowohl die Last
Das Balancer-Protokoll und das Instanzprotokoll sind für Port 80 auf TCP eingestellt und
SSL für Port 443 statt HTTP und HTTPS.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/Automattic/socket.io/issues/1846#issuecomment -61038664
.

Vielleicht irre ich mich, aber unsere Site läuft auf HTTPS (mit unserem SSL-Zertifikat). Wenn Sie sie ändern, werden viele Dinge auf der ganzen Linie zerstört. Ich habe X-Forwarded-Proto in meiner App überprüft, um sicherzustellen, dass es sich bei der Anfrage um HTTPS handelt, und wenn nicht, erzwinge ich eine Umleitung. Anscheinend gibt es keinen X-Forwarded-Proto-Header mit SSL/TCP und Express meldet req.secure als falsch (obwohl ich https eingegeben habe).

Anregung?

Nicht sicher, Sockets verwenden das TCP/SSL-Protokoll und nicht HTTP, daher müssen Sie es in TCP/SSL ändern, damit Web-Sockets funktionieren. Was den Rest Ihrer App angeht, habe ich keine Ahnung.

Danke für die Hilfe. Ich muss eine neue Umgebung schaffen und ein bisschen herumspielen. Es gibt viele Zahnräder in der Maschine!

Ist es möglich, Websockets auf ihren eigenen Ports laufen zu lassen? Wenn ja, könnten Sie eine Dokumentation verlinken? (Ich bin mir ziemlich sicher, dass es das nicht gibt, aber ich könnte mich irren)

Sie können an jedem gewünschten Port arbeiten, geben Sie einfach an, wann Sie den Port wie folgt verbinden:

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

Ich verwende Elasticbeanstalk und stehe vor dem gleichen Problem. Ich habe kein SSL installiert, sondern eine Verbindung über normales http.

Hallo,
Ich habe das gleiche Problem, obwohl ich SockJS verwende.
Meine Anwendung ist eine Java Spring 4-Anwendung, funktioniert auf einer Entwicklungsmaschine und
Erhalten Sie den gleichen Fehler bei AWS.
Sieht so aus, als ob der Upgrade-Header von jemandem gelöscht wurde, kann ich ihn auf dem Client sehen.

könnte noch eine lösung finden...

Ich bin im selben Boot und in einem Live-Chat mit einem AWS-Ingenieur und wir sind beide ratlos. Ich habe bestätigt, dass der ELB von HTTP/HTTPS auf TCP (oder SSL (Secure TCP)) geändert werden muss, aber ich erhalte immer noch häufig 400 Fehler. Dieses Problem hatte ich bis zum Wechsel zu einem Elastic Beanstalk-Cluster mit Lastenausgleich noch nie.

Bitte versuchen Sie, irgendwelche app.use-Middleware-Zeugs (Header/Cors-bezogen) zu kommentieren, falls vorhanden, oder app.get("/", ich bin mir nicht sicher, welche für mich funktioniert hat, aber posten Sie bitte Ihre Ergebnisse.

Update: Ich habe bestätigt, dass es sich um den ELB handelt, egal ob er für HTTP- oder HTTPS-Verkehr konfiguriert ist, socket.io schlägt fehl. Wenn ich direkt zu einem der EC2s gehe, funktioniert alles super.

Im Anhang ist das, was ich sehe, wenn ich durch die ELB gehe.
snipimage

Ich habe mein Problem anscheinend gelöst, indem ich die Route53-Instanz vor dem Loadbalancer hinzugefügt habe.
Ich habe jetzt einen funktionierenden Websocket mit sicheren Verbindungen in einer AWS-Umgebung.

Versuchen Sie, Route 53 hinzuzufügen. Wenn dies Ihr Problem nicht löst, teile ich gerne meine Konfiguration mit.

@yoav200 Denkst du, du könntest deine gesamte Konfiguration teilen, was dafür

Ich habe eine Route 53- Instanz eingerichtet, die meine Domäne verwaltet.
Ich habe eine gehostete Zone mit einem Eintrag konfiguriert, der meine Domain direkt auf den Load Balancer verweist.

Der Load Balancer ist so konfiguriert, dass er die Anfrage an meine Tomcat-Instanzen weiterleitet, wie hier gezeigt:
lb-listeners

die Sicherheitsgruppe für ELB ist ziemlich Standard:
lb-security-group

Benutzt du nginx? Mussten Sie bei der Konfiguration etwas Besonderes tun?

Ich bin kurz davor, dass dies funktioniert, habe in den letzten zwei Tagen fast 8 Stunden mit einem AWS-Supporttechniker verbracht. Musste nginx aus der Mischung reißen, bin aber sehr nah dran, Sockets funktionieren gut durch den ELB über http, morgen denke ich, dass ich das https-Zeug serverseitig statt auf ELB-Ebene handhaben kann.

Ich melde mich mit meinen Erkenntnissen zurück.

Ich benutze kein nginx, ich verwalte alles bei Amazon, ich habe meine Domain auch zu Amazon umgezogen,
Ich habe meine Anwendung jedoch von einer gehosteten Cloud-Umgebung migriert, die AWS für ihre Instanzen verwendet, aber die Last mit nginx verwaltet, und ich hatte dort keine Probleme.

Als sie gefragt wurden, wie es für sie funktioniert, war ihre Antwort:

Wir verwenden keinen Amazon Elastic Load Balancer, sondern unsere eigene NGinx-Lastausgleichsschicht.
Eine Lösung könnte darin bestehen, anstelle des ELB einen Nginx- oder HAProxy-Server zu verwenden und eine Autoscaling-Gruppe mit 1 Knoten des haproxy/nginx zu verwenden, um die Hochverfügbarkeit der Komponente sicherzustellen.

Ja, mir wurde gesagt, dass HAProxy eine weitere Option wäre, aber ich bin mir ziemlich sicher, dass es am Ende des Tages mit den folgenden Diensten funktionieren wird:

  • Elastische Bohnenranke
  • ELB
  • EC2 Autoscaling-Gruppe (erstellt von EB)
  • RDS
  • ElastiCache

Die Node-App funktioniert derzeit mit all diesen Diensten, aber wie gesagt, nur über HTTP, sodass nicht mehr viel zu tun ist, um die Produktion vorzubereiten. Ich melde mich später mit meinen Ergebnissen/Konfigurationen.

@niczak könntest du ein bisschen davon

Im Moment versuche ich, eine Verbindung zu Socket.IO auf meiner Node-Instanz auf einem EC2 herzustellen, während ich Redis von ElastiCache verwende.

Ich habe die EC2-Instanz für die Öffentlichkeit geöffnet und mit einer öffentlichen IP-Adresse geantwortet, damit ich mich leicht mit dem Socket verbinden konnte (http://coding-ceo.ghost.io/how-to-run-socket-io-behind -elb-on-aws/). auf meinem ELB verwende ich Sticky Sessions (in der Hoffnung, dass dies verbunden bleibt), aber mein Socket verbindet sich immer noch nicht und gibt mir das schöne fehlgeschlagen: Verbindung geschlossen, bevor eine Handshake-Antwort empfangen wird.

Das Polling funktioniert zwar gut, aber es wird versucht, die Sockets und den gesamten Pfad zum Laufen zu bringen.

Ich würde hier gerne einen Anwendungsfall sehen, damit ich meine Instanz richtig konfigurieren kann (auch wenn sie nur auf HTTP statt auf http und https läuft), da ich mir schon seit einiger Zeit den Kopf zerschmettere.

Vielen Dank für deine Hilfe!

@petrogad

Hallo Pete!

Meine ELB-Listener sind so einfach wie möglich (siehe Bild) und standardmäßig wird auf dem EC2-Port 80 über iptables auf 8080 weitergeleitet. Nachdem dies gesagt wurde, kann ich meinen Server über HTTPS erreichen, dann hört meine Knoten-App auf 8080 und stellt das SSL-Zertifikat selbst bereit.

elb

Der Knotencode für die Handhabung von Zertifikaten lautet wie folgt:

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

Damit Web-Sockets funktionieren (ohne auf langes Polling zurückzugreifen) _musste_ ich das Cross-Zone Load Balancing deaktivieren. Leider behauptet AWS nicht, Web-Sockets über ihr ELB zu unterstützen, daher sind diese Arten von Konfigurations-„Hacks“ notwendig. Hoffentlich reicht dies, um Sie zum Laufen zu bringen!

Danke @niczak !

Alles funktioniert perfekt, hatte HTTP-Verkehr, der die Dinge durcheinander brachte. Auch Redis über mehrere Instanzen hinweg funktioniert; Das letzte ist, nur an reCluster zu arbeiten und einer TCP-Route zu erlauben, bei einem bestimmten Worker zu bleiben.

Hatten Sie damit viel Erfolg? Ich benutze Express, also hat Sticky-Session nicht so gut funktioniert. Hattest du damit Glück?

Nochmals vielen Dank und hoffentlich kann, sobald dies alles abgeschlossen ist, ein netter Blog-Post für andere veröffentlicht werden, die mit einem ähnlichen Artikel zu kämpfen haben.

Danke @niczak !!

Endlich habe ich meine auch zum Laufen gebracht. Zusätzlich zur Konfiguration
1) Load Balancer zur Verwendung des TCP-Protokolls
2) Load Balancer zum Deaktivieren des Cross-Zone Load Balancing

muss ich auch einstellen
3) Proxy-Server muss im Abschnitt Software-Konfiguration auf "none" stehen.

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

Das sind großartige Neuigkeiten @aidanbon und @petrogad , huzzah für Sockets auf AWS! :+1:

Vielen Dank! Es hat mein Problem mit elastischer Bohnenstange gelöst. Es ist sinnvoll, den nginx-Proxy zu entfernen

Ein Update aus meinem ursprünglichen Beitrag:

Ich habe mein HTTPS in SSL (443 ---> mein benutzerdefinierter Port) geändert und HTTP belassen (80 ---> mein benutzerdefinierter Port).

Ich habe Code, der mit Express !req.secure && X-Forwarded-Proto !=== https überprüft wurde, der Sie zu HTTPS umleitet, wenn Sie an Port 80 ankommen ...

JEDOCH

Der Wechsel zu SSL führt dazu, dass X-Forwarded-Proto undefiniert zurückkommt.... diese Verbindung unterbricht. (auch req.secure scheint veraltet zu sein)

Also jetzt:

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

scheint gut zu funktionieren, und ich bekomme den 400-Fehler in der Konsole nicht mehr.

Hallo - Ich habe das mit Node, NGINX, SSL und einem ELB auf Elastic Beanstalk zum Laufen gebracht, indem ich Folgendes getan habe:

Erstellen Sie einen Containerbefehl in .ebextensions, um das nginx-Konfigurationsskript so zu ändern, dass es Proxy-Websockets enthält:

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

Installieren Sie Ihr SSL-Zertifikat auf dem Load Balancer mithilfe der Elastic Beanstalk-Webkonsole.

Gehen Sie dann zur EC2-Webkonsole und ändern Sie den Load Balancer so, dass er auf SSL 443 -> TCP 80 hört. Dies funktionierte nicht, als ich es in der EB-Webkonsole geändert habe, ich musste es direkt in EC2 tun.

Damit sollte alles funktionieren. Ich musste keine Umleitungen vornehmen und habe es auch geschafft, NGINX zum Laufen zu bringen.

@ChrisEdson muss das Paket noch etwas enthalten, um diese Lösung zu verwenden?
Ich habe es versucht, aber die Bereitstellung ist aufgrund von Fehlern fehlgeschlagen. Das Protokoll zeigt die folgende Zeile:

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

Kannst du deinen Code posten?

Am Freitag, den 4. September 2015 um 13:13 Uhr schrieb Treyone [email protected] :

@ChrisEdson muss das Paket noch etwas enthalten, um diese Lösung zu verwenden?
Ich habe es versucht, aber die Bereitstellung ist aufgrund von Fehlern fehlgeschlagen. Das Protokoll zeigt die folgende Zeile:

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

Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an:
https://github.com/socketio/socket.io/issues/1846#issuecomment -137718880

Der App-Code ist eine extrem einfache Socket.io-Implementierung, fast eine sofort einsatzbereite Beispielverwendung.
Das einzige, was ich hinzugefügt habe, ist die .config-Datei in .ebextensions, in die ich den oben zitierten Code-Schnipsel kopiert habe.
Also ich habe nicht viel zu posten :)

Keine Sorge, es ist nur schwierig, ohne den Code oder die Protokolle zu debuggen. Kannst du die Logs posten? Wahrscheinlich nicht angemessen, um hier aufzukleben, vielleicht in einen Kleisterbehälter.

Am Freitag, den 4. September 2015 um 15:26 Uhr schrieb Treyone [email protected] :

Der App-Code ist eine extrem einfache Socket.io-Implementierung, fast eine sofort einsatzbereite Beispielverwendung.
Das einzige, was ich hinzugefügt habe, ist die .config-Datei in .ebextensions, in die ich den oben zitierten Code-Schnipsel kopiert habe.

Also ich habe nicht viel zu posten :)

Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an:
https://github.com/socketio/socket.io/issues/1846#issuecomment -137749890

Hm, ich habe meinen Code über Grunzen anstelle einer manuellen Verpackung veröffentlicht und es funktioniert wie ein Zauber. Automatisierung sollte Pflicht sein ;)

Froh das zu hören!

Am Dienstag, 8. September 2015 um 15:14 Uhr schrieb Treyone [email protected] :

Hm, ich habe meinen Code über Grunzen anstelle einer manuellen Verpackung veröffentlicht und es funktioniert wie ein Zauber. Automatisierung sollte Pflicht sein ;)

Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an:
https://github.com/socketio/socket.io/issues/1846#issuecomment -138572724

Rette meinen Tag!

Dieses grundlegende Problem haben wir auch gesehen. Da SocketIO zwei Anforderungen zum Herstellen der Websocket-Verbindung sendet, wird die Sitzungs-ID nicht erkannt und der Handshake schlägt fehl, wenn diese Aufrufe über mehrere Instanzen hinweg verbunden werden, was dazu führt, dass SocketIO auf lange Abfragen zurückgreift. Dies gilt unabhängig davon, ob Sie ws oder wss verwenden oder nicht; Es wird davon ausgegangen, dass Sie den Lastenausgleich auf Layer-4 (TCP) eingerichtet haben, da ich den Lastausgleich auf Layer-7 (HTTP) nicht zum Arbeiten mit Websockets erhalten konnte.

Die Lösung wäre, Sticky Sessions zu aktivieren, damit der Load Balancer diese Anfragen weiterhin an dieselbe Instanz sendet, sobald ein Anruf an eine Instanz weitergeleitet wird. Wenn Sie jedoch die ELBs von AWS verwenden, erlauben sie Ihnen nicht, Sticky Sessions für den Layer-4-Lastausgleich zu verwenden.

Was wir letztendlich gemacht haben, war, rohe Websockets anstelle von SocketIO zu verwenden, da dann keine Sitzungsdaten vorhanden sind, die über Aufrufe hinweg beibehalten werden müssen (nur ein Aufruf, der Handshake, findet statt, und das funktioniert).

Ein Fix von AWS wäre, Sticky Sessions in irgendeiner Weise für den Layer-4-Lastausgleich zuzulassen.

Ein Fix von SocketIO wäre, es so zu machen, dass der Websocket-Handshake den Kontext der vorherigen Sitzungs-ID nicht erfordert (ich kenne den Zweck oder den Lebenszyklus dazu nicht; ich gehe davon aus, dass er sowohl für lange Abfragen als auch für mehr existiert im Falle eines Verbindungsabbruchs schnell wieder verbinden; wenn der Client feststellt, dass eine Verbindung unterbrochen wurde, könnte er eine neue Sitzung generieren und erfolgreich wieder verbinden, anstatt dass das Backend den Handshake ablehnt, weil es glaubt, dass eine Verbindung bereits besteht).

Eine mögliche Lösung wäre die Verwendung von Redis, um den Sitzungsstatus über alle Instanzen hinweg beizubehalten. Ich habe dies nicht getestet.

Eine Problemumgehung, wenn Ihre Last dies zulässt, besteht darin, auch nur eine einzelne Knoteninstanz pro Verfügbarkeitszone sicherzustellen und den zonenübergreifenden Lastenausgleich zu deaktivieren. Auf diese Weise werden alle Aufrufe standardmäßig an einen einzelnen Knoten geleitet, wodurch dieses Problem vermieden wird.

@aidanbon Ich konnte Proxy server to be "none" in the Software Configuration section nicht finden?

Ich verwende einfach einen Ubuntu-Server und MeteorJS mit MUP-Bereitstellung. Könnten Sie mir bitte einen Link besorgen?

Beifall

@sahanDissanayake Ich habe meine Proxy-Server-Konfigurationsoption gefunden über:

  1. Klicken Sie bei der gewünschten Umgebung auf "Konfiguration"
  2. Klicken Sie auf der Konfigurationsseite auf "Softwarekonfiguration".
  3. Das Dropdown-Menü "Proxy-Server", wie in meinem vorherigen Screenshot gezeigt.

Hinweis: Meine Umgebung wurde vor fast einem Jahr bereitgestellt. Nicht sicher, ob das AWS-Panel für neuere Umgebungen aktualisiert wurde. Ich kann dieses Dropdown-Menü jedoch heute noch in meiner Umgebung sehen.

@aidanbon Ich benutze keine anderen Dienste außer ec2.. Ihre Einstellungen sind also für mich nicht relevant? oder muss ich diesen Poxy-Server verwenden?

Das Problem, das ich habe, ist also, dass meine Web-App-Websockets in Port 8080 funktionieren, aber NICHT in Port 80.

Das ist das Problem

@lostcolony Danke für die Zusammenfassung. Ich bin zu dem gleichen Schluss gekommen. Hast du diesen Blogbeitrag gelesen: https://medium.com/@Philmod/load -balancing-websockets-on-ec2-1da94584a5e9#.hd2ectz8t? Er sagt im Wesentlichen, dass man Layer-4 (TCP) an eine HAProxy-Instanz weiterleiten könnte, die dann den PROXY-Header abnimmt und den Verkehr mit Sticky Sessions an die richtige Instanz leitet. Allerdings ist mir nicht ersichtlich, wie die beiden HAProxy ihre "Backend"-Serverliste konfiguriert bekommen und wo sie läuft und wo der eigentliche socket.io-Server läuft. Kannst du das irgendwie nachvollziehen?

EDIT: Ich glaube, ich habe jetzt geklickt. Er kennt die Liste, weil er einen bekannten Satz von Servern hat und sich nicht um die automatische Skalierung kümmert...

Die Serverliste würde auf jeder HAproxy-Box konfiguriert. Ich bin mir nicht sicher wie
damit dies mit automatisch skalierenden ec2-Instanzen funktioniert, es sei denn, Sie haben einige geschrieben
zusätzliche Infrastruktur, um diese Liste zu aktualisieren, wenn ein neuer Server kam
online. Socket.io laufen sie auf demselben Server wie ihre Web-App, also
Verbindungen, die über die Elb eingehen, mit einer HAproxy-Instanz verbunden sind,
die HAproxy-Instanz(en) stellen sicher, dass IPs-Verbindungen immer zu denselben gehen
Web-/App-Server, auf dem socket.io eingerichtet wurde.
Am 13. Januar 2016 um 2:50 Uhr schrieb "Felix Schlitter" [email protected] :

@lostcolony https://github.com/lostcolony Danke für die Zusammenfassung. ich
sind zu dem gleichen Schluss gekommen. Hast du diesen Blogbeitrag gelesen:
https://medium.com/@Philmod/load -balancing-websockets-on-ec2-1da94584a5e9#.hd2ectz8t?
Er sagt im Wesentlichen, dass man die Schicht 4 (TCP) an a weitergeben könnte
HAProxy-Instanz, die dann den PROXY-Header abnimmt und die
Datenverkehr zur richtigen Instanz mithilfe von Sticky Sessions. Es ist jedoch nicht
Mir ist klar, wie die beiden HAProxy ihre "Backend"-Serverliste bekommen
konfiguriert ist und wo es läuft und wo der eigentliche socket.io-Server läuft.
Kannst du das irgendwie nachvollziehen?


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/socketio/socket.io/issues/1846#issuecomment -171208211
.

@lostcolony OK, ich habe gesehen, dass es ein interessantes Projekt in Bezug auf die automatische Skalierung auf Amazon mit HAProxy gab - zumindest nützlich als Referenz: https://github.com/markcaudill/haproxy-autoscale. Was ich nicht bekomme ist, warum einen ELB vor HAProxy verwenden? Es darf nur eine HAProxy-Instanz geben. Wie würden Sie andernfalls sicherstellen, dass der ELB Traffic an die richtige HAProxy-Instanz sendet? Es sei denn, sie (die HAProxy-Instanzen) teilten eine gemeinsame Sticky-Tabelle irgendwie mit ElastiCache oder Redis oder etwas in dieser Richtung? ... Mir ist klar, dass wir _weg_ vom Thema abschweifen.

Wenn Sie die HAProxies so konfiguriert haben, dass Verbindungen basierend auf der IP weitergeleitet werden, können Sie
könnte garantieren, dass es in derselben Instanz enden würde. Das heißt, wenn die HAProxies
alle hatten die gleiche Regel, die besagt, dass ip ABCD an Instanz 1 gerichtet ist,
dann würde egal auf welchen HAProxy der ELB traf, er würde gleich enden
Ort. Das ist, was in dem Link passiert, den du gesendet hast, sie balancieren
über die Quelle, d. h. die HAProxy-Instanz hasht die IP und verwendet diese, um
bestimmen, zu welcher Instanz es geht. Mehrere HAProxies, sofern sie alle
von denselben Instanzen wissen, würde also Verkehr von einem Standort an senden
dieselbe Back-End-Instanz.

Am Mittwoch, den 13. Januar 2016 um 13:19 Uhr, Felix Schlitter [email protected]
schrieb:

@lostcolony https://github.com/lostcolony OK, ich habe gesehen, dass es ein gab
interessantes Projekt in Bezug auf Auto-Scaling auf Amazon mit HAProxy -
zumindest als referenz nützlich:
https://github.com/markcaudill/haproxy-autoscale. Was ich nicht verstehe ist warum
einen ELB vor HAProxy verwenden? Es darf nur eine HAProxy-Instanz geben,
Wie würden Sie andernfalls garantieren, dass die ELB den Verkehr nach rechts sendet?
HAProxy-Instanz? Es sei denn, sie (die HAProxy-Instanzen) haben ein gemeinsames
Sticky Table irgendwie mit ElastiCache oder Redis oder so ähnlich
Linien? ... Mir ist klar, dass wir _weg_ vom Thema abschweifen.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/socketio/socket.io/issues/1846#issuecomment -171386260
.

@lostcolony Ich verstehe, dass der Hash deterministisch für eine bestimmte IP abgeleitet wird, es muss jedoch eine Zuordnung von "Hash -> Instanz" geben. In Ihrem Fall sagen Sie, dass es eine Regel gibt, die besagt, dass ABCD an Instanz 1 geleitet wird, aber möchten Sie nicht, dass HAProxy anhand einer Liste verfügbarer Server selbst bestimmt, wohin die Umleitung erfolgen soll? Schließlich ist "ABCD" nur die IP eines Clients und nicht im Voraus bekannt.

Die Regel zum Zuordnen des Hashs zu einer Instanz ist für alle HAProxy gleich
Instanzen. Das heißt, ABCD führt unabhängig davon zum gleichen Hash
HAProxy-Instanz, auf die es trifft, und dieser Hash wird demselben Server zugeordnet, nein
unabhängig von der verwendeten HAProxy-Instanz, vorausgesetzt, jeder HAProxy weiß davon
die gleichen Instanzen (und möglicherweise in der gleichen Reihenfolge/den gleichen Namen). Der
tatsächliche IPs müssen nicht im Voraus bekannt sein, da sie unwesentlich sind.
Jede IP wird auf denselben Server gehasht, unabhängig vom HAProxy, den sie übergibt
durch.

Für ein komplett gefälschtes Beispiel (HAProxy verwendet etwas, das nicht so ist
vorhersehbar, da bin ich mir sicher), stellen Sie sich vor, wir hätten drei Server, die konfiguriert sind
in der Reihenfolge server0, server1 und serve2 (die tatsächlichen Details spielen keine Rolle,
nur dass es eine klare Reihenfolge gibt, implizit ist in Ordnung). Jeder HAProxy
-Instanz hat die gleichen Server in der gleichen Reihenfolge. Das gleiche haben sie auch
Regel, wie mit einer eingehenden IP-Adresse umzugehen ist. Für dieses banale Beispiel
es addiert alle vier Teile der Adresse als ganze Zahlen (leicht erweiterbar auf
IPv6 unterstützen, alles als Hex zur Basis 10 addieren) und durch 3 dividieren, nehmen die
Rest. Also IP 123.12.61.24 = (123+12+61+24) % 3, oder 1. Also wird es geroutet
zu server1. Egal in welche HAProxy-Instanz es kommt, das
Verbindung wird an server1 gesendet.

Wenn nun server1 offline geht, ändert sich der Algorithmus über alle HAProxy
Instanzen, um alle Teile hinzuzufügen, Modul 2.

Und das funktioniert im Allgemeinen - es sei denn- Sie erhalten einen Netsplit (oder konfigurieren die
HAProxy-Instanzen eine andere Serverliste haben). Wo man HAProxy sieht
3 Instanzen und eine andere sieht 2. Wenn das passiert, können Sie nicht garantiert werden
um dasselbe Backend zu erreichen. Und tatsächlich kann sich das als Problem erweisen. Aber
Das ist die Lösung, die im Link beschrieben wird.

Am Mittwoch, den 13. Januar 2016 um 15:51 Uhr, Felix Schlitter [email protected]
schrieb:

@lostcolony https://github.com/lostcolony Ich verstehe, dass der Hash ist
deterministisch für eine gegebene IP abgeleitet, es muss jedoch eine Abbildung geben
von "hash -> Instanz". In Ihrem Fall sagen Sie, dass es eine Regel gibt, die lautet:
sagen "ABCD ist an Instanz 1 gerichtet", aber würden Sie nicht wollen?
HAProxy, um selbst zu bestimmen, wohin umgeleitet werden soll, wenn eine Liste der verfügbaren
Server? Schließlich ist "ABCD" nur die IP eines Clients und nicht bekannt
Vorderseite.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/socketio/socket.io/issues/1846#issuecomment -171428465
.

Ich habe festgestellt, dass auf Elastic Beanstalk, obwohl ich den Load Balancer so eingerichtet hatte, dass er TCP und SSL mit der Webschnittstelle verwendet, als ich die Load Balancer-Konfiguration direkt überprüfte, immer noch HTTPS für den sicheren Listener verwendet wurde. Daher sollten Sie wahrscheinlich im Abschnitt EC2 > Load Balancers überprüfen, ob die Ports so eingerichtet sind, wie sie sein sollten:

screen shot 2016-03-08 at 16 08 34

Sobald das sortiert ist, füge das Folgende zu .ebextensions hinzu und alles funktioniert gut für mich :)

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

Dies funktioniert jedoch nur zu 100%, wenn Sie nur eine Instanz haben, da die Unterstützung für Sticky-Sessions nicht über TCP funktioniert.

@lostcolony , @williamcoates Post hat mich gerade daran erinnert, Ihnen für die Erklärung zu danken. Ich kann nicht glauben, dass ich das vergessen habe. Ihre Erklärung war sehr hilfreich, also vielen Dank, dass Sie sich die Zeit genommen haben.

Also hatte ich das gleiche Problem und stellte sich heraus, dass ich die EZB so eingerichtet hatte, dass sie HTTPS verwendet.
Ich habe HTTPS in SSL geändert und bekomme die Nachricht nicht mehr.
Verwenden Sie also nicht HTTP/HTTPS, sondern TCP/SSL

Ab August 2016 können Sie anstelle des "klassischen" ELB den Application Load Balancer (ALB) von Amazon verwenden. Hat bei mir "out of the box" mit Listenern auf HTTP 80 und HTTPS 443 funktioniert.

@trans1t Süßer Mann, danke für die Info! Ich werde das prüfen müssen.

@niczak - Ich habe auch auf ALB umgestellt, um die Klebrigkeit des Socket-Verkehrs zu gewährleisten. Ich hatte jedoch zuerst Probleme mit der ALB Sticky Sessions-Konfiguration (da es zu diesem Thema nicht allzu viele Dokumente gab; zumindest vor ein paar Monaten). Habe es endlich herausgefunden. Das Wichtigste ist, dass "Stickiness auf Zielgruppenebene definiert wird", also stellen Sie sicher, dass Sie eine Zielgruppe erstellen, um Ihren Traffic zu bedienen, und fügen Sie dann Stickiness hinzu.

@aidanbon Das sind fantastische Informationen, vielen Dank fürs Teilen!

Für alle, die immer noch ein Problem mit AWS Application Load Balancer haben, versuchen Sie, Ihre Sicherheitsrichtlinie zu aktualisieren. Ich bin auf das gleiche Problem gestoßen, obwohl es bei der genauen Einrichtung für eine andere Website einwandfrei funktionierte, aber bemerkte, dass die Sicherheitsrichtlinie etwa 1 Jahr im Rückstand war. Ein Update auf ein neueres scheint das Problem gelöst zu haben.

@michaelmitchell haben Sie etwas geändert oder einfach ohne Änderung aktualisiert?

Ich habe nichts an meiner Anwendung geändert. Der einzige zusätzliche Schritt, den ich unternommen habe, bestand darin, den HTTPS-Listener auf der ALB zu entfernen und erneut hinzuzufügen, da nach dem Wechsel zur neuen Richtlinie nicht zu funktionieren schien.

Ich habe jedoch erfahren, dass das Erscheinen des Fehlers auch nach dem Aktualisieren der Sicherheitsrichtlinie wahrscheinlich darauf zurückzuführen ist, dass meine Browsersitzung die alte Sicherheitsrichtlinie beibehalten hat Das Schließen aller meiner Chrome-Sitzungen und das erneute Öffnen hat gut funktioniert und seitdem nicht mehr gesehen.

Gut zu wissen, danke!

Le ven. 31 März 2017 à 12:02, Michael Mitchell [email protected] a
schreiben:

Ich habe an meiner Bewerbung nichts geändert, der einzige zusätzliche Schritt, den ich gemacht habe
nehmen war, den HTTPS-Listener auf der ALB wie nachher zu entfernen und wieder hinzuzufügen
Die Umstellung auf die neue Richtlinie schien nicht zu funktionieren.

Ich habe jedoch erfahren, dass der Fehler auch nach der Aktualisierung der Sicherheit angezeigt wird
Richtlinie war wahrscheinlich, dass meine Browsersitzung die alte Sicherheitsrichtlinie beibehalten hat
Daher bin ich mir nicht sicher, ob das Hinzufügen/Erneut-Hinzufügen des Listeners wirklich nötig war, aber
Inkognito öffnen funktionierte es gut und nachdem ich alle meine Chrome-Sitzungen geschlossen hatte
und wieder öffnen hat gut funktioniert und habe es seitdem nicht mehr gesehen.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/socketio/socket.io/issues/1846#issuecomment-290672158 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/ADrIi_SXqccWOLUMIWF1IhClGXvKAGMcks5rrM8sgaJpZM4C0swP
.

Es scheint, als wäre dieser Thread zu einem Ort geworden, um Probleme mit AWS/socket.io herauszufinden.

Mein Setup ist, dass der Client eine HTTPS-Anfrage mit Daten für eine socket.io-Verbindung stellt.
Die HTTPS-Anfrage sollte mit den für Sticky Sessions erforderlichen Cookies antworten. Das Problem ist, dass ich keinen cookie Header in der socket.io-Verbindung übergeben kann.

Ich verwende eine ALB mit diesen Listenern:
image

Was auf eine Zielgruppe mit einer so konfigurierten Klebrigkeit hinweist:
image

Ich habe zuerst den HTTPS-Endpunkt erreicht mit:

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

dann initialisieren Sie den Socket mit

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

Die Instanz, auf die die HTTPS-Anforderung trifft, _muss_ die Instanz sein, die die Socket-Verbindung trifft.

Sobald ein Socket eingerichtet ist (wenn er durch dummes Glück die richtige Instanz trifft), bleibt er dort und die Dinge funktionieren gut. Das Problem besteht darin, den Websocket dazu zu bringen, denselben Endpunkt wie die HTTPS-Anforderung zu erreichen.

Mein erster Instinkt ist zu benutzen

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

Dies funktioniert in node , aber im Browser ist cookie ein verbotener Header für XMLHTTPRequests, daher kann ich ihn nicht mitschicken.

Hat jemand ähnliches gemacht?

Ich habe ähnliches nicht gemacht, aber während ALBs immer noch kein Header-basiertes Routing haben, haben sie doch host-basiertes Routing. Dies ist als solches extrem hackisch, aber Sie könnten es im Grunde so machen, dass jede Instanz hinter der ALB einen expliziten Pfad hat, den die Instanz kennt. Wenn diese anfängliche HTTP-Anforderung ausgeht, enthält ein Teil der Antwort den Pfad und die Verbindung für den Websocket enthält diesen Pfad. Dh die HTTP-Anfrage trifft auf Instanz '5' (basierend auf welchen Kriterien; generierte UUIDs wären besser), gibt '5' als Teil der Antwort zurück und der Websocket wird für url/5 geöffnet. Die ALB hat eine Regel, dass url/5 an Instanz 5 weitergeleitet wird.

Wenn Sie Autoscaling verwenden (und Ihre Instanzen Rinder und keine Haustiere sind), muss Ihr Code auf der Instanz ausgeführt werden, um die ALB-Einstellungen zu ändern, um die entsprechende Domäne dorthin weiterzuleiten.

Lesen Sie hier mehr: https://aws.amazon.com/blogs/aws/new-host-based-routing-support-for-aws-application-load-balancers/

Ich werde jedoch auch sagen, dass Sie das Muster, das Sie verwenden, wenn möglich vermeiden möchten. Die in der HTTP-Anfrage eingehenden Daten sollten für jede Instanz (DB o.ä.) zugänglich gespeichert oder nach dem Aufbau über die Websocket-Verbindung gesendet werden. Zwischen der HTTP-Anfrage und dem Öffnen des Websockets könnte immer noch eine Instanz sterben, und Sie könnten auf dasselbe Problem stoßen (wenn auch viel seltener).

@lostcolony danke für den Rat – das ist definitiv einen Versuch wert.

die http-Anfrage löst das Hochfahren des Websocket-Servers aus (er befindet sich tatsächlich in einem Docker-Container, aber das ist abstrahiert). Die beiden Anfragen müssen an dieselbe Instanz weitergeleitet werden, damit der Websocket-Server auf der Instanz vorhanden ist, mit der eine Verbindung hergestellt wird

bei dieser zeile hilft es, den jupyter-server hinter der elb zu sitzen.

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

falls jemand mit kubernetes auf aws zu diesem Ticket kommt.

Ich deaktiviere einfach das HTTP2 dann ist es für mich in Ordnung. Für ELB müssen Sie nichts weiter tun.

Screen Shot 2019-12-13 at 16 12 49

Hallo,
Ich habe das gleiche Problem, obwohl ich SockJS verwende.
Meine Anwendung ist eine Java Spring 4-Anwendung, funktioniert auf einer Entwicklungsmaschine und
Erhalten Sie den gleichen Fehler bei AWS.
Sieht so aus, als ob der Upgrade-Header von jemandem gelöscht wurde, kann ich ihn auf dem Client sehen.

könnte noch eine lösung finden...

Hallo @yoav200 ,

RETTE MICH.
Ich stecke im selben Problem fest. Bitte helft
Ich verwende Springboot 2.x und SockJs für Websocket
Ich habe eine in AWS bereitgestellte Tomcat-Anwendung erstellt,
Elastic Beanstalk mit klassischem Load Balancer

Jetzt ist das Problem
Der iOS-Entwickler kann keine Verbindung herstellen, er erreicht mein Backend, aber er schlägt beim Handshake fehl
Unten sind die Protokolle, die ich sowohl in CLB als auch in ALB bekomme


13.12.2019 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 : Org.springframework.web.socket.sockjs.support zugeordnet. SockJsHttpRequestHandler@30c6a17
13.12.2019 15:21:22.714 DEBUG 27543 --- [nio-8080-exec-2] oswssthDefaultSockJsService : Transportanfrage verarbeiten: GET http://mydomain.com/wtchat/websocket
2019-12-13 15:21:22.716 FEHLER 27543 --- [nio-8080-exec-2] cwcMyHandshakeHandler : Handshake fehlgeschlagen wegen ungültigem Upgrade-Header: null

13.12.2019 15:21:22.717 DEBUG 27543 --- [nio-8080-exec-2] oswsDispatcherServlet : 400 BAD_REQUEST abgeschlossen

Ich habe befolgt, was du gesagt hast
image
image

hat in Route 53 einen Datensatz erstellt, der direkt auf den Load Balancer verweist.

Nachdem ich dies auch getan habe, erhalte ich den gleichen Fehler wie oben.

Was muss ich noch tun?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen