Man unterscheidet bei Programmen allgemein, zumeist aber sind Serverdienste (Dämonen) gemeint, zwischen drei Hauptvarianten im Design. Das älteste Modell ist fork(). Hierbei erzeugt der Hauptprozess bei jedem weiteren Zugriff eines Clients z.B. über das Netzwerk - eine Kopie von sich selber. Hierzu wird eine komplette Kopie des Programms im RAM erzeugt, welches eigenstängig Speicher zugeordnet bekommt. Bei einem DoS (denial of service) Angriff z.B. mit dem Apache Webserver beiliegenden Benchmark - Programm "ab", konnte leicht durch zigtausende Netzwerkverbindungen der Server zum Swappen (auslagern von Prozessen auf Festplatte) gebracht werden.
Threads sind im Prinzip eigenständige Prozesse (#ps -lawm), die jedoch mit dem Hauptprozess sich den Speicher gemeinsam teilen (shared memory. Threads und ihre Zustände im RAM kann man sich in der Shell mit "#ps -lawm" anschauen. Insbesondere die Spalte WCHAN gibt darüber Auskuft, wie ein Programm arbeitet, wie es programmiert wurde (poll, epoll, ...). Threads sind viel schneller zu erzeugen, als neue Prozesse mit fork(). Der Vorteil von Threads ist, daß sie z.B. Daten vom Hauptprozess an einen Interpreter übergeben können (PHP, PERL, PYTHON, JAVA), ohne die Daten kopieren zu müssen, oder via IPC (Inter Process Communication) als Datenstom übergeben müssen. Dank moderner Abschnitt 7.9 wird hierzu kein echtes RAM mehr verwendet, sondern das Binary wird von der MMU auf zwei oder mehr Prozesse aufgeteilt, also wiederverwendet. Jeder TCP/IP Verbindung wird dann ein Thread zugeordnet (altes Modell). Neuere Designs von Servern, wie z.B. der Apache 2.0+ (Prefork-Multithread-Modell) öffnen schon beim Start mehrere Prozesse und Threads, um die Last direkt verteilen zu können, nicht erst bei auftreten der Last (mod_perl, mod_php, ...).
Noch moderner sind singe threaded Daemonen. Hier verwaltet ein Prozess alle Anfragen. Je Anfrage wird zwar Stack und Heap verbraucht, jedoch wird das Binary stets wiederverwendet. Der Nachteil liegt auf der Hand. Ein einziges Memory - Leak (der Prozess frisst langsam Speicher auf) sorgt dafür, daß der Server ständig neu beendet und gestartet werden muß. Bei Webservern und Webhosting ist dieses Modell daher nicht so zuverlässig.., siehe auch Abschnitt 7.13. Die Frage ist auch, in wiefern single threaded Dienste / Daemonen von mehreren Prozessoren bzw. Hyperthreading profitieren - garnicht. Es sei denn, daß diese Unteraufgaben an Kernel - Threads abgeben, z.B. die Interpretation von ASP/PHP Skripten oder z.B. COM - Objekte beim Microsoft IIS Server, die nicht multi threaded programmiert wurden.
Desweiteren unterscheidet man noch zwischen drei verschiedenen Varianten von Threads: Kernel - Threads (1:1) - alle (auch von User - Prozessen) erzeugten Threads laufen auf Kernel - Ebene ab. Hierzu wird der Adressraum des dem Kernel zugewiesenen RAM verwendet. Bei 32 Bit Betriebesystemen, die generell nur 4 GByte insgesamt Adressieren können (2^32 Bits), ist RAM für Anwendungen, user space genannt, und Linux Kernel, kernel space genannt, aufgeteilt split memory. Je nach Linux Distribution gibt es eine andere Aufteilung (3/1, 2/2), insbesondere bei SLES8/9, Redhat 2.1/3.0, cAos 2.1/3.0/3.3, sodaß evtl. Prozesse nicht mehr als 2 GByte RAM nutzen können, obwohl viel mehr RAM existiert. IBM hat daher einen Software Patch (PAE) für Linux herausgebracht, mit welchem dem damaligen EMS386 System für DOS bis zu 8/16/64 GByte adressierbar sind, mit z.B. einem 4/4GByte memory split. Mehr hierzu, siehe Kapitel 26
Dann gibt es das Modell, wo 1 Kernel Threads N User - Threads zugeordnet bekommt (1:N) und noch das viel flexiblere Modell, daß M Kernel - Threads N User - Threads zugeordnet werden (M:N). Die von IBM und RedHat neu in Linux Kernel 2.6 eingeführte Native Posix Threading Library ist eine M:N - Implementierung, siehe auch NTPL Design. Hiermit können ab Kernel 2.6 100.000 Threads in 2 Sekunden erzeugt werden, anstelle von 15 Minuten bei Kernel 2.4.x - eine gewaltige Verbesserung. Leider nur mußten hierzu unzählige Server - Dämonen unter Linux abgepasst werden. Die unbedingt erforderlichen Anpassungen im Code von Anbietern kommerzieller Software, insbesondere Datenbanken, steht also noch bevor. Die RedHat - Distribution ist hier führend, und die erste gewesen, die die NPTL eingeführt hat. Inzwischen ist sie fester Bestandteil der GNU LIBC, der Standard - C-Library.
So passierte es z.B. beim Apache Webserver 1.2 und 1.3, daß ein User ein PHP - Skript ausführen konnte, ein anderer User hierdurch blockiert wurde, weil der PHP Interpreter nur 1 Programm gleichzeitig ausführen konnte. Insbesondere Bei längeren Uploads via CGI "POST" oder "PUT" war der Server (ohne Last anzuzeigen) blockiert. Die Ursache lag aber auch im Fehlen von anderen Features im Kernel, wie Abschnitt 7.10. Ein weiteres Negativbeispiel ist MySQL. MySQL ist ein multi threaded - Server, welcher bei vielen, gleichzeitigen Zugriffen über Netzwerk völlig zusammenbricht, hängt, siehe Abschnitt 11.6 und ReiserFS, welches ähnliche Probleme zeigt: Abschnitt 7.19.3.
Tatsache ist, daß Linux Kernel 2.4 für Server - und Datenbankanwendungen mit vielen, gleichzeitigen Netzwerkzugriffen, vielen Threads und Prozessen völlig unbrauchbar war. Erst Kernel 2.6 arbeitet auch bei hoher Last noch zuverlässig und flink. Die Zahl der Threads je Prozess ist bei Linux begrenzt, mehr hierzu siehe Abschnitt 7.12. Zur Programmierung von Threads in C/C++, siehe Advanced Linux Programming - Threads.
| Zurück | Inhaltsangabe | Weiter |
| Nach oben | Stack/Heap/RAM-Verbrauch limitieren |