© Shahjehan/Shutterstock.com
Teil 1: Mean Value Analysis

Pimp your Application


Oft sieht sich die Softwareentwicklung mit Fragen konfrontiert: Was passiert, wenn wir die Anwendung erweitern? Wie viel mehr an Ressourcen, z. B. CPU, brauchen wir, wenn wir einen neuen Use Case implementieren? Einfach nur die zu erwartende Auslastung der CPU zu addieren, führt oft nicht zum Ziel oder gar in die Irre.

Oft zählt der Ressourcenbedarf zu den Unbekannten eines neuen Use Case. Zusätzlich fällt das Verhältnis I/O-Bedarf zu CPU-Bedarf ins Gewicht. Ein sehr prominentes und irritierendes Beispiel ist, dass I/O-lastige Programme unter bestimmten, vermeintlich besseren Bedingungen von der CPU verdrängt werden können. Diese laufen möglicherweise mit der neuen und schnelleren CPU wesentlich langsamer als zuvor [1]. Wir wollen daher einen Weg aufzeigen, wie der Softwareentwickler an viele solcher Fragestellungen methodisch herangehen und diese mit der Mean Value Analysis (MVA) untersuchen kann.

Unser grundlegendes Problem besteht darin, dass wir einen Verbund von Rechnern haben, über den verschiedene Auftragsströme fließen. Dieses Szenario ähnelt einem Optimierungsproblem einer Produktionsstraße oder einer Supply Chain in einem Logistikverbund. Probleme dieser Art erinnern an eine elektronische Schaltung mit verschiedenen Baugruppen (engl. device). Unsere Baugruppen sind Rechner in den einzelnen Hardware- bzw. Software-Tiers. Rechner werden aus Sicherheitsgründen über Web- oder Datenbank-Tier sowie Batch- und Applikation-Tier verteilt. Möglicherweise handelt es sich auch um Reliability-Gründe über mehrere Brandabschnitte oder Rechenzentrumsgrenzen hinweg. Router und Switches, allgemein das Netz, lassen sich als weitere Baugruppen verstehen. Die Performance wird von den langsamen Komponenten bestimmt. Ist Komponente X zehnmal langsamer als Komponente Y, macht es sicherlich keinen Sinn, Komponente Y mithilfe eines Profilers zu optimieren.

Mikrobenchmarks, Untersuchungen mit Profilern oder Code zu instrumentalisieren, liefert Einblick in das Laufzeitverhalten der einzelnen Prozesse oder Programmkomponenten. Diese Informationen nutzen wir. Oft adressieren sie das Problem aber nicht auf der richtigen Flughöhe. Mehrere Auftragsströme von verschiedenen Programmen können sich zu einem Bottleneck addieren und lassen sich nicht durch bloße Analyse des Codes aufspüren. Um die Ursache des Bottlenecks, die verursachenden Programmteile bzw. die Baugruppe einzugrenzen, sollten wir die Analyse auf der makroskopischen Ebene (Applikationsebene bzw. Applikationsverbundebene) beginnen. Ebenso wichtig ist bei Performancebetrachtungen, dass der Entwickler nicht blind einer Methode folgt, sondern dass er auch deren Grenzen kennt und sie berücksichtigt. Kein Tool und keine Methode stellt ein Patentrezept oder eine Silver Bullet zur Verfügung. Wir erläutern diese makroskopischen Betrachtungen am besten an Beispielen, denn wie Mephistopheles schon wusste: „Grau, teurer Freund, ist alle Theorie“ [2].

Eine einfache Anwendung

„Mir wird von alledem so dumm, // als ging mir ein Mühlrad im Kopf herum.“ [2]

Nicht nur, dass es uns bei Performanceproblemen am Anfang genauso geht wie dem Studenten im Faust, der obigen Ausspruch macht. Sondern auch einem Mühlrad gleich laufen die Verarbeitungsaufträge unserer Applikation immer im Kreis durch ein sogenanntes geschlossenes Queueing-Netzwerk. Wie so ein Netzwerk aus Sicht der Performanceanalyse aussehen kann, ist schematisch in Abbildung 1 skizziert. Wir haben drei Server im Application bzw. Batch Tier und eine gemeinsame Datenbank. Wir lesen unsere Aufträge aus der Datenbank und schicken den nächsten Auftrag sofort ab, sobald der vorherige fertiggestellt ist. In diesem geschlossenen Stromkreislauf ist daher nur ein infiniter Server (Dummy IS in Abb. 1) mit einer Denkzeit möglicher User Z = 0 s eingezeichnet. Aber im Fall einer Batchanwendung sitzen ja keine Nutzer als Lastgeneratoren mit einem Browser am Rechner. Es fließen drei unterschiedliche Ströme von Aufträgen Xjc (X1, X2 sowie X3) innerhalb des Netzwerks. Der Mail-Server generiert den Mail-Strom X1, der sich aus den einzelnen Mails zusammensetzt, die wir als jeweils einen Auftrag auffassen (hier X1 = <Mails>/<Zeit>, Einheit: 1 Ms). X2 und X3 werden von zwei verschiedenen Batchservern erzeugt, die beispielsweise neue Daten in die Datenbank laden. Diese Ströme bilden einen Gesamtstrom aus X1, X2 und X3 bei den Zugriffen auf die Datenbank und belasten kumulierend das Netz. Diese Ströme sind wie oben beschrieben unterschiedlich, da sie unterschiedliche Ressourcenanforderungen an die Baugruppen stellen. Daher werden diese unterschiedlichen Ströme Xjc, Servicezeiten Sjc usw. formal mit der Auftragsklasse jc (engl. job class) indiziert.

Dieses Modell wollen wir im Laufe des Artikels mit unterschiedlichen Lösungsansätzen diskutieren und uns einen physikalischen Einblick verschaffen, der über die reine Mathematik hinausgeht. Wir brauchen für die Arbeit einfache physikalische Bilder, die die Realität erklären, und einfache Lösungsmöglichkeiten für ein Problem. Den genauen Effekt zu berechnen, ist eigentlich nur nebensächlich und nicht exakt machbar. Noch eine Bemerkung: Die mit JMT (Java Modelling Tool [3]) gezeichnete Abbildung 1 zeigt die logische Sicht auf unsere Beispielanwendung, um eine verständliche Darstellung zu haben. Bei einer Simulation mit JMT muss man diese in der grafischen Eingabekomponente JSIMgraph noch etwas topologisch umformen.

kuhn_mva_1.tif_fmt1.jpgAbb. 1: Logischer Netzwerkplan unserer Beispielapplikation
...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang