Ruby optimalisaties

Ik las gisteren de presentatie die Joe Damato en Aman Gupta gaven op de Ruby Hoedown conferentie. Ze hadden het over threads (green vs native vs hybrid), toepassing ervan in Ruby, en de problemen + oplossingen hiervan. Verbaasd over de impact dat sommige van hun oplossingen hadden deed ik wat tests met hun patches, en kreeg een verbluffend resultaat. In dit artikel bespreek ik de 2 belangrijkste

Welke Ruby?

Op de pro-003 (“zink”) kozen we voor Ruby Enterprise Edition, gebaseerd op Ruby 1.8.6. Deze bood op dat moment de beste performantie, terwijl het toch nog gebaseerd was op Ruby 1.8.6, de “standaard” Ruby op dat moment. Nu Rails 3.0 er stilaan aankomt, en het ernaar uitziet dat die minstens Ruby 1.8.7 zal nodig hebben, was REE geen optie meer op pro-004. Debian (onze favoriete Linux distributie) heeft wel een standaard Ruby 1.8.7 pakket, dus leek dat een evidente keuze.

To pthread or not to pthread …

Ruby 1.8 maakt geen gebruik van “kernel” threads, maar handelt dat volledig zelf af (zogenaamde Green Threads. Debian compileert Ruby wel met kernel thread ondersteuning (pthreads), omdat een aantal extra pakketten (waaronder ruby-tk, een grafische omgeving voor Ruby) dat nodig hebben. Het probleem is dat dit ook enkele andere zaken activeert in Ruby, die absoluut niet geheugen- en CPU efficiënt zijn.

“Maar ik gebruik helemaal geen Threads in mijn Ruby applicatie” hoor ik u denken. Dat kan, maar de kans is groot dat je die wel gebruikt zonder dat je het weet. Alles waarvoor je Timeouts gebruikt (zoals oa. alles in de HTTP library), gebruik je eigenlijk threads!

De Debian Ruby 1.8.7 hercompileren zonder ondersteuning voor pthreads, geeft op standaard benchmark tests gemakkelijk een 10 tot 20% snelheidswinst. Op sommige tests tot 50% winst en meer.

Alarm!

Aangezien Ruby 1.8.7 geen gebruik maakt van Kernel threads, moet het zelf bepalen wanneer en hoe een thread stilgelegd wordt en een andere thread voorrang krijgt. Het doet dit door om de 10 miliseconden een wekkertje te doen afgaan, dat het lopende proces kort onderbreekt en controleert of er geen andere threads zijn die even kort aandacht willen.

Damato en Gupta hebben ontdekt dat Ruby hier redelijk dom in is. Van zodra je proces 1 keer een nieuwe thread gestart heeft, blijft het die alarmsignalen geven, zelfs als er geen lopende threads meer zijn! De korte onderbreking van dat alarmsignaal zorgt op zich niet voor zo’n grote vertraging, maar ze worden elke 10 miliseconden uitgevoerd, en alles samen maakt dat wel een merkbare en meetbare vertraging.

Eenvoudigweg deze alarmsignalen stoppen als de laatste thread gestopt wordt, brengt een mooie snelheidswinst met zich mee voor processen die af en toe een extra thread gebruiken, maar verder single-threaded zijn.

Welke Ruby op pro-004?

Gezien de aanzienlijke snelheidswinst van deze twee kleine aanpassingen, hebben we beslist deze aanpassingen te gebruiken op pro-004 en enkele private VDS-en van klanten.

Welke Ruby op pro-005, pro-006 enz?

Goede vraag… Ik hoorde van de ontwikkelaars van REE dat zij druk bezig zijn aan een REE versie gebaseerd op Ruby 1.8.7. Waarschijnlijk zullen we dus opnieuw REE gebruiken op pro-005. Ruby 1.9 zou een natte droom zijn, maar ik vrees dat nog lang niet alle modules, plugins en Ruby-applicaties compatibel zullen zijn met Ruby 1.9 tegen dan. Misschien is dit iets voor pro-006 of pro-007?

Geschreven op 03/09/2009

Door Frank Louwers

Tags: debian

Reageer