Archiv der Kategorie 'Entwicklung'

CentOS 6.2 & VirtualBox: Kernel Panic

Freitag, den 13. April 2012

Nach einem Update auf einer CentOS 6.2 Instanz unter VirtualBox bootete diese komischerweise immer direkt in eine Kernel Panic.

Das Problem ließ sich lösen, indem man in den Systemeinstellungen der VM den Chipsatz von “PIIX3″ auf “ICH9″ ändert. :-)

(nur falls noch jemand dieses Problem hat - erspart viel Debugging…)

MySQL-Fehler für Fortgeschrittene

Freitag, den 27. Januar 2012

Manchmal ist es schon echt zum verzweifeln, wie hart einen Bugs in fremden Produkten treffen können.

Unser Hosting Control Panel unterstützt ja auch MySQL als Backend zur Speicherung der “eigenen” Daten. Der Zugriff auf MySQL erfolgt aus Performancegründen ausschließlich mittels Prepared Statements. Nun hat uns kürzlich ein LiveConfig-Kunde auf ein merkwürdiges Problem aufmerksam gemacht: regelmäßig erschien nach der Durchführung eines MySQL-Backups (via mysqldump) in LiveConfig die Fehlermeldung “Prepared statement needs to be re-prepared”.

Die Suche hiernach führte zum MySQL-Bug #41119. Als Workaround haben wir daher nun eine explizite Fehlerbehandlung nach mysql_stmt_execute() eingeführt, welche mit mysql_stmt_errno() die jeweilige Fehlernummer ausliest und in unserem Fall (Fehlercode 1615) das betroffene Statement explizit neu erzeugt.

Nur leider funktionierte dieser Workaround nicht. Also überhaupt nicht.

Ein ausführliches Debugging und Tracing aller Datenbankzugriffe hat dann ergeben, dass unsere Fehlerbehandlung gar nicht aufgerufen wird. Zusätzliche Debug-Ausgaben bestätigten dann tatsächlich, dass mysql_stmt_errno() immer “0″ zurückliefert! WTF!?!?

Diesmal hat MySQL-Bug #53311 zugeschlagen. Beseitigt ist dieser Fehler seit knapp einem Jahr ab MySQL Connector/C 6.0.3. Dummerweise ist diese Version aber nach wie vor nicht freigegeben (”aktuell” verfügbar ist nur Version 6.0.2).

Letztendlich haben wir hier nun den über 650 MB großen bazaar-Branch von libmysql ausgeckeckt, und müssen uns nun zwangsweise die 6.0.3-Release selbst erzeugen

:roll:

Nachtrag:

Finger weg vom MySQL-Connector/C 6.0.3! Ich glaube zu verstehen, warum diese Version noch nicht freigegeben wurde - da funktioniert die Hälfte nicht mehr… vor allem bei Prepared Statements scheint diese Version besonders merkwürdige Fehler zu haben - so funktioniert selbst ein einfaches UPDATE mit drei bestimmten Parametern (String/Int/String) reproduzierbar nicht mehr; ändert man die Reihenfolge der Parameter (zB. String/String/Int oder Int/String/String) so klappt’s plötzlich wieder. Und der Bug liegt definitiv nicht bei uns - selbst ein eigenes Testprogramm (basierend auf dem Beispiel von MySQL) führt bei einer bestimmten Variablenfolge zu einem “Incorrect arguments to mysqld_stmt_execute”. Ob das mit MySQL-Bug #61225 zu tun hat weiß ich nicht, aber auch dessen Fehlerbeschreibung lässt einen fast erschaudern.

Der Trick zu einem stabilen und aktuellen MySQL-Client führt über die GA-Pakete des Community-Servers. Einfach dort die entsprechenden Bibliotheken und Developer-Pakete zusammensuchen, oder aus dem “Generic”-Paket (.tar.gz) die Verzeichnisse “/lib” und “/include” nehmen. Der Client aus MySQL 5.5.20 spricht ebenfalls Protokollversion 10 (wie auch Client 6.0.x), dürfte daher soweit kompatibel sein. Man muss seinen eigenen Code allerdings neu gegen diese Bibliotheken linken, da es ein paar kleinere ABI-Unterschiede gibt.

HTTP auf HTTPS-Port

Donnerstag, den 15. Dezember 2011

Für uns “Tekkies” ist das kein Thema, aber viele “normale” ;) Benutzer verwechseln gerne mal HTTP und HTTPS bei der Eingabe einer URL. Zum Glück kann OpenSSL erkennen, ob statt eines erwarteten SSL-Handshakes etwas eintrifft was eher nach einem “HTTP GET” ausschaut. Ist das der Fall, gibt OpenSSL die Fehlermeldung SSL_R_HTTP_REQUEST zurück.

So fängt LiveConfig in der nächsten Version (1.3) auch solche falschen Zugriffe ab und bietet dem Benutzer die “richtige” URL an. Ein kleines, aber praktisches Feature.

error400.png

Eventuell werden wir bei Gelegenheit auch einen Test einbauen, ob bei HTTP-Verbindungen ein SSL-Handshake eintrifft, um dann ebenfalls eine entsprechende Fehlermeldung zu erzeugen.

Datenbank-unabhängiges SQL

Freitag, den 5. August 2011

Beim Durchstöbern meiner RSS-Feeds bin ich eben auf die Meldung von Icinga gestoßen, wonach diese künftig zur Abstraktion der Datenbankabfragen Doctrine einsetzen, statt für jede unstützte Datenbank eigene SQL-Befehle zu pflegen.

Der Hintergrund ist folgender: möchte man seine Daten beispielsweise sowohl in einer MySQL- als auch in einer Oracle-Datenbank speichern können, müssen beide Datenbanksysteme häufig mit unterschiedlichen SQL-Statements angesprochen werden. Das liegt darin begründet, dass jeder Datenbankhersteller sein eigenes Süppchen kocht - verschiedene Standards (SQL-92, SQL-99) werden zwar relativ breit unterstützt, aber manchmal hört es mit der Kompatibilität schon auf, wenn man nur einen Datum-Wert in einem Statement verwenden möchte. Sowas wird übrigens gerne auch als Vendor Lock-In bezeichnet.

Ein Ansatz ist eben, die eigentlichen Zugriffe durch die Verwendung eines Objektpersistenz-Frameworks zu abstrahieren. Der Vorteil ist ganz klar eine ordentliche Trennung der verschiedenen Funktionsbereiche und eine saubere Klassenstruktur. Ein Nachteil dabei kann aber sein, dass man auf die Performance durch Optimierung der Abfragen vielleicht keinen Einfluss hat (kommt sehr auf den jeweiligen Einzelfall an).

Ein anderer Weg wäre, für alle zu unterstützenden SQL-Dialekte eigene SQL-Statements zu pflegen. Davon rate ich aber entschieden ab: zum Testen muss die komplette Anwendung somit auf allen unterstützten Datenbanksystemen vollständig geprüft werden, der Pflegeaufwand ist sehr hoch und entsprechend auch sehr fehleranfällig.

Bei LiveConfig standen wir vor einer ganzen Weile vor genau dem selben Problem. Es sollen verschiedene Datenbanksysteme unterstützt werden (vorerst SQLite und MySQL, später PostgreSQL und vielleicht auch Oracle), während aber nicht für jedes DBMS eigene SQLs gepflegt werden sollen. Doctrine kam nicht in Frage (schließlich entwickeln wir in C/C++), und besonders viele leichtgewichtige C/C++-Persistenz-Frameworks auf SQL-Basis scheint’s nicht zu geben.

Wir haben daher einen völlig anderen Ansatz verfolgt. Das war zwar mit einem recht hohen Initial-Aufwand verbunden, zahlt sich aber (unserer Ansicht nach) auf Dauer aus: die Entwicklung eines eigenen SQL-Übersetzers. Man muss sich das so vorstellen: die Anwendung “spricht” einen relativ generischen SQL-Dialekt (im Groben und Ganzen ein SQL99), und bevor ein Statement zur Datenbank gesendet wird, wird es in den entsprechenden Ziel-Dialekt übersetzt.

Beispiel: es sollen die Datensätze 11 bis 15 einer Tabelle abgerufen werden. In MySQL macht man das mit

SELECT a, b, c FROM table WHERE b=1 ORDER BY a LIMIT 5 OFFSET 11

während man mit Oracle (als Extrembeispiel) etwas mehr tricksen muss:

SELECT a, b, c FROM (SELECT a, b, c, rownum AS limit_rownum FROM (SELECT a, b, c FROM table WHERE b=1 ORDER BY a)) WHERE limit_rownum BETWEEN 11 AND 15

Unsere Lösung wird in Form einer eigenen C-Bibliothek in den Code eingebunden und stellt eine datenbankunabhängige API zur Verfügung. Die Bibliothek kümmert sich dabei selber um das Laden der notwendigen Datenbank-Treiber (libmysqlclient, OCI, …); somit weiß man auf Anwendungs-Ebene im Grunde auch gar nicht, auf welchem System die Anfragen nun tatsächlich ausgeführt werden.

In unserem Fall würde die Anwendung für o.g. SQL-Anfrage also folgendes Statement verwenden:

SELECT a, b, c FROM table WHERE b=:1 ORDER BY a LIMIT :2 OFFSET :3

Intern wird dieses dann automatisch in den gewünschten Ziel-Dialekt (s.o.) übersetzt. Jede Anfrage wird dabei als Prepared Statement abgearbeitet, welches durch unsere Bibliothek intern auch noch zur Wiederverwendung gecached wird. Die Vorteile liegen auf der Hand:

  • die Übersetzung in den Ziel-Dialekt muss während der gesamten Laufzeit nur ein einziges Mal durchgeführt werden
  • auch die Datenbank muss das Statement nur ein einziges mal parsen
  • da alle Parameter über Variablen gebunden sind, sind SQL Injections praktisch unmöglich

Das Ergebnis: eine unschlagbare Performance und gleichzeitig voller Einfluss auf den Aufbau der SQL-Statements. Die Bibliothek lässt sich isoliert wunderbar testen (für alle SQL-Anfragetypen haben wir entsprechende checklib Unit Tests geschrieben), und auch für andere Projekte prima recyclen.

Der Hauptaufwand bestand in der Entwicklung des entsprechenden SQL-Parsers (hier auf Basis von lex und yacc) sowie der möglichst vollständigen Unit-Tests. Natürlich wird nur ein Bruchteil des kompletten SQL-Sprachumfangs abgedeckt, aber eben alles, was unsere Anwendungen benötigen. Als letztes “Leckerli” können wir natürlich auch zentral alle SQL-Anfragen loggen, und diese Logs analysieren (z.B. die Häufigkeit der Statements auswerten, oder fertig übersetzte Statements zur Optimierung der Tabellen-Indizes verwenden).

Für Perl bin ich vor Jahren mal über SQLFairy gestoßen, was scheinbar einen ähnlichen Ansatz verfolgt. Eine andere (etwas schwergewichtigere) Alternative wäre übrigens ODBC.

Das Orakel befragen…

Donnerstag, den 9. Juni 2011

Schon bei der Übernahme von MySQL durch Oracle hatte ich irgendwie kein gutes Gefühl im Bauch. Die letzten Monate über hat sich das immer weiter bestärkt. Am 30.12.2010 kam ein Brief aus den USA (per DHL-Express - ich will gar nicht wissen was das gekostet hat), mit dem alle bisherigen Partnerverträge von Sun fristlos aufgekündigt wurden. Danach hat es einige Monate gedauert, bis Oracle das hauseigene “OPN” (Oracle Partner Network) um eine Hand voll MySQL-Produkte erweitert hat (in der Zwischenzeit ging bekanntlich “gar nichts”). Nach einem mehrstufigen Registrierungsprozess, spontanen Anrufen von Oracle-Callcentern und etlichen Webcasts kann darf man dann (theoretisch) MySQL-Produkte verkaufen - aber nur, wenn man mindestens den “Gold-Level” (für schlappe $2.995,- pro Jahr) hat.
Das eigentliche Problem besteht aber woanders: stellt man nun eine (kommerzielle) Software her, die nicht unter GPL-Lizenz steht und auch nicht die Kriterien für die FOSS-Ausnahmen erfüllt, dann kann man derzeit MySQL-Datenbanken nicht unterstützen. Die Verwendung der Client-Bibliotheken ist alternativ nämlich nur mit einer OEM-Lizenz möglich, und die gibt es bei Oracle derzeit irgendwie nicht. Ich stehe nun schon seit Wochen in Kontakt mit dem “Orakel” :) (u.a. mit dem viel zitierten “OEM Sales Team”), aber habe schlicht und ergreifend noch gar keine Antwort erhalten. Telefonisch wies man mich mit Floskeln auf die eben erwähnte Gold-Level-Mitgliedschaft im OPN hin, wenngleich diese auch keine OEM-Lizenzen oder vergleichbare Berechtigungen beinhaltet. Und selbst wenn - ich sehe es nicht ein, Geld für die Anbindung eines Open-Source-Datenbanksystems zu zahlen.

Wie geht es weiter? Nun, die Idee, die eigene Software einfach mit den MySQL-Client-Bibliotheken einer Distribution zu verlinken, klappt auch nicht, da immer noch die unter GPL stehenden MySQL-Header genutzt werden (müssen). Ich sehe derzeit folgende alternative Ansätze:

  • eine Ausnahme in der (alten) MySQL-Lizenzvereinbarung, die es erlaubt, bisher veröffentlichte Produkte mit MySQL-Client-Bibliotheken in der selben Version auch weiterhin veröffentlichen zu dürfen -> ist halt blöd wenn man Updates machen will
  • eigene Header-Files, welche ABI-kompatibel zum derzeitigen MySQL-Client sind, und unter “großzügigeren” Lizenzen stehen. Ist aber auch blöd, weil dann natürlich alle Funktionsnamen, Strukturen usw. an die “eigenen” Header angepasst werden müssen. Außerdem ist die Lizenzfrage in so einem Fall immer noch recht strittig: der MySQL-Client steht nämlich unter GPL und nicht LGPL
  • Verwendung des Drizzle-Clients, der (angeblich) zu MySQL kompatibel ist. Problem: nach einer kürzlichen Code-Konsolidierung des Clients in den Haupt-Codebaum kaum separat bzw. “von Hand” compilierbar…
  • Entkoppelung der Datenbankanbindung durch eine eigene Bibliothek, die unter einer der FOSS-Lizenzen steht. Nachteil: diese Zwischen-Bibliothek müsste dann aber im Sourcecode veröffentlicht werden.

Vielleicht liest zufällig ja jemand bei Oracle diesen Artikel, und möchte dann Kontakt mit mir aufnehmen. Ich hatte auch auf der CeBIT einige Gespräche in dieser Richtung, und viele Entwickler sind derzeit äußerst zurückhaltend was die MySQL-Unterstützung betrifft, da Oracle es nicht schafft mal eine klare Aussage zu treffen.

Mir wäre es ja am liebsten, wenn Oracle das bisherige “MySQL Enterprise Driver Software License Agreement” wieder aktivieren und fortführen könnte… *wink_mit_dem_Zaunpfahl*

Bug report

Dienstag, den 29. März 2011

Softwareentwickler kennen das: die eigene Software hat einen Fehler, und man findet ihn einfach nicht. Dummerweise tritt der Fehler nur in ganz seltenen Fällen und irgendwo zwischen dem eigenen Code und einer externen Bibliothek auf. Nun wäre es natürlich einfach, die Ursache auf die externe Bibliothek zu schieben - wenn die aber zig millionenfach im Internet genutzt wird, dann ist es doch eher wahrscheinlich, dass der Fehler im eigenen Code steckt.

So geschehen in einem aktuellen Fall bei uns: unter ganz besonderen Bedingungen sind Datenbankabfragen an eine SQLite-Datenbank schief gegangen. Nun “spricht” unsere Software aber nicht direkt mit SQLite, sondern nutzt eine zwischengeschaltete Bibliothek (ebenfalls von uns), welche alle Datenbankzugriffe abstrahiert und optimiert.

Gestern habe ich dann Testcode geschrieben, welcher das Fehlverhalten sowohl mit unserer Datenbank-Middleware als auch direkt mit SQLite reproduzieren ließ. Zeilenweise wurde der Test dann gekürzt, bis klar war, wo der Fehler steckte: in SQLite. Das hilft einem in diesem Moment zwar auch nicht viel weiter, ist aber schonmal eine gewisse Genugtuung. :-) Hier ist der Bug Report - zwar “nur” ein Documentation Bug, aber durchaus mit weitreichenden Folgen wenn man sich auf die in der Dokumentation beschriebene Gültigkeit von Pointern verlässt.

Proudly presenting: LiveConfig®

Montag, den 14. Februar 2011

lc-productbox.pngJa, da ist es nun: das Ergebnis monatelanger Arbeit wird in zwei Wochen (am 01.03.2011) auf der CeBIT präsentiert - unsere Serververwaltungssoftware LiveConfig.

Vor über sechs Jahren habe ich mich im Rahmen meiner Studienarbeit quasi “akademisch” mit dem Thema Serververwaltung beschäftigt. Eine umfangreiche Analyse der verfügbaren Produkte brachte einige gemeinsame Schwachpunkte zu Tage, die bis dato offenbar noch niemand angegangen ist. Außerdem hatte ich so die Gelegenheit, mal völlig frei die “Wunsch-Software” zur Serververwaltung zu skizzieren. Erst 2008 habe ich den Entschluss gefasst, die Ideen von damals in einem kommerziellem Produkt umzusetzen. Spätestens die Teilnahme am Businessplan-Wettbewerb Nordbayern brachte so viel positives Feedback, dass wir Mitte 2009 mit der Entwicklung “from scratch” begonnen haben - weitere Vollzeit-Entwickler wurden eingestellt, Fördermittel beantragt, Kontakte geknüpft - und nun isses soweit.

Wir sind tatsächlich mit einem eigenen Stand (Reihe 9, Stand B20) auf der CeBIT 2011 in Hannover vertreten (was ich mir vor 15 Jahren als Schüler nie hätte träumen lassen ;-) ). Dort werden wir LiveConfig in aller Ausführlichkeit präsentieren und den ersten 1000 Interessenten auch eine kostenlose Business-Lizenz anbieten.

Was ist nun das Besondere an LiveConfig? Das auffälligste Merkmal dürfte sein, dass LiveConfig in C/C++ programmiert ist. Alles was für die SSL-geschützte Weboberfläche notwendig ist, ist fest integriert. Administratoren können so also beliebige Versionen von Perl oder PHP auf dem Server installieren, ohne das Control-Panel zu zerschießen. Von manchen anderen Lösungen werden auch regelmäßige Probleme mit PHP-Extensions (insbesondere IonCube Loader) berichtet - das kann es mit LiveConfig nicht geben.

Dabei ist der Code nicht komplett “geschlossen”: die kniffligen Aufgaben, also die tatsächliche Erzeugung der Konfigurationsdateien, werden mit Lua-Scripts erledigt. Lua ist eine sehr einfach erlernbare Sprache und die Scripte liegen im Quelltext vor - können also ohne Probleme an eigene, eventuell exotische Anforderungen angepasst werden.

Der zweite große Unterschied zu vielen anderen Lösungen ist, dass sich LiveConfig minimal-invasiv verhält. Konkret bedeutet das, dass LiveConfig die jeweils eingesetzte Linux-Distribution automatisch erkennt und die von dieser bereitgestellten Softwarepakete konfiguriert. Wer mit LiveConfig etwa einen Webserver verwaltet, bekommt also nicht von uns irgendwelche “eigenen” Apache- und PHP-Pakete aufgedrückt, bei denen er dann bei Updates erstmal warten muss. Im Gegenteil - wir passen uns sogar der Konfigurationsstruktur der jeweiligen Distribution an. Das heißt bei Debian beispielsweise, dass wir unsere vHosts auch in /etc/apache2/sites-available/ anlegen und mit “a2ensite” aktivieren. Das geht so weit, dass man LiveConfig rückstandslos wieder vom Server deinstallieren könnte und alle Dienste im zuletzt konfigurierten Zustand weiter laufen würden.

Meiner Meinung nach hat es normalerweise seinen Grund, warum sich jemand für oder gegen eine bestimmte Distribution entscheidet - seien es persönliche Kenntnisse, Fortbildungen oder unternehmensinterne Richtlinien. Und LiveConfig orientiert sich eben möglichst an den Bedürfnissen des Administrators.

Das Ganze hat natürlich seinen Preis - wir brauchen hier im Team verschiedene Spezialisten für die einzelnen Distributionen, aber das bekommt man gut in den Griff. Nicht zuletzt haben wir eine echt coole Testplattform auf Xen-Basis aufgebaut, in der jede Nacht für alle von uns ausdrücklich unterstützten Distributionen die Software komplett compiliert, installiert, getestet und wieder deinstalliert wird. Sollte mal ein Bug auftauchen (nobody’s perfect), dann können wir über die Testplattform sicherstellen, dass dieser dauerhaft beseitigt ist.

So - genug getextet. Wer Interesse hat, den lade ich herzlich auf die Website http://www.liveconfig.com ein. Die Download-, Demo- und Shop-Seite schalten wir erst zur CeBIT frei - bis dahin wird noch etwas poliert und die letzten Feedbacks unserer heimlichen Betatester berücksichtigt. Diskussionen zu LiveConfig sowie jegliche Fragen dazu sollten am besten direkt im LiveConfig-Forum erfolgen (daher schließe ich auch die Kommentare zu diesem Blog-Beitrag).

Hello, World!

Dienstag, den 24. August 2010

Den Titel dieses Blog-Beitrags wusste ich schon seit Monaten, nur der genaue Zeitpunkt war unklar. :-)

p1010027_550px.jpg
Ich bin nun ein vor Glück und Freude platzender Papa, und für einige Tage/Wochen erstmal nur sehr eingeschränkt erreichbar. :-)

Auf die an dieser Stelle üblichen Nerd-Gags mit fork(), sleep(), usw. verzichte ich. :-P