Aaron Fischer Ingenieur, Vater, Heimwerker, Problemlöser

27 July, 2009

Load Balancing für Ruby

Technologie

Web-Anwendungen werden immer anspruchsvoller und komplexer. Sobald der erste Server in die Knie geht, muss man sich Gedanken über Performance und Lastverteilung machen. Gerade bei Anwendungen, die mit Ruby oder Python geschrieben wurden, stößt man häufig schneller an die Grenzen als mit anderen Skriptsprachen wie PHP oder Perl.

Für Ruby gibt es mehrere Ansätze, wie man die Last auf mehrere Server verteilen kann. Ich möchte hier nun eine der vielen Möglichkeit vorstellen. Für dieses Beispiel verwende ich Lighttpd als Webserver, Thin als Dispatcher, Ramaze als Web-Framework und MySQL zur Datenhaltung.

Schema

Fangen wir von vorn an: Wenn ein Request eintritt, wird zuerst entschieden, ob das anzufragende Objekt erst noch generiert werden muss. Wird ein Bild, eine CSS-Datei oder eine andere statische Datei angefragt, kann diese direkt zurückgeliefert werden. Anders sieht es bei Webseiten aus, die zuerst durch Ruby gerendert werden müssen. Hier kommt die Lastverteilung mit ins Spiel. Wir konfigurieren Lighttpd so, dass er die Last auf zwei andere Webserver umleitet. Hier die nötige Konfiguration:

$HTTP["host"] =~ "example\.com" {
        server.document-root = "/var/www/"
        $HTTP["url"] !~ "^/(css|images|js|libs)" {
                proxy.balance = "fair"
                proxy.server = ( "/" => (
                        ("host" => "192.168.0.50", "port" => 7000),
                        ("host" => "192.168.0.51", "port" => 7000)
                ))
        }
}

Thin selbst muss natürlich auf den beiden Hosts 192.168.0.50 und 192.168.0.51 gestartet und konfiguriert werden. Das nimmt uns Ramaze ab, in dem wir in der app.rb (der Startdatei) folgendes hinterlegen:

Ramaze.start(
  :adapter => :thin,
  :port => 7000,
  :file => __FILE__
)

Mit dieser Konfiguration starten wir die Anwendung auf beiden Hosts. Thin kann auch von Hand gestartet werden, der Befehl dazu ist, wer hätte es anders erwartet: thin. Wenn die Performance in die Knie geht, kann man so einfach eine neue Thin-Instanz auf einem separaten Server starten und einbinden.

Natürlich lässt sich jetzt noch die Datenbank auf mehrere Server verteilen. Hier sollte man allerdings darauf achten, dass der Server mit dem Anwendungscode und der Datenbankserver physikalisch im selben LAN bzw. im selben Rechenzentrum untergebracht sind, denn sonst ist zwar die Last verteilt, aber die Performance geht in den Keller, da mehr Zeit zum Übertragen der Datensätze verbraten wird als das eigentliche berechnen.