Webserver: Ausliefern zufälliger Inhalte
Auch wenn die Problematik vielleicht selten vorkommen mag, ist das Ausliefern zufälliger Inhalte für eine Webanwendung nicht trivial. So viele Möglichkeiten...
Motivation
Die Seite shipitsquirrel.github.io finde ich klasse. Dort wird einfach ein Eichhorn gezeigt, welches zum Shippen eines Produkts auffordert. Ich wollte etwas ähnliches haben.
Es gibt niemanden, der "Make it so." besser sagen kann, als der Captain des Raumschiffs USS Enterprise NCC-1701-D aus dem Universum von Star Trek. Jeder, der von der Serie Star Trek - The Next Generation noch nie etwas gehört hat, wird jetzt nur noch wtf? denken, aber das ist mir egal. Die Allgemeinbildung ist einfach nicht gleichmäßig verteilt.
Gerne möchte ich beim Aufruf des Systems immer mal ein anderes Bild mit dem Spruch "Make it so" ausliefern lassen. Es soll schließlich nicht gar so schnell langweilig werden.
Die Subdomain makeitso war von mir schnell angelegt und während sich das nun munter unter den DNS-Servern herumgesprochen hatte, stand ich vor der Qual der Wahl.
Möglichkeiten
In welchem Layer meines Setups löse ich das nur?
Varnish-Cache
Varnish kann selbst praktisch keine bei sich liegenden Inhalte ausliefern. In seiner Konfigurationssprache VCL kann man lediglich kurze personalisierte Fehlermeldungsrückgaben zusammenbauen. Damit ein Bild auszuliefern, ist Quark. Mit Umleitungen kann Varnish aber sehr gut umgehen. Ein Round-Robin-Umleiter ist in VCL schnell zusammengesteckt.
sub vcl_recv { if(req.http.host ~ "makeitso.gnuheidix.de"){ error 750 "Make it so"; } } sub vcl_error { if (obj.status == 750) { set obj.status = 302; # true on each odd request id if (req.xid ~ "[13579]$"){ set obj.http.Location = "http://ownsite.de/1.jpg"; }else{ set obj.http.Location = "http://ownsite.de/2.jpg"; } return(deliver); } }
Abhängig von der Anzahl der Bilder wird öfters ein anderes kommen als beim Aufruf zuvor. So ganz prickelnd finde ich die Lösung nicht, weil man tatsächlich weggeleitet wird und man für jede Bildererweiterung an der Varnish-Konfiguration basteln muss. Zur Syntaxprüfung der Konfiguration kann man folgenden Befehl nutzen.
sudo varnishd -C -f /etc/varnish/default.vcl
Die Weiterleitungsziele sollten auch auf eigenen Systemen liegen, damit sich niemand anders gestört fühlt. Zum einen hat nicht jeder ein performantes Setup und zum anderen kostet Traffic Geld. Weiter ist Bandbreite leider für jede Maschine endlich.
Nginx
Es gibt ein sehr schönes Modul, welches genau für den Zweck zu passen vermag. Mithilfe vom HttpRandomIndexModule kann man Inhalte eines Verzeichnisses zufällig ausliefern lassen.
Bei Ubuntu ist das Modul aber nur in den Nginx des Pakets nginx-extras hineinkompiliert, wodurch ich nginx-full ersetzen musste. Das ist nicht schlimm, dachte ich. Nach dem Ersetzen des Pakets kam Nginx nicht mehr hoch. Er meldete, dass Port 80 bereits durch einen anderen Prozess belegt ist. Das ist vollkommen richtig. Varnish gehört dieser Port. Tatsächlich hat der Paketwechsel die Defaultkonfiguration mittels Symlink in /etc/nginx/sites-enabled/ aktiviert. Naja, das Paket hat es gut gemeint, aber es hat mir gezeigt, dass man bei Ubuntu nicht stets die volle Kontrolle hat.
Varnish muss bei diesem Ansatz alles zum Webserver durchleiten ohne an Caching zu denken.
sub vcl_recv { if(req.http.host ~ "makeitso.gnuheidix.de"){ return (pass); } }
Nginx wird auf das Verzeichnis ausgerichtet und browserseitige Cachingmechanismen werden entschärft.
server { listen 127.0.0.1:8081; root /srv/www/makeitso.gnuheidix.de; server_name makeitso.gnuheidix.de; location / { random_index on; if_modified_since off; add_header Last-Modified ""; } }
Funktioniert! Seht Euch makeitso.gnuheidix.de an und ladet ein paar Mal neu. Der Zufall hält sich bei zwei Dateien zwar in Grenzen, aber so muss es aussehen. Die Erweiterbarkeit ist auch sehr gut, weil man keine Konfiguration ändern muss, um neue Bilder aufzunehmen.
PHP
Die im Webservermodul realisierte Funktionalität hätte ich auch in einem PHP-Skript abbrennen können. Es wäre allerdings um Welten langsamer. Auf eine mögliche Beispielimplementierung verzichte ich an dieser Stelle.
Ergebnis
Mein MakeItSo-Generator ist schick umgesetzt und gefällt mir. Alles, was nicht bis in die niedrigste Systemschicht muss, ist eine potenziell erwägenswerte Lösung.
Kommentare