Performance Tipps zu Web Services
20.09.2009 Permalink Kommunikation über SOAP ist große Mode geworden, nicht zuletzt, da jede bedeutende Technologieplattform einen mehr oder minder ausgereiften SOAP-Stack bereithält. Nun ist SOAP fix auf XML gebunden, besser gesagt: auf das XML Infoset. Und auch REST, mit dem wegen seines einfachen Grundprinzips so mancher liebäugelt, kommt praktisch nicht ohne XML aus, obwohl beliebige Formate zulässig sind.Das Verarbeiten von XML ist teuer, Remote Kommunikation ist sowieso teuer, aber wir nehmen das in Kauf. Es ist für betriebliche Informationssysteme üblich, sparsamen Umgang mit Rechenzeit und Speicher zugunsten von Interoperabilität, Portabilität und Wartbarkeit entweder zu opfern oder mit mehr "Blech" zu ersetzen. Auch wenn Techniker gerne das Gesicht verziehen, angesichts anhaltend hoher Personalkosten und stetig fallender Preise pro Taktzyklus und Speichereinheit macht das Sinn.
Manch ein Projektteam treibt das sorglose Spiel aber zu weit. Es entsteht Software, von der maßgeblich der Eindruck bleibt, dass sie nicht lasttauglich oder zu langsam ist und schlecht skaliert. Die ersten beiden Fragen, die ich stelle, wenn ich mir eine Meinung in einem solchen Fall bilden will, sind:
- Wie sieht das Kommunikationsverhalten zwischen den Teilsystemen aus?
- Wie sehen die Zugriffe auf Datenbanken aus?
Zur ersten Frage treibt mich immer das folgende Bild, das die Aufrufzeiten für verschiedene Technologien vergleicht:
Man erkennt, dass ein Nachrichtenversand über das Netzwerk verglichen mit lokalen Methodenaufrufen extrem teuer ist, und solange wir in einem System davon unnötig viele haben, brauchen wir nicht weiter nach Optimierungsmöglichkeiten zu suchen. Durch Reduktion der Anzahl können wir ein gewaltiges Potential ausschöpfen. Abgesehen davon, dass diese Maßnahme meist aufwändig ist, weil sie verlangt, die beteiligte Software stark zu verändern, ist die Idee trivial, und hat insbesondere mit Web Services und XML nicht viel zu tun. Wo können wir aber speziell bei Web Services ansetzen, wenn diese erste Maßnahme noch nicht reicht?
Hier meine zweitbesten Ideen:
HTTP 1.1 und Keep-Alive verwenden
Der TCP Verbindungsaufbau selbst kostet bei jedem Austausch Zeit, die enorm
ansteigt, wenn z.B. SSL/TLS
im Spiel ist, denn zur Aushandlung des symmetrischen Sitzungsschlüssels ist
asymmetrische Kryptographie erforderlich. Durch Keep-Alive, das bei HTTP 1.1 default
ist, kann man die Häufigkeit der Aushandlung reduzieren.
Schemavalidierung in Produktion abschalten
Während Integrationsstests ist Schemavalidierung hilfreich, um die
Übereinstimmung der versendeten Nachrichten mit den Angaben aus den
Schnittstellenspezifikation festzustellen. Ist ein System aber getestet, so
bringt die Validierung auf den meisten Kommunikationsstrecken keinen Wert
mehr. Da sie teuer ist, kann man sie auch abschalten.
Kompression bei Kapazitätsproblemen Ist Netzwerkkapazität ein Flaschenhals, dann können sich die beteiligten Teilsysteme auf GZip Kompression und/oder Fast Infoset einigen, was sich vor allem bei großen Nachrichten deutlich auswirkt. Die Kompression benötigt natürlich mehr Rechenzeit, das muss man dann abwägen.
Teildekodierung von Nachrichten
Gerade bei Diensten, die im wesentlichen als Router fungieren, ist eine
vollständige Deserialisierung großer XML Nachrichten nur teurer Luxus. Um
inhaltsbasiert Entscheidungen zu treffen, reichen XPath Anfragen auf der nackten XML
Nachricht.
MTOM für umfangreiche Binärdaten
Binärdaten in Base64 sind
zwar in XML zulässig, aber bei Mengen über 100K eine ziemliche Belastung für
XML Parser. MTOM verwendet das
MIME Multipart Verfahren, um
die Binärdaten aus XML auszulagern, ohne dass die Anwendung diese Zerlegung
merkt.
Einsatz von WS-Security überdenken
Die Signaturberechnung und Verschlüsselung bei WS-Security verwendet
asymmetrische Verfahren, die rechenintensiv sind. Gerade Verschlüsselung kann
man auch durch SSL/TLS erreichen. Oder man richtet durch Firewalls oder VPN
Vertrauenszonen ein, in denen keine Sicherheitsmaßnahmen auf dem Application
Layer mehr erforderlich sind.
Einsatz von Reliable Messaging überdenken
Fragt man den unbedarften Anwender, dann darf natürlich keine einzige
Nachricht verloren gehen, die Kommunikation muss jederzeit vollständig
zuverlässig sein. Folgt man diesem hehren Ziel, dann zwingt das zum Einsatz
von Messaging Lösungen, die jede Nachricht transaktionsgesichert auf einen
Plattenspeicher schreiben. Das ist zwar sicher, aber eben auch teuer. Was
kostet es tatsächlich, wenn bestimmte Nachrichten verloren gehen?
Ganz gleich, was wir am Ende umsetzen, es ist entscheidend, Performanceprobleme früh zu entdecken, denn gerade eine Restrukturierung von Teilsystemen, so dass weniger Aufrufe stattfinden, will man nicht erst nach einem Integrationstest beginnen. Frühes Entdecken gelingt, wenn man
- so früh wie möglich zwei oder mehr Teilsysteme auf eigener Hardware unter Last bringt und den Durchsatz beobachtet (z.B. mit JMeter), und dies bzgl. Mengengerüste und Anforderungen an die Antwortzeiten bewertet,
- Messpunkte definiert und Werte in Monitoren sammelt und ausgibt, um herauszufinden, wo die Zeit verbraucht wird,
- im Zweifel verschiedene Optimierungsideen ausprobiert, um die Wirksamkeit einschätzen zu können. Da lernt man dann, welchen Spielraum man im Falle eines Falles noch hat.