Kategorien
Allgemein

Mit angezogener Handbremse

Seit einigen Wochen hatten wir ein Problem mit unserem Softwareloadbalancer, der auf einem unserer Tomcatserver läuft. Dachten wir.

Die durchschnittliche Last (loadavg) auf dem Server ging in relativ regelmäßigen zweistündlichen Abständen auf über zehn. Da die Lastprobleme mit dem Lastverteiler  umzogen hatten wir den nebenher laufenden Tomcat relativ früh als Verursacher der Probleme ausgeschlossen.

Ein Irrtum.

Wegen eines anderen Problemes haben wir während einer solchen hochlast Phase den Tomcat mittels

kill -quit $TOMCAT_PID

mehrere Threaddumps schreiben lassen. Bei der Analyse dieser Dumps fiel uns dann auf, dass ein übervorsichtiger Programmierer eine Garbage Collection bei jedem Aufruf seines Servlets veranlasste.

Glücklicherweise kann mittels Parameter der JavaVM das Beachten dieser Aufforderung ausgetrieben werden. Seit wir die Option -XX:+DisableExplicitGC für die Tomcat JavaVM nutzen, sind alle Lastprobleme verschwunden. Ebenso zeigte sich, dass die Anzahl der möglichen Anfragen an das Servlet von etwa vier Anfragen pro Sekunde auf etwa 200 Anfragen pro Sekunde hochschnellten.

Und netterweise sind in dem Servlet auch die Aufrufe von System.gc() verschwunden.

Kategorien
Allgemein

Super Fehlermeldungen

Gut formulierte Fehlermeldungen können einem Administrator viel Zeit ersparen. Schlechte kosten im besten Fall nur Nerven.

In meinem letzten Fall hat es mich insgesamt mehrere Tage gekostet. Ganz konkret ging es um den Imap Server von Cyrus. Um dem erhöhten Mailaufkommen beizukommen wollen wir unseren derzeitigen Mailserver (auch von Cyrus) durch eine Cluster-Installation ersetzen. Der letzte Test bestand dann darin, dass der MTA eine Mail über einen Lmtp-Proxy an den eigentlichen Speicherort der Mail weiterreicht.

Das hat er in meiner Testinstallation auch wunderbar gemacht.

In der Produktionsinstallation weigerte er sich mit einer Meldung, dass es keine „worthy mechs“ gäbe. Also keine Mechanismen zur Authentisierung/Authorisierung, mit denen der Proxy mit dem Backend sprechen wollte.

Goggle bietet hier schnell viele Treffer an, die alle in die Richtung TLS Verschlüsselung gehen. Nur die funktionierte bei meiner Installation.

Des Rätsels Lösung lag darin, dass für den Namen des Backends kein Passwort in der Konfiguration des Frontends hinterlegt war.

Tolle Fehlermeldung.

Kategorien
Allgemein

Auch auf der Internetallee glänzt es schon

Kaum liest man im Heise Newsticker gefühlte hundert Nachrichten über Googles neuen Webbrowser, so blitzt er auch schon in den Log-Dateien von unserem geliebten Server auf.

Der Gewinner des ersten Besuchs aus der leuchtenden Chrome-Welt ist die Seite von nektra. Dort war heute schon um 12:51 Uhr ein Browser mit dem untenstehenden gekürzten Log-Eintrag zu sehen:

[03/Sep/2008:12:51:17 +0200] … „Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13“

Kategorien
Allgemein

Alleinherscher

Da wollte ich endlich auch mal eine Windows Installation machen und dann so was.

CD einlegen, Rechner davon booten und installieren, fertig. Dachte ich.

Die ersten male waren aber eher CD einlegen, Rechner davon booten und nach einer kurzen Einblendung „gleich geht’s weiter“ wurde mir schwarz vor Augen. Oder zumindest der Bildschirm.

Reboot tut immer gut, aber in diesem Fall blieb das Ergebnis immer dasselbe. Schwarz. Ist zwar auch schön, aber bunter wäre netter. Also auf ins Internet und nach Windows installation und schwarzer Bildschirm gesucht. Viele Tipps, noch mehr Ratlosigkeit. Die meisten Hinweise deuteten aber darauf hin, dass die Windows XP CD kein anderes Betriebssystem neben sich mag und der einfachste Weg ein

dd if=/dev/zero of=/dev/sda bs=512 count=1

wäre. Damit ist dann zwar die Partitionstabelle weg, aber der Installer glücklich. Gut, dass in der Linux Installation noch nichts konfiguriert war.

Kategorien
Allgemein

Wie sage ich es meiner Funktion

Ein Kollege fragte mich heute, wie man in Perl nochmal Parameter an eine Funktion übergibt.

Das ist ja im Prinzip ganz einfach. Eine Funktion in Perl erhält als Übergabeparameter eine einfache Liste mit Namen @_. Aber damit fängt es dann erst an.

Nehmen wir mal an, wir haben eine einfache Funktion mit zwei Parametern:

sub twoParamFunction {
    my ($one, $two) = @_;
    print "$one and $twon";
}

Hier wird die Liste @_ einer Liste mit gerade frisch deklarierten Variablen zugewiesen. Es werden also alle zusätzlichen Parameter verworfen. Diese Art der Parameterübergabe ist vermutlich eine der gebräuchlichsten und einfachsten.

Aber natürlich war das nicht die Art der Übergabe, die mein Kollege im Sinn hatte. Also gut, wir können auch benannte Parameter mit Standard-Werten benutzen:

sub hashAsParam {
    my %hash_param = ( 
        'one' => 'Eins',
        'two' => 'Zwei',
        @_ );
    print "$hash_param{one} und $hash_param{two}n";
}

Hier wird die Liste in eine Hashstruktur eingeblendet und so können die benannte Parameter one und two sowohl übergeben, als auch weggelassen werden – dann erhalten sie eben ihre Standardwerte.

Aber ach, das war es auch nicht. Nun gut, wir können beide Methoden mischen:

sub mixedParams {
    my ($one, $two, %optional) = @_;
    print "$one and $twon";
    print join("; ", keys %optional) . "n";
}

Hier werden aus der Parameterlliste die ersten beiden Elemente $one und $two zugewiesen, und der Rest wird wie in hashAsParam einer Hashstruktur aufgehen. Wenn hierbei auch noch Standardwerte vorgegeben werden sollen, kann das in einer extra Zeile geschehen.

Hmhm, das war es auch nicht. Ok, wir können natürlich auch noch die Liste einzeln abarbeiten:

sub oneStep {
    my $one = shift;
    my $two = shift;
    print "$one and $twon";
}

Ja, genau das wars! Aber wo wir jetzt schon so viele Varianten hatten, können wir eine noch zusätzlich anbieten:

sub selectAFew {
    my ($one, $four) = @_[0,3];
    print "$one a $fourn";
}

Äh? Aber ab hier sollte eigentlich spätestens klar sein, dass man perldata und man perlsyn mal wieder besucht werden sollten. Um den ganzen die Krone aufzusetzen, kam mein Kollege eine halbe Stunde später wieder an. Diesmal wollte er aber die Möglichkeiten der Rückgaben aus Perl-Funktionen wissen…

Kategorien
Allgemein

Perl ausprobieren

Immer mal wieder frage ich mich, was ein einfacher Perl-Ausdruck denn nun wirklich macht. Da kommt der eingebaute Debugger genau richtig.

Für einfache Ausdrucke und Versuche ist es natürlich am einfachsten einen Perl-Einzeiler zu benutzen. Also

perl -e 'print "Hallo Weltn"'

Für Ausdrucke, die aber auf Variablen zur Laufzeit angewiesen ist, kann es recht müßig sein die History der Shell zu nutzen, oder eine Datei zu öffnen und dort  zu experimentieren.

Debugger to the rescue

Da bietet sich dann an den Debugger zu benutzen. Aber ich will ja eigentlich keine Datei entwanzen. Das Programm für den Debugger muss aber auch gar nicht gross sein. Eine einfache 0 tut es da auch. Mit perl -d -e 0 gelangt man mit dem folgenden Ausdruck in seine persönliche Perl Spielwiese:

user@rechner:~$ perl -d -e 0
Loading DB routines from perl5db.pl version 1.28
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(-e:1):    0
  DB<1> $a="hallo"

  DB<2> print "$a weltn"
hallo welt

Wie man sieht, kann man im Debugger Variablen setzen und auf diese im nächsten Ausdruck zugreifen.

Mit dem üblichen Debugger Befehl x – Untersuche (eXamine) diesen Ausdruck/diese Variable – können wunderbar auch geschachtelte Datenstruckturen anschaulich dargestellt werden.

  DB<3> @a=qw(hallo welt)

  DB<4> x @a
0  'hallo'
1  'welt'
  DB<5> x @a
0  ARRAY(0x8404d64)
   0  'hallo'
   1  'welt'
  DB<6>

Macht man einen Fehler, so gibt der Debugger eine Fehlermeldung aus und man hat wieder einen neuen Versuch.

  DB<6> $a[a)
syntax error at (eval 11)[/usr/share/perl/5.8/perl5db.pl:628] line 2, near "a)"
Missing right curly or square bracket at (eval 11)[/usr/share/perl/5.8/perl5db.pl:628] line 4, at end of line
Kategorien
Allgemein

Immer eins nach dem anderen

Ein kleines Beispiel zeigt, wo die Reihenfolge der Deklaration von Variablen in Java Klassen wichtig ist.

Auf der Tomcat Mailingliste kam heute eine Mail, in der jemand fragte, warum sein Singleton im Tomcat nicht einamlig in der JVM vorhanden war. Die Lösung war wohl, dass er zwei verschiedene Classloader benutzte und daher zwei verschiedene Instanzen.

Ein anderes Problem seines Codes war aber ganz anderer Natur. Der Code sah etwa so aus:

public class Singleton {
    private static Singleton instance = new Singleton();
    private static int counter = 0;

    private Singleton() {
         System.out.println("Counter: " + (++counter));
    }

    public static getInstance() {
        return instance;
    }

    public int getCounter() {
        return counter;
    }
}

Auf den ersten Blick sieht das in Ordnung aus. Der Konstruktor gibt brav ein "Counter: 1" aus und man ahnt nichts böses. Bis dann ein kleiner Testfall mit jUnit aufkreuzt:

public class SingletonTest extends TestCase {
     public void testSingletonCounter() {
          Singleton instance = Singleton.getInstance();
          assertEquals(instance.getCounter(), 1,
              "Es kann nur einen geben");
     }
}

Hier wird dann plötzlich klar, dass intern der counter trotz anderweitiger Ausgabe wieder auf 0 gesetzt wurde. Das liegt daran, dass die Initialisierung der statischen Klassenvariablen der Reihe nach geschieht. Im Konstruktor ist counter also erstmal nicht definiert – implizit also null – und wird dann auf eins inkrementiert. Nach dem Konstruktor wird dann die vermeintlich noch nicht initialsierte Variable auf 0 gesetzt.

Das kann ganz schön ins Auge gehen.

Kategorien
Allgemein

Schick und schmerzhaft

Die neuen metallenen Tastaturen für die iMac’s sehen schön aus, aber anfassen darf man sie nicht.

Denn dann gibt es einen auf die Finger. Sven hatte mir von seinen Kollegen erzählt, dass die immer einen gewischt bekommen, sobald sie sich an die Tastatur ihres iMac setzen.

Heute habe ich das in der Stadt auch ausprobiert und – zack – der Funken sprang über. Tolles Design.

Kategorien
Allgemein

Hohe Hürden für wahre Helden

Ich kann die armen PHP Programmierer nur bedauern. Das schreiben von einfachen Anwendungen mit PHP soll ja recht einfach sein, aber wehe es gibt einen Fehler. Das Debuggen von PHP Programmen ist nicht einfach.

Aus dem Grunde werden wohl die meisten PHP Anwender das Debuggen per echo oder var_dump anwenden. Wenn das aber nicht mehr ausreicht, so muss doch ein echter Debugger her. Da gibt es mehrere in der OpenSource Welt.

Ausprobiert habe ich XDebug und DBG.

DBG war als erstes an der Reihe. Nachdem ich das Modul nach Anleitung kompiliert und installiert hatte, dauerte es auch nur noch einen halben Tag, bis ich mich mit PHPEclipse mit dem Debugging anfangen konnte. DBG kann sich pro Anfrage per Parameter auf einen anderen entfernten Debugger einlassen. Was von Vorteil ist, wenn mehrere Entwickler mit einem Webserver arbeiten. Leider habe ich es nicht hinbekommen, dass auch jede Anfrage an den Debugger weitergeleitet wurde. Alles in allem, keine schöne Erfahrung.

Danach habe ich noch XDebug ausprobiert, da es von der pdt Erweiterung des Eclipse-Projektes genutzt werden kann. Mit der von DBG gewonnenen Erfahrung bin ich schon viel schneller zum Debuggen gekommen. Aber anscheinend geht XDebug davon aus, das immer nur ein Entwickler debuggen will. Denn das PHP Modul verbindet sich immer mit einem bei Apache Start voreingestellten Host und Port. Dafür zeigte sich der Debugger etwas stabiler als DBG. Als nettes Beiwerk verändert XDebug die Ausgabe von var_dump und den Fehlermeldungen von PHP. Auch ist ein einfacher Profiler einschaltbar, dessen Ergebnisse mit kcachegrind auswertbar sind. (DBG soll auch einen Profiler enthalten, aber die Doku ist quasi nicht vorhanden.)

Alles in allem: Arme PHP Entwickler.

Kategorien
Allgemein

XML-RPC und Zope mit Ümläüten

In Vorbereitung auf den WS-Vortrag von Jörg, wollte ich eine einfache Zope Methode per XML-RPC nutzen. Und wieder einmal kam mir das Character-encoding dazwischen.

Das Problem bei dem XML-RPC Aufruf war die fehlende Kodierungsangabe in der XML Deklaration den Zope für die Antwort automatisch generiert. Fehlt aber keine Kodierung wird bei XML Dokumenten von UTF-8 ausgegangen. Wie ich bei den JSP Seiten schon erwähnt hatte.

Da Zope aber anscheinend gar nicht wusste, dass meine String-Antworten Umlaute enthielten und sie auch nicht als Unicode-Strings vorlagen, hat es sie auch nicht als UTF-8 kodierte Strings in die XML-RPC Antwort eingebettet. Glücklicherweise wusste ich sowohl die Kodierung der Strings in meiner Methode und auch, wie ich sie in Unicode-Strings umwandele:

unicode_string = unicode(alter_string, 'iso-8859-1')

Kaum war diese Umwandelung aktiv, funktionierte die Anfrage auch von meinem XML-RPC Client heraus.

Nun kann Jörg also loslegen.