Podcast

Switching Protocols

Schnell, schnell!

In Folge 92 haben Robert und Lucas die Grundlagen des Webs erklärt. Ein wichtiges Thema dabei: HTTP, das Protokoll, mit dem Ressourcen vom Server zum Client kommen. Schnell wie SPDY Gonzales schieben wir nun eine weitere Folge nach, in der Lars von Lucas erfährt, wie man ein Quantum Performance aus diesem Protokoll herausholen kann.
Listen to other episodes

Shownotes & Links

Transkript

show / hide transcript

Lars:

Hallo und herzlich Willkommen beim INNOQ Podcast. Schön, dass ihr heute wieder eingeschaltet habt. Wir haben heute die Folge Nr. 101 und die hat den Titel „Switching Protocols“. Wir möchten heute über HTTP sprechen und dafür habe ich mir den Lucas eingeladen.

Lucas:

Hallo Lars.

Lars:

In der Folge Nr. 92 hat Robert schon mal den Lucas interviewt und da ging es um das technologische Backbone des Webs und da haben sie über viele Dinge gesprochen, die mit HT anfangen. Zum Beispiel HTTP und HTML. Sonst noch Irgendwas Spannendes in der Folge?

Lucas:

Ich glaube, das waren die Hauptteile. Wir haben ab und zu auch mal JavaScript und CSS erwähnt, aber der Fokus war auf jeden Fall auf den beiden HTs.

Lars:

Ja genau. Und wir haben in der Folge einiges über HTTP gehört, aber da gibt es noch ganz viel mehr Material, weil HTTP sich natürlich auch sehr stark weiterentwickelt hat. Vielleicht hat der eine oder die andere schon mal etwas über HTTP/2 zwei und HTTP/3 gehört. Und da wollen wir uns heute ein bisschen Zeit nehmen, in die Tiefe zu gehen. Aber machen wir vielleicht erstmal noch einen kleinen Recap. Lucas, erkläre mir doch mal als jemanden, der wirklich gar keine Ahnung von Web hat, was HTTP eigentlich genau macht.

Lucas:

Die lange Version in anderthalb Stunden epischer Länge könnt ihr gerne noch mal nachhören, wenn ihr möchtet. Aber die Kurzzusammenfassung ist, dass es ein Applikationsprotokoll ist, also ein Protokoll, das auf weiteren Layern draufliegt. Ich erwähne sie jetzt schon nochmal, weil sie später noch mal eine Rolle spielen. In der Webwelt gibt es den Internet Protokollstack und da gibt es das IP-Protokoll, da kommen zum Beispiel IP-Adressen her, daher kennen das viele. Das ist erst mal die grundsätzliche Möglichkeit eine Verbindung zwischen zwei Punkten aufzubauen. Und dann habe ich darauf aufbauend die Möglichkeit, entweder eine verlässliche oder eine unverlässliche Verbindung aufzubauen. Die verlässliche ist die TCP-Verbindung und die UDP die unzuverlässige Verbindung. Unzuverlässig ist natürlich schneller, aber unzuverlässig. Und traditionell hat HTTP auf TCP aufgesetzt, weil es nicht akzeptabel ist, dass Pakete verloren gehen. Wir kommen aber nachher dazu, warum das sich auch geändert hat. Aber das, was wir bisher gesprochen haben, war TCP. Ganz klar ist auch, dass das, was wir da sprechen, Plain Text ist. Das heißt, wir müssen dafür sorgen, dass es vertraulich bleibt zwischen den Parteien, in dem Fall zwischen dem Client und dem Server. Das heißt, wir haben auf diesem TCP Layer noch ein TLS Layer - Transport Layer Security. Das heißt, die Verbindung wird verschlüsselt. Und das ist heute so wichtig, dass man das auch nicht mehr ignorieren kann. Das ist auch nicht mehr optional. Das sollte immer da sein. Und mit so Sachen wie Let’s Encrypt können wir das auch kostenlos für alle unsere kleinen Spielprojekte einführen. Also gibt es eigentlich keinen Grund mehr, das nicht zu tun.

Lars:

Und das ist alles super einfach zu konfigurieren. Eigentlich muss ich mich um diese Dinge gar nicht mehr so richtig kümmern. Wenn ich irgendein Switch in meinem Webserver anklicke, läuft das.

Lucas:

Das ist schon sehr cool. Leute, die sich selbst zutrauen einen http-Server zu betreiben, die kriegen das auf jeden Fall auch hin. Das ist auf jeden Fall auf dem Level. Wir können auch gerne noch mal ein, zwei Tutorials verlinken, wie man Let’s Encrypt vielleicht mit so was wie Apache oder NGenix einrichtet. Und jetzt darauf basierend gibt es dann ein Plain Text Protokoll, das ist ein Request-response Protokoll. Das heißt, es gibt einen Client, es gibt einen Server und alles was wir machen ist immer: Der Client schickt eine Anfrage und der Server beantwortet sie. Der Server kann von sich aus nicht einfach eine Antwort schicken, ohne dass er dazu aufgefordert wurde. Das wird auch gleich noch mal wichtig. Wichtig ist auch, dass es ein Status Protokoll ist. Das bedeutet, dass jeder Request für sich selbst steht. Das heißt, wenn ich ein Request schicke und dann auch noch mal ein Request schicke, dann kann der zweite beantwortet werden, obwohl der erste nicht wirklich bekannt ist, was super wichtig ist für so Sachen wie Load Balancing, so dass wir mehrere Server auf dieselben Nachrichten hören lassen können und darauf reagieren. Das hat auch noch mal seine ganz eigenen Probleme, Sessions und so weiter. Da können wir bestimmt auch noch mal eine Folge zu machen. Da lade ich vielleicht da doch mal den Stefan Tilkov ein, der redet doch so gerne. Das heißt also, wir haben immer ein Request-Response Zyklus und aus dem können wir auch nicht ausbrechen. Und das ganze Protokoll basiert darauf, dass man immer erst mal eine Header Section hat, sowohl bei den Requests als auch bei den Responses und darunter einen Body. Und das HTTP Protokoll ist hauptsächlich quasi die Spezifikation von einer Reihe von HTTP Headern, die immer implementiert sein müssen. Da haben wir ganz ausführlich gesprochen, Caching und so weiter. Und das ist auch etwas, was quasi auf lange Zeit bleiben wird. Es wird immer diese Pärchen von Headern geben und die erinnern sich auch nicht. Alles, was wir jetzt in der Folge sagen, ändert nichts an diesen Headern.

Lars:

Genau. Ich glaube aber, wir sollten auch die ganzen HTTP Semantiken, die Verben und den ganzen Kram sollten wir heute mal ausklammern, weil wir uns eigentlich über das zugrunde liegende Protokoll unterhalten, wie man da irgendwelche Performance dann ausquetscht.

Lucas:

Genau. Wie gesagt, das kann man in der Folge 92 nachhören.

Lars:

Eine Empfehlung auf jeden Fall. Da sind wir schon gleich beim Thema Performance. Im Web ist es so, dass ich mit allen möglichen Arten von Clients rechnen muss. Ich habe einerseits natürlich denjenigen, der an der fetten Glasfaser sitzt und mehr oder weniger direkt am Rechenzentrum sitzt. Dann habe ich aber auch Leute, die Mobilfunk in Deutschland benutzen, dann haben die vielleicht 2G, wenn sie gerade mal Glück haben. Und es ist also extrem wichtig, dass Seiten möglichst performant ausgeliefert werden. Und das ist die Grundidee, warum man an HTTP noch mal geschraubt hat. Ich weiß nicht, wann kam die erste Version von HTTP/1.0 auf? Auch schon eine ganze Weile her.

Lucas:

Ja, 1990 ungefähr.

Lars:

Und seitdem hat sich natürlich einiges geändert. Und da müssen wir mal schauen, wie wir die Performance ein bisschen verbessern.

Lucas:

Absolut. Und wenn man über Performance spricht, dann muss man sich erst einmal kurz überlegen, was man damit genau meint. Das ist auch wieder so ein Wort, das ganz viele verschiedene Bedeutungen hat. In einer Netzwerkanwendung ist ein wichtiger Punkt, immer die Bandbreite und die Latenz. Das sind zwei Begriffe, die einem immer wieder begegnen und die noch mal kurz einzuordnen. Die Latenz ist die Zeit, die es braucht quasi ein einzelnes Paket, ganz winzig klein, vom Start bis zum Ende und wieder zurückzuschicken. Das ist die Latenz. Das heißt, es geht darum, wenn ich jetzt dem Lars irgendeine Information schicke, wie lange dauert das, bis die bei ihm ist? Und das ist völlig unabhängig von der Bandbreite. Die Bandbreite ist die Frage: Wie viele Bits kann ich denn quasi gleichzeitig durch die Leitung schieben? Da hilft uns dann eine super Leitung mit viel Bandbreite. Da können wir dann riesige Dateien zum Beispiel viel schneller herunterladen. Aber unabhängig davon gibt es noch die Latenz. Oft ist es natürlich so, dass wenn wir eine gute Latenz haben, wir auch eine gute Bandbreite haben. Das ist ganz klar. Aber es sind trotzdem erst mal zwei unabhängige Faktoren.

Lars:

Ich habe ein schönes Beispiel aus der Uni, als ich die Netzwerkvorlesung gehört habe bei uns im Grundstudium, da gab es mal eine Hausaufgabe, da sollte man zwei Sachen vergleichen. Die eine Sache war eine ISDN Verbindung und die andere Sache war einfach ein LKW, der mit Festplatten über die Autobahn brettert. Und dann stellte sich raus, dass der LKW mit den Festplatten wirklich eine extrem hohe Bandbreite hat, aber leider eine sehr schlechte Latenz. Während ISDN eine gute Latenz hat, aber leider eine sehr schlechte Bandbreite. Und in der Praxis haben wir natürlich keine Webseiten, die wir mit LKW auf der Autobahn ausliefern. Aber wir haben Leute, die in Australien auf unsere Seite zugreifen wollen und die haben eigentlich eine gute Bandbreite. Aber aus physikalischen Gesetzmäßigkeiten folgt, dass die Latenz ein Problem sein könnte.

Lucas:

Genau. Wenn sie jetzt auf einen europäischen Server zugreifen. So lange sie auf einen australischen Server zugreifen, ist alles wieder fein. Aber darüber müssen wir auch nachdenken. Und bei Latenz gibt es Themen, die wir auch vorhin schon angesprochen haben, so was wie CDNs. Wir versuchen den Server näher zu dem Client zu bringen. Und bei Bandbreite wären auch schon so Sachen wie Compression. Wie sorge ich dafür, dass Gzip oder Brotli zum Beispiel nutze, um Texte kleiner zu bekommen. Oder wie sorge ich dafür, dass ich ein moderneres Bildformat habe, dass das schon mal kleiner macht? Das würde nur die Bandbreite beeinflussen, überhaupt nicht die Latenz, weil ich muss immer noch nach dem Bild fragen und kriege das Bild zurück. Daran ändert sich gar nichts. Aber ich kann zumindest mal dafür sorgen, dass es dann weniger Bandbreite benötigt. Bandbreite ist natürlich auch noch relevant, immer auch noch mit Datenvolumen. Das hängt natürlich eng zusammen. Aber wenn ihr einen Vertrag habt, meistens Mobilfunkvertrag, der eine Bandbreitenbeschränkung hat, dann freut ihr euch auch wenn die Anwendung so gebaut ist, dass ihr wirklich wenig Bandbreite braucht, weil das verbraucht gleichzeitig auch wenig Volumen von eurem Vertrag. Das ist so etwas, worauf wir auch immer Rücksicht nehmen sollten, wenn wir Anwendungen bauen, weil doch viele Leute, gerade auch in Deutschland ein bandbreiten-beschränken Mobilfunkvertrag haben.

Lars:

Genau, dann haben wir euch schon mal ausreichend motiviert, warum Performance wichtig ist. Dann erkläre mir doch mal, Lucas, warum die Performance bei HTTP/1.0 einfach nicht so gut ist und warum man da überhaupt Hand anlegen muss.

Lucas:

HTTP/1.0 ist dieses uralte Protokoll. Wir kommen gleich direkt danach zu HTTP/1.1, bevor irgendjemand verwirrt ist, das Protokoll, das jetzt quasi fast 30 Jahre lang das dominante Protokoll war. HTTP/1.0, wir haben eben über diese Schichten gesprochen. Und da muss man sich jetzt vorstellen, wenn ich jetzt auf eine Webseite gehe und ich möchte mir die HTML-Seite herunterladen, muss ich erst mal eine TCP Verbindung aufbauen. Dann ist die TCP Verbindung aufgebaut, dann muss ich eine TLS Verbindung aufbauen, diese Verschlüsselung aufsetzen und dann fange ich an die ersten Bits hin- und her zu schicken. Bei HTTP/1.0 war es dann so, nachdem ich diese HTML-Seite bekommen habe, habe ich gesagt: Vielen Dank, dann mache ich die TLS Verbindung wieder zu. Dann mache ich diese TCP Verbindung wieder zu. Und dann sage ich: Ah, du wolltest auch noch das Bild haben, was hier referenziert ist auf der HTML-Seite. Da mache ich wieder eine neue TCP Verbindung auf, mache wieder eine neue TLS Verbindung auf. Ihr könnt euch das ungefähr vorstellen. Warum ist das jetzt ein Problem? Erst mal ist es so, dass eine TCP und TLS Verbindung aufzubauen relativ viel Overhead hat. Wir müssen uns vorstellen, dadurch, dass TCP ein reliable Protocol ist, machen wir erst mal so ein Handshake am Anfang. Und der kostet allein schon Zeit. Danach machen wir noch einen zweiten Handshake, nämlich den TLS Handshake, wo das Zertifikat ausgetauscht wird. Wenn wir uns jetzt vorstellen, dass wir beispielsweise eine Latenz von 28 Millisekunden haben, das wäre jetzt von Deutschland in die USA beispielsweise, ist es ungefähr ein 28 Millisekunden-Latenz bei den meisten Verbindungen, dann würde schon mal der TCP Handshake schon mal 56 Millisekunden dauern. Danach machen wir den TLS Handshake, der dauert nochmal 112 Millisekunden. Das heißt, in der Zeit sind noch keine Nutzdaten übertragen worden. Aber wir haben schon mal die ersten 160 Millisekunden verbraucht.

Lars:

Also sollte man auch dazusagen, als HTTP/1.0 rausgekommen ist, hat das noch niemand für Verschlüsselung interessiert. Das heißt, diese 100 Millisekunden Overhead hat man damals einfach nicht eingepreist, weil man es nicht braucht.

Lucas:

Und vor allem hatte auch keiner gedacht, dass irgendjemand 120 oder 160 Millisekunden interessieren. Das sollte man vielleicht auch noch mal dazu ergänzen. Da hatte man noch ganz andere Probleme. Aber das ist jetzt erst mal der Overhead, der ist einfach da, wenn man eine TCP und TLS Verbindung aufbaut. Die habt ihr auch, wenn ihr eine Verbindung zwischen eurem Applikations-Server und eurem Datenbankserver aufbaut. Da ist sie meistens nicht so problematisch, weil die Latenz innerhalb eures Data Centers oder innerhalb von eurer AWS Cloud viel geringer ist, weil die näher aneinander sind. Aber grundsätzlich habt ihr diesen Overhead bei jeder Verbindung, die ihr aufbaut und der ist umso schlimmer, je länger die Leitung zwischen den beiden Parteien ist.

Lars:

Und ich erinnere mich auch noch aus der gleichen Netzwerk Vorlesung, dass TCP erst mal langsam anfängt. TCP, wenn man den Handshake erfolgreich hat, ballert man noch nicht gleich mit der gesamten Bandbreite auf die Leitung, weil man weiß noch gar nicht zu dem Zeitpunkt wie viel die Leitung hergibt und dann macht man diesen Slow Start.

Lucas:

Genau, absolut. Slow Start, der Name klingt erst mal negativ, weil niemand möchte langsam starten, aber es ist ein Feature. Es ist kein Bug, dass Slow Start existiert. Und wie Lars schon sagte, das ist quasi ein Feature von TCP, sich langsam daran zu tasten. Was ist denn die Bandbreite, die wir sprechen können? Wenn ihr euch vorstellt, Lars und ich bauen jetzt eine Connection auf, dann weiß keiner der beiden Parteien zu diesem Zeitpunkt, wie die Bandbreite zwischen uns sein wird. Weil es könnte sein, dass Lars in seinem super Münchner Büro eine superklasse Leitung und ich auf meinem kleinen Landsitz muss mit dem Modem rechnen und die Bandbreite ist quasi der dünnste Punkt der Leitung überhaupt. Es bringt dem Lars gar nichts, dass eine riesige Leitung hat, wenn die Leitung bei mir ganz dünn ist, weil dann einigen wir uns quasi auf den dünnsten Punkt, weil das nützt nichts. Ich kann das nicht entgegennehmen sonst. Und es könnte sogar sein, dass beide von uns superschnelle Glasfaserverbindungen mit total super Bandbreite haben, aber irgendwo auf dem Weg ist die Bandbreite schlecht. Dann würde trotzdem die Gesamtbandbreite geringer sein.

Lars:

Wir haben hier Glasfaser zum Rechenzentrum jeweils und im Rechenzentrum wird dann per Fax gemacht.

Lucas:

Genau, oder per Carrier pitchen. Das wäre alles möglich. Und das versucht TCP quasi explorativ herauszufinden. Was ist unsere Bandbreite? Und das macht es darüber, dass es quasi mit ganz kleinen Paketen anfängt, die Pakete dann immer größer werden lässt, bis es zu einem Packet loss kommt, weil das bedeutet, dass unsere Pakete zu groß sind für die Bandbreite, die uns zur Verfügung stellen. Und dann macht es die congestion avoidance und dann geht die Paket Größe wieder runter und er fängt an langsamer die Größe zu vergrößern, so dass er quasi sich in Wellen auf die tatsächliche Bandbreite zubewegt. Und so kommt es dann nach einigen Round Trips erst dazu, dass er tatsächlich die perfekte TCP Paket Größe findet für die tatsächliche Bandbreite.

Lars:

Solange bis ich in den Zug einsteige und dann wieder auf … Aber das habe ich jetzt schon mal verstanden. Immer wieder für jede Ressource einen neuen Request machen ist ein bisschen aufwendig. Weil wenn ich mir so moderne Webseiten anschaue, da sind irgendwie nicht nur HTML, sondern noch 20 andere Ressourcen drin. Nicht so eine gute Idee und was ich erwähnt habe, mit HTTP/1.1 kann man als Nachfolgerprotokoll, was ist da denn besser geworden?

Lucas:

Also erst einmal kurz damit jetzt nicht die Leute denken, dass es gerade erst aufgefallen ist. HTTP/1.1 ist von 1997. Es ist schon eine ganze Zeit her, dass das entdeckt wurde, dass man das besser machen kann. Das heißt, in der Praxis benutzt HTTP/1.0 wirklich niemand mehr. Viele Server unterstützen das auch gar nicht mehr, weil das keine Relevanz hat. Alle haben auf 1.1 geupdated. Was kann jetzt HTTP/1.1? Es führt im Kern zwei Neuerungen ein. Das eine ist das Keep-alive und das ist genau um dieses Problem zu verbessern. Anstatt, wenn ich jetzt meine Verbindung zu Lars' Homepage aufgebaut habe, nachdem ich das HTML heruntergeladen habe, die Verbindung zu kappen, lasse ich die Verbindung auf und schicke das nächste Paket über dieselbe Leitung. Das heißt, ich benutze einfach den schon bestehenden TCP und TLS Tunnel und schicke da meine Pakete durch. Das ist erst mal die Idee, die dahinter steckt.

Lars:

Es sollte auch gar nicht so schwer zu implementieren sein, würde ich mal schätzen.

Lucas:

Absolut, dadurch, dass uns der Server, wenn er uns die Antwort schickt, schon sagt, wie groß die sein wird, kann ich quasi einfach danach aufhören zu lesen und dann einfach die Verbindung offen halten und den nächsten Request schicken. Das heißt also, ich baue quasi eine TCP Verbindung zum Server auf und die benutze ich einfach wieder. Recycling quasi. In der Praxis ist es tatsächlich, dass die Clients nicht eine Verbindung zum Server aufbauen, sondern sechs bis acht, je nach Browser, weil sie schon wissen, dass sie vermutlich noch einiges an Bildern, CSS und JavaScript herunterladen werden, auf einer Webseite. Da ist das mit einem nicht getan. Das heißt also, sie bauen quasi 8 Verbindungen pro Domain auf. Und bei jedem davon benutzen sie Keep-alive, um die dann wieder zu verwenden für all diese Requests. Diese sechs bis acht, das ist einfach ein Erfahrungswert, dass das eine gute Zahl ist. Es könnte Server geben, da ist das viel zu viel und dann ist es blöd, dann haben wir eine Verbindung aufgebaut, die wir gar nicht brauchen. Und es kann Server geben, das ist eigentlich zu wenig. Weil wir müssen so viele verschiedene Ressourcen herunterladen, dass das nicht reicht. Aber wir haben darauf als Serverbetreiber keinen Einfluss. Das entscheidet der Browser, wie viele Verbindungen er zum Server aufbaut.

Lars:

Das ist ein subtiler Punkt. Den sollte man vielleicht noch mal erwähnen. Trotz der Tatsache, dass jetzt in HTTP/1.1 eine Verbindung recycelt werden kann, kann ich immer noch nicht mehrere Ressourcen parallel herunterladen. Wenn ich jetzt zum Beispiel eine HTML-Seite habe und dann sind da 20 Bilder drauf, kann ich mit HTTP/1.1 diese Bilder immer noch nicht parallel herunterladen. Das kann ich machen, indem ich von Browser Seite einfach sage: Mache noch mehrere Verbindungen auf, mit dem Wissen natürlich, dass ich da bei jedem davon diesen Overhead bezahlen muss. Aber in der Summe rentiert sich es dann, wenn ich Sachen parallel herunterladen kann.

Lucas Das ist der wichtige Punkt an der Stelle. Das kann der Browser quasi selbst entscheiden, ohne dass man dafür HTTP Spezifikationen neu schreiben muss. Weil da steht nirgendwo, wie viele TCP Verbindungen ich zum Server aufbaue. Das konnte ich auch schon bei HTTP/0.9 machen. Das wäre auch da schon möglich gewesen, hat zu dem Zeitpunkt kein Mensch gemacht, aber wäre gegangen. Dann hätte ich trotzdem immer wieder eine Verbindung aufgebaut und die dann direkt wieder zumachen müssen, weil das die Spezifikation verlangt hat. Und das ist das, was ich in 1.1 nicht mehr machen muss, wenn ich den Connection Header auf Keep-alive setze. Und das ist normal eigentlich. Das macht jeder Browser auf jeden Fall. Das macht auch so was wie Curl, da kannst du sagen: Bitte mach Keep-alive, all das, ist gar kein Problem. Das kriegen wir alles hin.

Lars:

Kann HTTP/1.1sSonst noch was außer diese Connection am Leben halten?

Lucas:

Aus unserer Performance ist auf jeden Fall noch wichtig ist das sogenannte Chunked encoding. Ich habe eben schon erwähnt. Der Server antwortet und gibt eine sogenannte Content length mit. Das heißt, der sagt wie groß Bytes der Körper von meiner Antwort ist, damit ich weiß, wo ich aufhören muss zu lesen. Wer schon mal TCP Kram von Hand gemacht hat, der weiß, dass man da immer so sagen muss, wie viele Bytes hättest du denn noch gerne? Kann man auf diese Art und Weise entscheiden, wie viele man dann lesen möchte. Und bei 1.1 habe ich jetzt die Möglichkeit stattdessen ein Chunk encoding anzugeben und dann ist die Content length nicht mehr erforderlich. Dann kann der Server mir Antworten schicken und sagen: Hier ist wieder noch mal eine Portion, hier ist noch mal eine Portion und muss dafür nicht am Anfang schon wissen, wie viel er uns schicken wird. Und das können wir zum Beispiel benutzen für so was wie Server Sent Events, was eine Alternative ist zu Web Sockets. Wir bauen eine Verbindung zum Server auf und der Server kann dann einfach auf meine Anfrage immer wieder weitere Schnipsel von Events z.B. zurückschicken, Server Sent Events. Ich bin ein großer Fan, aber das ist jetzt ein bisschen ein Nebenthema. Wichtig an der Stelle ist nur, dass uns das nicht ermöglicht zu sagen: Ich schicke jetzt ein request an Lars' Server, der schickt mir das HTML zurück und schickt dann einfach direkt noch CSS hinterher, weil ein Request hat eine bestimmte Ressource angefragt und die Response muss sich auf die Ressource beziehen. Mit dem Chunk encoding kann ich nicht sagen: Achso, übrigens, das ist jetzt eine ganz andere Resource, die ich dir jetzt gerade zurückschicke. Das ist nicht erlaubt. Das heißt, es geht tatsächlich um dieselbe Ressource, aber ich kann sie quasi scheibchenweise schicken, auch zwischendurch mal eine Stunde nichts schicken, theoretisch. Wenn da nicht wieder Probleme gibt. Aber grundsätzlich könnte ich das tun und dann könnte ich Daten hinterherschicken.

Lars:

Ja, schon sehr praktisch. Dadurch, dass aber jetzt HTTP/1.1 nicht das Protokoll ist, was immer noch das Aktuelle ist, gehe ich mal stark davon aus, dass es da trotz dieser genialen Verbesserungen immer noch Potential gab.

Lucas:

Absolut genau. Wir haben jetzt schon gesehen, wir versuchen sparsam TCP Verbindungen aufzubauen und sie möglichst wieder zu verwenden. Das ist das eine. Da haben wir schon die ersten Lösungen für. Da kommen aber noch ein paar Lösungen dazu. Da kommen wir gleich dazu. Wir können es noch weiter verbessern. Das andere Problem, was aber von 1.1 gar nicht gelöst wurde, ist, das sogenannte Head of Line Blocking. Wenn wir uns jetzt vorstellen, ich schicke ein Request an den Server von Lars und der Lars schickt mir jetzt die HTML-Antwort zurück und dann weiß ich, dass ich jetzt drei Bilder herunterladen muss. Und ich möchte die drei Bilder alle über dieselbe TCP-Verbindung laden und das erste Bild davon ist nicht im Hot Cache, muss noch von der Platte gelesen werden, dauert einfach ewig, dann ist quasi erst mal alles blockiert, was hinter meinem Bild kommt. Ich kann nicht sagen: Aber ich hätte das andere Bild, da bin ich schon fertig, das weiß nur der Server, das weiß der Client nicht. Dieses Bild, das könnte er dir sofort schicken, weil das liegt hier bei mir im RAM. Das könnte ich jetzt fortschicken. Kann er aber nicht, weil du hast nach dem ersten Bild gefragt. Das heißt also, wenn ihr euch das vorstellt, wie eine Supermarkt Schlange, wenn die erste Person doch unbedingt mit Cent Stücken alles noch mal zurechtlegen möchte und nicht einfach mit Karte zahlt, dann ist halt Pech. Auch wenn die anderen viel schneller wären, müssen jetzt alle darauf warten, dass die vorderste Person fertig wird. So kann man sich das Head of Line Blocking vorstellen.

Lars:

Man steht eh immer in der falschen Schlange.

Lucas:

Genau. Und das ist in der HTTP Welt tatsächlich auch nicht anders. Und das Problem haben wir bei solchen TCP-Verbindungen grundsätzlich. Und dazu kommt, dass TCP ein reliable Protocol ist. Das bedeutet, wenn ich ein Paket schicke, muss immer erst eine Bestätigung zurückkommen, bevor ich das nächste annehme. Das bedeutet auch, wenn sich irgendeins von den Paketen aus irgendeinem Grund verlaufen hat, dann blockiert das auch alle weiteren Pakete, egal ob sie zur selben Ressource gehören oder nicht. Das ist auch wichtig zu verstehen bei Head of Lining.

Lars:

Ja, sonst noch Schwierigkeiten bei HTTP/1.1?

Lucas:

Damit verwandt ist die Priorisierung, also wenn ich jetzt zum Beispiel sage, ich baue eine Webseite auf und der Browser möchte gerne schon mal die Bilder anzeigen und das JavaScript ist ihm nicht so wichtig, dann kann er das nicht so richtig priorisieren. Der kann einfach sich entscheiden, ein Request früher zu schicken, aber er kann dem Server nicht sagen: Bitte schickt mir doch priorisiert lieber diese Sachen zurück. Es gibt keine Möglichkeit zu priorisieren, außer einfach die Request in einer richtigen Reihenfolge loszuschicken. Und das andere Problem ist noch Wiederholung zwischen Requests. Wir haben über die Statelesness gesprochen am Anfang, dass wir damit irgendwie umgehen müssen, dass wir den Request schicken und der nächste Request quasi unabhängig vom ersten existiert. Das bedeutet zum Beispiel, wenn ich einen Cookie mit schicke, dann schicke ich ihn bei jedem einzelnen Request mit. Das heißt also der Lars hat von der Server Seite aus einen riesigen Cookie geschickt, mit irgendwelchen jot tokens. Dann schicke ich jetzt ab sofort bei jedem einzelnen Request diesen riesigen jot token an den Server. Und das ist erst mal was gutes. Ganz wichtig, das ist erstmal eine gute Eigenschaft, weil das bedeutet, dass der Server wenn ich jetzt zu dem anderen Server eine Verbindung aufbaue, der auch den jot token kriegt und den dann auslesen kann und so weiter. Aber es sind natürlich sehr viel Daten, die da über die Leitung gehen und das ist dann irgendwie komisch, wenn ich eine TCP-Verbindung mit Keep-alive habe. Ich schicke ein Paket und der antwortet und ich schicke über die gleiche Leitung ein Paket und antworte, dann weiß ich ja, dass auf der anderen Seite dasselbe System lauscht. Das heißt also, ich weiß, die wissen ja schon, dass ich diesen Cookie mit schicke, aber ich schicke ihn trotzdem jedes Mal wieder mit. Das heißt also, wir haben eine Redundanz zwischen einzelnen Requests, die auf derselben TCP Leitung existieren. Es ist ein Feature, dass das nicht so ist, wenn ich eine neue TCP Verbindung aufbauen muss, weil das ist gut, dass es stateless ist, weil sonst könnte ich bestimmte Sachen nicht machen. Aber das ich auf derselben Verbindung immer dieselbe Information schicke, das ist blöd, dass verbraucht sehr viel Bandbreite.

Lars:

Ja und was machen wir da jetzt? Wie lösen wir das Problem? Ich schätze mal, die Lösung lautet HTTP/2.0.

Lucas:

Sehr gut geraten Lars.

Lars:

Hätte auch 1.2 sein können.

Lucas:

Ja, das stimmt. Guter für Punkt. 1.2 hat es nie gegeben. Wir sind direkt zu 2 gesprungen. Also genau genommen war es ein ganz kleines bisschen anders. Es war erst mal so, dass Google natürlich solche Probleme sehr viel intensiver spürt, dass der Hasenzüchterverein hier, der hier immer wieder erwähnt wird. Weil die natürlich viel mehr Traffic haben und viel mehr schauen müssen, dass sie schnell antworten. Das heißt, die haben sich schon mal überlegt, was könnten wir denn machen? Wie könnten wir das denn ersetzen? Und Google hat sich ja strategisch sehr geschickt aufgestellt und hat gesagt: Wir haben irgendwie die beliebteste Webseite des Internets auf der einen Seite und wir haben den beliebtesten Browser auf der anderen Seite. Das heißt, wir können ja Sachen einbauen in unserem Browser, der nur für unsere Webseite, die beliebteste auf der Welt, existiert. Und wenn die beiden miteinander reden in dieser Kombination, dann probieren wir einfach schon mal Sachen aus, die die anderen überhaupt noch nicht standardisiert haben.

Lars:

Das findet das Kartellamt bestimmt super gut, dass sie das machen.

Lucas:

Genau, aber die verstehen glaube ich nichts von HTTP, deswegen habe ich das so jetzt nicht mitbekommen. Also es ist natürlich aus so einer Sicht so ein bisschen bedenklich, dass so ein Player so was machen kann. Aber hat in dem Fall halt dazu geführt, dass sie ein neues Protokoll ausprobieren konnten, was sie SPDY genannt haben, also SPDY ausgesprochen “Speedy”, was ausprobieren wollte, wie können wir denn diese Probleme in einem neuen Protokoll lösen? Und das gab es am Anfang erst mal nur für diese Kombination aus Google Server und Google Browser und wurde dann halt schrittweise ein bisschen offen gelegt, bis sie es dann irgendwann zum Prozess freigegeben haben. Womit das dann so HTTP/2 wurde, das heißt also SPDY, das Protokoll ist deprecated, das spricht heute wahrscheinlich auch keiner mehr, also man könnte es noch, es ist ja noch da, aber ich glaube, das wurde aus den meisten Browsern auch schon wieder ausgebaut, bin jetzt aber nicht ganz sicher, aber HTTP/2 ist quasi der Nachfolger von SPDY, die erste Version von HTTP/2, also der erste Vorschlag war quasi eins zu eins SPDY dann haben halt ein paar Leute sich dazu nochmal geäußert und dann hat sich das natürlich auch nochmal verändert. Das heißt also HTTP/2 ist nicht gleich SPDY, aber SPDY ist quasi die Urform von HTTP/2. Und die grundsätzliche Idee war, erstens was wäre, wenn wir anstatt ein Plain Text Format ein binär Format sprechen? Also war so ein bisschen die Idee, dass man in diesem binär Format vielleicht weniger Platz verbraucht, beispielsweise. Wir kommen noch mal gleich zurück dazu, was für Nachteile binär Formate haben. Das hat aber auch so eine Sache ermöglicht und das ist die Header Compression. Also für mich ist Header Compression eines der wichtigsten, also vielleicht sogar das wichtigste Thema innerhalb von HTTP/2, dass die Performance verbessert hat. Was bedeutet Header Compression? Also ich habe ja eben gesagt, wir wiederholen immer wieder dieselbe Information, obwohl wir über denselben TCP Kanal sprechen und die Header Compression, die erlaubt mir jetzt zu sagen: Lieber Server, bitte füge hier den Header ein, den ich dir beim letzten Mal schon mal geschickt habe. Das heißt also, es ist nicht so eine Compression, also nicht hauptsächlich so eine Compression wie jetzt gzip, die jetzt eine einzelne Antwort kleiner macht, sondern eine Antwort oder ein Request, der sie auf einen vorigen Request bezieht und sagt, diese Information hast du schon, bitte benutzt die wieder. Ja, das ist grundsätzliche Idee davon. Das heißt also, anstatt zu sagen: Hier ist mein Cookie und hier ist nochmal mein Cookie, sage ich: Hier ist mein Cookie und beim zweiten Mal sage ich, ich möchte wieder denselben Cookie schicken, den ich dir eben schon geschickt habe. Und dieser Algorithmus, der dahinter steckt, der heißt HPACK. Und der besteht zum einen aus diesem Teil und zum anderen ist es auch wirklich eine Kompression. Man kann sich nämlich vorstellen, dass dadurch, dass die meisten HTTP standardisiert sind, ist es ja so, dass immer wieder dieselben Namen auf der linken Seite stehen. Also wenn man das jetzt als Key-Value Pairs vorstellt, sind die Keys zum größten Teil aus einem bekannten Pool. Und wenn wir jetzt einfach jedem aus dem Pool schon mal einen Identifier geben, Huffman encoding mäßig, dann können wir quasi sagen, hier anstatt jetzt zu sagen Content length schicke ich halt was viel kürzeres, was einfach nur beiden bekannt ist als Content length. Das heißt also, es ist so eine Dictionary Compression. Also wir haben ein gemeinsam bekanntes Dictionary, in dem Einträge drinnen stehen, auf die wir uns dann beziehen können und das ist ein dynamisches Dictionary, was sich über die Verbindung hinaus, also innerhalb einer Verbindung besteht auf beiden Seiten, so dass man immer wieder Einträge aus dem Dictionary referenzieren kann.

Lars:

Aber das heißt ja dann auch, dass ich, wenn neue Header dazukommen und vielleicht den Server noch nicht unterstützt, dann kann ich hier immer noch verwenden, weil wenn ich hier so ein geteiltes Dictionary hätte, wo einfach nur eine feste Liste von Headern benutzt werden dürfte, dann ist das ja auch nicht mehr erweiterbar.

Lucas:

Exakt. Also es ist immer noch so, dass ihr euch beliebige eigene Header ausdenken könnt. Die werden auch übertragen. Die sind da natürlich nicht so stark komprimiert by default, im ersten Request, weil da muss ich ihn ja einmal ganz schicken, aber danach beim zweiten Request kann ich dann sagen, ich schickt dir jetzt wieder den Super Lars Header und dann ist der Super Lars Header wesentlich kleiner. Und wenn der Super Lars Header dann sogar noch denselben Value hat wie beim ersten Request, dann ist er noch kleiner, weil dann das gesamte Paket referenziert werden kann und das ist HPACK. Und mir fällt es schwer, mir vorzustellen, wie man HPACK in Plain Text umsetzen könnte. Weil irgendwie in einem Plain Text so back references immer wieder einzubauen, halte ich für schwierig. Es ist möglich, aber ich glaube, das ist eine der Gründe, warum das binär Format gewählt wurde, um so etwas zu ermöglichen.

Lars:

Ich meine letztendlich die Request und Response Bodies werden ja meistens auch mit gzip gepackt und dann hat man ja auch schon binär Format. Damit hat man sich ja schon von der reinen Leere des Plain Text, HTML und was auch immer verabschiedet. Also kann man sich auf den Standpunkt stellen. Du kannst schon seit zehn Jahren keinen HTTP mehr, partiell nicht so richtig von Hand machen. Dann auch die Header binär machen.

Lucas:

Das wäre meine Argumentationsweise. Was man hätte sagen können ist, anstatt jetzt uns eine eigene Header Compression auszudenken, wenn ihr euch das vorstellt in plain Text. Also ihr habt jetzt wirklich einfach erst die Header, also erst diese erste Zeile, dann kommt die Header und dann kommt der Body. Dann hätte man jetzt auch einfach sagen können: Nimm das ganze Ding und gzip das doch einfach. Also gzip die Header mit und nicht nur den Body. Das wäre auch eine Alternative gewesen. Das hätte aber nicht den Vorteil gehabt, dass die eine Message, eine Referenz auf die vorige Message gehabt hätte. Also das hätten wir damit nicht hinbekommen. Das heißt, was wir hätten machen müssen, wäre tatsächlich ein Weg zu finden in dem Header zu sagen, bitte setze an dieser Stelle den Header aus dem vorigen Request ein oder sowas. Ich könnte mir vorstellen, dass das geht, aber es wurde auf jeden Fall nicht so gemacht.

Lars:

Ich gehe stark davon aus, dass wenn Google großflächig damit experimentiert hat, dass die sich da schon Gedanken gemacht haben, hoffe ich jetzt zumindest mal.

Lucas:

Das hoffe ich auch, aber es ist auf jeden Fall ein großer, also diese Kombination, dass daraus im binär Format herausfällt, ist auf jeden Fall ein großer Kritikpunkt an HTTP/2, dass man eben nicht mehr dieses schöne Plain Text Format hat. Das bedeutet auch, dass natürlich Server komplexer werden, weil man kann nicht einen einfachen HTTP Server schreiben, so wie ich das aktuell beispielsweise in dieser Web Architekturschulung mache und zeige jetzt einfach mit NetKet oder Telnet wie man so einen Server aufbaut. Das geht damit nicht. Ich kann dieses binär Format nicht von Hand runter tippen, also das verlieren wir auf jeden Fall, das ist weg. Und es bedeutet auch, dass natürlich Tools, die jetzt auf den Traffic schauen wollen, um irgendwelche Bugs zu finden, ich möchte jetzt Wireshark benutzen um irgendwie in die Pakete rein zu gucken, die müssen auch HTTP/2 verstehen, um in diese Suppe reingucken zu können. Aber wie Lars schon sagt, in der Praxis ist es auf jeden Fall so, dass der Body ist sowieso schon immer binär Suppe. Also der ist eine gzip oder Brotli. Brotli Suppe klingt lecker. Das ist also sowieso schon der Fall. Aber die HTTP Header konnte ich bislang, also bis zu dem Zeitpunkt immer schon mal im Plain Text, auch im Wireshark auslesen und das geht nur, wenn Wireshark dann ein Modul hat, das halt auch HTTP aufmachen kann. Und vor allem muss Wireshark dann aber auch alle vorigen Pakete kennen, um an dieser Stelle reinzuschauen. Wir können nicht einfach mitten im Traffic reinschauen, weil dann sind ganz viele back references da drinnen, die wir nicht kennen. Also wir müssen das Dictionary mitgeführt haben.

Lars:

Vor allen Dingen darf es auch nicht verschlüsselt sein. Sonst kann Wireshark auch nichts damit anfangen.

Lucas:

Genau das sowieso, aber in so einem Testing Szenario, das kriege ich wahrscheinlich noch hin. Aber das sind auf jeden Fall Nachteile im binär Format, wo ein Plain Text Format schon cooler ist. Aber ich kann mir sehr schwer vorstellen, wie man dann so einen Header Compression hinbekommen würde, wenn ihr da Ideen habt mich würde es tatsächlich interessieren, weil mich das schon länger beschäftigt, ob man das hätte anders lösen können, dieselben Vorteile zu bekommen ohne binär Format. Aber mir fällt kein Weg ein, sag ich mal.

Lars:

Ja noch was anderes, was da bei HTTP/2 neu dazugekommen ist oder was auch Google sehr stark pusht, ist, dass man auf TLS sich festgelegt hat. Also dieses Clear Text das passiert eigentlich immer seltener und wenn man heutzutage im Chrome oder im Firefox oder sonstwo eine Seite aufruft, wo nur HTTP Doppelpunkt Slash da steht ohne das S, dann kriegt man schon eine ziemliche Warnung angezeigt: Das ist insecure. Kannst du vielleicht mal kurz erklären, wie das mit HTTP/2 zusammenhängt auch.

Lucas:

Also SPDY das Protokoll der Vorgänger von HTTP/2 war ausschließlich über TLS spezifiziert. Also es gab keine Möglichkeit ein HTTP, also HTTP 2 ohne TLS zu sprechen. Und das ist auf Kritik gestoßen, weil es gerade auch für eine lokale Entwicklung unglaublich unpraktisch ist. Dann müssen wir nämlich für eine lokale Entwicklung uns selbst ein Zertifikat ausstellen, das Zertifikat selbst akzeptieren und so weiter. Das ist total blöd. Deswegen haben sich mehrere Leute gewünscht, dass es doch bitte auch ein Plain Textversion davon gibt. Deswegen gibt es HTTP 2 im Plain Text und ohne Plain Text. In der Praxis ist es aber so, dass euer Browser HTTP 2 ausschließlich über TLS spricht. Alle anderen Sachen werden nicht funktionieren. Und der Grund dafür ist eigentlich so ein bisschen wie so eine historische Sache. Das Problem ist, wenn ihr euch vorstellt, dass sie über Port 80 mit einem Server sprecht, dann ist es so, dass auf dem Weg, also es ist ja plain Text, da kann ja jeder reingucken und jeder weiß über Port 80 wird HTTP gesprochen. Dann können also Leute, die die Pakete entgegennehmen und weiterleiten, da reinschauen. Und das ermöglicht so Sachen wie Proxys und so weiter, die halt gute Sachen machen können wie Caching und so weiter. Wenn ihr jetzt also in einem Unternehmen seid, wo zum Beispiel so ein Proxy, also so ein Forward Proxy drinsteht, der Caching macht oder so was und auf einmal kommt da nicht mehr HTTP, sondern irgend so eine binär Suppe, die der gar nicht versteht, dann verschluckt er sich daran. Der sieht halt so, Moment, ich versuche hier HTTP zu parsen und dann stürzt der einfach ab und dann bricht vielleicht die Verbindung ab.

Lars:

Oder noch schlimmer du hast einen Root Exploit auf dem Proxy.

Lucas:

Oder so was genau. Oder es ist vielleicht sogar ein Security Feature, dass er sagt: Oh mein Gott, das sieht mir nicht aus wie HTTP, wir müssen das auf jeden Fall verhindern. Und das hat in der Praxis dazu geführt, dass HTTP/2 Verbindungen, die über Plain Text liefen, einfach kaputt gegangen sind. Das hat einfach gar nicht funktioniert. Das heißt also, in der Praxis können wir neue Protokolle, die über bekannte Ports funktionieren, nur einführen, wenn wir sie verschlüsseln, weil dann kann keiner reinschauen. Das ist der Hintergrund da dahinter.

Lars:

Ich habe das Gefühl, das lässt sich mit Pstel’s Law erklären oder so.

Lucas:

Eventuell.

Lars: Wäre cool, wenn wir eine Podcastfolge dazu hätten zu dem Thema.

Lucas:

Genau. Könnt ihr noch mal im Archiv schauen, ob es dazu was gibt. Genau und das ist das eine und das andere Problem ist, jetzt könnte man sagen, dann ist es ja egal, dann führen wir halt ein neuen Port ein, dass wäre auch eine Alternative. Die Praxis ist nur, dass an ganz vielen Orten immer noch ganz viele Ports gesperrt sind und im Prinzip Port 80 und Port 443 die einzigen sind, die durchgelassen werden, weil das sind ja der HTTP und der HTTPs Port. Das heißt, neue Ports einzuführen, die der Browser verwendet, ist auch nicht ohne Weiteres möglich. Das heißt also, die einzige praktikable Lösung ist, über den 443er Port von HTTPS zu sprechen, weil da schaut keiner rein und dann verschlüsselt zu sprechen. Und tatsächlich ist das auch das gleiche, WebSocket ist auch ein eigenes Protokoll. Das ist jetzt out of scope für diese Folge. Aber das verwendet auch den Port 443 und eine verschlüsselte Verbindung, damit es eben auch nicht diese Probleme reinläuft. Also das ist der eigentliche Grund, warum euer Browser in der Praxis immer nur TLS macht. Also ich finde das jetzt nicht schlimm. Ich finde es gut, weil wir sollten sowieso im Internet immer verschlüsselt kommunizieren. Das ist eine gute Idee. Deswegen habe ich damit jetzt kein Problem. Aber das ist der technische Hintergrund, warum es gar nicht anders geht in der Praxis, als das verschlüsselt zu machen.

Lars:

Ja, aber wollen wir jetzt zu den Problemen von HTTP 2 kommen. Glaube man muss da noch ein wichtiges Feature erwähnen, was wir vergessen haben.

Lucas:

Genau. Wir müssen nämlich noch einmal kurz auf das binär Format eingehen, weil es nämlich auch super wichtig ist, nämlich auf die binären Frames. Also wir haben jetzt die Möglichkeit auf eine der Leitungen zu Multiplexen. Das heißt, ich schicke eine Request an den Lars Webserver, bekomme das HTML zurück und jetzt weiß ich möchte diese drei Bilder und diese zwei CSS-Datei laden, dann kann ich jetzt über eine TCP Verbindung fünf Requests gleichzeitig losschicken und dann kommen dann einzelne Teile von den Antworten miteinander verwoben an mich zurück und ich kann sie wieder auseinander puzzeln. Das ist das was ich eben am Anfang gesagt habe, was da nicht geht, weil da müsste ich jetzt eine zweite TCP Verbindung aufmachen, um das andere Bild noch zu laden, weil ich kann erst meinen nächsten Request schicken, wenn ich meine Response bekommen habe. Das geht einfach nicht anders in HTTP/1.1 und das geht dann in HTTP/2.0. Da kann ich jetzt einfach sieben Ressourcen hintereinander einfach losschicken und dann kommen die bei mir an in einzelnen Paketen und die kann ich wieder auseinander puzzeln und dann bei mir zusammensetzen. Und das schöne daran ist, sagen wir mal, das eine Bild ist tatsächlich jetzt ganz langsam, dann blockt das jetzt erst mal nicht mehr die anderen Bilder. In der Praxis ist das aber wieder nicht mehr ganz so, da kommen wir jetzt gleich noch mal bei den Problemen darauf zurück. Das hat nämlich wieder seine Probleme. Aber das heißt erst mal, dass auch die Browser, wenn ihr eine HTTP 2 Verbindung aufbaut, tatsächlich auch nur eine aufbauen zum Server und über die ihre Nachrichten schicken. Das nennt man dann wieder Multiplexing. Das heißt, wir benutzen eine Leitung, aber wir können darüber mehrere logische Sachen gleichzeitig machen, die dann miteinander verwoben sind.

Lars:

Ja, das klingt ja zumindest schon mal nach einem easy win eigentlich, also dann kannst du, wenn du dazwischen load balancer hast, kann der dann die mehreren parallelen Requests dann auch an verschiedene Backend Server leiten. Oder es gibt zum Beispiel einen Asset Server, der nur ein S3 oder so und dann das Zeug herholt und die Geschäftslogik wird dann halt auf den anderen Server verteilt.

Lucas:

Genau. Das können wir sowieso machen. Und wenn wir jetzt unsere Verbindung aufgebaut haben, dann kann der Reverse Proxy die nachher aufdröseln wieder in eigenes Einzelteil. Das ist gar kein Problem. Er könnte sogar im Hintergrund wieder HTTP/1.1 Request machen. Das ist gar kein Problem. Also da hält uns nichts von ab. Leider ist es aber wieder, der Lars hatte ja schon nach dem Problem gefragt, hat es auch wieder Probleme. Und das ist wieder Head-of-line Blocking, aber diesmal auf einer anderen Ebene. Wir haben jetzt also die Situation, ich schicke die Bilder an den Lars Server und jetzt ist dieses eine Bild, da hat der Lars schon eine Antwort losgeschickt. Also solange die Antwort nicht losschickt, ist alles fein, weil er einfach weiß, dieses Bild ist noch nicht fertig und schickt nicht los, dann ist auch nichts geblockt. Aber er schickt mir jetzt tatsächlich die Antwort zurück, dann kann es jetzt sein, dass dieses eine Paket sich irgendwo im Internet verlaufen hat. Das braucht einfach länger. Das hat ein anderes Routing benutzt und ist irgendwie abhanden gekommen. Dann ist es jetzt immer noch so, dass bei TCP, haben wir ja, dieses Ordering der Nachrichten und diese Reliability, das jedes einzelne bestätigt werden muss. Das heißt jetzt dieses eine Paket kommt bei mir jetzt noch nicht an und jetzt muss ich als Browser einfach warten, weil der Betriebssystem Kernel, der ist ja dafür zuständig, diese Pakete zu ordnen und der schickt mir erst die nächsten Informationen, auch die nächsten Binary Frames von meinem Ding, wenn das erste übermittelt wurde. Das heißt also, hier ist jetzt nicht mehr das Problem, dass der Server nicht mehr die Möglichkeit hat, ein Paket, einen Request später zu beantworten und dadurch zu blocken, sondern ist das Problem, dass wenn auf diesem Transportweg Pakete verloren gehen, dass die das blocken können. Es ist wichtig zu betonen, weil das manchmal so Präsentation über HTTP/2 so klingt, als wäre das ein Desaster. Das ist eine extreme Verbesserung des Zustands im Gegensatz zu HTTP/1.1. Weil die Probleme vom Head-of-line blocking in HTTP/1.1 und viel größer als die von 2.0. Aber sie existieren immer noch, weil eben das Internet nicht eine reliable Connection ist. Es kann immer sein, dass da was verloren geht. Und dann haben wir wieder Head-of-line Blocking innerhalb unseres TCP Kanals.

Lars:

Das heißt, wir bewegen uns jetzt so mit unseren Problemen, dem Protokoll Stapel nach unten. Also wir haben angefangen, hatten die Latenz durch TLS und dem ganzen anderen Gedöns und hat nur das Head-of-line Blocking bei HTTP und irgendwann gibt es dann HTTP 25 und da wird dann irgendwie ein spezielles Protokoll auf der Glasfaser kommen wahrscheinlich.

Lucas:

Exakt. Also es ist durchaus denkbar, dass zukünftige Versionen zum Beispiel optimieren auf irgendwelchen mobilen Protokollen oder so was. Also halte ich nicht für undenkbar. Probleme von HTTP/2 würde ich sagen, einmal halt binär Protokolle haben halt ihre Tücken, gerade beim Debugging. Und das andere ist, dass wir auf Head-of-line blocking innerhalb von diesen Streams haben können. Jetzt ist es so, es gibt noch ein weiteres Feature von HTTP/2 und das ist der sogenannte Server Push. Der wurde am Anfang sehr gefeiert. Alle waren begeistert und haben gesagt, dass wird das Killer Feature. Mittlerweile sind sich eigentlich ziemlich alle einig, dass das Killer Feature ist, vor allem die Header Compression, weil die halt echt viel ausmacht, weil Header sehr groß sind. Und der Server Push hat heute fast keine Relevanz mehr. Die Idee von Server Push ist jetzt erst erstmal, sagen wir der Lars möchte mir eine HTML Seite zurückschicken und er weiß schon, dass er darin auch eine CSS-Datei und vier Bilder referenziert. Jetzt könnte der Lars ja einfach sagen, du schickst die HTML Anfrage, dann weiß ich ja schon, du wirst gleich nach dem CSS fragen, dann schicke ich dir das einfach auch schon mal. Das ist die Idee von Server Push. Das heißt also, der Lars schickt mir mehr zurück, als ich angefragt habe, weil er weiß, dass ich das als nächstes brauchen werde. Das ist die grundsätzliche Idee von Server Push.

Lars:

Aber dann habe ich ja wahrscheinlich ein Problem mit dem Caching, oder? Weil was ist, wenn der Webbrowser das vielleicht schon kennt? Du warst schon gestern auf meiner Webseite und hast da das CSS runtergeladen und hat sich seitdem nicht geändert. Und dann schiebe ich dir das einfach noch mal rüber.

Lucas:

Genau und das ist einfach blöd. So, jetzt gibt es innerhalb von HTTP/2 Protokoll, dafür eine Lösung und das ist, wenn ich anfange, wenn ich die Daten dir schicke, dann kann der Client ein Cancel schicken. Dann kann er sagen: Danke, aber nein, das habe ich schon. Nur ist das Problem daran, da ist es ja schon zu spät. Weil da hast du ja schon angefangen, die Daten zu schicken. Das ist nur dann eine Lösung, wenn du mir wirklich eine enorm große Datei schickst und dann sage ich, ich breche jetzt mal ab, die habe ich schon. Aber da habe ich schon ganz viel Brei in meinem Browser drinnen empfangen, den ich direkt weggeworfen habe. Und das Problem lässt sich jetzt erst mal eben in dieser Philosophie nicht lösen. Der Server Push verträgt sich nicht ohne Weiteres mit Push. Und in der Praxis wurde festgestellt, dass kaum jemand diese Server Push Funktionalität benutzt. Und deswegen gibt es jetzt auch schon eine ganze Zeit, ich habe jetzt nicht mehr das Datum nachgeguckt, einen sogenannten Intent To Remove. Das ist also eine Ankündigung von einer deprecation, dass man sagt, wir wollen dieses Feature entfernen im Chrome. Das heißt also, die Leute, die sie ursprünglich erfunden haben, haben mittlerweile gesagt, wir wollen das wieder ausbauen. Soweit ich weiß, ist es immer noch nicht ausgebaut, sondern es ist immer noch ein Intent To Remove, also es immer noch theoretisch da, aber es könnte halt jederzeit in der neuen Chrome Version rausfliegen und deswegen ist es in der Praxis auf jeden Fall auch nicht mehr empfehlenswert, das zu verwenden. Also allein deswegen schon nicht. Aber ich würde es sowieso nicht empfehlen, selbst wenn es im Chrome drinnen bleibt, weil es eben aus Caching Sicht kein sinnvoller Weg ist damit umzugehen, sondern da würde ich mir lieber so was wie Browser Hints beispielsweise anschauen.

Lars:

Die musst du dann mal kurz erklären für die, die es nicht kennen.

Lucas:

Okay gerne. Also Browser Hints sind eine ganz coole Idee eigentlich. Die sind ein HTTP Header, beziehungsweise können wir den auch als Link Tag schreiben. Die hat die gleiche Funktionalität zwei Ausdrucksweisen für das gleiche. Und da kann ich sagen: Lieber Browser, also das ist ein Response Header vom Server, du wirst in naher Zukunft folgende Ressourcen auch noch benötigen. Also da könnte dann z.B. drinstehen CSS und folgende drei Bilder und noch mal Font, könnte ich da reinschreiben und dann empfängt das der Browser und dann sagt der Browser: Ah cool, da schaue jetzt erst mal, ob ich die vielleicht schon gecached habe und wenn ich jetzt schon gecached habe, dann sage ich: Danke, dann weiß ich Bescheid, dann werde ich die gleich brauchen, alles gut. Aber wenn ich sie nicht gecached habe, dann kann der Browser entscheiden, sich die schon mal zu holen. Das heißt, er schickt, obwohl er noch nicht weiß, warum er sie brauchen wird schon mal die nächsten Server und holt die sich.

Lars:

Also so eine Art Fetching dann demzufolge?

Lucas:

Im Prinzip schon, aber der Browser ist in der Kontrolle. Der Browser kann sich auch entscheiden, das nicht zu tun. Beispielsweise du nutzt dein Mobiltelefon und du hast da so Datenspar-Modus eingestellt, weil du am Ende deines Volumens bist. Der Browser könnte diese Information aus dem Betriebssystem auslesen und sagen: Ah, der Lars möchte gerade Daten sparen, da mache ich keinen Prefetching. Also, Vorschläge vom Server, das könntest du tun, ich halte das für sinnvoll, aber du kannst dich dagegen entscheiden. Zum einen finde ich, ist es wesentlich kompatibler zur Web Philosophie, zu dieser Aufteilung zwischen Server und Client. Und zum anderen ist es viel kompatibler zur Caching Strategie. Und deswegen würde ich das immer vorziehen. Und es ist auch eine super Optimierung, die ja auf euren Webseiten durchführen könnt. Ich gehe noch mal kurz auf Latenz ein, weil das einfach ein super wichtiges Thema ist. Stellen wir uns vor, ihr ladet die Webseite runter und drin ist eine CSS-Datei referenziert. In der CSS Datei ist natürlich auch wieder eine Font-Datei referenziert. Da steht drin blabla, Fontface und so weiter und da ist die Font-Datei referenziert. Und wenn ihr jetzt wieder an die Latenz denkt bedeutet dass erst mal, schicke eine Request an den Server, kriegt die HTML einfach zurück. Erstes mal hin und zurück gegangen. Jetzt krieg ich das HTML, jetzt muss ich anfangen das HTML zu parsen. Ich komme im HTML an die Stelle, wo das CSS drinsteht. Jetzt steht da: Bitte CSS holen, dann kann ich den nächsten Request losschicken und die Antwort kommt zurück. Jetzt muss ich anfangen das CSS zu parsen. Jetzt komme ich im CSS an die Stelle, wo der Font referenziert ist. Jetzt kann ich an dieser Stelle erst den Request losschicken und die Response zurückbekommen. Das heißt also, es geht hier um drei Round Trips, bis der Front bei mir ist. Das kann ich so nicht verhindern, weil ich muss erst mal parsen, damit ich weiß, was ich brauche. Und Browser hints sind jetzt für mich eine Möglichkeit, tatsächlich das zu umgehen. Das heißt, ich könnte im HTML schon sagen: Du wirst diesen Font brauchen, auch wenn der jetzt noch nirgendwo referenziert ist, kann ich den schon mal herunterladen und dann habe ich schon mal den Font runtergeladen. Wenn jetzt im CSS steht bitte diesen Font nehmen, dann ist er ja in meinem Cash drin, bzw. liegt er da schon bereit weil ich ihn prefetched habe und dann brauche ich nicht noch mal loszulaufen. Das ist eine Performance Optimierung, die sich sehr lohnt. Wenn ihr solche Sachen machen könnt, dann macht das. Das habe ich zum Beispiel auch bei einem unserer Kunden genau so gemacht. Gerade Fonts und Logos, die im CSS referenziert sind, frühzeitig zu holen, weil die auf allen Seiten benötigt werden und ihr macht damit kein Cashing kaputt oder sonst etwas. Und deswegen ist das für mich eine sehr leichtgewichtige, coole Lösung, das hinzubekommen.

Lars:

Dann würde ich an der Stelle kurz HTTP 2 zusammenfassen. Wir haben eine coole Header Kompression, die macht viele Sachen besser, wir haben das Multiplexing, das macht auch viele Sachen besser. Server Push war eine gute Idee, hat sich nicht so gut rausgestellt, wird wieder entfernt. Wir haben aber immer noch dieses Head of Line Blocking Problem, von dem du gemeint hast, dass es Jammern auf hohem Niveau ist, aber so ein Google hat natürlich dieses Problem sehr viel breiter als der Hasenzüchterverein von dem du erzählt hast und deswegen vermute ich kam dann HTTP 3, dann erzähl uns kurz, wie HTTP 3 das lösen will.

Lars:

Überraschend für alle wird jetzt sein, dass das auch wieder eine Google Initiative ist. Auch hier hat sich Google wieder hingesetzt, hat gesagt: Komm, wir bauen das einfach wieder in unseren Browsern und unseren Servern ein und probieren das einfach mal aus.

Lars:

Das Kartellamt weiß immer noch nicht was HTTP ist.

Lucas:

Ja, wir sollten die mal unterrichten. Und an der Stelle hat sich Google überlegt, Lars hat es ja schon etwas in seiner Frage festgestellt, eventuell ist ja der TCP das Problem. Wir haben das Problem, dass wir innerhalb von TCP jetzt solche Priorisierung nicht mehr darstellen können. Das heißt, die Idee von Google war: Lass uns doch die TCP durch ein neues Protokoll ersetzen und dieses Protokoll, das heißt Quic. Das schreibt man ohne K. Das ist das Quic Protokoll. Man merkt ein Thema in den Namensgebungen von Google, genau wie bei Brotli und Softli. Das ist jetzt erst mal die Idee gewesen: Wir führen ein neues Transport Protokoll ein und dann setzen wir HTTP in dieses Protokoll rein. Das heißt, es gibt ein neues Transport Protokoll und HTTP 3 ist eigentlich nur HTTP 2, aber wir benutzen das neue Transport Protokoll. Jetzt ist das Problem, wir hatten eben schon mal kurz über diese Prozesse im Web gesprochen, dass man nicht ohne Weiteres neue Sachen einführen kann und genauso ist es bei Transport Protokollen. In der Theorie ist es ja so: Wir haben IP und darauf aufbauend können wir weitere Transport Protokolle definieren. Und das sind in der Praxis bisher TCP und UDP. Nur in der Praxis ist es so Wir können keine neuen Protokolle einführen, weil es gibt viel zu viel Hardware und Software zwischen unseren Endpunkten, die das dann nicht kennen würden und dann kaputt gehen oder nicht wissen, was sie tun sollen, dass wir in der Praxis nicht ohne Weiteres ein neues Protokoll einführen können. Das hat selbst Google gesagt und die haben ja schon diese große Macht, dass sie beide Enden kontrollieren. Aber selbst Google kontrolliert nicht alle Punkte zwischen den beiden Punkten und sagt: Wir können nicht einfach ein neues Protokoll einführen. Das heißt, wir müssen entweder TCP oder UDP nehmen.

Lars:

Kurze Zwischenfrage: Ist es nicht auch so, dass das Betriebssystem ganz viel übernimmt bei TCP und UDP? Man müsste dann ja auch noch einen Teil des Betriebssystems im Browser nachbauen, was dann hohe IP Pakete rausballert.

Lucas:

Absolut. In der Praxis ist es so, dass der Betriebssystem-Kernel, da drin sind solche Protokolle wie TCP und UDP eingebaut, egal ob im Linux-Kernel oder im Windows-Kernel. Das ist einfach tief da drin. Und wir können auch IP roh vielleicht sprechen, das könnten wir vielleicht hinbekommen, aber es wäre auf jeden Fall langsamer, weil es jetzt im User Space abläuft. Das ist einfach so und es läuft nicht im Kernel Space ab.

Lars:

Du hast ja gesagt: UDP ist jetzt nicht so optimal, aber wir nehmen es halt trotzdem her, weil alles andere macht noch mehr Probleme.

Lucas:

Richtig, die Idee ist eigentlich relativ einfach, weil UDP fügt ja zu IP extrem wenig hinzu. Es ist ja fast rohes IP. UDP fügt vor allem Ports hinzu als Konzept und noch so ein, zwei Kleinigkeiten, aber es ist nicht mehr viel, was auf IP drauf ist. Und deswegen haben sie halt gesagt, weil wir uns nicht roh auf IP setzen können, setzen wir uns auf UDP, was das beste ist was wir bekommen können und bauen ein neues Protokoll auf UDP Ebene. Aber wie wir schon besprochen haben, ist es ja dann so, dass es ein Unreliable Protokoll ist. Das heißt also in Quic müssen die Sachen nachgebaut werden, die in TCP schon drin sind. Also alle Reliability Feature. Dadurch, dass wir es aber eine Ebene höher ziehen, können wir jetzt auf dieser Ebene Sachen machen, wie zum Beispiel parallele Streams, die unabhängig voneinander priorisiert werden können. Wir können so was machen, wie ich eben bei HTTP/2 beschrieben habe und sagen: Hier ist jetzt ein Paket, das gehört übrigens zu diesem größeren Kontext. Wir reden jetzt nicht über Ressourcen, wir sind ja auf einem niedrigeren Level, aber wir können und das wie eine Ressource vorstellen. Das heißt: Dieses Paket hier gehört zu diesem Paket, aber nicht zu diesem Paket. Das heißt, wenn diese zwei Pakete bei dir ankommen, dann ist das fein, dass das dritte Paket noch nicht da ist. Das ist etwas, was wir TCP nicht ausdrücken können, und das können wir tatsächlich jetzt in diesem Protokoll ausdrücken und haben jetzt Multiplexing. Wir schicken einzelne UDP Pakete los, die sind ja alle unabhängig voneinander, weil die nicht Connection gebunden sind. Und auf der kleinen Seite wissen wir, dass es einzelne Pakete sind, die zusammengehören, und dadurch können wir einzelne Ressourcen wieder einzeln zusammenbauen auf dem Client. Ich hoffe, das hab ich jetzt einigermaßen verständlich ausgedrückt. Das war etwas wirr glaube ich.

Lars:

Wir wollen auf hoher Ebene schon die Trennung von Ressourcen haben, aber wenn ich es richtig verstanden habe, ist es so, dass wir das jetzt dem Browser aufbürden, dass der jetzt diese ganzen verschiedenen Fäden einfach wieder zusammensetzt.

Lucas:

Nicht ganz. Grundsätzlich reden wir noch nicht unbedingt über den Browser. Das Protokoll Quic hat erst mal nichts mit dem Browser zu tun. Das Quic-Protokoll weiß aber im Gegensatz zu TCP, dass mehrere Pakete die geschickt wurden zusammengehören und andere nicht, obwohl sie zur selben Connection gehören. Das ist der große Unterschied.

Lars:

Das heißt, ich könnte theoretisch auch irgendwas anderes als HTTP auf diesem Dings bauen.

Lucas:

Absolut. Es ist ein Transportprotokoll und wir können HTTP darüber sprechen, wir können aber auch andere Sachen darüber sprechen. Das heißt ein Datenbankhersteller könnte sich hinsetzen und etwas wie das Process Connection Protokoll erfinden, was nicht auf TCP aufsetzt, sondern stattdessen auf Quic. Genauso gibt es halt verschiedene Gruppen, die versuchen sich ein neues Protokoll für DNS auszudenken, was eben auf Quic aufsetzt. Das ist alles denkbar.

Lars:

Ich hatte bei Quic erst gedacht, dass das dieses ISO, OSI- Schichtenmodell was sie mir an der Uni beigebracht haben komplett ignoriert, aber das ist dann ja gar nicht der Fall. Man hat immer noch eine leichte Trennung in Applikationsebene und Transportebene.

Lucas:

Genau. Wenn du jetzt das OSI Schicht Modell erwähnst: In der Praxis ist es so, dass das OSI Schichten Modell wesentlich mehr Schichten als die tatsächlichen Schichten der Welt hat. Eigentlich teilen wir in der realen Welt in vier Schichten ein. Wir haben dieses Physical oder Signal Layer, wo so Sachen sind wie Internet oder die ganzen Mobilfunk Protokolle oder WLAN Standards usw. Darauf aufbauend das Internet Protokoll als IP und darauf die Transport Protokolle, darauf die Applikationsprotokolle und diese Einteilung bleibt. Wenn das das Schichtenmodell ist, dann bleibt dieses schlichten Modell bestehen, weil statt TCP reden wir jetzt UDP plus Quic. Aber diese beiden Protokolle sind das Zusammenbild des Transport-Layer.

Lars:

Das mit der Fußnote, die du gerade erwähnt hast, dass das kriegt natürlich ein bisschen was weiß über das Applikationsprotokoll was drüber gesprochen wird. Jetzt nicht, dass es HTTP sein muss, aber dass es diese Kontexte von verschiedenen Streams da hat.

Lucas:

Exakt und mit dem weiteren Unterschied, wenn wir es genau nehmen, Transport Layer Security, verrät das ja schon so ein bisschen. Das ist ja eine Verschlüsselung auf Transport Ebene, aber auch auf dem Transport Layer des Schichtenmodells. Das heißt, in der Realität sprechen wir sowieso nicht TCP, sondern wir sprechen TCP/TLS, was auch schon zwei Protokolle sind. Und ich hatte ja schon erwähnt, dass eine Sache die Google besorgt hat, dass das bei diesem Connection Aufbau zwei Handshakes hintereinander macht, erst mal einen für TCP und dann einen für TLS. Und Quic ist jetzt ein Protokoll, was immer verschlüsselt ist, da gibt es keine Ausnahmen für. Und in diesem verschlüsselten Protokoll ist es so, dass wir den Handshake, den wir brauchen, um die Verbindung aufzubauen und den Handshake, den wir brauchen, um eine verschlüsselte Verbindung aufzubauen, zusammenfassen. Das heißt, wir machen nur einen Handshake und damit haben wir direkt beides abgefrühstückt. Das ist die Idee. Wenn man sich jetzt die Pakete vorstellt, es gibt dieses SYN-ACK als Handshake. Wenn wir jetzt in dem ersten Paket, wo wir sagen: Ich möchte gerne mit dir sprechen, direkt schon wissen, dass das verschlüsselt ist, dann kann der Server schon mal sein Zertifikat mitschicken, weil er weiß, wir werden sowieso verschlüsselt kommunizieren, wir können uns dieses ein Mal hin- und herspringen sparen. Das ist ein bisschen der Trick bei Quic, dass wir eben diese Layer zusammengefasst haben, die aber in der Praxis sowieso schon auf einem Layer sind. Ich würde behaupten, dass Quic diese Schichten nicht signifikant ändert, weil die waren schon zusammengefasst. Wir ersetzen TCP und TLS durch UDP und Quic und Quic enthält TLS .

Lars:

Aber wie kriege ich dann eigentlich als Browser oder anderer http-Client mit, dass sich HTTP 3 mit dem Server sprechen kann?

Lucas:

Ich würde die Frage kurz zurückstellen, weil ich noch eine Sache ergänzen möchte. Ich habe eben gesagt, Quic ist ein Protokoll, was wir einführen auf den Transport Layer und darauf setzen wir einfach das bestehende Protokoll auf. Und das stimmt nicht zu 100 Prozent, weil eine Sache ändert sich, und die ist signifikant. Ich hatte bei HTTP2 über diese Binär Frames gesprochen und die sind aus dem HTTP 3 Standard wieder rausgeworfen, weil die jetzt auf einem Layer drunter funktionieren. Das heißt, dass das Feature, das wir verschiedene Frames haben, die diese logischen Einheiten bilden, ist in unserem Schicht Modell 1 runtergerutscht. Das heißt das HTTP 3 Protokoll ist im Prinzip einfacher als das HTTP 2 Protokoll, weil es ein Feature weniger hat, weil es dafür einfach das Transport Layer benutzt.

Lars:

Ich nehme an, die Header Compression ist noch da.

Lucas:

Genau die Header Compression ist noch da. Genau genommen ist es nicht mehr H Pack sondern Q Pack. Aber auf dem Level wo ich es erklärt habe ist es genau das Gleiche, es ist halt noch ein bisschen optimiert. Irgendwelche weiteren coolen Ideen, aber die führen jetzt zu weit, weil ich die auch gar nicht kenne.

Lars:

Ich glaube die Komplexität ist ja auch dadurch erhöht, dass ich nicht mehr diese lineare Ordnung von TCP habe, also diese nicht parallel verschiedenen UDP Streams los ballern kann, dann kann ich mich ja nicht mehr drauf verlassen, dass der eine Header bei dem einen schon angekommen ist und ich referenzieren kann. Stelle ich mir noch spaßig in der Implementierung vor.

Lucas:

Ja, absolut. Aber wir können uns schon vorstellen, dass das für uns in der Praxis dann bedeutet, dass wir UDP sprechen müssen. Da kommen wir auf jeden Fall gleich noch mal drauf zurück. Da ist das Head-of-Line-Blocking tatsächlich vollständig als Produkt, als Problem entfernt. Es gibt gar kein Head-of-Line-Blocking in Quic. Und wichtiges Take Away: Quic ist einfach ein generisches Protokoll, was wir für weitere unterschiedlichste Dinge benutzen können, wo wir halt Multiplexing benötigen, was es attraktiv macht im Vergleich zu TCP. Aber das gibt es immer nur verschlüsselt. Das ist auch wichtig.

Lars:

Dann würde ich jetzt noch mal die Frage stellen: Würde ich jetzt als HTTP Client einfach mal versuchen UDP Pakete auf Port 443 zu ballern oder was mache ich denn da?

Lucas:

Das ist gar nicht so einfach zu beantworten, weil der Browser kann erst mal nicht wissen, ob der Server es kann oder nicht. Das was du jetzt gerade vorschlägst wäre ja: Der Client geht davon aus, der Server kann schon HTTP 3.0, dann schickt er das hin, der Server sagt: Was ist das? Und dann sagt er Ja gut, wenn du das nicht kannst, dann versuche ich mal HTTP/2. Dann sagt er: Hä, was ist das? Und dann schicke ich HTTP/1.1. Das wäre ein komisches Verfahren. Es gibt in der Praxis tatsächlich zwei Verfahren. Das eine ist, das was wir verwenden um HTTP/2 zu machen und das heißt ALPN. ALPN ist eigentlich ein Feature aus TLS, das es auch schon vor HTTP/2 gab und ALPN ist eine Möglichkeit das in dem TLS Handshake der Server dem Client mitteilt, welche Protokolle er beherrscht. Das heißt Application Protocolls er beherrscht. Das heißt er sagt: Hallo, ich bin der Server. Ich hier ist mein Zertifikat und hier ist meine Liste von Protokollen, die du mit mir sprechen kannst. Und dann könnte er zum Beispiel sagen: Ich kann die Protokolle HTTP/1.1, HTTP/2.0 und Web Sockets und alles kann ich dir anbieten, dann kommt das beim Client an, der weiß jetzt, das ist das Zertifikat vom Server, ich kann jetzt eine verschlüsselte Verbindung aufbauen und sucht sich jetzt aus dieser Liste von Protokollen das raus, was er am liebsten sprechen würde. Das heißt er sieht deshalb kann er HTTP/2.0. Das erste Paket, was er an den Server schickt, kann schon HTTP/2 sein.

Lars:

Das ist ja ein bisschen wie Content Negotiation, wenn man versucht, den richtigen Content Type …, sondern nur das das schon im TLS Handshake passiert. Da wo es eigentlich technisch noch nicht relevant an dieser Stelle ist, aber später relevant wird.

Lucas:

Richtig, es ist dasselbe Prinzip wie Content Negotiation. Wir handeln aus, welches Protokoll wir sprechen wollen. Und das ist ein Feature, was bei TLS mit dabei ist, was auch alle TLS Implementierungen beherrschen. Und dadurch bedeutet das, dass wir HTTP/2 sprechen wollen, brauchen wir kein einziges HTTP 1 Paket loszuschicken und wir können trotzdem sicher sein, dass der Server es versteht. Das ist eine ziemlich coole Sache und dadurch gibt es auch kein Problem, dass wir erst mal überlegen müssen: Wird es erst mal langsamer, weil ich erst mal versuche mich zu upgraden o.ä. Das existiert in diesem Kontext nicht mit ALPN.

Lars:

Aber mit HTTP 3 kann ich das ja nicht machen, weil die TLS Verbindung geht über TCP. Dann müsste ich wieder den Handshake machen. Dann müsste mir der Server sagen: Ach übrigens, ich kann auch Quic und dann müsste man den Handshake abbrechen und nochmal mit Quic Neuanfang.

Lucas:

Exakt. Wir müssen sowieso alles abreißen, was wir bis dahin gemacht haben, weil wir TCP ersetzen wollen. Wir wollen statt TCP auf einmal UDP sprechen. Und dafür gibt es auf diesem Level erst mal keine Möglichkeit. Wir können nicht einfach so upgraden on the fly, wie wir das bei HTTP 1 zu 2 gemacht haben. Was wir stattdessen machen ist wir setzen einen Header, den ALT SVC Header, den Alternative Service header, dass es ein ganz normaler HTTP Header und in dem steht drin: Diesen Service, den du hier ansprichst, den gäbe es auch in HTTP 3 wenn du möchtest. Das bedeutet aber in der Konsequenz, dass wenn ihr mit einem HTTP 3 Server sprecht, dann macht ihr immer erst mal eine HTTP/2 Verbindung auf, bzw. wie wir es eben besprochen haben, diese TLS Verbindungen, die das erst mal Negotiated und das erste HTTP hin und her wird auf jeden Fall auf HTTP/2 Ebene gemacht. Das HTML kommt über HTTP/2 an, dann kann der Client sagen: Aha, du kannst ja HTTP 3 und ich auch, jetzt mache ich die Verbindung zu also beendet die TCP Verbindung, mache eine neue Verbindung über UDP auf und startet die HTTP 3 Verbindung. Das heißt die erste Kommunikation mit dem Server findet nie über HTTP 3 statt.

Lars:

Ich sehe schon http 3.1 vor mir, wo dann der TLS Handshake recycelt wird.

Lucas:

Ich befürchte auch, dass da noch etwas kommen wird, aber aktuell ist es zumindest so und ich weiß auch nicht, wie das in der Praxis funktionieren würde und Leute, die sich wesentlich besser mit solchen low level Protokollen auskennen wie ich, haben anscheinend auch keine Lösung gefunden.

Lars:

Die haben wenig Expertise bei sowas.

Lucas:

Protokolle und so haben die keine Ahnung von. Das heißt, das ist die Situation und das bedeutet auch, dass euer Server auf jeden Fall erst mal HTTP/2 antworten können muss, weil sonst kommt gar keine hat HTTP 3 Verbindung zustande, das ist definitiv so. Was aber auch so ist, ist wenn der Client von dem Server diesen Header bekommen hat, dann kann er sich den merken und wenn er das nächste Mal mit demselben Server spricht, dann kann er direkt eine HTTP 3 Verbindung aufbauen. Vorher ging es ja vor allem darum: Verbindung aufbauen und danach eine existierende Verbindung weiterverwenden. Und hier geht es darum: Was ist, wenn wir die Verbindung beenden, weil wir den Browser Tab zu machen, morgen gehe ich wieder auf die Webseite und bauen eine neue Verbindung zum Server auf. Dann kann an der Stelle jetzt tatsächlich diese neue Verbindung zu dem Server, den ich schon kenne, schneller ablaufen als vorher, weil er schon weiß, dass er HTTP 3 sprechen kann.

Lars:

Verstehe. Das heißt aber auch ich kann dann HTTP 3 nicht mehr so unbedingt abschalten, wenn ich das abschalte, dann laufen die ganzen Clients erst mal time out, bis sie dann vielleicht irgendwann mal realisieren, dass das dann doch nicht mehr geht.

Lucas:

Absolut, das ist dieselbe Entscheidung, die ich treffen kann. Ich kann jetzt zum Beispiel dem Client mitteilen: Bitte sprich mit mir immer nur TLS und niemals Plain Text. Wenn ich das mitteile über den Header, dann bedeutet das auch wenn ich jetzt aus irgendeinem Grund mein TLS Zertifikat verliere und ich möchte doch über Plain Text meine Seite ausliefern, dann kommt auch keine Verbindung zustande, weil alle versuchen TLS Verbindung aufzubauen. Das ist derselbe Trade off. Bei TLS würde ich sagen, ist der Trade off relativ easy, weil warum sollte ich mich entscheiden kein TLS mehr zu sprechen, das ist einfach eine schlechte Idee. Bei HTTP 3 ist es nicht ganz so, finde ich, weil wenn du jetzt feststellst okay, die Performance, die wir hier gewinnen, die ist einfach Mist und das sollten wir nicht mehr machen, dann kann ich nicht ohne Weiteres Downgraden auf HTTP2. Das ist halt blöd, das sollten wir im Hinterkopf behalten. Aber ich würde auf jeden Fall auch noch darauf eingehen wollen, ob wir hat HTTP 3 überhaupt einsetzen sollten.

Lars:

Ich wollte gerade sagen: Wir plaudern schon seit über einer Stunde, das wird schon wieder so eine monumentale Folge, das ist schon wieder ein bisschen eskaliert. Deshalb würde ich sagen, wir gehen ein bisschen in den Hinweisblock, die Ratschläge Block. Als besonderen Service habe ich mir die Folge 77 nochmal rausgekramt. Da wurde über Asset Pipelines gesprochen und da zitiere ich den Lucas: Also manche Leute haben das irgendwie seitdem es HTTP/2 gibt als abgehakt im Kopf gespeichert. Zu einem bestimmten Thema und dann hat der Robert geantwortet: Da können wir doch mal einen Podcast dazu machen, zu HTTP/2. Das ist hiermit geschehen. Lucas, erinnerst du dich noch, was da als abgehakt gelten sollte?

Lucas:

Das, was da als abgehakt gelten sollte, war die Idee, dass man seine Assets wie z.B. sein JavaScript oder sein CSS bundeln muss. Heißt statt viele kleine CSS Dateien zu schicken, schickt man eine große. Das war die Idee. Und das Thema hat sich durch HTTP/2 verändert. Es ist nicht so, dass es alles genauso ist wie früher. Es ist ja, wie ich ja schon erklärt habe, durch dieses Multiplexing, ist es viel attraktiver, kleinere Pakete zu schicken als ein großes. Da können wir die cachen und es ist ja auch nicht mehr so ein Problem mit Head-of-Line-Blocking und so weiter. Aber HTTP/2 muss ich trotzdem noch drüber nachdenken, dass die Latenz nicht verschwunden ist. Ich muss immer noch darüber nachdenken, wie viele einzelne Requests muss ich loslösen und wie bilden Sie eine Kaskade von Requests? Wenn meine Kaskade super lang wird, dann hilft mir auch nicht das ich HTTP/2 spreche, weil dann habe ich immer noch jedes Mal das Abwarten bis alles gepasst hat und dann kommt die Antwort.

Lars:

Das ist in HTTP 3 auch nicht unbedingt verschwunden so eine Kaskade, dann ist es vielleicht so, dass die Latenz dann da runtergegangen ist, aber ganz weg ist sie dann immer noch nicht, weil der Browser kann ja immer noch nicht in die Zukunft schauen.

Lucas:

Richtig, das ist ein fundamentales Problem, was sich auch durch 2 und 3 nicht geändert hat. Das heißt also, wenn es euch darum geht: Wie kriege ich die Information möglichst schnell zum Client, dann müsst ihr darüber nachdenken, dass ihr eine gute Balance findet zwischen riesig großen Paketen und sehr kleinen Paketen, weil wenn die kleinen Pakete in einer Kaskade ausgelöst werden, ganz viele Request gleichzeitig schicken, kein Problem, könnt ihr immer gerne machen. Das ist mit HTTP/2 und 3 viel besser als früher. Aber eine Kaskade aufzubauen bleibt ein Problem, auch wenn HTTP/2 und 3 da sind. Das ist wichtig zu verstehen. Was uns dabei bisschen helfen kann, ist das, was ich schon erwähnt habe, nämlich diese Browser Hints. Also der Hinweis darauf, dass weitere Pakete kommen. Aber das kommt natürlich auch irgendwann an eine Grenze, weil ich kann ja auch nicht einen Browser hinschicken, über 500 Dateien oder so was. Das ist auch nicht praktikabel. Das heißt, ich muss eine Balance finden und ich vermute, dass es auch in zehn Jahren noch so sein wird, dass ich nicht eins zu eins dieselben Dateien wie sie in der Entwicklung benutze, in Produktion an den Client schicke, weil das einfach zu viel mit der Latenz macht. Und die Latenz wird auch in zehn Jahren noch ein Problem sein.

Lars:

Aber dann, wenn ich dich richtig verstanden habe, sagst du: HTTP/2 supi, kann man einfach anschalten, löst nicht alle unsere Probleme. Also müssen weiterhin noch ein bisschen Frontend-Architektur vernünftig machen und schauen, dass wir nicht 25 Millionen Files ausliefern wollen. Und dadurch, dass HTTP/2 ja nun auch nicht so besonders neu mehr ist, kann ich das wahrscheinlich auch überall einfach anknipsen. Vielleicht in meinem Webserver oder in meinem CDN oder sonstwo. Und wenn ich dich aber, also wenn du die Anspielung gemacht hast, du sagst ja so HTTP 3, ist das überhaupt möglich? Dann etwas, was man dann braucht. Wie stehst du dazu?

Lucas:

Genau. Also ich stimme dem erstmal zu, was du gerade gesagt hast. Also HTTP/2 anmachen. Do it, jetzt sofort.

Lars:

Aber erst mal den Podcast fertig anhören, dann anschalten.

Lucas:

Genau, erst dann anschalten. HTTP 3 ist wesentlich schwieriger das zu beantworten. HTTP 3, der Lars hat das eben schon so ein bisschen angedeutet, mit Bourg, mit dem Kernel und so weiter. Es gibt aktuell kein Betriebssystem Kernel, in dem Quic implementiert ist. Das heißt also, das was im Kernel drinnen ist, ist nur UDP und das Transport Layer Protokoll ist in User Land implementiert, aufbauend auf die UDP. Das wird sich irgendwann bestimmt ändern. Irgendwann wird im Linux-Kernel dann Quic eingebaut werden, bin ich mir ziemlich sicher. Aber aktuell ist es auf jeden Fall noch nicht so. Das heißt, ihr habt einen höheren Overhead im Vergleich zu anderen Protokollen. Das heißt also, die CPU muss mehr tun, wenn ihr HTTP 3 sprecht, als wenn ihr HTTP/2 sprecht. Das ist erst mal ein Fakt, der sich aber über die Zeit verändern wird. Was aber dazu kommt ist, bestimmte Clients sind bei UDP Paketen misstrauisch, weil die UDP Pakete sind auch nicht so wichtig, wenn auch immer runter priorisiert. Das heißt, es gibt häufig bei UDP ein höheren Package Loss als bei TCP. Das hat auch Google in der Praxis schon festgestellt. Das heißt also, es kann einfach sein, dass der Package Loss so viel höher wird, dass das die Vorteile wieder aufgefressen werden dadurch, dass er ein schnelleres Protokoll hat. Das müsste man aber messen und ausprobieren und so weiter. Das kommt dann auch sehr auf die Clients an und was für eine Umgebung die haben und so weiter. Deswegen UDP ist auch schon wieder ein Problem. Dazu kommt, dass das Quic dadurch, dass es aktuell so eine Library ist, die dann im Betriebssystem läuft, hat auch nicht irgendwelche Standard APIs wie jetzt TCP und UDP auf einer Kernel Ebene. Das kann ja gar nicht sein. Das heißt also, es ist alles noch sehr in den Kinderschuhen, wie das jetzt im Betriebssystem nachher eingebaut wird. Ich denke, das wird sich über die Zeit verändern, auch die UDP, also das UDP, anders behandelt wird, wird sich wahrscheinlich auch über die Zeit ändern. Aber ich würde jetzt nicht sagen, das ist was, was ich in den nächsten zwei Jahren ändert, sondern eher vielleicht in den nächsten fünf Jahren. Also das dauert einfach noch ein bisschen. Hinzu kommt, dass es natürlich auch weniger Tooling gibt, also wenn ihr an so etwas denkt wie WireShark, wo ihr mal in die Pakete reinschauen wollt, weil ihr was debuggen wollt. Ganz viele Sachen davon funktionieren nicht, die müssen auch erst mal so funktionieren, weil das ja auch immer verschlüsselt ist, dass ihr die verschlüsselten Pakete reinschauen könnt und so weiter. Das heißt, ihr werdet viel größere Probleme haben, Debugging und so weiter zu machen bei solchen Paketen. Auch das sollte man beachten. Mein letzter Stand ist ein bisschen veraltet, zwei Jahre, da hat auf jeden Fall Google gesagt, dass drei bis sieben Prozent aller Versuche, eine Quic Verbindung aufzubauen, fehlschlagen. Einfach weil die UDP Pakete geblockt wurden oder sonst irgendwas.

Lars:

Relativ viel. Also drei bis sieben Prozent?

Lucas:

Ja, das ist sehr viel.

Lars:

Also wenn man sich vorstellt, dass drei bis sieben Prozent aller HTTP Requests abgelehnt würden, dann würde das Internet anfangen zu brennen. Es wäre eine Katastrophe.

Lucas:

Kurz noch mal um klar zu stellen, es geht um sobald die Verbindung steht, ist alles gut. Aber es geht um den Aufbau der Verbindung, dass das fehlschlägt.

Lars:

Genau. Ich sage also, wenn man das immer auf HTTP verallgemeinert oder angenommen wir hätten hypothetisches Web, wo alles nur noch HTTP 3 spricht und dann würden drei bis sieben Prozent aller Verbindungen gar nicht erst zustande kommen. Das ist eine Katastrophe.

Lucas:

Genau. Aber es kann natürlich auch sein, dass das mittlerweile einfach dadurch, dass es sich herumgesprochen hat, an vielen Stellen vielleicht gefixt wurde. Also die Zahl ist wahrscheinlich heute niedriger, aber trotzdem muss man das einfach im Hinterkopf behalten, dass das sein könnte, dass es da Probleme gibt. Und deswegen ist meine Empfehlung: Lasst HTTP 3 auf jeden Fall noch mal eine Weile liegen. Lasst sie die Großen wie Amazon und Cloudflare und so weiter erst mal sich die Zähne daran ausbeißen, bis dann alle Leute sich da daran abgearbeitet haben. Und wenn das dann soweit ist, da könnt ihr immer noch auf HTTP 3 updaten, aber heute noch nicht.

Lars:

Also mein Mitgefühl geht raus an die ganzen Netzwerk Leute, die da solche Sachen debuggen müssen und dann irgendwelche Firmen, Upgrades von irgendwelchen Routern an DE-CIX installieren müssen. Also Grüße gehen raus und bis ihr damit fertig seid, lassen r es erst mal bleiben sozusagen.

Lucas:

Genau das ist meine Empfehlung zusammengefasst. Und als Fußnote noch mal als Erinnerung benutzt bitte auch keinen Server Push bei HTTP das lohnt sich nicht. Schaut euch stattdessen Browser Hints an. Das ist die bessere Lösung und ich glaube, da sind auch schon mal noch weitere Ideen aktuell in der Entwicklung. Da kommt bestimmt noch mal was. Aber Server Push in der derzeitigen Form ergibt keinen Sinn. Würde ich nicht tun.

Lars:

Okay, ja, dann würde ich sagen, haben wir doch jetzt ganz Service orientiert am Ende noch ein paar Ratschläge gegeben, die die Leute gleich mal umsetzen können. Dann würd ich sagen, machen wir doch erst mal den Deckel darauf, oder? Ja, vielen Dank Lucas für die ausführliche Erklärung. Also ich habe sehr viel gelernt.

Lucas:

Sehr gerne.

Lars:

Ich hoffe, euch geht es auch so. Wir werden auf jeden Fall ganz viele Links in die Shownotes packen, wo wir noch mal im Detail Ressourcen haben, die das erklären, was wir alles angesprochen haben. Und dann würde ich sagen wir verabschieden uns und ich hoffe, euch hat die Folge gefallen. Feedback gerne an [email protected] und dann schaltet auch wieder bei der nächsten Folge ein. Tschüß!

Lucas:

Tschüß.

Alumnus

Lars worked as Senior Consultant with INNOQ in Munich until December 2022. They are interested in programming languages – especially the functional variety –, web development, and theoretical computer science. They write articles and talk about a multitude of topics.

Alumnus

Lucas was a senior consultant at INNOQ until August 2023. He works on the architecture, conception, and implementation of web applications on the front and back end. He programs in Ruby and JavaScript and helps with technology decisions & the adoption of different NoSQL solutions. Lucas is one of the authors of the book “The Rails 7 Way”. You can hear his voice on the INNOQ podcast quite regularly. He does open source and community work (like organizing and teaching at the local CoderDojo).