Skip to content

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. :-D 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

Noch keine Kommentare

Kommentar schreiben