JPA Dependency Injection mit Jersey in JEE Containern

Ziel des Posts ist es eine Webanwendung soweit aufzuwerten, dass sie mittels Dependency Injection auf Entitiymanager zugreifen kann, die durch den Container verwaltet werden.

@PersistenceContext(unitName = "test")
EntityManager em;

Die wichtigsten Punkte zusammengefasst

Auf Seiten von JPA wird die Datenbankverbindung durch die Java Transaction Api (JTA) übernommen. Dies wird in der persistence.xml Datei durch folgenden Eintrag erreicht:

<persistence-unit name="test" transaction-type="JTA">
<jta-data-source>jdbc/TestConnection</jta-data-source>
...
</persistence-unit>

die JTA Data Source wird anschließend im Container definiert. In Glassfish kann das im Adminpanel gemacht werden und ist 1 sehr ausführlich am Beispiel MySQL beschrieben.

Um nun eine erfolgreiche Dependency Injection für den EntityManager zu erreichen muss der EJB Container wissen, dass er dies überhaupt tun soll. Am Beispiel einer Jersey REST Page sieht man deutlich wie dies umgesetzt wird.

@Stateless
@Path("/user/{id: [0-9]+}")
public class UserOverview {

Im wesentlich war es das schon. Ohne die @Stateless-Annotation endet eine Anfrage an den EntityManager mit einer NullPointerException.

Ich habe mich bewusst kurz gehalten, um im wesentlich nur eine Unterstützung für meine eignene Aufzeichnungen zu liefern. Für weitergehende Fragen kann ich auf Wunsch gerne eingehen, sofern Bedarf vorhanden ist.

Nginx – Eine neue Liebe

Nach dem Umzug auf Ubuntu kam ich auf die Idee mal wieder zu schauen wie die Performance des vServers so ist.

Vor der Optimierung

Ein geeigner Lasttest ist im Inernet schnell gefunden 1. Er ist kostenlos und simuliert in 10er-Schritten die Auslastung bis zu 50 Usern gleichzeitg. Vor der Optimierung mit einer Standard Apache2 Installation sah das Ergebnis sehr schlimm aus:

Was sehen wir in dem Graphen?

Nun zunächst fällt einem die wunderbare exponentielle Kurve ins Auge. Wir sehen auf der x-Achse die Anzahl der Clients sowie auf der y-Achse die Antwortzeit des Servers. Um es gleich zu sagen: dies ist eine Beispielkurve. In Realität sah meine Kurve genauso aus, ich habe den Test allerdings bei 40 Usern abgebrochen, weil mein Server merklich den Geist aufgab. Das Problem das wir dort sehen ist auf die Leistungsbegrenzung des Systems zurückzuführen 2. Wie ich festellen musste war es vor allem die CPU Auslastung, welche durch Apache 2 hervorgerufen wurde, die dem System zuschaffen machte. Ich hab absichtlich eine Seite mit vielen Bildern und Informationen gewählt, welche auch in PHP Rechenleistung in Anspruch nimmt.

Wie kann man das System optimieren?

Um das System zu optimieren müssen wir uns überlegen wo die Probleme entstehen: Apache startet für jeden Request einen Prozess der nicht besonders Ressourcenschonend ist. Ziel ist also alle unwichtigen Anfragen (alles außer php Requests) vorher abzufangen und nicht an Apache weiterzugeben. Hierfür eignet sich besonders gut Nginx 3. Nginx wird als Reverse Proxy vor Apache betrieben und fängt eingehende Anfragen ab. Dort werden die Anfragen nach statischen und dynamischen Anfragen sortiert. Statische Anfragen werden direkt von Nginx bearbeitet und nehmen somit nur die Rechenleistung von Nginx in Anspruch. Nginx ist sehr schlank programmiert und genau auf dieses Szenario ausgelegt. Dynamische Anfragen wie PHP Seiten werden von Nginx an Apache per Proxy Request weitergeleitet und dort bearbeitet. Das Ergebnis wird von Nginx empfangen und an den Besucher der Webseite ausgeliefert. Zusätzlich komprimiert Nginx die Anfrage und verringert somit das aufkommende Datenvolumen.

Nach der Optimierung


Für alle die jetzt noch meckern wollen: Mir ist klar, dass der erste Graph deutlich mehr Connections verzeichnet – lasst euch gesagt sein, bei mir der Graph bereits nach 40 Connections so aus. Leider habe ich das Bild nicht gespeichert und habe deswegen auf das Bild aus der Dokumentation zurückgefriffen. Trotzdem denke ich, sprechen die Daten für sich.

Was bleibt zu tun?

Nun, zunächst einmal freue ich mich, dass das funktioniert hat. Bei Interesse werde ich nochmal im Detail auf die notwendige Konfiguration eingehen und einen ausführlichen Post verfassen, wie man Nginx zähmt. Des weiteren gibt es nun noch die Möglichkeit zwischen Nginx und Apache einen Cache einzupflegen, der schaut ob man überhaupt eine neue Berechnung der PHP Seite braucht oder ob sich das Ergebnis in den letzten Minuten überhaupt nicht verändert hat. Hierfür bietet sich Varnish an 4. Sollte ich die Zeit dafür finden werde ich ihn umgehend ausprobieren.

Linux Shell Batch Power

Nur um mal ein wenig aktivität auf dieser Seite zu verzeichnen und um auch mir eine kleine Gedankenstütze zu bauen poste ich ein kleines Bash Snippet, welches mir innerhalb von 4 Minuten 4009 JPG Dateien verlustfrei optimiert hat. Der Speicherplatz wurde um sage und schreibe 10% verringert – und um es nochmal zu wiederholen: Verlustfrei!

find ./images/ -name *.jpg -exec jpegoptim –strip-all {} \;

Warum macht man das? Nun, Stefan und ich arbeiten an einem Projekt welches sich hauptsächlich mit Mediendateien beschäftigt. Die Optimierung der Dateien für die Verarbeitung durch einen Webserver reduziert/löst einige Performanceprobleme, welche auf High-Traffic-Seiten auftreten können.

Sobald wir einen Namen für unser Projekt gefunden haben und die Domain geschaltet ist werden weitere Optimierungen Folgen. Bei Gelegenheit werde ich sie hier zur Verfügung stellen.

Server wechsel dich zurück

Wie ich vor einigen Monaten schrieb kam ich auf die glorreiche Idee von Ubuntu zu openSuse zu wechseln. Eigentlich hatte ich bereits von Anfang an ein schlechtes gewissen… SuSe 7.1 war das erste Linux, mit dem ich in Berührung kam. Direkt mit KDE fingen aber die Probleme an – hab ich schon erwähnt, dass ich Linux eigentlich nur Headless mag? Gnome konnte mich immerhin bei Ubuntu begeistern so dass ich damit mitlerweile sehr gerne Arbeite. Damals wie heute kam ich mit Yast überhaupt nicht zurecht. Ich glaube entweder man mag es, oder man mag es nicht – ich kenne niemanden der Yast und Apt-Get mag. Immerhin habe  ich es geschafft, das mein Server 2 Monate stabil unter openSuse lief.

Doch dann kam es leider zu einem sehr unfreudigen Zwischenfall. Wer daran Schuld ist kann ich bis heute nicht nachvollziehen. Die Sicherheitslücke in 1 wurde bereits Anfang November gefixed und findet ja normalerweise schnell die Wege ins Yast. Die Tatsache das Strato (ja, ich weiß) einen eigenen Mirror vorhällt um Traffic zu sparen ist eigentlich auch kein Problem. Wie der Name schon sagt sind Mirrors ja mit der entsprechenden Verzögerung Up-2-Date. Tatsache war auf jeden Fall, dass das Sicherheitsupdate auf meinem System (und scheinbar auch auf vielen anderen) nicht eingespielt wurde. Entsprechende Email seitens Strato lies nicht lange auf sich warten in der ich darauf hingewiesen wurde, dass mein Server Portscanning und DOS Angriffe betreibt (Und alle so: Yeah!). Die Email enthielt das übliche Säbel rasseln und ein paar lächerliche Tipps (Neuinstallation…).

Anbei einige Ideen wie man kompromitierte Server wieder unter die eigene Kontrolle bringt:

  • root Passwort ändern
  • Unnötige Accounts deaktivieren
  • ProFTPd updaten oder am besten gleich deinstallieren (Achtung: dabei deinstalliert man unter SuSe auch Plesk)
  • Plesk deinstallieren (sollte man so oder so machen) In allen aktivierten user accounts mit SSH Zugang den Ordner .ssh untersuchen und die registrierten Keys prüfen – zur Not alle Keys löschen und den eigenen neu registrieren
  • zum Schluss: root Passwort ändern

Gerade für das angesprochene Problem ist das meist schon alles was man tun muss – bei mir musste ich nur den root Account von ssh Keys bereinigen und der Server lief wieder sicher. Interessant war nur, dass ca. 2 Wochen nachdem ich befallen wurde eine allgemeine Email an Strato Kunden herausgegangen ist, in der einige “Tipps” standen zum erkennen von Rootkits. Die Email von Strato war des weiteren nicht besonders hilfreich 2. Naja, die Sicherheitslücke wurde mitlerweile geschlossen indem und ich habe mich nach weiteren 4 Wochen auf SuSe dazu entschlossen wieder zu Ubuntu LTS zurück zu wechseln. Strato verbietet leider jede Form von BSD – dafür ist der VHOST sehr günstig und sehr zuverlässig.

Server wechsel dich

Leider läuft nicht immer alles so wie man es sich wünscht, und deswegen war ich gezwungen mein Ubuntu 8.04 LTS gegen einen aktuellen openSUSE einzutauschen. Wie schwer einem der Umstieg von einem Debian mit apt-get zu einem .rpm basierten System fällt ist mir erst richtig aufgefallen, als es zu spät war ;) Sobald ich meine Finger an Ubuntu 10 LTS bekomme werde ich wieder zurück in das heimische Ökosystem gehen.
Immerhin konnte ich die Downtime auf ein Minimum reduzieren und alles ist soweit wieder am laufen – von ein paar Kleinigkeiten einmal abgesehen ;) Wem Fehler auffallen, der darf sich gerne bei mir melden und ich schau was sich machen lässt…

SVN in Eclipse mit Subclipse unter Ubuntu 10.04

Ich habe die Tage mit Ubuntu so meine Probleme gehabt. Nachdem man die Eclipse Version im Repo aufgrund der mangelnden Aktualität nicht wählen sollte habe ich versucht Subclipse mit JavaHL zum laufen zu bringen. Die Installation aus dem Subclipse Eclipse Repo erfolgt ohne Probleme, aber beim Zugriff auf die SVN Einstellungen wird man immer wieder mit dieser Meldung konfronitert:

Failed to load JavaHL Library.
These are the errors that were encountered:
no libsvnjavahl-1 in java.library.path
no svnjavahl-1 in java.library.path
no svnjavahl in java.library.path
java.library.path = /usr/lib/jvm/java-6-sun-1.6.0.03/jre/lib/i386/client::/
usr/lib/jvm/java-6-sun-1.6.0.03/jre/lib/i386::/usr/lib/firefox:/usr/lib/
firefox/:/usr/java/packages/lib/i386:/lib:/usr/lib

Das einfachste um diesen Fehler zu vermeiden ist der Wechsel von JavaHL auf SVNKit (Pure Java). Sollte man wie ich aber auf JavaHL angewiesen sein haben sich folgende Schritte als hilfreich erwiesen.

Installation und Konfiguration

Die Installation der nötigen Pakete erfolgt per apt-get unter Ubuntu (man kann auch aptitude verwenden – soltle man sogar). libsvn-java enthällt die nötige libsvnjavahl und legt sie unter /usr/lib/jni ab.

sudo  apt-get install libsvn-java

Hat man Eclipse aus dem Repo installiert so findet Eclipse beim Neustart die entsprechende Bibliothek und der Fehler gehört der Vergangenheit an. Hat man Eclipse selbst installiert, da man die neueste Version – Bleeding Edge sozusagen – nutzen will, dann muss man Eclipse noch mitteilen, wo es die Bibliothek findet. In die Datei ~/.eclipse/eclipserc trägt man folgende Zeile ein:

VMARGS="-Djava.library.path=/usr/lib/jni"

Nach einem Neustart sollte der Fehler ebenfalls der Vergangenheit angehören. Viel Spaß!