www.zh.ch ist 50x schneller (und stabiler)

speed_fast_needle_indicator_sticker-p217786337103706993envb3_400

Technologie: Adobe CQ Plattform: Linux Hoster: Aspectra Systemübersicht: Die Website des Kantons Zürich wird von von mehr als 200 Autoren verwaltet, niedergelassen in ganz verschiedenen Zweigsstellen und Ämtern. Der beim CQ mitgelieferte Dispatcher-Cache hat die Eigenart, dass er bei jeder … Weiterlesen

Puppenspiele

3903-puppet.jpg

Ich habe ein neues Spielzeug: Puppet.

Puppet, an automated administrative engine for your *nix systems, performs administrative tasks (such as adding users, installing packages, and updating server configurations) based on a centralized specification.

Wie oft musste ich Server einrichten, Apaches konfigurieren und dergleichen. Nach dem x-ten mal kommt zwar eine gewisse Routine auf. Aber dann ändert etwas; einem Apache muss ein Varnish-Cache vornedran gestellt werden – hmm. Was muss ich jetzt schon wieder alles anpassen? Ports der VirtualHosts, der Listen Port… Ganz gewiss geht was vergessen, und erst nach dem 3. mal Dienste neustarten und ausprobieren funktioniert alles.

Das ist jetzt Vergangenheit.

Introducing: Puppet – ein zentrales Konfigurationsmanagement-Werkzeug.

Ich definiere 1x eine gute Konfiguration; einen gewünschten Endzustand. Und kann das dann auf beliebig viele Server anwenden.

Möchtest Du mal schauen, wie geil wir zukünftig Server konfigurieren?

Hier eine Definition eines Nodes:

3888-config.png

Auf der Kommandozeile gebe ich folgendes ein:

puppetd –test

Und jetzt geht’s ab.
Puppet stellt sicher, dass Apache, PHP und MySQL installiert sind, erstellt die nötigen Webverzeichnisse und setzt das MySQL-Passwort. Das ist natürlich alles definiert, und zwar in Modulen. Mehr dazu in 3 Minuten.

Jetzt möchte ich etwas anpassen. Ich will einen zusätzlichen Vhost-Eintrag, „about.namics.com“. Dann soll das ganze mit Varnish gecached werden.

Neue Konfiguration:

3891-newconfig.png

Puppet erstellt den neuen Vhost-Eintrag, die dazugehörigen Verzeichnisse, passt die Apachekonfiguration für den Varnish an und startet am Schluss alle betroffenen Dienste neu:

3894-vhost-thumb-500x554-3893.png

Kommandozeilenpornografie.

Was genau wie konfiguriert sein muss und wie die Abhängigkeiten sind, wird in Modulen definiert.

Hier das Modul Apache (Teilauszug):

3896-module.png

Das bedeutet: Wenn das Modul in einem Node verwendet wird (include apache), dann muss httpd installiert sein (ensure => installed), der Service httpd muss laufen (ensure => running), braucht aber vorher das Paket httpd (require => Package[„httpd“]) und die httpd.conf wird aus einem Template erstellt. Wenn sich dort was ändert, wird der Dienst httpd neu gestartet (notify => Service[„httpd“]).

Ah, Templates.

Puppet ist in Ruby geschrieben und verwendet als Template-Sprache erb. Hier ein Auszug aus dem httpd.conf Template:

3897-template.png

Heisst:

Für jeden Vhosts bitte einen VirtualHost-Eintrag erstellen. Falls Varnish benutzt wird, auf Port 8080 lauschen, sonst auf Port 80.
Der Rest ist selbsterklärend.

Prima einsetzen kann man Puppet auch als Sicherheitsgarantiersicherstellungsprogramm. Also. Ich habe eine Typo3-Installation. Böse Spammer aus China suchen nach Schwachstellen.

Ich definiere, was wie abgesichert werden muss:

3898-secconfig.png

ENABLE_INSTALL_TOOL darf nicht vorhanden sein. Die localconf.php darf nicht schreibbar sein. Das gesamte Verzeichnis (recurse => true) unter /typo3conf/ext ebensowenig.

Wenn irgendwas faul ist, merkt das Puppet und korrigiert die Abweichungen gleich:

3900-sec-thumb-500x203-3899.png

Das wunderbare daran: Ich kann diese Module für jeden Server verwenden. Ein neues Verzeichnis muss abgesichert werden? Kein Problem. 1x definieren, auf allen Servern aktiviert.

Voll Laser!

3902-laserfido.gif

Varnish-Cache – einer für alle

Kunde möchte eine voraussichtlich stark frequentierte Seite mit Typo3 bei sich hosten. 
Erwartet werden 5000 Benutzer gleichzeitig – die geschätzt alle 10 Sekunden klicken. Ergibt 500 Requests/s. Wir sollen die Architektur vorschlagen.

Mein Metier. Nach einer zweiwöchigen Evaluation kristallisierte sich Nginx mit FastCGI als Webserver heraus, weil der FastCGI Anfragen cachen kann und somit auf eine tolle Geschwindigkeit kommt.

Das Problem ist nicht der Cache an sich. Das Problem ist, wie Nginx damit umgeht, wenn der Cache verfällt.

Der Cache hat ein Ablaufdatum, eine Time-To-Live, TTL. Läuft diese ab, muss das HTML vom Backend neu geholt werden. Und wenn der Cache bei 500 gleichzeitigen Anfragen pro Sekunde abläuft, muss das HTML 500 mal gleichzeitig vom Backend geholt werden. Schönä!

2842-face down.png

Ich habe verschiedene Reverse-Proxies ausprobiert. Unter anderem den Varnish-Cache. Und der hat eine Besonderheit, die ich sonst bei keinem Cache finde:

When several clients are requesting the same page Varnish will send one request to the backend and place the others on hold while fetching one copy from the back end. (Source)

2844-face up-thumb-500x264-2843.png

Ich beglücke den Webserver mit 5000 Benutzern. Gleichzeitig.

5000 Benutzer prasseln auf den Server. Nach einer Minute wird _eine_ Anfrage an den Webserver geschickt – die 5000 Benutzer werden weiterhin mit dem „alten“ Inhalt bedient.
Die Antwort kommt, der Cache wird erneuert und von jetzt an wird der neue Inhalt an die 5000 Benutzer ausgeliefert.

So sieht die Aktivität auf dem Server aus:

2845-varnish_protects.png

Genau ein httpd ist am schwitzen, und nicht fünfzig. Und der varnishd tobt sich aus…

So sieht meine Netzwerkauslastung aus:

2846-bw.png

I can haz more bandwidth?

Zwei Proxysniffer im Verbund auf Vollgas. Schampar schade dass unser Netzwerk nicht mehr als 800MBit hergeben will:

2848-AnalyseLoadtestResultTotalNetworkImageWeblet-thumb-500x255-2847.gif

Ça fait rock.

Und der Varnish lässt sich unendlich flexibel konfigurieren. Ich kann z.B. anhand der URL Anfragen auf unterschiedliche Backends leiten, mehrere Backends mit einer gewichteten Lastverteilung aufstellen und und und…

Ein Beispiel.

backend crappy_j2ee_enterprise_grüselapp {
    .host = "server.example.com";
    .first_byte_timeout = 5s;
    .max_connections = 10;
    .probe = {
        .url = "/check.jsp";
        .interval = 5s;
        .timeout = 1s;
        .window = 5;
        .threshold = 3;
    }
}

Das Backend wird alle 5 Sekunden vom Varnish angefragt (interval). Von 5 Anfragen (window) müssen 3 korrekt sein (threshold) und unter 1s antworten (timeout).

Ist dies nicht der Fall, bekommt das Backend den Status „unhealthy“ verpasst. Jetzt liegt es an der Konfiguration, was jetzt passiert.

if (! req.backend.healthy) {
    set req.grace = 30d;
} else {
    set req.grace = 1m; 
}

Ist das Backend nicht verfügbar, wird es für 30 Tage nicht mehr angefragt bei einem User-Request, auch wenn die TTL für die Seite abgelaufen ist. Der Health-Check läuft normal weiter.

#renew content every minute
set beresp.ttl = 1m;

#save content for 30 days - if backend fails
set beresp.grace = 30d;

Nach einer Minute wird der Webserver nach neuen Inhalten abgefragt. Die Antwort wird 30 Tage lang gespeichert – sollte der Webserver abliegen, kann die Website noch 30 Tage lang von dieser Notration überleben.

Und das ist toll – ich kann meine Apache’s stoppen. Ein paar Benutzer haben Pech – in den maximal 5 Sekunden, bis Varnish das merkt und das Backend als ungesund deklariert. Aber dann läuft alles wie gewohnt weiter. Sobald die Webserver wieder da sind, werden die Cache-Inhalte erneuert.

Voraussetzung für den ganzen Gspass ist natürlich eine statische Seite ohne personalisierte Inhalte.

Man könnte es noch auf die Spitze treiben mit dem Caching und für verschiedene Inhalte eigene TTLs definieren:

2849-esi.png

Did you know? Wikileaks setzt auch auf Varnish:

2850-varnishleaks.png

Ich weiss nicht wie viel Traffic Varnish wirklich verarbeiten kann. Aber ganz offensichtlich mehr als 10 Gigabit:

2852-Bildschirmfoto 2010-12-17 um 10.58.07-thumb-500x185-2851.png

http://twitter.com/wikileaks/status/9609091915718656

http://www.varnish-cache.org/

Javascript meets Blinkenlights

Kleines Projekt, entstanden an ein paar verregneten Nachmittagen:

Blinkentube – das ist Blinkenlights im Browser!

Blinkenlights erblickte 2001 die Lichter der Welt. Ein Hochhaus mit 8 Stockwerken und 18 Fensterreihen – platziert man hinter jedes Fenster einen Scheinwerfer, ergibt das ein Display mit 18×8 Pixeln.
Jeder konnte mit Blinkenpaint seine eigenen Blinkenlights-Movies erstellen und auf dem Gebäude abspielen lassen.

Es gab zahlreiche Folgeprojekte und Nachbauten. Blinkenlights mit LEDs, Simulatoren, räumliche Blinkenlights, Wände, Uhren, C64 Lights und viele mehr.
Ein Nachbau fehlte mir aber auf dieser Liste: Blinkenlights im Browser.

Ich habe mit Blinkenpaint herumgespielt, und es fiel mir auf, dass die CPU-Auslastung konstant auf 100% war. Und die Animationen spielten sich eher etwas langsamer ab. Auch das Laden eines Blinkenmovies (eine XML-Datei) kann schon mal 2 Sekunden dauern…
Ich habe mich gefragt: Ist es wirklich so rechenaufwändig, ein paar Lichter an- und auszuschalten? Geht das auch in meinem Browser?

Und ob!
Nach einem Abend habe ich die Lichter (ok, „1“ und „0“ in einer HTML-Tabelle) zufallsmässig an- und ausgeschaltet. Läuft prima.
Hmm… Ich muss ja das Rad nicht neu erfinden. Warum nicht gleich Blinkenmovies laden und abspielen? Ob das Parsen von 3000 Zeilen XML wohl genug schnell geht?

Und ob!
Am nächsten Abend spielt ein Blinkenmovie in meinem Browser. Das Parsen geht *zagg* *bumm* – sofort da. Wonderful.

Aber die HTML-Tabelle ist hässlich. Wenn schon, dann jetzt mit den Originalbildern der leuchtenden Fenster.

Tabellenlos. Und es läuft immer noch tipptopp in Echtzeit und ohne gröbere CPU-Belastung…
Und – das hat mir dann die Schuhe ausgezogen – selbst im IE6! :p

Und als kleines Goodie vom verregneten Samstagnachmittag: Man kann seine eigenen mit Blinkenpaint erstellten Movies hochladen.

Blinkenpaint: http://blinkenlights.net/blinkenlights/blinkenpaint

Namics Blinkenmovie: http://scratchbook.ch/blinkentube/#namics

Filme, die ich im Netz gefunden habe:
http://scratchbook.ch/blinkentube/#changing-figures
http://scratchbook.ch/blinkentube/#ampel
http://scratchbook.ch/blinkentube/#the-game
http://scratchbook.ch/blinkentube/#bit-laden
http://scratchbook.ch/blinkentube/#column-shooting
http://scratchbook.ch/blinkentube/#le-chat-noir
http://scratchbook.ch/blinkentube/#der-wasserhahn
http://scratchbook.ch/blinkentube/#james-blond
http://scratchbook.ch/blinkentube/#labyrinth
http://scratchbook.ch/blinkentube/#tetris
http://scratchbook.ch/blinkentube/#the-fly
http://scratchbook.ch/blinkentube/#thunderstorm
http://scratchbook.ch/blinkentube/#winter-in-the-city
http://scratchbook.ch/blinkentube/#worm
http://scratchbook.ch/blinkentube/#x-ball

Kartenspiele

Wir haben schon ein paar Mapping-Projekte realisiert. Zeit, einen Blick unter die Haube zu werfen.

Anforderungen:

Alle Geschäftsstellen einer Bank sollen wahlweise mit oder ohne Bankomaten auf einer Karte dargestellt werden.
Wenn man auf einen Marker klickt, öffnet sich eine Sprechblase mit Infos wie Öffnungszeiten, Adresse etc.

Das Ganze soll in eine Lotus Notes Anwendung eingewoben werden, und somit steht auch fest, wo die Koordinaten gespeichert werden: In der dokumentorientierten Datenbank von Notes.

*Am Anfang war der Marker*

Google stellt eine Mapping-API zur Verfügung, um Karten in die eigene Homepage einzubinden und mit allerhand tollen Sachen auszuschmücken.
Was wir brauchen, sind Marker.

1657-Bildschirmfoto 2010-04-16 um 15.59.31.png
1658-Bildschirmfoto 2010-04-16 um 15.49.40.png

Viele Marker. Die Bank besitzt fast 1500 Geschäftsstellen mit über 5500 Bankomaten – die wollen alle dargestellt werden!

Spätestens bei 200 Markern ist im IE 6 dann aber Feierabend – jeder Marker ist ein DOM-Element mit einem Event drauf. Und viele Events = langsam.

Wir müssen die Anzahl der gleichzeitig dargestellten Marker einschränken.
Aber wie? Local.ch stellt tausende Marker gleichzeitig dar und jeder einzelne von denen ist klickbar!

1659-Bildschirmfoto 2010-04-16 um 15.43.28.png

Magie? Nicht ganz, sondern ein schlauer Trick. Später dazu mehr.

*Nur Marker aus der Umgebung*

Wir entscheiden uns, Marker auf der niedrigen Zoomstufe zu einem Gruppenmarker zusammenzufassen.

1661-Bildschirmfoto 2010-04-22 um 10.05.51-thumb-500x342-1660.png

Sobald man näher heranzoomt, werden alle Marker aus der Umgebung geladen und dargestellt.

Marker aus der Umgebung laden – bei einer SQL Datenbank mit „SELECT WHERE distance < mittelpunkt“ (vereinfacht gesagt) nicht so aufwändig.
Aber wie sieht’s aus bei einer dokumentorientierten Datenbank wie Lotus Notes, wo man solche Abfragen nicht machen kann?

Alex hat ein ausgeklügeltes Backend gebaut. Wir unterteilen die ganze Schweiz in Kacheln und speichern alle Marker, die sich in einer Kachel befinden. Die Kacheln sind eine vorberechnete Notes-View, indiziert mit Start- und Endkoordinaten. Anhand der übergebenen Koordinaten findet Notes heraus, welche Kachel(n) es laden muss und liefert die dazugehörigen Marker zurück.

1664-Bildschirmfoto 2010-04-22 um 10.09.19-thumb-500x432-1663.png
1667-Bildschirmfoto 2010-04-22 um 10.09.00-thumb-500x412-1666.png

*JSON ist toll*

Wir haben eine JSON-Datenstruktur definiert, wie das Backend die Marker zurückliefern soll.

Es gibt „locations“ mit „bancomats“, welche je eine Positionsangabe haben und im Attribut „data“ mit beliebigen Zusatzinformationen angereichert werden können.

1670-Bildschirmfoto 2010-04-16 um 14.10.27-thumb-500x224-1669.png

Das schöne daran ist: Ich kann diese Datenstruktur holen und in Javascript gleich so verwenden – und zwar für die Generierung der Marker auf der Karte, wie auch für die Darstellung des Menüs links. Beide greifen auf die gleichen Daten zurück, und somit kennen sich die Titel und die Marker.

Ganz zu schweigen vom Fakt, dass JSON ein kompaktes Klartextformat ist, und ich alle tollen Features nutzen kann, die mir Klartext bietet: Ich kann es komprimieren, zwischenspeichern, maschinell verarbeiten und auf anderen Systemen weiterverwenden. #wooha
Mir gefällts.

*Magie auf mehreren Ebenen*

Zurück zur magischen Karte bei Local.ch.

Viele Marker. Richtig viele. Und es läuft difig, selbst im IE6. Wie machen die das?

Ich weiss wie! :-)

Es werden transparente Bilder mit den Markern (in Echtzeit?) berechnet und auf die gesamte Karte als Layer drübergelegt.

1673-Bildschirmfoto 2010-04-16 um 15.43.13-thumb-500x31-1672.png
1675-Bildschirmfoto 2010-04-16 um 15.43.20.png

Man kann so praktisch unbegrenzt viele Marker in vielen Layern darstellen. Und mit Javascript kann man mit nur einem Event, der auf der Karte lauscht, herausfinden, wo der Benutzer auf der Karte geklickt hat und so tun, als hätte er auf einen Marker geklickt.

Und ich find’s enorm praktisch, dass die Erde eine Scheibe ist, denn so muss man nicht ständig Koordinaten mit komplizierten Formeln auf Pixel umrechnen.