Rewriting Favcharts – Part 1

Um in Form zu bleiben, widme ich möglichst jeden Tag 30-90 Minuten Nebenprojekten.

Diese Woche baue ich die favcharts neu. Die momentante Implementation der favcharts ist ein Haufen von “Hacks upon hacks”, weil die Charts aus einem Satz hastig programmierter Scripte und viel Zeitdruck entstanden sind. Es funktioniert irgendwie, aber so richtig super ist es nicht. Ein Rewrite ist schon seit einiger Zeit überfällig, jetzt ist es soweit.

Kurz zu den aktuellen favcharts: Der Code ist in PHP geschrieben, die Daten liegen in MySQL, klassischer LAMP-Stack also. Ein Crawler durchforstet regelmäßig die Favorites aller bekannten Nutzer und packt diese Daten in die Datenbank. Das Webfrontend liest aus der DB, macht Auswertungen, und speichert die Resultate dann zwischen, je nach Ansicht (täglich, monatlich, User-spezifisch, etc.) für ein paar Stunden bis mehrere Monate. Beim nächsten Zugriff wird dann nur der Cache gelesen, die Datenbank muss also nicht nochmal ran.

Soweit die Theorie. In der Praxis treten jedoch gehäuft Probleme auf: Viele Requests treffen den Cache gar nicht, weil z.B. jeder seine eigenen Charts abruft, und der User Cache dann irgendwann voll läuft und verdrängt wird. Oder es kommen Suchmaschinencrawler und fragen uralte Charts ab. Außerdem bieten die favcharts relativ viele Ansichten (verschiedene Zeiträume, verschiedene Gewichtungen, etc.), so dass die Anzahl der Cache-Einträge schnell hoch wird. Die Requests, die nicht vom Cache abgehandelt werden können, tun dann richtig weh: Je nach Scoring-Methode muss über riesige Datenmengen berechnet werden. Das kostet Zeit und I/O. Für die gewichtete Bewertung muss sogar das ganze Resultset zweimal durchlaufen werden. Dank mod_php wird dann für geraume Zeit ein Apache-Prozess blockiert und schluckt mehr und mehr Speicher und CPU, und der Rest der Apaches wird dadurch auch nicht schneller. In Stoßzeiten brauchen Requests so manchmal über zehn Sekunden. Der Crawlingprozess funktioniert dafür hervorragend – neue Favs sind oft schon nach wenigen Minuten erfasst. Das Datenbankzugriffsmuster ist allerdings eher ungesund: Gleichzeitig finden viele Writes (von den Crawlern) und viele lange Reads (vom Webfrontend) statt. Das führt zu Congestion, schlechten Indexen, und generell sehr unpraktischen Zugriffsmustern.

All das soll mit dem Rewrite besser werden. In den folgenden Posts beschreibe ich den Prozess des Rewrites, und mit welchen Ansätzen diese Probleme gelöst und in Zukunft verhindert werden sollen.

Und weil ich schon lange nichts mehr mit Ruby gemacht habe, und Rails nach wie vor “in” ist, wird die neue Version auf Ruby on Rails gebaut. Yee-haw.