Ruby 1.9.3 ahoi! Goodbye Spork!

Letzte Woche wurde Ruby 1.9.3 released. Es handelt sich dabei zwar nur um ein Minor-Release, trotzdem enthält es zwei Neuerungen, die für unser Entwicklungsteam interessant sind.

Loading performance

Viele haben die längeren Ladezeiten von Ruby 1.9.2 im Vergleich zu Ruby 1.8 bemängelt. Bereits im Mai hat Xavier Shay einen Patch für Ruby 1.9.2 veröffentlicht, der Rubys Class-Loader um 30-40% beschleunigt. Ruby 1.9.3 lässt uns jetzt auch ohne manuelles patchen von Xaviers Arbeit profitieren.

Garbage Collector

Das neue Release erlaubt, wie schon die Ruby Enterprise Edition (REE) zuvor, einen direkten Einfluss auf den Garbage Collector. Die Einflussnahme auf das Verhalten des Garbage Collectors hat natürlich für den Betrieb einer Anwendung große Relevanz. Läuft die Garbage Collection zu oft, hat das negativen Einfluss auf die Geschwindigkeit der Anwendung. Läuft sie zu selten, wird der Speicherverbrauch der Anwendung negativ beeinflußt. GC-Messungen und -Tuning im Rahmen des Betriebs einer Anwendung sollen hier allerdings nicht unser Thema sein.

Die Standard-Konfiguration des Garbage Collectors in Ruby 1.9 ist ziemlich konservativ. Dies hat zur Folge, dass der Garbage Collector schon während des Starts des Rails Frameworks mehrfach läuft und somit den Start von Rails unnötig verlängert.

Die Tests liefen mit den GC-Settings, die Twitter in der Produktion genutzt hat:

RUBY_HEAP_MIN_SLOTS=500000
RUBY_HEAP_SLOTS_INCREMENT=250000
RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
RUBY_GC_MALLOC_LIMIT=50000000

Konsequenzen für TDD

Sowohl die konservativen GC-Settings, als auch der nicht optimierte Class-Loader haben uns zu Zeiten von Ruby 1.9.2 nach Möglichkeiten suchen lassen, unsere Test-Runs zu beschleunigen. Denn genau während des Testens wird Rails ständig neu gestartet.

Eine Möglichkeit die Tests zu beschleunigen ist Spork. Spork ist ein Daemon, der die Rails-Applikation startet und im Speicher hält. Vor jedem Testdurchlauf lädt Spork dann nur die applikationspezifischen Dateien neu und führt die Tests aus. So konnten wir die Laufzeit eines kompletten Tests auf die Hälfte reduzieren. Der Vorteil ist bei Tests von einzelnen Models noch erheblicher, da das Laden der Anwendung im Vergleich zum einzelnen Test noch stärker ins Gewicht fällt.

Was sich hier so einfach anhört erfordert in der Praxis viel Feintuning. So muss sichergestellt werden, dass zu Beginn jedes Testlaufs alle Veränderungen an den Framework-Objekten rückgängig gemacht werden. Wäre das nicht der Fall, wären die Testläufe nicht mehr unabhängig und vorangegangene Tests hätten Einfluss auf den aktuellen Lauf. Das führt zu zusätzlicher Komplexität, wie sich sicher nachvollziehen lässt.

Quo vadis Spork?

Die spannende Frage ist also: Ist Ruby 1.9.3 mit optimierten GC-Settings schnell genug, um auf Spork verzichten zu können?

Dazu ein Vergleich verschiedener Testläufe unter Ruby 1.9.2 mit Spork und Ruby 1.9.3 ohne Spork:

Command Ruby 1.9.2 mit Spork Ruby 1.9.3 ohne Spork  
rspec spec/requests/x1_spec.rb 5,3 s 11,0 s 1 Example
rspec spec/models/user_spec.rb 14,7 s 20,9 s 12 Examples
rspec spec/requests 50,1 s 36,6 s 60 Examples (inklusive Selenium-Tests)
rspec spec/ 117,2 s 100,2 s Komplette Test-Suite

Wie man sieht, ist Spork nur bei ganz kurzen Tests im Vorteil. Bei allen anderen Tests schneidet Ruby 1.9.3 besser ab – und das ohne die zusätzliche Komplexität.

Es sieht also so aus, als seien die Zeiten von Spork in unseren Projekten gezählt. Ruby 1.9.3 ahoi! Die ersten Projekte sind bereits umgestellt.


Zur Blog-Übersicht