TCP stammt aus den 80ern – einer Zeit, in der Datenübertragungen nach heutigen Maßstäben eher Rinnsalen ähnelten. Für moderne Breitbandverbindungen ist es daher nicht optimiert. Mit Linux-Bordmitteln öffnen Admins allerdings die Schleuse für voluminöse Pakete.
Die meisten Internetdienste setzen auf das Transmission Control Protocol (TCP). Dazu zählen das E-Mail-Protokoll SMTP, HTTP/1.1 und 2.0. Daher wirken sich alle Optimierungen beim TCP-Stack positiv auf die Performance aus. Der Artikel schaut sich das TCP Initial Window (IW) an, das die Größe des ersten und damit auch die aller weiteren über TCP verschickten Pakete definiert.
Das erste RFC zu TCP (793) stammt aus dem Jahr 1981 [3]. Einer der wichtigen Aspekte von TCP war und ist, dass es die zur Verfügung stehende Netzwerkbandbreite maximal auslastet. Dabei überlastet es aber die einzelnen Komponenten der Verbindung beziehungsweise deren Puffer nicht. Das gelingt, indem es die zu übertragene Nutzlast (etwa eine HTML-Datei) in kleine Pakete aufteilt und diese nacheinander überträgt. Der Empfänger gibt dem Sender dabei regelmäßig Rückmeldung darüber, wie viele Pakete ihn bereits erreicht haben. Fehlt eins, schickt der Sender es erneut. Über Sequenznummern stellt TCP die richtige Reihenfolge der Pakete sicher.
In der Anfangszeit des Internets kamen Akustikkoppler mit einer Übertragungsrate von 300 Bit/s zum Einsatz. Inzwischen nutzen in den Großstädten viele Privatwohnungen Glasfaser mit Übertragungsraten von 1 GBit/s.
Das Grundkonzept des Transmission Control Protocol hat sich indes in all den Jahren nicht geändert. Da TCP nicht weiß, wie groß die maximale Übertragungsrate einer Netzwerkverbindung ist, fängt es mit einem kleinen Datenpaket an. Es sendet also nicht die komplett zu übertragende Datei, sondern erst mal ein kleines Stück davon.
Dieses TCP Initial Window (IW) hat sich über die Jahre hingegen durchaus verändert und liegt heute bei zehn Segmenten. Ein Segment kann 1500 Byte übertragen. Davon gehen aber 40 Byte als Overhead verloren. Das erste Datenpaket vom Server zum Empfänger ist entsprechend groß: (1460 * 10) / 1024 = 14 KByte. Dabei ist völlig irrelevant, ob es sich um eine moderne Glasfaserverbindung oder ein altes analoges Modem handelt.
Hat der Server den Empfang dieser 14 KByte vom Client bestätigt, verdoppelt TCP die Zahl der Segmente auf 20, was 28 KByte entspricht. Sind auch diese angekommen, verdoppelt TCP die Segmente weiter. Die Verdopplung setzt sich so lange fort, bis die Gegenseite ein Paket nicht empfängt und damit dem Server nicht bestätigen kann. Dann überträgt TCP beim nächsten Versuch wieder weniger Segmente. Bei schwankender Bandbreite oder Unterbrechungen greifen die gleichen Mechanismen.
Böser Trip
Wer also eine 100 KByte große Datei per HTTP/1.1 übertragen will und eine neue TCP-Verbindung mit einem IW von 10 benutzt, benötigt dafür vier Roundtrips: Tragisch an diesem Beispiel ist, dass der vierte Roundtrip allein schon über 100 KByte transportieren könnte, aber die vorherigen drei Roundtrips nötig hat, um auf diese Bandbreite zu kommen (Tabelle 1). Die Downloadgeschwindigkeit hängt also bei diesen 100 KByte nur von der Netzwerklatenz und nicht von der verfügbaren Bandbreite ab. Insgesamt legen die verschiedenen Netzwerkpakete die Strecke zwischen Server und Client acht Mal zurück.
|
Roundtrip |
Payload |
Summe |
|---|---|---|
|
1 |
14 KByte |
14 KByte |
|
2 |
28 KByte |
42 KByte |
|
3 |
57 KByte |
99 KByte |
|
4 |
114 KByte |
213 KByte |
Vor diesem Hintergrund wird auch klar, warum beim neuen 5G-Mobilfunknetz nicht die höhere Bandbreite, sondern die geringere Latenz ein schnelleres Surfen auf normalen Webseiten ermöglicht. Bei ganz großen Dateien (zum Beispiel beim Streamen von HD-Filmen) ist hingegen die Latenz nicht so wichtig, da zählt tatsächlich die Bandbreite.
Im Jahr 2013 setzte das RFC 6928 [4] das Initial Window von vorher zwei bis vier auf zehn Segmente hoch. Seitdem ist dieser Wert bei allen Linuxen Standard. Ein IW von zehn ergab im Jahr 2013 weltweit gesehen Sinn. Wer aber heute Webseiten meist in Deutschland ausliefert, kann einen höheren Wert einstellen.
Weltweit agierende CDNs und Cloudanbieter tun das ohnehin bereits. Das Paper unter [5] analysiert dies und zeigt, dass Amazon ein IW von 25, Microsoft eines von 30, Akamai bis zu 32 und der CDN Fastly sogar bis zu 100 Segmente benutzt. Dabei liefern diese Anbieter teilweise unterschiedliche Inhalte mit unterschiedlichen IWs aus.
Will ein normaler Benutzer ein höheres IW einstellen, braucht er dazu Rootrechte und das Kommandozeilentool »ip«. Zunächst findet er die eingestellte Standardroute heraus:
$ ip route show default via 123.123.123.241 dev eno1 onlink 123.123.123.240/29 dev eno1 proto kernel scope link src 123.123.123.242
Die Zeile, die mit »default« beginnt, ist die in diesem Fall wichtige. Mit ihr und dem »ip«-Befehl setzt der Nutzer nun ein IW von 32 Segmenten:
$ ip route change default via 123.123.123.241 dev eno1 onlink initcwnd 32
Im Anschluss ruft er noch einmal »ip route show« auf, um zu kontrollieren, ob der neue Wert angekommen ist. Und siehe da:
$ ip route show default via 123.123.123.241 dev eno1 onlink initcwnd 32 123.123.123.240/29 dev eno1 proto kernel scope link src 123.123.123.242
Mit einem IW von 32 braucht die oben beschriebene 100 KByte große Datei nur zwei Roundtrips, bevor sie beim Client landet. Die reine TCP-Auslieferung ist also doppelt so schnell.
Leider gibt es keinen für alle gültigen Wert für ein optimales IW. Für deutsche Server sollte ein IW von 20 völlig unproblematisch sein. Wer sicher ist, dass die meisten Gegenstellen aus Deutschland kommen, probiert ein IW von 32 aus. Wer einen zu hohen Wert wählt, schießt sich damit jedoch in den eigenen Fuß. In diesem Fall kann das Ausliefern länger dauern, weil Fehler auftauchen, die das Protokoll korrigieren muss, was dann weitere Roundtrips auslöst.
HTTP/3 auf dem Weg
Beim Übertragen von Webseiten wird TCP immer mehr zum Engpass. Aus diesem Grund setzt das künftige HTTP/3-Protokoll [1] auf das User Datagram Protocol. UDP ist ein minimales und verbindungsloses Netzwerkprotokoll. Es ist beim Datenversand schneller als TCP, garantiert aber weder die Zustellung noch die richtige Reihenfolge der versendeten Daten. HTTP/3 bildet diese Funktionen von TCP daher innerhalb eines verschlüsselten Tunnels im UDP selbst nach. Das zieht natürlich einen gewissen Overhead nach sich. Am Ende ist HTTP/3 dennoch schneller als HTTP/2.
Zwar kommt HTTP/3 in Deutschland noch kaum zum Einsatz, dennoch läuft es bereits sehr stabil. Google setzt es seit Langem ein, ursprünglich unter dem Namen Quic [2]. Da Google mit Chrome einen eigenen Browser im Rennen hat, kann es neue Technologien schnell und relativ unkompliziert ausprobieren. Wenn diese neuen Technologien funktionieren, wird ein RFC nachgeschoben. So ist es auch bei HTTP/3.
Wer die richtige Einstellung gefunden hat, kann den obigen Befehl in der Datei »/etc/network/interfaces« beim entsprechenden »iface« nach einem »post-up« eintragen. Dann führt ihn das System beim Restart automatisch aus.
Nach dem Hochsetzen des IW sollte der Admin zusätzlich auch noch Pacing [6] aktivieren. Das stellt sicher, dass TCP die verschiedenen Pakete mit minimal unterschiedlichen Zeitabständen verschickt. Dadurch kommt es bei Netzwerk-Engpässen zu weniger Stau-Effekten. Pacing lässt sich mit Rootrechten und dem Befehl »sysctl -w net.core.default_qdisc=fq« aktivieren [7]. Danach muss der Admin allerdings einen Neustart des Systems veranlassen.
Infos
-
RFC 793: https://tools.ietf.org/html/rfc793
-
RFC 6928: https://tools.ietf.org/html/rfc6928
-
Jan Rüth, Ike Kunze, Oliver Hohlfeld, “TCP’s Initial Window – Deployment in the Wild and its Impact on Performance”: https://www.comsys.rwth-aachen.de/fileadmin/papers/2019/2019-rueth-iwtnsm.pdf
-
Pacing: https://homes.cs.washington.edu/~tom/pubs/pacing.pdf
-
Pacing für TCP einstellen: http://man7.org/linux/man-pages/man8/tc-fq.8.html







