Schnellere Ladezeiten mit einem CDN wie AWS Cloudfront

04.05.2022 Tom Trapp
Cloud aws cdn cloud-native

Im ersten Teil unserer AWS native Serie wollen wir einen sehr bekannten Service von Amazon Web Services genauer unter die Lupe nehmen.

Content Delivery Network

Bevor wir uns dem AWS Service widmen, wollen wir uns kurz die Theorie hinter einem CDN anschauen. Wie bereits der Name vermuten lässt, handelt es sich hierbei um ein geografisch verteiltes Netzwerk, welches aus Gruppen von Servern besteht, die zusammenarbeiten, um Internetinhalte schnell bereitstellen zu können. Ziel ist es hier, dass relevante Ressourcen wie HTML-Seiten, JavaScript-Dateien etc. mit geringer Latenz geladen werden können.

An dieser Stelle möchte ich gerne erwähnen, dass ein CDN kein Webhost ist. Die eigentlichen Inhalte liegen an einer zentralen Quelle, dem Webhost (auch Origin genannt). Hierbei kann es sich zum Beispiel um einen AWS S3 Bucket handeln. Das CDN setzt Caching ein, um die Last auf den eigentlichen Webhost zu reduzieren. Befinden wir uns beispielsweise in Basel und wollen eine Website aus Kalifornien abrufen, so erhalten wir ohne CDN unsere Response direkt aus den USA. Dies sorgt für eine längere Ladezeit, da die physische Distanz und somit auch die Anzahl der Network-Hops (Zwischenschritt von einem Netzwerksegment zum nächsten) gross ist. Beim Einsatz eines CDN würde der Request automatisch an den nächsten CDN-Standort weitergeleitet werden. Im Fall von CloudFront wäre das beispielsweise Zürich oder Frankfurt. Der Content wurde zuvor dort gecached und kann so viel schneller zu uns geschickt werden.

CloudFront CDN Content Delivery Network

Technisch gesehen läuft der Verkehr über eine separate URL, welche in erster Linie nichts mit der eigenen Domain zu tun hat. Hier gilt es als Best-Practice, einen statischen Pfad auf der eigenen Domain zu registrieren und eine Weiterleitung zum CDN-Provider zu machen. So würde der Kunde beispielsweise bei Bildern die Adresse https://b-nova.com/static sehen, wobei der Pfad /static automatisch zur Adresse des CDN Providers z.B. http://d111111abcdef8.cloudfront.net/... weiterleitet.

Vorteile CDN

  • Schnellere Ladezeiten: Durch geografische Nähe sind Inhalte generell schnell und mit weniger Hops zu erreichen
  • Niedrigere Webhosting Kosten: Der eigentliche Webhost wird entlastet
  • Erhöhte Ausfallsicherheit & Stabilität: Da der Content auf der ganzen Welt verteilt ist

Ausserdem kann ein CDN durch bestimmte Sicherheitsmechanismen beispielsweise vor DDoS-Attacken schützen.

Nachteile CDN

  • Erhöhte Komplexität: Im Gegensatz zu einem einzelnen Webhosting Server
  • Weniger Transparenz: Da der Content extern komplett verteilt über den Globus liegt
  • Leichter Kontrollverlust: Da der Content weltweit verteilt ist

Grundsätzlich kann man aber sagen, dass es in vielen Fällen Sinn macht, ein CDN einzusetzen, da die Vorteile klar die Nachteile überwiegen.

CloudFront

CloudFront ist der Content Delivery Network (kurz CDN) Service von AWS. Einfach gesagt kann man damit statische und dynamische Webinhalte wie zum Beispiel HTML-, CSS-, JavaScript- und Bilddateien schnell und einfach dem Benutzer bereitstellen. Hierbei landet der User immer auf dem ihm nächsten Standort des von CloudFront bereitgestellten globalen Netzwerks. Konkret gibt es über 300 Standorte in aktuell mehr als 90 Städten in 47 Länder. So baut Amazon ein Netz aus einzelnen Knoten auf, um Content immer mit der kleinstmöglichen Latenz ausspielen zu können.

Solche einzelnen Standorte des globalen Netzwerks nennt man Edge Locations. Oft gibt es mehrere Edge Locations in einer Stadt, beispielsweise beherbergt Frankfurt aktuell 15 Edge Locations. Zusätzlich zu diesen Edge Locations gibt es aktuell noch 13 sogenannte Regional Edge Caches, welche als vorgelagerter Cache vor dem eigentlichen Origin stehen. So kann eine Edge Location den Content direkt beim Regional Edge Cache abholen, ohne Last auf der Origin zu erzeugen. Diese Regional Edge Caches stehen somit vor dem Origin, haben untereinander aber in erster Linie (mehr dazu später) keine Verbindung. In Europa gibt es aktuell beispielsweise drei Regional Edge Caches, in Dublin, Frankfurt und London.

Content Delivery mit CloudFront

Exemplarisch und vereinfacht wollen wir den Prozess, den ein Request durchläuft, genauer durchleuchten. Wir befinden uns erneut in Basel und wollen eine bekannte Cupertino-Website abfragen.

Ohne CloudFront:

  1. Basel (CH): Wir setzen den Request ab
  2. Stadt A: Routing
  3. Stadt B: Routing
  4. Stadt C: Routing
  5. ...
  6. Cupertino (US): Request kommt beim Webhost an, Seite wird gerendert und auf gleichem Weg an uns zurückgeschickt
  7. ...
  8. Stadt C: Routing
  9. Stadt B: Routing
  10. Stadt A: Routing
  11. Basel (CH): Content ist da

Mit CloudFront, erster Request:

  1. Basel (CH): Wir setzen den Request ab
  2. Zürich (CH), AWS Edge-Standort: Content für diesen Request ist noch nicht gecached
  3. Frankfurt (DE), AWS Regional Edge Cache: Content für diesen Request ist noch nicht gecached
  4. Stadt B: Routing
  5. Stadt C: Routing
  6. ...
  7. Cupertino (US): Request kommt beim Webhost an, Seite wird gerendert und auf gleichem Weg an uns zurückgeschickt
  8. ...
  9. Frankfurt (DE), AWS Regional Edge Cache: Antwort wird entgegengenommen und in den Cache geschrieben
  10. Zürich (CH), AWS Edge-Standort: Antwort wird entgegengenommen, in den Cache geschrieben und direkt an den Benutzer gestreamed
  11. Basel (CH): Content ist da

Mit CloudFront, weitere Requests:

Jeder weitere Request ist viel kürzer, da der Content bereits im Edge-Standort in Zürich zwischengespeichert ist.

  1. Basel (CH): Wir setzen den Request ab
  2. Zürich (CH), AWS Edge-Standort: Content für diesen Request ist gecached
  3. Basel (CH): Content ist da

Würde nun ein anderer User beispielsweise in Italien die Website aufrufen, würde der Request wie folgt aussehen:

  1. Bari (I): Wir setzen den Request ab
  2. Palermo (I), AWS Edge-Standort: Content für diesen Request ist noch nicht gecached
  3. Frankfurt (DE), AWS Regional Edge Cache: Content für diesen Request ist gecached
  4. Palermo (I), AWS Edge-Standort: Antwort wird entgegengenommen, in den Cache geschrieben und direkt an den Benutzer gestreamed
  5. Bari (I): Content ist da

Hier ist zu sehen, dass der Regional Cache den Content nun gecached hat (aufgrund vorheriger Requests aus z.B. der Schweiz) und diesen direkt zurückgibt. Es ist klar ersichtlich, dass, sobald der Content gecached ist, die Latenz und der gesamte Prozess wesentlich kürzer ist. Mittels einer (oder mehreren) sogenannten Cache Policy kann genau gesteuert werden, welche Informationen Teil des Cache-Keys sind und wie lange die Cachedauer sein soll. So können Inhalte beispielsweise anhand des Session-Cookies gecached werden. AWS hat auch für den ersten Case eine clevere Lösung; Sobald das erste Byte beim Edge-Standort ankommt, wird es direkt als eine Art Stream zum Benutzer weitergeleitet. Dies erlaubt es beispielsweise Livestreams via Edge-Standort anzusehen.

Eine weitere Möglichkeit, welche CloudFront uns bietet, sind sogenannte Failover Origins. So kann zum Beispiel ein Backup S3 Bucket als Failover Origin konfiguriert werden, von dem der Inhalt abgefragt wird, falls der primäre Origin ein Problem hat. Dies funktioniert komplett "behind-the-scence", der Benutzer bekommt davon nichts mit. Sollte dieser Fall auftreten kann das Real-Time-Logging von CloudFront sehr hilfreich sein. Dem Kunden könnte in diesem Fall eine Custom-Error-Page von CloudFront direkt angezeigt werden.

Performance

Nun ein paar Worte zur Performance. Selbstverständlich sollte sich die Performance alleine schon durch den Einsatz eines CDN sowohl für den Kunden als auch für die internen Webhosting-, Backend- und Datenbank-Systeme verbessern. Durch das ständige Caching von Inhalten wird die Last vermindert, was für kleinere Server, Datenbanken usw. spricht. Somit kann direkt Geld gespart werden.

CloudFront bietet zudem sehr detaillierte und professionelle Möglichkeiten an, weiter an der Performance oder der Cache Hit Ratio zu schrauben. Beispielsweise können wir via Origin Shield dafür sorgen, dass Content zentral von einem Regional Edge Cache abgefragt wird. Nehmen wir an, wir rollen via CloudFront ein grosses Update für ein webbasiertes Spiel mit sehr vielen globalen Usern aus. Da die Files neu sind und viele User gleichzeitig das Spiel aufrufen, werden viele Edge Locations angefragt, welche wiederum ihre Regional Edge Caches anfragen. Da die neuen Updates aber noch in keinem Regional Cache verfügbar sind, würden Requests von allen aktuell 13 Regional Caches an die Origin gehen. Mit Origin Shield lassen sich die Regional Edge Caches untereinander verbinden. So geht nur ein Request an den Origin, alle andere Regional Edge Caches bekommen das Ergebnis dann vom zentralen Cache zurück.

AWS CloudFront AWS Shield

CloudFront Functions und Lambda@Edge Functions

CloudFront ist aber nicht nur beschränkt auf eigenes Caching, sondern bietet zusätzlich die Möglichkeit, dynamische Daten durch Ausführen von bestimmten Funktionen zu erhalten. Dieses Konzept nennt sich Edge Computing, welches Raffael uns bereits in seinem TechUp Latenzfrei mit Edge Computing vorgestellt hat.

Bevor wir die beiden Funktionen genau anschauen wollen wir ihre Trigger genauer kennenlernen. Grundsätzlich gibt es im AWS Request Handling Umfeld vier Triggers, worauf Funktionen gebunden werden können:

  • Request: Trigger auf der Anfrage
    • Viewer: Wird bei jeden Request, bevor der CloudFront Cache geprüft wird, ausgeführt
    • Origin: Wird bei jedem Cache-Miss ausgeführt, bevor der Request zur Origin geleitet wird
  • Response: Trigger auf der Antwort
    • Viewer: Wird bei jeder Antwort ausgeführt, nachdem diese von der Origin oder aus dem Cache kommt
    • Origin: Wird bei jedem Cache-Miss ausgeführt, nachdem die Response von der Origin kommt

AWS CloudFront Triggers

Quelle [25.01.2022]

CloudFront Functions

Eine CloudFront Function ist eine Serverless Function, mit der Code bei einem Cloud-Provider ausgeführt werden kann. Diese Funktionen wurden im Mai 2021 veröffentlicht und laufen auf der Edge Location. Wichtig ist hier die Unterscheidung zu Lambda@Edge oder gar normalen Lambda Funktionen zu machen. Eine CloudFront Function ist so nah wie möglich am Benutzer in einer Edge Location und hat eine maximale Ausführungszeit von weniger als eine Millisekunde(!). Da eine CloudFront Function so nah am User läuft, gibt gewisse Einschränkungen. Beispielsweise hat die Funktion keine Network oder Filesystem Access. Ebenfalls wichtig zu erwähnen ist, dass man in einer CloudFront Function keinen Zugriff auf den eigentlichen Request Body hat. Ausserdem sind sie in ihrer Grösse sehr limitiert, im Gegensatz zu Lambda@Edge Functions aber auch günstiger. Technisch gesehen handelt es sich um eine JavaScript Funktion, welche ECMAScript 5.1 compliant ist.

Ihre klassischen Use-Cases sind:

  • Anreichern von HTTP-Headern (Request & Response)
  • URL Rewriting
  • URL Redirecting aufgrund der Sprache des Benutzers
  • JSON Web Tokens (JWT) überprüfen für beispielsweise zeitgesteuerte URLs (ohne IDP Calling)

Da die CloudFront Function direkt in der Edge Location läuft, kann sie nur an den Request Viewer und Response Viewer Trigger gebunden werden.

Lambda@Edge Functions

Eine Lambda@Edge Function dagegen läuft im Gegensatz zu einer CloudFront Function "weiter hinten". Die auf Node.js oder Python basierende Funktion läuft in den Regional Edge Caches und hat eine Maximum Execution Time von 5 Sekunden. Limitierungen wie Network-, Filesystem- oder Request-Body-Access fallen hier weg, ebenso sind die Grössenbeschränkungen flexibler.

Ihre klassischen Use-Cases sind:

  • Erhöhen von Cache-Hit-Ratio durch URL-Normalisierung oder Anpassen der Cache-Headers
  • Dynamic Content Generation: Anpassen / Generieren von custom Content anhand des Requests oder der Response
    • Bildskalierung (je nach Endgerät)
    • Seiten rendern mit sogenannten login-less templates wie z.B. Mustache
    • A/B Testing
  • Security: Authentication & Authorization via z.B.
    • Request Signing zum Origin (Zero-Trust)
    • Token Authentication z.B. via JWT
    • Bot Protection und weitere Security-Features & Headers
  • Umschreiben von URLs (Pretty-URLs), Routing, Matching und custom Load-Balancing bzw. Failover-Logic

Hier ist direkt zu sehen, dass die Lambda@Edge Functions im Vergleich zu den CloudFront Functions mächtiger sind. Sie können im Gegensatz zur CloudFront Function auf alle vier Trigger gebunden werden. Weitere Informationen und Details zu beiden Funktionen sind hier ersichtlich.

Security

CloudFront bietet eine breite Palette an Security Funktionen, auch genannt Security at the edge. So gibt es unterschiedlichste Access-Control Features wie:

  • HTTPS: CloudFront kann die Verwendung von HTTPs erzwingen
  • Privater Content: Die Veröffentlichung von Inhalten, welche nur über "signed URLs" oder mit "signed cookies" aufgerufen werden können, wird direkt at the edge gemacht
  • Zugriffseinschränkungen auf Load Balancer: CloudFront kann definieren, dass LoadBalancer nur via CloudFront aufgerufen werden können, im Fall einer DDoS-Attacke sind die LoadBalancer so besser geschützt
  • AWS WAF: Mittels der AWS Web Application Firewall können weitere "Rules" durchgesetzt werden, worauf CloudFront beispielsweise mit einer custom Error Page reagieren kann
  • Geografische Restriktion: Mittels CloudFront kann eingestellt werden, dass der Content zum Beispiel nur aus der Schweiz aufgerufen werden darf
  • Field-Level Encryption: Sensible Daten können at the edge auf Feld-Ebene verschlüsselt werden (Public / Private Key)
  • AWS Shield: Dieser Dienst ist automatisch aktiviert und schützt vor DDoS und weiteren Attacken (z.B. HTTP Desync Protection) und visualisiert Attacken in einem Dashboard

Ausserdem gibt es noch verschiedene andere Security Features wie Advanced Ciphers, Protocol Enforcement und weitere. So kann beispielsweise das TLS Encrypting mit dem AWS Certificate Manager direkt at the edge sehr nahe beim User gemacht werden. CloudFront ist selbstverständlich mit anderen AWS Diensten wie die oben erwähnte AWS WAF kompatibel, die Dienste lassen sich kombinieren.

Anwendungsfälle

Aus diesen Komponenten, Eigenschaften und Features ergeben sich exemplarisch folgende Use-Cases:

  • Statischen Content schneller bereitstellen: Bilder, StyleSheets, JavaScript-Dateien usw. können via Edge Location viel schneller abgerufen werden als z.B. direkt vom S3 Bucket
  • Video- und Livestreaming: Um Latenz gering zu halten, können ganze Videos oder nur einzelne Fragmente on the edge zwischengespeichert werden
  • Sicherheitsstandard erhöhen durch HTTPS, field-level encyrption und weitere Features, welche CloudFront mit sich bringt
  • Request und Response Handling durch Routing, Failover, Customization usw. ohne dabei den Origin zu belasten
  • Privaten Content veröffentlichen durch spezielle Regeln oder Geo-Filter

Grundsätzlich verfolgt CloudFront das übergeordnete Ziel jedes CDNs: Der Content soll schneller bereitgestellt werden können, die Cache-Hit-Ratio soll maximiert werden und die Origin, der eigentliche Server, soll entlastet werden.

Ausblick

Nun haben wir CloudFront sowie das theoretische Konzept dahinter kennengelernt.

Im nächsten TechUp von mir wollen wir eine komplette CloudFront Applikation mit verschiedenen Komponenten aufsetzen und Hands-On alles kennenlernen. Ziel dieses Deep-Dives soll es sein, praktische Erfahrungen aufzubauen sowie Vor- und Nachteile kennenzulernen. Stay tuned! 🔥

Tom Trapp – Problemlöser, Innovator, Sportler. Am liebsten feilt Tom den ganzen Tag an der moderner Software und legt viel Wert auf objektiv sauberen, leanen Code.