Harry: PHP / Shared Memory / Semaphoren

Holladiewaldfee,

ich bastel gerade vollkommen größenwahnsinnig an meinem eigenen CM-
System und ich werde mich durch nichts davon abbringen lassen ;-)

Das System arbeitet "event-basiert", d.h. es existiert eine zentrale
Klasse, die Events verteilt die Ergebnisse sammelt, verwurschtelt
und dann an den "Ausrufer" des Events zurückliefert. Der Sinn davon
ist es, eine Art API bereitzustellen, um jederzeit Plugins einbinden
zu können, ohne am Kern des Systems veränderungen vornehmen zu
können. Das System an sich ist ohne Plugins vollkommen hilflos, ist
also nur ein Framework. Somit kann ich das Framework, jenachdem
welche Plugins ich benutze, zu einem Forum, zu einem CM-System oder
einer Rolle Toilettenpapier umgestalten :)

Dieser hohe Abstraktionsgrad hat natürlich seinen Preis: Einen
Haufen Queries auf die Datenbank. Ich kann zwar die Queries der
einzelnen Plugins sowie die des Kerns optimieren, aber ich bringe es
nicht hin, "Brücken" für die Queries zu bauen, d.h. die Queries der
Plugins _und_ des Kerns in irgendeiner Weise zusammenzulegen - das
läuft ja auch irgendwie dieser maximalen Abstraktion entgegen.

Viele Queries brauchen viel Zeit, auch wenn die Indizes auf der
Datenbank "richtig" definiert sind. Deswegen habe ich mein Event-
Modell so erweitert, daß es jetzt prinzipiell auch mit Plugins
umgehen kann, die keine andere Aufgabe haben als diverse Aufgaben zu
cachen.

Die meisten dieser Plugins arbeiten selbst auf der Datenbank, d.h.
sie speichern z.B. komplette Baumstrukturen als serialisierten Wert
in einer speziellen Cache-Tabelle und machen somit aus 30 oder mehr
Queries, die zum Erzeugen der Baumstruktur notwendig wären, eine.
Das funktioniert sowei alles einwandfrei. Ob ich diese
Funktionalität im Kern verankere oder als Plugin anbiete macht
geschwindigkeitsmäßig keinen Unterschied (nur so als Nebenbemerkung).

Jetzt gibt es allerdings ein paar Sachen, die ich wirklich bei jedem
Aufruf brauche und für die ich deswegen gerne die Datenbank umgehen
würde. Nach einem bißchen stöbern in der PHP-Anleitung hab ich dann
die Lösung gefunden: Shared Memory.

Inzwischen habe ich mir eine "funktionierende" Lösung gebastelt, die
mit Semaphoren und SHM arbeitet. Allerdings heißt "funktionierend"
hier: Sie läuft auf meiner kleinen Testkiste im Keller, auf der mir
keiner Ärger macht. Ich weiß jedoch, daß hier im Forum schon ab und
zu mal über SHM diskutiert wurde und daß Semaphoren und SHM-Segmente
anscheinend keine Sache sind, mit der man bedenkenlos rumspielen
könnte. Bevor ich also den Server meines Providers töte würde ich
mich gerne noch etwas schlauer dazu machen :)

Also ...

  • Was genau tun die Semaphoren? Wozu brauche ich die?

  • Wo sind die Sicherheitsrisiken versteckt? Ich gehe mal davon aus,
    daß die irgendwo in der Ecke gleichzeitige Schreib-/ Lesezugriffe
    vergraben sind.

  • Wie muß ich bei sem_get() die Parameter max_acquire und perm
    festlegen. Ich bin davon ausgegangen, daß wenn ich max_acquire auf 1
    setze nur der eine Prozess, der die Semaphore anfordert, diese auch
    benutzen darf. Bremse ich mich damit aber nicht selbst wieder aus?
    Bei perm gehe ich davon aus, daß das Zugriffsrechte im Unix-Stil
    sind. Die Frage ist: Für wen gilt die zweite der drei (respektive
    dritte von vier) Ziffern, also group? Sind das z.B. alle Kinder des
    Apache-Vaterprozesses? Was ist mit dem ersten Parameter "key", kann
    ich mir da ne beliebige 8-stellige Hex-Zahl aus den Fingern saugen
    oder gilt es irgendwelche Beschränkungen etc. zu beachten?

  • Für das Problem mit gleichzeit lesen und schreiben werde ich wohl
    einen wie auch immer gearteten Locking-Mechanismus benötigen. Ich
    habe der Frage von CK entnommen, daß man da am blödsten irgendwelche
    Bits setzt, die aber selbst im SHM-Segment abgelegt sind. Wie kann
    ich aber sichergehen, daß in der Zeit zwischen auslesen des Bits und
    ausführen der Aktion auf dem Speicher nicht ein anderer Prozess das
    Bit umgekehrt hat (z.B. auf Schreiben verboten) und dann doch zwei
    Prozesse gleichzeitig im SHM rumschreiben?

Also, um's kurz zu machen:
Mangels entsprechender Ausbildung habe ich nicht besonders viel
Ahnung von SHM-Programmierung und Betriebssystem-Internas. Was ich
an Beispielen gefunden habe und was in der PHP-Anleitung stand hat
mich genau so weit gebracht, wie ich jetzt bin - nämlich so weit,
wie ich mir's grade selbst noch hab zusammenreimen können.

Gibt es irgendwie ein _gutes_ Beispiel, wie man Semaphoren und SHM-
Segmente halbwegs wasserdicht verwendet (am besten in PHP, meine
Perl und C-Kenntnisse sind nicht sooo super)? Oder vielleicht noch
besser: Kann mir jemand halbwegs Idiotengerecht erklären, wie dieser
ganze Krempel funktioniert, d.h.

  • Was macht die Semaphore und wie muß ich sie verwenden?
  • Wie realisiere ich den Locking-Mechanismus?
  • Welche nicht-trivialen Sicherheitslücken gibt es und wie entgehe
    ich diesen?
  • Wie muß ich die Rechte und Zugriffsbechränkungen setzen um
    möglichst geschwindigkeitseffizient auf dem SHM-Segment zu arbeiten?

Vielen Dank schonmal.

Ciao,

Harry

--
  Man weiß erst was man hatte, wenn man es verloren hat.
  Intelligenz ist nicht zwingend etwas positives.
  1. hey,

    bei Deinem speziellen Problem kann ich Dir nicht helfen, allerdings kann ich Dir vielleicht zu einem kleinen einblick in Sachen Semaphoren verhelfen ...

    http://rfhs8012.fh-regensburg.de/~kas32238/studium/sharedmem.pdf

    mfG,
        Markus.

  2. hi!

    • Für das Problem mit gleichzeit lesen und schreiben werde ich wohl
      einen wie auch immer gearteten Locking-Mechanismus benötigen. Ich
      habe der Frage von CK entnommen, daß man da am blödsten
      irgendwelche Bits setzt, die aber selbst im SHM-Segment abgelegt
      sind. Wie kann ich aber sichergehen, daß in der Zeit zwischen
      auslesen des Bits und ausführen der Aktion auf dem Speicher nicht
      ein anderer Prozess das Bit umgekehrt hat (z.B. auf Schreiben
      verboten) und dann doch zwei Prozesse gleichzeitig im SHM
      rumschreiben?

    Der Trick bei Semaphoren ist, dass man Funktionen verwendet, die
    atomar sind, d.h. es wird garantiert, dass während diese Funktion
    ausgeführt wird, kein anderer Prozess oder Thread dazwischenfunkt.
    Ansonsten hast du recht: wenn es sowas nicht gibt, kann der von dir
    beschriebene Fall auftreten.

    Die zwei Funktionen, die man für Semaphoren braucht, bedeuten dann
    soviel wie "setze eine Semaphore, wenn sie noch nicht gesetzt ist, und
    mache dann weiter oder warte bis du die Semaphore setzen kannst" und
    "gib die gesetzte Semaphore wieder frei". Alles, was dazwischen liegt,
    hat dann exklusiven Zugriff auf was auch immer.

    Ob PHP solche Funktionen hat, weiß ich gar nicht. Und mehr will ich
    über Semaphoren gar nicht schreiben. Wenn möglich, schau in ein gutes
    Buch, zb. "Moderne Betriebssysteme" von Tanenbaum oder eines über
    Thread-Programmierung. Da sind verschiedene Mechanismen für das
    Zusammenspiel mehrerer Threads/Prozesse detaillierter beschrieben.

    bye, Frank!

    --
    Never argue with an idiot. He will lower you to his level and then
    beat you with experience.