proftpd + mod_sql: solving "slow login" problem
Geschrieben von Harald Lapp in Allgemeines um 13:35
I had a very annoying problem with proftpd, which seems a common one at first sight: slow login and the problem, that a lot of ftp clients out there have a low timeout setting configured. The problem is that googling "slow connection" or "slow login" in combination with "proftpd" led me in a totally wrong direction. A lot of people seem to have a problem with DNS lookups, which can be easily fixed by adding ...
UseReverseDNS off
IdentLookups off
... to the configuration file, to turn of any DNS lookups. But this did not change anything for me. Running a ftp client in debug mode it turned out, that the authorization itself took a very long time, which led to a timeout with most ftp clients:
air:~ harald$ ftp -d ftp.xxxxxxxxxx.de
Connected to ftp.xxxxxxxxxx.de.
220 xxxxxxxxxx FTP Server
ftp_login: user `' pass `' host `ftp.xxxxxxxxxx.de'
Name (ftp.xxxxxxxxxx.de:harald):
---> USER harald
331 Password required for harald
Password:
---> PASS XXXX
...
The password was send, and than the ftp client had to wait 10 seconds and longer for a respone. Lot's of ftp clients have a timeout of less than 10 seconds, which results in a timed out connection for such a long response time.
After googling for quite some time without finding anything useful on this topic -- besides the DNS lookup problem -- i delved deeper into to the proftpd documentation and found a howto which gave me some hints of how to speed up ftp login.
As it turned out the problem was my SQLAuthenticate directive, which i just copied from the example configuration file of mod_sql. The configuration was set to:
SQLAuthenticate users userset
The problem with this configuration is, that the userset switch seems to be very, very expensive. I still don't know, why this switch is set in the configuration -- the documentation contains no useful examples of when to use / when to avoid this switch, but eventually i found a forum post of a proftpd maintainer, where he tells, that the userset switch is not necessary to be configured. After changing above configuration to ...
SQLAuthenticate users
... login is fast as hell. I'm still curious why the switch was there ...
Setting up Master-Slave replication using xtrabackup
Geschrieben von Harald Lapp in Datenbanken um 10:03
In a previous blog entry i described a method of how to setup master-slave replication with mysql. In steps #4 and #5 i used mysqldump and mysql-client for creating a database dump on the master and importing it on the slave. The problem with this approach is, that the database tables are locked, as long as the dump is running. For small databases this might not be a problem, but as data grows, the time to create a dump takes longer and longer. @work we apparently reached some critical level -- mysqldump ran hours and hours and would probably still run, if i had not stopped it already.
Luckily there are more suitable tools for large databases available. Innodb hot backup and xtrabackup. I've decided to go with xtrabackup, because it's open-source, free and actively developed. Innodb hot backup is closed-source and not for free
.
The following steps are ment to replace steps #4 and #5 of my previous blog post.
1. building xtrabackup
For Linux i had to build xtrabackup from the source package, because there was no binary package available for my architecture -- it's very easy, though:
harald@master:~/xtrabackup-0.9.5rc$ automake -a -c
...
harald@master:~/xtrabackup-0.9.5rc$ ./configure
...
harald@master:~/xtrabackup-0.9.5rc$ make
...
harald@master:~/xtrabackup-0.9.5rc$ cd innobase/xtrabackup
harald@master:~/xtrabackup-0.9.5rc/innobase/xtrabackup$ make
...
harald@master:~/xtrabackup-0.9.5rc/innobase/xtrabackup$ sudo cp \
innobackupex-1.5.1 /usr/local/bin
harald@master:~/xtrabackup-0.9.5rc/innobase/xtrabackup$ sudo cp \
xtrabackup /usr/local/bin
Needless to say, that xtrabackup needs to be deployed on every database server.
2. creating a database dump
After successfully building and installing xtrabackup, taking a database dump is very easy:
root@master:~# innobackupex-1.5.1 --user=... --password=... \
--defaults-file=... --databases="..." .
The command innobackupex-1.5.1 takes the following parameters:
- --user
- username to use for database connection
- --password
- password to use for database connection
- --defaults-file this parameter is required, if the my.cnf configuration file is not located at /etc/my.cnf
- --dabases
- space-separated list of databases to backup
- .
- destination directory to save dump to
Dumping the database with xtrabackup is incredible fast compared to mysqldump. With xtrabackup it's just a matter of minutes:
real 4m15.614s
user 0m11.710s
sys 0m14.960s
If xtrabackup was successful, it should have created a subdirectory which name is the current date/time, with all required files in it. The directory can now be copied to the slave:
root@master:~# scp -r 2010-03-02_15-02-24 root@xx.xx.xx.xx:~
3. Setting up the slave
The first thing to do on the slave is applying the binary log files to the database dump:
root@dbslave1:~# innobackupex-1.5.1 --apply-log 2010-03-02_15-02-24
...
100302 14:29:56 innobackupex: innobackup completed OK!
Innobackupex will show the message above, if everything was OK. Next task is to copy the database dump to it's new location on the slave. innobackupex is doing everything for you:
root@dbslave1:~# innobackupex-1.5.1 --copy-back 2010-03-02_15-02-24
...
100302 14:29:56 innobackupex: innobackup completed OK!
xtrabackup should now have copied the dump to the mysql data directory. It's a good idea to check the user and owner of the copied files and adjust them, when needed.
Last step is to start the replication. All information required to do so ist stored in the file xtrabackup_binlog_info:
root@dbslave1:~# cat 2010-03-02_15-02-24/xtrabackup_binlog_info
mysql-bin.000331 54249842
With this information available the replication can be set up as described in step #6 of my previous blog post.
New xserve arrived ...
Geschrieben von Harald Lapp in clipdealer.de um 15:47
Last year we purchased our first xserve. Yesterday our second one arrived at our office. Today "he's" standing on my desk. Tomorrow, when we moved him to our data center, he will help encoding videos ...
MySQL master / slave replication
Geschrieben von Harald Lapp in Datenbanken um 09:35
There are tons of tutorials about setting up master / slave replication for MySQL. Here are my own quick notes:
1. Master: /etc/mysql/my.cnf
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 1
max_binlog_size = 100M
2. Slave: /etc/mysql/my.cnf
[mysqld]
server-id = 2
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 10
max_binlog_size = 100M
3. Master: granting privileges for slave user on database master
GRANT REPLICATION SLAVE ON .
TO '<slave_username>'@'<slave_ip>'
IDENTIFIED BY '<slave_password>';
4. Master: creating database dump
Start mysql console as database root and enter the following command:
FLUSH TABLES WITH READ LOCK;
DON'T shut down the mysql client, otherwise the table lock is lost. Open a second shell to the database master and enter the following command on commandline:
mysqldump -u root -p... --databases ... --opt > masterdump.sql
Next, switch back to your mysql console and enter the following command:
SHOW MASTER STATUS;
The output will look something like:
mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000004 | 40140874 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
mysql>
Write down "File" and "Position" ... you will need it later for starting replication.
Now you can unlock the tables:
UNLOCK TABLES;
5. Slave: import database dump
Copy masterdump.sql to the slave server and import the database:
mysql -u root -p... < masterdump.sql
This may take quite some time ...
6. Slave: start replication
Start mysql client on slave and enter the following commands:
CHANGE MASTER TO
MASTER_HOST='<master_host>',
MASTER_USER='<slave_username>',
MASTER_PASSWORD='<slave_password>',
MASTER_LOG_FILE='<mysql-bin file name you've written down in step 4>',
MASTER_LOG_POS=<master position you've written down in step 4>;
START SLAVE;
long time -- no update
Geschrieben von Harald Lapp in Allgemeines um 09:27
I'm currently preparing to switch my blog software -- again. After using wordpress and serendipity for quite some time, i came to the conclusion, that i will only be satisfied with my own blog software. Therefore i'm currently developing something based on the php5 framework i developed for work. I also decided to switch language ... now i can practice my english and increase the audience of people, who won't be interested of what i am writing
.
cookie based redirect mit nginx
Geschrieben von Harald Lapp in LightTPD, nginx um 15:46
Vor einiger Zeit habe ich einen Tip beschrieben, wie man einen cookie-based redirect mit dem LightTPD konfigurieren kann. Das Problem an der Sache ist für mich, dass das für diesen Zweck verwendete Modul mod_proxy von LightTPD in dem von mir eingesetzen Entwicklungszweig (1.4.x) nicht SSL kompatibel ist und dementsprechend HTTPS Verbindungen fehlschlagen.
Seit einiger Zeit schon habe ich den Web- und (Reverse-) Proxy-Server nginx im Auge. Auch mit diesem Server ist es möglich einen Redirect einzurichten, so wie ich ihn brauche. Und: nginx unterstützt an dieser Stelle SSL!
server {
listen 80;
server_name *.devcenter.int;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
if ($http_cookie ~ "(; )?devredirect=harald") {
proxy_pass http://10.0.0.20;
break;
}
if ($http_cookie ~ "(; )?devredirect=markus") {
proxy_pass http://10.0.0.22;
break;
}
...
}
}
server {
listen 443;
server_name ....devcenter.int;
ssl on;
ssl_certificate /etc/nginx/....crt;
ssl_certificate_key /etc/nginx/....key;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
if ($http_cookie ~ "(; )?devredirect=harald") {
proxy_pass https://10.0.0.20;
break;
}
if ($http_cookie ~ "(; )?devredirect=markus") {
proxy_pass https://10.0.0.22;
break;
}
...
}
}
Hitzeprobleme beim iMac
Geschrieben von Harald Lapp in Mac OS X um 01:33
Die iMacs leiden offenbar unter Hitzeproblemen. Bei mir machte sich das seit ein paar Wochen bemerkbar, als mein weisser 24" iMac (von 2006) anfing nach längerem Arbeiten Grafikfehler zu produzieren. Angefangen hat es mit horizontalen Linien über den Bildschirm, zum schluss waren es Verzerrungen, merkwürdige Ränder an den Programmfenstern, verschwundene Dock-Icons und Pixel-Müll auf dem Bildschirm. Im Apfeltalk Forum gab man mir den Rat den Apple Hardware Test, der sich auf der ersten Installations DVD des iMacs befindet, zu benutzen, um Hardwarefehler auszuschliessen, da ähnliche Symptome offenbar auch bei Leuten auftraten, deren iMac-Grafikkarten defekte VRams aufwiesen.
Der Apple Hardware Test verlief glücklicherweise fehlerfrei. Ich hatte auch schon eine Vermutung, dass es möglicherweise ein Hitzeproblem sein könnte: der iMac ist superleise, einen Lüfter hört man praktisch nicht, da die Drehzahl von Haus aus sehr gering eingestellt ist. Ich habe mir also das Programm Temperaturmonitor besorgt und sah hier meinen Verdacht als durchaus begründet, da der Netzteilsensor über 80° gemessen hat und die Grafikkartensensoren zwischen 50° und über 60° anzeigten.
Beim Googeln entdeckte ich einen Artikel in einem Blog, der meinen Verdacht dann bestätigte: die Temperaturen sind viel zu hoch. In diesem Artikel wird das Programm smcFanControl erwähnt, das ich mir sogleich installiert habe. Über diese Software lassen sich die Drehzahlen dreier Lüfter im iMac einstellen. Ich habe mir im smcFanControl nun ein Profil angelegt, mit dem ich die Lüfter auf maximale Drehzahl laufen lassen kann. Damit konnte ich die Temperaturen laut Sensoren um 20° bis 30° absenken und siehe da -- keine Grafikfehler mehr.
Ich bin erleichtert, dass es offenbar "nur" ein Hitzeproblem ist und kein Hardware-Defekt. Mit verschiedenen Profilen im smcFanControl kann man sich optimale Lüfterdrehzahlen zusammenstellen. Ich habe festgestellt, dass die Grafikfehler bei mir bei den Werten "Grafikprozessor Kühlblech 1 > 40° und Grafikprozessor Temperaturdiode > 55°" (etwa) auftauchten. Deshalb habe ich nun ein Profil, welches die Werte konstant darunter hält. Das funktioniert eigentlich ganz gut. Ich bin noch nicht sicher, ob das ein Dauerzustand sein kann -- die Lüfterdrehzahlen sind zwar immernoch so niedrig, dass die Geräuschentwicklung nicht wirklich störend ist, evtl. aber ist der iMac innen verstaubt und man müsste ihn mal zum Reinigen öffnen. Aber für den Moment bin ich zufrieden -- so wie es ist.
"Ports of Call" auf dem iPhone
Geschrieben von Harald Lapp in iPhone um 10:11
Wem der Spieleklassiker "Ports of Call" (POC) nichts sagt, ist entweder zu jung und / oder hat die Zeit der Homecomputer nicht erlebt, hatte keinen Amiga oder kannte niemanden der einen Amiga sein Eigen nannte. "Ports of Call" ist ein Handelsspiel, in dem es darum geht eine Reederei aufzubauen und Handel über Seewege zu treiben. Das Spiel war seiner Zeit aber irgendwie voraus, denn es war nicht nur ein Handelsspiel, sondern beinhaltete auch einen Simulator. So konnte man sein Geschick versuchen und die Hafen ein- und ausfahrten selbst steuern. Oder man fuhr eine Route mit Eisbergen und musste diese umschiffen.
Seit geraumer Zeit schon wird das Spiel weiterentwickelt. Inzwischen gibt es Portierungen für aktuelle Windows Versionen und sogar einen richtigen 3D Simulator.
Gestern erschien nun die iPhone / iPod Touch Portierung von POC und ich dürfte einer der ersten gewesen sein, die das Spiel im App Store erworben haben. Bei der Portierung handelt es sich um die alte Classic Version und mit entsprechendem Charme kommt sie auch daher. Bedienen lässt sich das Spiel natürlich über den Touch Screen. Der Bildschirm wird leider nicht voll ausgenutzt, da dort wo es nötig ist, zusätzlich Kontrollflächen eingeblendet werden. So wurden z.b. Schaltflächen zum Manövrieren des Schiffes an den Seitenrand gepackt. Aufgrund der Tatsache, dass die Kontrollflächen des Spiels ansonsten nicht angepasst wurden, sind diese gemessen an der Bildschirmauflösung teilweise recht klein. Deshalb weiss ich auch nicht ob es an meinen grossen Fingern liegt oder ob es tatsächlich so ist, dass die Schaltflächen nicht immer beim ersten "Klick" bzw. Anfassen reagieren.
Alles in allem macht es selbst nach 20 Jahren, die das Spiel inzwischen auf dem Markt ist, noch spass damit zu spielen. Auch auf dem iPhone macht es Spass ein Schiff aus dem Hafen zu navigieren oder den Riffen in schwierigem Gewässer auszuweichen. Das Spiel ist mit seinen 3,99 € sicher nicht eines der günstigen im App-Store, dafür bekommt man aber einen echten Klassiker, der nichts von seinem Charme verloren hat und der für viele Stunden Spielspass sorgen kann.
ORMs sind doof
Geschrieben von Harald Lapp in Datenbanken, PHP um 10:55
ORM
Objektrelationale Abbildung (englisch object-relational mapping, ORM) ist eine Technik der Softwareentwicklung, mit der ein in einer objektorientierten Programmiersprache geschriebenes Anwendungsprogramm seine Objekte in einer relationalen Datenbank ablegen kann. Dem Programm erscheint die Datenbank dann als objektorientierte Datenbank, was die Programmierung erleichtert. [...]
Inzwischen bringt ja so ziemlich jedes PHP Framework seine eigene ORM Implementierung mit, es gibt aber auch einige Framework-unabhängige ORM Implementierungen. Ich habe mir in den letzten Jahren immer mal wieder verschiedenste ORM Implementierungen angesehen -- immer dann, wenn in mir der Wunsch nach einer objektorientierten Zugriffsweise auf meine Datenbanken aufkam. Leider jedoch konnte mich bisher keine ORM Implementierung überzeugen.
ORMs sind doof
Auch in mir kommt immer mal wieder der Wunsch auf objektorientiert auf meine Datenbanken zuzugreifen, da dies den Zugriff auf einzelne Datensätze -- Objekte -- erheblich vereinfacht. Jedoch -- zu welchem Preis wird diese Vereinfachung erkauft?
Modellierung
Ich modelliere meine Datenbanken schon seit Jahren mit dem ER Modeller dbWrench. Das ist meiner Meinung nach super komfortabel. Ich sehe auf einen Blick all meine Tabellen und die Abhängigkeiten bzw. Verknüpfungen zwischen einzelnen Tabellen. Über die Funktion "Forward Engineering" kann dbWrench mein Datenbankschema in der Datenbank immer aktualisieren. Da ich bei MySQL den Tabellentyp InnoDB verwende, sind auch in der Datenbank sämtliche Verknüpfungen festgehalten und liessen sich z.b. über die INFORMATION_SCHEMA Tabelle leicht auslesen.
Nun ist es leider so, dass offenbar so ziemlich jede ORM Implementierung die Datenbankdefinition auf Ihre Weise bekommen möchte. Da muss man entweder seitenweise XML oder YAML Konfiguration, oder gar ellenlangen PHP Code schreiben -- nur um der Anwendung eine Information bekannt zu geben, die eigentlich exakt so schon in der Datenbank vorhanden ist?
Abstraktion
Wie weit muss man die Datenbankzugriffe abstrahieren? Nun, es gibt da sicherlich die verschiedensten Anforderungen. Ich denke bei der Entwicklung von Unternehmenssoftware kann man die Anforderungen ziemlich genau spezifizieren. Man entscheidet sich zu einem gewissen Zeitpunkt für ein bestimmtes Datenbankprodukt. Normalerweise wird diese Entscheidung nicht nach wenigen Monaten oder Jahren über den Haufen geworfen -- es sei denn es gibt sehr triftige Gründe dafür.
Deshalb bin ich der Meinung, dass die Abstraktion nicht so weit gehen muss, dass sämtliche Datenbankzugriffe abstrahiert werden und für beliebige Datenbanksysteme geeignet sind. Im Gegenteil: ich entscheide mich ja nicht für eine bestimmte Datenbank nur aus Kostengründen, sondern auch, weil diese vielleicht Features mitbringt, die ein anderes Datenbanksystem nicht unterstützt.
So erweitert z.b. MySQL den SQL Standard um eigene spezifische Befehle, die es in anderen Datenbanken nicht gibt, die aber sehr praktisch sind. Das ist kein Alleinstellungsmerkmal von MySQL. Beispiel: Hätte ich mich für Oracle entschieden, wäre ich doch dumm, würde ich zum Abbilden / Abfragen von Hierarchischen Strukturen nicht CONNECT BY verwenden -- nur weil dies nicht Teil des SQL Standards ist und dies so mit keiner anderen Datenbank funktioniert.
Nur: keine ORM Implementierung kann auf diese einzelnen Datenbankfeatures eingehen -- womit ich beim nächsten Punkt angelangt wäre.
Abfrage
Das grösste Manko aller (PHP) ORM Implementierungen ist meiner Meinung nach die Abfrage einer Datenbank. Ich gebe zu: ich mag SQL -- es gibt mir das passende Werkzeug zum Abfragen einer relationalen Datenbank in die Hand -- es wurde zu diesem Zweck entwickelt! Ich schreibe gern SQL, da es strukturiert und übersichtlich ausschaut und mich schnell zum Ziel führt. Ich gebe weiterhin zu: Ich nutze auch gern MySQL spezifische SQL Features -- aus den oben genannten Gründen.
Nun ist es jedoch so, dass die ORM Implementierungen in der Regel den Zugriff soweit abstrahieren, dass -- normalerweise -- kein SQL mehr geschrieben wird. CONNECT BY und ähnliche Dinge wären damit Unmöglich. Heutzutage hat sich folgende Schreibweise zum Erstellen von Datenbankabfragen etabliert:
$dbo
->select(array(
'media.media_id', 'media.media_name', 'member.member_name', ...
))
->from('media')
->join('member', 'member.member_id = media.member_id')
->where('media.category_id = ?')
->order('media.media_id')
...
Ich bin kein Fan einer solchen Schreibweise:
- Es ist kein SQL

- Es ist wesentlich mehr Aufwand als beim Schreiben von SQL erforderlich
- Ich kann keine Datenbankspezifischen SQL Erweiterungen verwenden
- Ich habe keine Kontrolle darüber, welchen SQL Code die ORM Implementierung daraus generiert
- Es liegt in der Natur der Sache, dass ein derartiges Konstrukt niemals auch nur annähernd so performant sein kann wie ein simples SQL Statement übergeben an die Datenbank
- Ich kann das Statement nicht per Copy / Paste zwischen meinem Datenbank Client und der Anwendung hin und her kopieren -- praktisch, wenn man das ganze erstmal testen will
- Wenn ich den Datenbanktreiber einer nicht-relationalen Datenbank hinterlege, weil ich mich z.b. entscheide statt MySQL MongoDB anzusprechen, wird diese Schreibweise ohnehin ad Absurdum geführt. (Nur als beispiel -- ich weiss nicht, ob irgendeine PHP ORM Implementation überhaupt nicht-relationale Datenbanken unterstützt)
Natürlich bietet so ziemlich jede ORM Implementierung einen Fallback zur Herkömmlichen Absetzung von SQL Anfragen ohne ein Objekt-Mapping. Nur, wenn ich damit an einer Stelle in meiner Anwendung anfange: warum dann überhaupt eine derartige Abstraktion nutzen?
Fazit
Meiner Ansicht nach erkauft man sich den konsequenten Einsatz eines ORM zu einem zu hohen Preis. Deshalb habe ich den Einsatz eines solchen für mich immer wieder verworfen. Mein Wunsch wäre ein SQL -> Objektmapper. D.h.: Ich schreibe SQL, zurück bekomme ich Objekte, mit denen ich weiterarbeiten kann ...
MongoDB + PHP + OSX
Geschrieben von Harald Lapp in Datenbanken, PHP um 14:01
Ich spiele gerade ein wenig mit Mongo DB. Da ich das die Tage sicherlich noch mal gebrauchen kann, mache ich mir hier mal ein paar wichtige Notizen zur Installation:
- Der Aktuelle PHP Treiber ist nicht kompatibel zum aktuellen stable Release (0.8.0) auf der Mongo DB Seite. Deshalb muss ein daily-build von Mongo DB heruntergeladen werden. Am besten lädt man hier das Paket inkl. aller Tools und Treiber (beinhaltet auch den Source der PHP Erweiterung). Mongo DB also herunterladen und irgendwohin installieren (z.b. /opt/mongo).
- Zum Compilieren des PHP Treibers benötigt man die Boost C++ Libraries. Beim Compilieren der Boost Libraries wurden die Namen der Bibliotheken derart angelegt, dass sie beim Compilieren des PHP Treibers von Mongo DB nicht gefunden werden konnten. Deshalb habe ich nach dem ./configure --prefix=/opt/boost von Boost die Datei Makefile editiert und die Zeile BJAM_CONFIG= nach BJAM_CONFIG='--layout=system' geändert.
- Nachdem Boost Installiert wurde, lässt sich nun der Mongo DB Treiber compilieren. Bei mir befindet sich der PHP Treiber unterhalb des Verzeichnisses /opt/mongo/drivers_and_tools/mongo-php-driver. Ein phpize, ./configure --with-mongodb=/opt/mongo/ --with-boost=/opt/boost/, make, make install und der Treiber ist gebaut und installiert.
Eigentlich ganz einfach ... aber ich vergesse es sonst garantiert wieder ![]()
cookie based redirect mit lighttpd
Geschrieben von Harald Lapp in LightTPD um 20:15
Alle unsere Entwickler haben eine komplett eigene Entwicklungsumgebung inkl. WebServer installiert. Manchmal ist es praktisch den aktuellen Entwicklungsstand am Checkout eines Entwicklers zu sehen. Anstatt für jedes Projekt und jeden Entwickler eine interne Subdomain einzurichten, kann man viel praktischer einen zentralen Reverse Proxy nutzen, der anhand einer Cookie Einstellung den Host des jeweiligen Entwicklers auswählt:
$SERVER["socket"] == "10.0.0.20:80" {
...
$HTTP["host"] =~ "^.*\.devcenter.int$" {
$HTTP["cookie"] =~ "(; )?devredirect=harald" {
proxy.server = (
"" => (("host" => "10.0.0.20", "port" => 8080))
)
}
$HTTP["cookie"] =~ "(; )?devredirect=markus" {
proxy.server = (
"" => (("host" => "10.0.0.22", "port" => 8080))
)
}
}
}
Die oben gezeigte Konfiguration installiert einen Reverse Proxy für Subdomains von 'devcenter.int' -- z.B. 'clipdealer.devcenter.int'. Über das Cookie 'devredirect' kann spezifiert werden, welcher Host angesprochen werden soll.
ssh von unterwegs
Geschrieben von Harald Lapp in Closed Source Tools, iPhone um 11:16
Es kam schon oft vor, dass ich unterwegs gerne einen Blick auf einen Server geworfen hätte. Wie habe ich mich deshalb gefreut, als vor ca. einem Jahr die erste SSH Software für das iPhone angekündigt wurde -- pTerm. Leider erwies sich diese Bezahlsoftware als nicht wirklich ergiebig. Die ersten Versuche zu Hause im WLAN waren zwar erfolgreich, unterwegs über edge wollte das ganze jedoch leider nicht funktionieren. Bis heute weiss ich nicht warum -- die pTerm Diskussionsgruppe war in dieser Hinsicht auch nicht wirklich hilfreich. In der Zwischenzeit wartet man auf ein Update der Software, das nicht kommt.
Nun habe ich kürzlich ein wenig im App-Store gestöbert und bin bei dieser Gelegenheit auf das Tool TouchTerm gestossen, welches -- im Gegensatz zu pTerm -- auch in einer kostenlosen Variante erhältlich ist.

Auf den ersten Blick bietet TouchTerm in der kostenlosen Variante ähnliche Features wie pTerm, mit dem einen Unterschied: es funktioniert auch von Unterwegs über edge problemlos. Die kostenpflichtige Pro Variante -- derzeit mit einem Preis von € 11,99 nicht gerade eine der günstigen Anwendungen im App-Store -- bietet zusätlich Gestures (wobei ich da bei einer Shell Angst hätte versehentlich rm -rf zu erwischen
), Copy/Paste innerhalb der Anwendung, grafische Verzeichnisnavigation sowie umfangreichere Einstellungsmöglichkeiten.
gearman job queue server
Geschrieben von Harald Lapp in PHP um 17:28
Die letzten Wochen habe ich für die Arbeit einen Workflow Prozessor entwickelt, über den wir zukünftig unsere Medien Uploads verarbeiten werden. Unter anderem gehört zu seinen Aufgaben die Erzeugung von Still Images aus Videos, Wave- und Spektrum-Analyse aus Audiodateien, Erzeugung von Thumbnails und Previews für die Darstellung auf der Web Seite. Der Workflow Prozessor arbeitet von der Console bzw. als Hintergrundprozess (Dämon) und ist in PHP entwickelt. Wird er auf einem Server gestartet, kann der Hauptprozess beliebig viele Worker-Prozesse forken.
Ein Problem bei der Entwicklung war die Verteilung der Prozesse an die Worker. Hier habe ich zunächst auch auf eine reine PHP basierte Lösung gesetzt und die Verteilung der Aufgaben vom Hauptprozess übernehmen lassen, der über Socket-Pairs mit den Worker-Prozessen kommunizieren kann. Bei Tests während der Entwicklung im kleinen Rahmen und mit wenigen Jobs hat das auch wunderbar funktioniert. Bei umfangreicheren Tests traten dann allerdings die Probleme zu Tage.
Einmal abgesehen davon, dass die ganze Sache nicht wirklich der Performance-bringer war, war sie dank der direkten Kommunikation Client->Worker auch fehleranfällig und schlecht bzw. gar nicht skalierbar, denn wie soll man mit dieser Methode mehrere bzw. beliebige Worker-Server transparent ansprechen?
Zum Glück habe ich schon seit einiger Zeit gearman in meinen Lesezeichen. Gearman ist eine Serversoftware, die -- einfach ausgedrückt -- den Zweck erfüllt Jobs zu verteilen. Mögliche Einsatzgebiete sind z.b. die Verteilung von Jobs an Systeme, die besser für die jeweilige Aufgabe geeignet sind, die Lastverteilung auf beliebige Server oder um Jobs parallel abarbeiten zu können. Hierfür wird seitens gearman eine (persistente) Warteschlange implementiert, an die ein Client einen Job senden kann. Ein Worker kann sich einen Job aus der Warteschlange holen und diesen abarbeiten.
Gearman wurde ursprünglich von Brian Fitzpatrick (livejournal, memcached, ...) in Perl entwickelt und vor einiger Zeit von Brian Aker und Eric Day nach C portiert. Der Entwicklungsstand des C Zweiges von gearman ist seiner Version (0.3) zu schliessen noch relativ jung. Insgesamt aber scheint sich das ganze schon derart bewährt zu haben, dass gearman produktiv und unter hoher Last z.b. von digg und yahoo eingesetzt wird.
Zum erfolgreichen Kompilieren von gearman unter OSX muss sichergestellt sein, dass man eine aktuelle Version der libevent Bibliothek installiert hat. Danach lässt sich auch gearman problemlos unter OSX bauen und installieren. Sowohl für libevent wie auch für gearman funktioniert das wie üblich:
$ ./configure
$ make
$ make install
Anschliessend kann man gearman starten. Der Parameter "-d" bewirkt dabei, dass gearman als Hintergrundprozess losgelöst vom Terminal gestartet wird:
/usr/local/bin/gearman -d
Per default lauscht gearman auf Port 4370. Dies ist der offizielle Port, der von der IANA für gearman reserviert wurde.
Client/Worker APIs zur Kommunikation mit gearman gibt es bereits für C (enthalten im gearman Download), Perl, MySQL (als UDF) und PHP. Zum Ansprechen von gearman unter PHP gibt es ein pear package, net_gearman, sowie seit kurzem auch eine native Erweiterung für PHP, die allerdings noch experimentell ist und dementsprechend mit Vorsicht zu geniessen ist. Unter OSX konnte ich sie z.b. zwar einwandfrei kompilieren und installieren, die ersten Versuche scheiterten dann aber an segfaults. Nicht weiter tragisch, da das pear paket bisher einwandfrei seine Arbeit macht.
Eine Client Anwendung, die Jobs an den gearman Server übergibt, ist mit dem pear Paket schnell entwickelt:
#!/usr/bin/env php
<?php
require_once('Net/Gearman/Client.php');
$set = new Net_Gearman_Set();
function result($resp) {
print_r($resp);
}
$files = array(
'/Users/harald/Movies/00001.mov'
);
foreach ($files as $file) {
print "adding task $file\n";
$task = new Net_Gearman_Task('test', array(
'filename' => $file
));
// $task->attachCallback('result');
$set->addTask($task);
}
print "running set ...\n";
$client = new Net_Gearman_Client(array('127.0.0.1:4730'));
$client->runSet($set);
?>
Der erste Parameter beim Instanzieren der Klasse Net_Gearman_Task spezifiziert übrigens den Namen des Jobs, der vom Worker registriert werden muss, damit dieser entsprechende Jobs annehmen und verarbeiten kann. Normalerweise wartet der Client, bis alle Jobs abgearbeitet sind und kann wenn eine Callback Methode registriert wurde, mögliche Ergebnisse verarbeiten, die die Worker zurückliefern. Dieses Verhalten kann möglicherweise unerwünscht sein, z.b. wenn viele Jobs eingereicht werden und der Client während der Abarbeitung nicht blockiert sein soll. Hierfür implementiert die Net_Gearman_Task Klasse ein öffentliches Property:
public $type = self::JOB_NORMAL;
Um das Verhalten zu ändern, sind folgende Typen definiert:
- Net_Gearman_Task::JOB_NORMAL -- Standardverhalten: Client blockiert während der Abarbeitung der Jobs
- Net_Gearman_Task::JOB_BACKGROUND -- Client reicht Jobs an gearman weiter und blockiert nicht
- Net_Gearman_Task::JOB_HIGH -- selbes Verhalten wie JOB_NORMAL, allerdings wird die queue übersprungen und ein Job kann sofort von einem Worker verarbeitet werden. Sinnvoll z.b. für höher priorisierte Jobs
Eine einfacher Klasse, die die Aufgabe 'test' implementiert, könnte folgendermassen aussehen:
<?php
class test extends Net_Gearman_Job_Common {
function run($args) {
print_r($args);
print "sleeping 5 seconds ...\n";
sleep(5);
print "done!\n";
return "OK!";
}
}
?>
Der Worker selbst wird folgendermassen aufgebaut:
#!/usr/bin/env php
<?php
define('NET_GEARMAN_JOB_CLASS_PREFIX', '');
define('NET_GEARMAN_JOB_PATH', '.');
require_once('Net/Gearman/Worker.php');
$worker = new Net_Gearman_Worker(array('127.0.0.1:4730'));
$worker->addAbility('test');
$worker->beginWork();
?>
Normalerweise erwartet Net_Gearman Klassen, die Aufgaben implementieren unterhalb eines Verzeichnisses, das in der PEAR Verzeichnisstruktur angesiedelt ist. Weil man dies normalerweise nicht möchte, gibt es folgende Konstanten, die man mit eigenen Werten füllen kann um so alternative Verzeichnisse zu setzen:
// spezifiziert ein Prefix für den Namen der Klasse
define('NET_GEARMAN_JOB_CLASS_PREFIX', '');
// spezifiziert das Verzeichnis, in dem Klassen gesucht werden
define('NET_GEARMAN_JOB_PATH', '');
Unschön ist, dass für einzubindende Klassen Dateien mit folgendem Namensschema erwartet werden, z.b: test.php. Da ich meine Klassen immer z.B. -- test.class.php -- benenne, ist dies also leider eine kleine Unschönheit, mit der man offenbar leben muss.
Zum Abschluss sei noch zu sagen, dass gearman in den ersten Tests mit mehreren 1000 Jobs in der Queue seine Arbeit tadellos und sehr zufriedenstellend erledigt hat.
Empfohlene weiterführende Links:
JavaScript: The World's Most Misunderstood Programming Language
Geschrieben von Harald Lapp in Javascript um 08:13
Eigentlich sollte ich stolz sein: es gibt tatsächlich Leser meines Blogs, die meine Artikel aufgreifen und sich darüber kritische(?) Gedanken machen. Gestern bin ich zufälligerweise auf einen Artikel in einem Blog gestossen, in dem sich der Autor über meine Einstellung zu JavaScript lustig macht. Bei all seinem Sarkasmus vergisst der Autor leider Argumente vorzubringen warum er meine Einstellung so lächerlich findet. Die im Text eingestreuten Klischees, die man ähnlich so eigentlich nur aus dem Heise-Forum kennt, können es kaum sein.
Dabei kann ich die Einstellung tatsächlich sogar verstehen: In JavaScript lässt es sich ähnlich schmutzig und disziplinlos programmieren, wie mit PHP. Nur: dort wo PHP einem Steine in den Weg legt, weil der Parser viele dinge einfach nicht zulässt, ist JavaScript in der Regel offen und man kann einen sehr sauberen und eleganten Programmierstil fahren. Nun ist es bei JavaScript so wie mit jeder Programmiersprache: man muss sich damit beschäftigen. Was PHP und JavaScript darüberhinaus gemein haben ist, dass es für beide Sprachen wenig gute Literatur, dafür aber umso mehr schlechte Literatur gibt.
Bei ernsthaftem Interesse an JavaScript möchte ich an dieser Stelle auf einen Artikel von Douglas Crockford verweisen -- JavaScript: The World's Most Misunderstood Programming Language. Dieser Artikel räumt mit einigen Vorurteilen gegenüber JavaScript auf und macht vielleicht auch verständlich, warum JavaScript einen derart schlechten Ruf hat.
ClipDealer Widget Test
Geschrieben von Harald Lapp in Allgemeines um 15:02











