<?xml version="1.0"?>
<!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.de.xsl"?>
<modulesynopsis metafile="mod_unique_id.xml.meta">
<name>mod_unique_id</name>
<description>Stellt eine Umgebungsvariable mit einer eindeutigen Bezeichnung
für jede Anfrage zur Verfügung.</description>
<status>Erweiterung</status>
<sourcefile>mod_unique_id.c</sourcefile>
<identifier>unique_id_module</identifier>
<summary>
<p>Dieses Modul stellt eine Umgebungsvariable mit einer
Bezeichnung für jede Anfrage zur Verfügung, die unter bestimmten
Bedingungen für jede Anfrage eindeutig ist. Diese Bezeichnung
ist auch für unterschiedliche Rechner eines entsprechend konfiguierten
Cluster eindeutig. Die Umgebungsvariable <code>UNIQUE_ID</code>
wird für jede Anfrage gesetzt. Eindeutige Bezeichnungen sind für
verschiedene Zwecke nützlich, deren Beschreibung den Rahmen dieses
Dokuments sprengen würde.</p>
</summary>
<section id="theory">
<title>Hintergrund</title>
<p>Beginnen wir mit einer kurzen Zusammenfassung der Funktionsweise des
Apache-Servers unter Unix funktioniert. (Unter Windows NT wird dieses
Modul nicht unterstützt.) Auf Unix-Rechnern erzeugt der Apache mehrere
Kindprozesse, von denen jeder (die ihm zugeteilten) Anforderungen
nacheinander abarbeitet. Jeder Kindprozess kann
während seiner Lebensdauer mehrere Anfragen bedienen. Im Zusammenhang
dieser Erläuterung wird davon ausgegangen, dass die Kindprozesse keine
Daten gemeinsam nutzen. Sie werden als HTTPD-Prozesse bezeichnet.</p>
<p>Die Website operiert mit einem oder mehreren Rechnern, die in
ihrer Gesamtheit als Cluster bezeichnet werden. Jeder Rechner kann mehrere
Apache-Instanzen ausführen, die hier in ihrer Gesamtheit als
"Universum" bezeichnet werden. Wir werden nachweisen, daß es unter
bestimmten Voraussetzungen in diesem Universum möglich ist, eindeutige
Bezeichnungen für jede Anfrage zu erzeugen, ohne dass dafür
eine ausführlichere Kommunikation zwischen den Rechnern des Clusters
erforderlich ist.</p>
<p>Die Rechner des Clusters sollten die folgenden Anforderungen
erfüllen
(selbst wenn nur ein Rechner vorhanden ist, sollte dessen Uhr mit
NTP synchronisiert werden):</p>
<ul>
<li>Die Uhrzeiten der Rechner werden über NTP oder ein anderes
Netzwerkprotokoll synchronisiert.</li>
<li>Die Host-Namen aller beteiligten Rechner unterscheiden sich
voneinander, so
dass das Modul eine Suche nach Host-Namen durchführen kann und
für jeden Rechner des Clusters eine andere IP-Adresse
erhält.</li>
</ul>
<p>Hinsichtlich des Betriebssystems wird davon ausgegangen, dass die
Pids (Prozess-IDs) maximal 32 Bit lang sind. Verwendet das Betriebssystem
mehr als
32 Bit für eine Pid, dann lässt sich der Code leicht anpassen.</p>
<p>Unter diesen Voraussetzungen kann zu einem bestimmten
Zeitpunkt jeder HTTPD-Prozess eines beliebigen Rechners aus dem
Cluster von allen anderen HTTPD-Prozessen unterschieden werden. Hierfür
reichen die IP-Adresse des Rechners und die Pid des HTTPD-Prozesses
aus. Um eindeutige Bezeichnungen für jede Anfrage erzeugen zu
können,
müssen lediglich die verschiedenen Zeitpunkte unterschieden werden.</p>
<p>Für diese Unterscheidung wird ein Unix-Zeitstempel
(die seit dem 1. Januar 1970 (UTC) vergangegenen Sekunden) und ein
16-Bit-Zähler verwendet. Der Zeitstempel hat nur eine Genauigkeit von
einer Sekunde, weshalb der Zähler dafür verwendet wird, bis zu
65.536
verschiedene Werte pro Sekunde darstellen zu können.
Dieses Quadrupel aus <code>ip_addr</code>,
<code>pid</code>, <code>time_stamp</code> und Zähler reicht
aus, um 65.536 Anfragen pro Sekunde und HTTPD-Prozess zu
nummerieren. Die Tatsache, dass die Prozess-IDs im Laufe der
Zeit wiederverwendet werden, wird durch den Zähler
berücksichtigt.</p>
<p>Wird ein HTTPD-Kindprozess erzeugt, dann wird der Zähler mit
dem Restwert der Division der (Anzahl der vergangenen Mikrosekunden
durch 10) dividiert durch 65.536 initialisiert, um Varianzprobleme
mit den niederwertigen Bits des Mikrosekunden-Zeitgebers einiger
Systeme zu vermeiden. Für das Erzeugen einer eindeutigen Bezeichnung
wird der Zeitstempel der Eingangszeit der Anfrage beim Webserver benutzt.
Der Zähler wird beim Erzeugen einer Bezeichnung immer
inkrementiert (und darf überlaufen).</p>
<p>Der Betriebssystemkernel erzeugt beim Aufspalten jedes Prozesses eine Pid
, beider es irgendwann zum Überlauf und damit zur Wiederverwendung der
Pids kommt (bei vielen Unix-Systemen ist sie 16 Bit und bei neueren maximal
32 Bit lang). Erfolgt diese Wiederverwendung jedoch nicht innerhalb der
gleichen Sekunde, wird die Eindeutigkeit des Quadrupels nicht gestört.
Es wird also
davon ausgegangen, dass das System nicht mehr als 65.536 Prozesse
pro Sekunde startet (bei einigen Unix-Systemen können es zwar bis zu
32.768 Prozessen sein, was allerdings sehr unwahrscheinlich ist).</p>
<p>Angenommen, daß aus irgend einem Grund dieselbe Uhrzeit
ein zweites Mal auftritt. Das heißt also, daß der Stand
der Systemuhr ruiniert wurde und sie einen vergangenen
Zeitpunkt noch einmal durchläuft (oder daß sie zu weit
in der Zukunft steht, anschließend auf den korrekten Wert
zurück gesetzt wird und danach den Zeitpunkt in der Zu-
kunft ein zweites Mal erlebt). Für diesen Fall läßt sich leicht
nachweisen,
daß es zu einer Wiederverwendung der Kombination aus Pid
und Uhrzeit kommen kann. Die Wahl des Startwertes für den Zähler soll
dabei helfen, mit dieser Situation fertig zu werden. Beachten Sie, daß wir
eigentlich dringend eine echte Zufallszahl verwenden sollten, um diesen
Zähler
zu initalisieren, die aber bei den meisten Systemen nicht
zur Verfügung steht (insbesondere kann die Funktion <code>rand()</code>
nicht verwendet werden, weil zunächst einmal deren Generator
initialisiert werden müßte - und genau dafür dürfen wir die
Uhrzeit nicht verwenden, weil diese sich ja bereits
wiederholt hat). Diese Lösung ist nicht perfekt.
</p>
<p>Wie gut ist die Lösung? Angenommen ein Rechner bedient
500 Anfragen pro Sekunde (was eine realistische Obergrenze ist, weil Systeme im
Allgemeinen mehr zu tun haben, als einfach nur den Inhalt statischer Dateien
zu versenden).
Hierfür benötigt er eine Reihe von Kindprozessen, deren Zahl von
der Anzahl der konkurrierenden Clients abhängt. Aber wir sind mal
pessimistisch und gehen davon aus, dass bereits ein einzelner Prozess in der
Lage wäre, bis zu 500 Anfragen pro Sekunde zu bedienen. Daraus ergeben
sich 1.000 mögliche Anfangswerte für den Zähler, bei denen zwei
Sequenzen
von je 500 Anfragen einander überlappen würden. Bei einer
Zeitwiederholung und einer Zeitauflösung in Sekunden besteht daher eine
Wahrscheinlichkeit von 1,5 % für eine Wiederholung des Zählerwertes
und
für eine Aufhebung der Eindeutigkeit. Dies ist eine sehr pessimistische
Ausgangssituation, die in der Praxis wahrscheinlich nicht eintreten wird.
Falls Ihr System derartig beschaffen ist, dass diese Wahrscheinlich-
keit Ihnen immer noch zu hoch ist, dann sollten Sie möglicherweise
den Zähler auf 32 Bit verlängern, indem Sie den Modulquellcode
entsprechend anpassen.</p>
<p>Vielleicht sind Sie jetzt besorgt wegen der 'Zurückstellung' Ihrer
Systemuhr bei der Umschaltung auf Sommerzeit. Dies ist jedoch kein
Problem, weil die hier verwendete Zeit die UTC ist, welche immer
vorwärts läuft. Beachten Sie, daß ein auf x86 basierendes Unix
eine entsprechende
Konfiguration benötigen kann, um diese Eigenschaften zu garantieren:
Es sollte so konfiguriert sein, daß es die Uhrzeit seines Motherboards
als UTC interpretiert und entsprechende Umrechnungen dynamisch vor-
nimmt. Aber selbst in diesem Fall wird die UTC-Zeit ziemlich bald nach dem
Neustart wieder korrekt sein, falls Sie NTP verwenden.</p>
<p>Die Umgebungsvariable <code>UNIQUE_ID</code> wird durch
Kodierung des 112 Bit großen Quadrupels (32-Bit-IP-Adresse,
32-Bit-Pid, 32-Bit-Zeitstempel, 16-Bit-Zähler) mit Hilfe des Alphabets
<code>[EMAIL PROTECTED]</code> in einer mit der MIME-base64-Kodierung
vergleichbaren Form mit 19 Zeichen konstruiert. Das MIME-base64-Alphabet
umfasst eigentlich die Zeichen <code>[A-Za-z0-9+/]</code>, die Zeichen
<code>+</code> und <code>/</code> müssen in URLs jedoch speziell
kodiert werden und sind daher nicht so erwünscht. Alle Werte werden
in der Netzwerk-Bytereihenfolge kodiert, so dass die Kodierung
bei Architekturen mit unterschiedlicher Bytereihenfolge vergleichbar ist.
Die
tatsächliche Reihenfolge der Kodierung lautet: Zeitstempel, IP-Adresse,
Pid, Zähler. Diese Reihenfolge hat einen Sinn, aber es sollte an
dieser Stelle
ausdrücklich betont werden, dass Applikationen nicht versuchen
sollten, diese
Kodierung wieder zu analysieren..
Programme sollten die komplette kodierte <code>UNIQUE_ID</code>
als in sich geschlossene Einheit betrachten, die mit anderen
<code>UNIQUE_ID</code>-Variablen nur auf Gleichheit verglichen
werden kann.</p>
<p>Die Reihenfolge wurde gewählt, damit die Kodierung geändert
werden
kann, ohne dass Sie sich Sorgen über Kollisionen mit
<code>UNIQUE_ID</code>-Datenbank machen müssen. Die neue Kodierung
sollte ebenfalls den Zeitstempel als erstes Element verwenden, darf jedoch
ansonsten dasselbe Alphabet und dieselbe Bitlänge verwenden. Da die
Zeitstempel im Wesentlichen eine ansteigende Sequenz sind,
reicht ein Pausen-Flag für die Sekunde aus, zu der alle Rechner des
Clusters
die Verarbeitung von Anfragen unterbrechen, das Kodierungsformat
wechseln und anschließend die Arbeit mit der neuen Kodierung wieder
aufnehmen.
</p>
<p>Dies halten wir für eine relativ portable Lösung dieses
Problems, die
auch für Multithread-Systeme wie Windows NT übernommen und
zukünftigen
Bedürfnissen angepasst werden kann. Die erzeugten Bezeichnungen sind im
Prinzip ewig gültig, weil zukünftige Bezeichnungen bei Bedarf mit
einer
größeren Länge erzeugt werden können. Eine
Kommunikation zwischen den Rechnern des Clusters ist abgesehen von der
nicht weiter ins Gewicht fallenden NTP-Synchronisation nicht erforderlich.
Eine Kommunikation zwischen den HTTPD-Prozessen ist ebenfalls nicht
notwendig (sie findet implizit über die vom Betriebssystemkernel
zugewiesene Pid statt). In ganz speziellen Situationen kann die Bezeichnung
verkürzt, werden, wobei dann jedoch zusätzliche Annahmen
erforderlich sind
(die 32 Bit lange IP-Addresse ist beispielsweise übertrieben für
jede einzelne Site, aber es gibt keinen kürzeren und dennoch
portablen Ersatz dafür). </p>
</section>
</modulesynopsis>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]