Designing for Performance

Verbesserung der Performance durch Optimierung der User Experience

Für ein besseres Lesegefühl wird in diesem Artikel das generische Maskulinum verwendet. Dies schließt natürlich alle Geschlechter ein.

1. Einleitung

„If you are making decisions about the look and feel of a website, you are making decisions that directly impact the performance of that site…“ [1, S. XV]. Folgerichtig ist die Aufgabe eines Webdesigners nicht nur, sich mit der Gestaltung der Webseite zu beschäftigen, sondern sich auch Gedanken hinsichtlich der Entwicklung zu machen. Sowohl der Designer als auch die Entwickler sind für die Performance einer Anwendung verantwortlich. Deswegen ist es umso wichtiger, dass auch ein Designer den Prozess danach versteht und nicht nur den Gestaltungsaspekt. Je früher man zusammen agiert und je mehr sich der Designer auch mit dem Prozess danach auseinandersetzt, desto besser wird das Ergebnis. Dazu zählt auch, dass man stets das Ziel des Projektes und die Zielgruppe vor Augen behält sowie bestimmte Funktionen vor der Umsetzung immer wieder hinterfragt: Ist das wirklich eine optimale Lösung für den Nutzer, um vorhandene Probleme zu lösen [2]? „Jedes Element im Layout muss auch seinen Grund haben und Lösungen liefern, die nicht nur gut aussehen, sondern auch messbar sind. Das Layout muss für die Zielgruppe optimiert werden.“ [2].

Inzwischen ist die Regel „Jede Webseite, deren Ladezeit eine Sekunde überschreitet, tut dem Benutzer weh.“ [3]. Nur ein kurzer Augenblick entscheidet aus diesem Grunde bereits über Erfolg oder Misserfolg einer Webseite. Performance – Optimierungen sollten dementsprechend frühestmöglich in den Entwicklungsprozess einer Anwendung integriert werden.  Zehn Prozent eines Entwicklungsprojektes sollte für die Benutzerfreundlichkeit investiert werden, um bereits eine 135 Prozent höhere Benutzerfreundlichkeit zu erzielen [4]. 

Continue reading

WebSockets: Technischer Einblick und Performance-Vergleich

In diesem Artikel wird ein kurzer Blick auf die zu Grunde liegende, technische Funktionsweise von WebSockets geworfen und ihre Performance im Vergleich zu HTTP und Server-sent Events (SSE) untersucht, wodurch letztlich das Potenzial von WebSockets eruiert werden kann.

Hintergrund & Entstehung

In der Vergangenheit war es bei Webanwendungen nur unter unsachgemäßer Verwendung des Hypertext Transfer Protokolls (HTTP) realisierbar, eine bidirektionale Verbindung zwischen Client und Server herzustellen. Dabei sind folgende Probleme entstanden: (1.) Der Server muss verschiedene Transmission Control Protocol (TCP) Verbindungen für jeden Client nutzen. Eine, um Informationen zum Client zu senden, und eine neue für jede eintreffende Nachricht. (2.) Es gibt einen großen Overhead, da jede Client-to-Server Nachricht einen eigenen HTTP-Header hat. (3.) Das Client-seitige Skript muss sich merken, welche abgehenden Verbindungen zu welchen eingehenden Verbindungen gehören. Nur so können Antworten verfolgt werden. [vgl. 1]

Eine bessere Lösung wäre eine einzige TCP-Verbindung für beide Richtungen – hier kommt der WebSocket-Standard ins Spiel. Der Standard setzt sich zusammen aus dem WebSocket-Protokoll und der WebSocket-API (WSAPI). Der WebSocket-Standard kann einen bidirektionalen Kommunikationskanal zwischen einer Webanwendung und einem Server herstellen. Es stellt dadurch eine Alternative zu allen bislang verwendeten, HTTP-basierten Kommunikationstechnologien dar. [vgl. 1]

Im Jahr 2009 hat Google das WebSocket-Protokoll der Internet Engineering Task Force (IETF) als Draft vorgelegt [vgl. 2]. Die IETF ist ein weltweites Komitee, welches die Standardbetriebsprotokolle für das Internet definiert [vgl. 3]. Bis Mai 2010 [vgl. 4] wurde das Protokoll von Google und anderen weiterentwickelt und kontinuierlich verbessert. Nach einem zweimonatigen Stillstand hat die „BiDirectional or Server-Initiated HTTP (HyBi)“-Arbeitsgruppe – eine Gruppe der IETF – die Weiterentwicklung offiziell fortgeführt. Im Dezember 2011 ist das WebSocket-Protokoll schließlich unter dem Request for Comments (RFC) 6455 erschienen [vgl. 1]. Ein RFC ist die Form, in welcher die IETF die Standardbetriebsprotokolle formuliert [vgl. 3].

Technische Funktionsweise

Opening-Handshake

Sobald im Browser eine WebSocket-Verbindung aufgebaut wird, findet durch den sogenannten Opening-Handshake zunächst der Verbindungsaufbau statt. HTTP-basierend wird dabei ein WebSocket-Kanal eröffnet. Ein beispielhafter HTTP-GET-Request ist nachfolgend zu sehen. [vgl. 5, S. 35]

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13

GET /chat spricht den Endpunkt des WebSocket-Servers an. Ein Server kann dabei mehrere WebSocket-Endpoints besitzen. Mit Upgrade: websocket wird mitgeteilt, dass auf das Websocket-Protokoll umgestellt werden soll. Der eigentliche Wechsel passiert durch Connection: Upgrade. Im Header Sec-WebSocket-Key steht eine Zufallszahl. Mit ihr wird überprüft, ob der Server das WebSocket-Protokoll unterstützt. Über den Origin kann der Client den Server darüber informieren, von welcher Ursprungsdomain der Request gesendet wurde. Darauf basierend kann der Server entscheiden, ob er die Verbindung annimmt. Über den Header Sec-WebSocket-Protocol kann der Client dem Server optional mitteilen, welche Subprotokolle über den WebSocket-Kanal verarbeitet werden können. Die Versionsnummer des WebSocket-Protokolls wird mit Sec-WebSocket-Version angegeben. Da die Reihenfolge der Header vom Client zufällig gewählt werden, spielt sie keine Rolle. Wenn ein Handshake-Request nicht alle notwendigen Felder liefert, wird keine Verbindung aufgebaut. [vgl. 5, S. 36 f.]

Wird die Handshake-Anfrage vom Server akzeptiert, sendet er eine HTTP-Response an den Client [vgl. 5, S. 37]. Eine beispielhafte Response ist nachfolgend zu sehen.

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+0o=
Sec-WebSocket-Protocol: chat

Diese Antwort enthält den Statuscode 101 Switching Protocols, wodurch bestätigt wird, dass der Protokollwechsel stattfinden kann. Der Wert für Sec-WebSocket-Accept wird folgendermaßen erstellt: Zunächst wird ein Globally Unique Identifier (hier: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11) and den Sec-WebSocket-Key des Handshake-Requests angehängt. Dadurch ergibt sich dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11. Aus dieser Zeichenkette wird unter Einsatz der kryptografischen Hashfunktion SHA-1 ein Hashwert erzeugt, welcher daraufhin mittels einer Base64-Codierung [vgl. 6] in einen Textstring umgewandelt wird. Dieser String ergibt den Wert des Headers Sec-WebSocket-Accept. Nun ist es dem Client möglich, anhand des Sec-WebSocket-Keys und des Sec-WebSocket-Accepts zu überprüfen, ob die Antwort von dem richtigen WebSocket-Server kommt. Sofern in dem Opening-Handshake-Request Subprotokolle im Header Sec-WebSocket-Protocol angegeben wurden, teilt der Server im gleichnamigen Header der Response mit, welche Subprotokolle er unterstützt – hier: chat. Es finden Verbindungsabbrüche statt, wenn angeforderte Subprotokolle nicht unterstützt werden oder wenn der Server mit einem nicht-angefragten Subprotokoll antwortet. Nach erfolgreichem Ablauf aller genannten Schritte gilt der Handshake als abgeschlossen und der WebSocket-Kanal wurde aufgebaut. Über diesen Kanal können nun sequenzweise Daten in Form von sogenannten Frames in beide Richtungen geschickt werden. [vgl. 5, S. 37-39]

Datentransfer

Die zu transportierenden Daten liegen als Sequenz von Frames vor. Die Protokollnachricht besteht – wie üblich – aus einem Header mit Kontrolldaten und den Nutzdaten im Payload. Ein vereinfachter Aufbau eines WebSocket-Frames ist in Abbildung 1 dargestellt. Aus dieser Darstellung ist auch abzulesen, wie schlank das WebSocket-Protokoll ist – im Vergleich zu HTTP. Der kleinste WebSocket-Frame, der vom Server zum Client gesendet wird, beträgt 2 Bytes. Ist die Header-Länge maximal, so beträgt sie 14 Bytes. [vgl. 5, S. 39]

Abbildung 1: Vereinfachter Aufbau eines WebSocket-Frames [vgl. 5, S. 39]

WebSockets übertragen Nutzdaten sequenzweise. Besondere Bedeutung hat dies, wenn Nutzdaten zum Übertragungszeitpunkt nicht vollständig sind. Sie können daher weder in ein WebSocket-Frame eingefügt werden, noch kann die Datenlänge der Nutzdaten im Frame-Header angegeben werden. Dennoch besteht die Möglichkeit, in diesem Fall Daten zu übertragen – nämlich stückchenweise. Das FIN-Bit des ersten Bytes gibt Auskunft darüber, ob der Frame vollständig ist. Trifft dies zu, so ist das Bit auf 1 gesetzt, anderenfalls auf 0. Das FIN-Bit ist in Abbildung 1 zu erkennen. [vgl. 5, S. 42 f.]

Für alle Frames, die vom Client zum Server geschickt werden, gibt es aus Sicherheitsgründen eine Besonderheit: Sie müssen maskiert werden. Für jeden Frame muss der Client dazu eine neue, noch unverwendete 32-Bit-Zufallszahl generieren. Dieser sogenannte Masking-Key wird in das entsprechende Header-Feld gesetzt (siehe Abbildung 1). Mittels eines Algorithmus werden die Nutzdaten unter Verwendung des Masking-Keys maskiert. Das Demaskieren erfolgt auf Serverseite entsprechend umgekehrt. [vgl. 5, S. 43–45]

Closing-Handshake

Ein Closing-Handshake kann sowohl vom Client als auch vom Server veranlasst werden und wird durch einem sogenannten Close-Frame gestartet. Haben sowohl Client als auch Server einen solchen Close-Frame empfangen und gesendet, gilt der Closing-Handshake als abgeschlossen. Der darunterliegende TCP-Kanal wird vom Server beendet. [vgl. 5, S. 53 f.]

Performance-Vergleich

HTTP vs. WebSockets

In einem Blogpost auf Feathersjs.com vergleicht David Luecke die Performance von HTTP und WebSockets. Der Test-Server ist dabei auf Heroku gehostet und gibt auf einen Request ein JSON-Objekt zurück. Über eine Webseite können eine festgelegte Anzahl von Requests durchgeführt werden, während die dafür benötigte Zeit gestoppt wird. [vgl. 7]

Abbildung 2: Vergleich der benötigten Zeit für einen Request zwischen HTTP und WebSocket [vgl. 7]

Die durchschnittliche Dauer eines einzigen HTTP-Requests beträgt 107 Millisekunden, während ein einzelner WebSocket-Request 83 Millisekunden dauert (siehe Abbildung 2). Für alle durchgeführten Tests wird die Zeit, die benötigt wird, um die WebSocket-Verbindung herzustellen, nicht berücksichtigt. Größere Unterschiede zeigen sich, sobald mehrere parallele Requests durchgeführt werden: 50 WebSocket-Requests dauern 180 Millisekunden, während für dieselbe Anzahl über HTTP 5 Sekunden benötigt werden (siehe Abbildung 3). Über HTTP können ungefähr 10 Requests pro Sekunden geschickt werden – bei WebSocket sind es knapp 4.000 Requests. Hauptgrund hierfür ist, dass der Browser die Anzahl der gleichzeitigen HTTP-Verbindungen begrenzt. Bei Google Chrome – dem Testbrowser – liegt die Anzahl standardmäßig bei 6 Requests. Bei WebSockets gibt es solche Beschränkungen hingegen nicht. [vgl. 7]

Abbildung 3: Vergleich der benötigten Zeit für 50 parallele Requests zwischen HTTP und WebSocket [vgl. 7]

David Luecke hat auch die übertragenen Datenmengen verglichen. Auch hier wird der initiale WebSocket-Verbindungsaufbau nicht berücksichtigt. Ein HTTP-Request und -Response erzielt eine Übertragungsmenge von 282 Bytes. Unter Verwendung eines WebSockets liegt die entsprechende Datenmenge bei 54 Bytes (31 Bytes für den Request und 24 Bytes für die Response). Zu beachten ist jedoch, dass diese Differenz mit steigender Nutzdatenmenge (Payload) abnimmt, da die Header-Größe bei HTTP gleichbleibend ist. [vgl. 7]

Abbildung 4: Vergleich der bei einem Request übertragenen Datenmenge zwischen HTTP und WebSocket [vgl. 7]

Abschließend hat David Luecke Benchmark-Tests (Lasttests) durchgeführt, um herauszufinden, ob und wie sich die bisherigen Ergebnisse verändern, wenn mehrere Clients mit dem Server kommunizieren. Die Benchmarks laufen mit 100 gleichzeitigen Verbindungen und beinhalten auch die Verbindungsaufbauzeit des WebSockets. Wenn nur ein einziger Request pro Verbindung getätigt wird, so ist HTTP etwa doppelt so schnell wie WebSocket. Bei 50 Requests pro Verbindung ist der WebSocket allerdings ca. 50 Prozent schneller. Bei einer hohen Anzahl an Requests pro Verbindung erzielen WebSockets also bessere Ergebnisse. [vgl. 7]

Server-sent Events vs. WebSockets

Bei Server-sent Events (SSE) wird ein einzelner HTTP-Request kontinuierlich aufrechterhalten, um darüber Updates zu schicken. Das bedeutet, dass Header nur einmalig – wenn der Request veranlasst wird – gesendet werden müssen. Dadurch werden für jedes Update nur die notwendigen Informationen übertragen, wodurch sich die Datenmenge reduziert. Ein weiterer Vorteil von SSE ist, dass sie sich im HTML5-Standard befinden. Das bedeutet: Bestehende Anwendungen können mit minimalem Aufwand nachträglich auf SSE umgestellt werden. Es ist jedoch zu beachten, dass SSE unidirektional funktionieren, das heißt Updates können nur vom Server zum Client gesendet werden – nicht andersherum. Eine Verbindung vom Client zum Server würde einen zusätzlichen HTTP-Request benötigen. Laut einem Test von Alexis Abril schneiden SSE im Vergleich zu WebSockets ähnlich performant ab. Die Menge der übertragenden Daten unterscheidet sich lediglich um wenige Kilobytes. Die Ergebnisse sind in Abbildung 5 dargestellt. Alexis Abril kommt zu dem Ergebnis, dass sich für die meisten Webanwendungen SSE aufgrund ihres geringeren Entwicklungsaufwands besser eignen. Falls jedoch häufig Daten vom Client zum Server geschickt werden müssen, liefern WebSockets eine bessere Performance, wodurch der etwas höhere Implementierungsaufwand gerechtfertigt werden kann. [vgl. 8]

Abbildung 5: Testergebnisse Vergleich zwischen Server-sent Events und WebSocket [vgl. 8]

Vor- und Nachteile von WebSockets

Vorteile von WebSockets sind, dass über einen bidirektionalen Kanal Daten in Echtzeit zwischen Client und Server übermittelt werden können. Dies beschränkt sich dabei nicht auf Textdateien, sondern es können auch binäre Daten (z. B. Video-, Audio- und Bilddateien) übertragen werden. Zudem haben WebSockets nur einen kleinen Overhead, d. h. es werden geringere Datenmengen übertragen, wodurch eine bessere Performance erzielt werden kann. Gerade für Anwendungen, die häufig mobil genutzt werden, kann dies entscheidend sein. [vgl. 5, S. 35]

Ebenso weisen WebSockets eine sehr gute Browserunterstützung auf. Seit 2013 werden sie von allen gängigen Desktop-Browsern unterstützt und inzwischen auch von den vertretenen Smartphone-Browsern. Welche Browser WebSockets unterstützen ist aus Abbildung 6 zu entnehmen. [vgl. 10]

Abbildung 6: Browserunterstützung von WebSockets [10]

Gravierende Nachteile weisen WebSockets nicht auf. Man sollte sich jedoch über gewisse Sicherheitsrisiken bewusst sein und entsprechende Schutzmaßnahmen einrichten. Die Risiken gleichen denen des zugrundeliegenden HTTP-Protokolls. So sind beispielsweise Denial-of-Service-Angriffe (DoS-Angriffe) möglich, da die Anzahl an Verbindungen zum Server nicht begrenzt wird. Bei einer DoS-Attacke wird eine hohe Anzahl an Anfragen an den Server gesendet, sodass das System enorm langsam wird oder sogar zusammenbricht [vgl. 11]. Zudem findet keine Authentifizierung und Autorisierung während des Handshake-Prozesses statt. Ebenso wird der Nutzer-Input nicht geprüft, wodurch z. B. Cross-Site-Scripting (XSS) und SQL-Injections möglich sind. [vgl. 12]

In [13] sind einige Best Practices einzusehen, die für einen sicheren Einsatz von WebSockets umgesetzt werden sollten.

Fazit

In WebSockets steckt großes Potenzial, da es bislang keine andere Technologie gibt, die eine bidirektionale Verbindung zwischen Client und Server ermöglicht. Auch kann eine sehr hohe Performance erzielt werden. Allerdings gibt es gewisse Sicherheitsrisiken, auf die bei der Implementierung geachtet werden sollte. Sofern Textdaten lediglich unidirektional vom Server zum Client gesendet werden müssen, empfielt sich stattdessen die Verwendung von Server-sent Events. Diese erzielen eine vergleichbare Performance, bei einem geringeren Entwicklungsaufwand.

Literatur

The Surprising Truth About Vue and React’s Web Speed with JSWFB

ReactJS vs VueJS

Comparative Web Performance evaluation of Vue & React using JSWFB

Abstract

During this period of time where, the digital world, where nearly 5 billion people are using the internet, comes the need to build a web application that is intuitive, interactive and with higher speed performance. That’s where the JavaScript Libraries and Frameworks come into the picture. In the current web development culture, ReactJS and VueJs are the most used and most loved web frameworks. They are used to develop interactive single web page applications. This paper will evaluate these frameworks regarding their performance and usage using the JS Web Framework Benchmark.

ReactJS vs VueJS
ReactJS vs VueJS
Continue reading

Neue Bildformate im Vergleich

Bilder und andere Medienelemente gelten im Internet heute als selbstverständlich. Wie aus dem HTTP Archive hervorgeht, generieren 99,9% aller Webseiten mindestens eine Anfrage für eine Bildressource und 95,9% enthalten mindestens ein <img>-Element [1]. Die restlichen 4% entfallen beispielsweise auf Favicons und Hintergrundbilder.

Für die breite Verwendung von Bildern gibt es gute Gründe: Sie transportieren Informationen schneller als Text, lockern das Layout auf und regen Nutzer zu mehr Interaktion an [2]. Wie Abbildung 1 veranschaulicht, schlägt sich dies auch im Anteil von Medienelementen an der gesamten Größe einer Webseite (Page Weight) nieder [3]. So machen Bilder, Animationen und Videos durchschnittlich zwei Drittel des gesamten Page Weights aus – und selbst im zehnten Perzentil nehmen sie noch einen Anteil von etwa 44% ein.

Continue reading

Drei Sekunden sind zu lang – Auswirkung der Ladezeit von Webseiten auf die User Experience

Warum ist es so wichtig, die optimale Ladezeit anzustreben?

Auf jemanden oder auf etwas zu waren ist uns Menschen nicht fremd. Im Schnitt verbringt jeder Mensch in seinem Leben rund ein bis zwei Jahre mit Warten. Dies kann an der Bushaltestelle, Suppermarktkasse, dem Abwarten auf die Ankunft einer Zustellung, oder die Ankunft einer geliebten Person sein. Viele Menschen erscheint das Warten auf etwas oder jemanden als lästig. Dies kann verschiedenste Gründe haben wie bspw. Langeweile, die seelische Verfassung und der allgemeine Gemütszustand, sowie Zeitdruck. Ganze Geschäftsmodelle wie das “Priority Boarding” am Flughafen beruhen darauf, dass Menschen bereit sind mehr Geld zu bezahlen, nur um nicht anstehen zu müssen. (D. Lenz 2018)

Continue reading

Automate Performance Optimization

In order to display a website as quickly as possible, performance optimization is necessary. Since manual optimization can be time-consuming and often several steps need to be performed, automating performance optimization can be a good idea. This in turn can include, for example, reporting (speed analysis of the website) and performance optimization itself (compression, code reduction, …).
This article gives an overview of where automation can be used, which tools are suitable for this and what these tools offer.

Continue reading