Basic Apache Performance Tips

Anyone mass-hosting virtual domains on apache knows the problems. Over the time I collected some basic and important performance tips which I want to give back to the community in aggregated form. Sorry, that I don’t remember all sources of information – so I will mention none. Google will help you. Here’s the list: Den Rest des Beitrags lesen »

Advertisements

ActiveRecord look-alike written in PHP using AdoDB

Since I developed with Rails using the ultra-comfortable ActiveRecord I felt the need for a similar solution in PHP. Googling around I found some people saying this is impossible. That’s true: Ruby’s OOP implementation is in many ways superior to PHP’s.

But anyway I decided: Some of ActiveRecords comfort must be possible in PHP. I’ve decided to build on AdoDB for PHP since it already does the heavy lifting of database abstraction very good.

The interface is currently very limited and should be very self explanatory. For all interested hackers I’ve set up a git repository at GitHub and would be very interested on your feedback.

This project grew out of the need to ease up database development in an already existing legacy application. It’s not meant as an exact ActiveRecord replacement in PHP – just similar in convenience.

Just follow this link: http://github.com/kakra/adodbrecord/

Ruby-Scripte mittels FCGI unter Lighttpd ausführen

Im Netz habe ich nach einer längeren Google-Recherche endlich einen universellen FCGI-Wrapper für Ruby-Scripte gefunden. Meistens stößt man nur auf Rails-Lösungen, aber das war einfach Overkill in diesem Fall. Ich wollte einfach nur ein kleines Script, daß Query-Parameter einem Kunden zuordnet und mittels ActiveRecord in eine Tabelle schreibt. Anschließend sollte ein ActionMailer noch eine Mail versenden. Gestoßen bin ich letztenendes auf folgende Seite:

FastCGI Ruby dispatcher:

There was always Ruby on Rails, but I didn’t want an application server, just applications. To that end, I created a very lightweight FastCGI server that executes Ruby scripts referenced by lighttpd directly in a binding context that only imports the CGI object for the request. (Derrick Pallas)

Also genau das, was ich haben wollte. Funktionierte auch auf Anhieb prima. Aber nur der erste Aufruf liefert die Parameter wirklich an mein Script aus. Beim zweiten Aufruf bleibt der Parameter-Hash leer. Das ist der Codeschnippsel bisher:

#!/usr/bin/env ruby

puts cgi.header

require 'yaml'
require 'rubygems'
require 'active_record'
require 'action_mailer'

[...]

ActiveRecord::Base.logger = Logger.new(STDERR)
ActiveRecord::Base.colorize_logging = false

config = YAML.load_file('.../database.yml')
ActiveRecord::Base.establish_connection(config['...'])

params = cgi.params.select { |q,| %w{system keyword udh smstext absender time client}.include? q }
params = Hash[*params.flatten]

[...]

Einige Dinge hab ich jetzt mal bewußt weggelassen und nur das grundsätzliche Gerüst übergelassen. Sobald ich den Bug – falls es einer ist – gelöst habe, erscheint hier nochmal Feedback. Außerdem stellt sich mir noch die Frage, ob der FCGI-Wrapper so in dieser Weise wirklich einen Performance-Gewinn darstellt. Immerhin läd er die FCGI-Klasse im Voraus und hält einmal geöffnete Scripte als MMap-Objekte bereit. Der eigentliche Boot-Vorgang des Scripts (ActiveRecord initialisieren) wird aber jedes Mal ausgeführt. Hier ist Rails dann eben doch spezialisierter.

Veröffentlicht in FastCGI, Lighttpd, Ruby. 1 Comment »

Mehrere Rails-Anwendungen pro VHost auf Lighttpd

Wer es schonmal versucht hat, Ruby on Rails unter Lighttpd zum Laufen zu bekommen, wird wissen, daß dies im Prinzip super einfach ist. Sobald man aber eine Rails-Anwendung in einem Unterverzeichnis der Domain laufen lassen möchte, bekommt man gewaltige Kopfschmerzen. Alle googlebaren Tricks führen entweder dazu, daß man beim Deployment Code ändern muß, böse Hacks in den Routen vornehmen muß oder an Stellen Hack’s einbaut, die nicht nötig sind.

Sogar Lighttpd selbst bringt einen solchen Hack mit, der beim Request das Prefix von der URL entfernt und dem Rails-Dispatcher so vorgauckelt, er würde im Hauptverzeichnis laufen. Dies führt zwar dazu, daß die Routen richtig erkannt werden, dafür muß bei allen Links in den Templates das Prefix manuell ergänzt werden. Kategorie: Buh! *thumbsdown* Die Idee war für mich gestorben.

Der nächste Hack führt eine Variable ein, die je nach Situation im Rails-Quellcode entweder gesetzt oder eben wieder gelöscht wird, um den Routen-Generator und den Routen-Parser zu überlisten. Auf so einen Blödsinn hatte ich keine Lust.

Nach dem Studium des Quellcodes fand ich heraus, daß es eine Variable RAILS_RELATIVE_URL_ROOT gibt, die man im Environment selbst setzen kann und die unter Apache sogar per Autodetect durch Rails selbst gesetzt wird. Weil Lighttpd aber etwas anders funktioniert, ist das dort nicht einsetzbar.

Anders gesprochen: Wenn ich also diese Variable händisch setze, müßte Rails ja damit klar kommen. Ist leider nicht so, Rails weiß überhaupt nichts davon, daß diese Variable gesetzt ist, wenn man den dokumentierten Weg für die Einstellungen des FCGI-Servers geht:

9 fastcgi.server = (
10   ".fcgi" => (
11     "localhost" => (
12       "min-procs" => 1,
13       "max-procs" => 5,
14       "socket" => approot + appname + "/tmp/lighttpd.socket",
15       "bin-path" => "/usr/bin/ruby " + approot + appname + "/public/dispatch.fcgi",
16       "bin-environment" => ( "RAILS_ENV" => "production", "RAILS_RELATIVE_URL_ROOT" => "/" + appname ))))

Dies ist wegen einer schlecht dokumentierten Eigenschaft des FCGI-Protokolls zum Scheitern verurteilt, da der Rails-FCGI-Dispatcher zum Zeitpunkt der Ausführung keinen Zugriff auf diese Variable mehr hat. Der Trick ist, die Variable aus dem „bin-environment“-Array herauszunehmen und mit dem Lighttpd-Modul „mod_setenv“ zu setzen. Der komplette Code-Schnippsel für die Rails-Konfiguration in Lighttpd sieht dann wie folgt aus:

5 server.error-handler-404 = "/" + appname + "/dispatch.fcgi"
6 alias.url = ( "/" + appname => approot + appname + "/public" )
7 index-file.names = ( "index.html", "dispatch.fcgi" )
8 setenv.add-environment = ( "RAILS_RELATIVE_URL_ROOT" => "/" + appname )
9 fastcgi.server = (
10   ".fcgi" => (
11     "localhost" => (
12       "min-procs" => 1,
13       "max-procs" => 5,
14       "socket" => approot + appname + "/tmp/lighttpd.socket",
15       "bin-path" => "/usr/bin/ruby " + approot + appname + "/public/dispatch.fcgi",
16       "bin-environment" => ( "RAILS_ENV" => "production" ))))

Den etwas umständlichen „bin-path“-Aufruf führe ich so aus, damit sich Grsec und PaX im Kernel eines Hardened-Linux nicht über Ausführungsrechte in einem potentiell unsicheren Verzeichnis beschweren. Andere Lighttpd-Rails-Beispiele im Netz starten hier direkt den FCGI-Dispatcher ohne den Interpreter explizit anzugeben. Die Variablen „approot“ und „appname“ sind vorher entsprechend zu besetzen. Auch „server.document-root“ sollte noch richtig gesetzt werden (passiert bei mir in einer seperaten Config-Datei und fehlt hier deshalb).