[PHP] Performantes Poiling

mercsen

Lt. Commander
Registriert
Apr. 2010
Beiträge
1.680
Moin liebe CB Runde!

Ich sitzte aktuell an einem Projekt welches im Kern auf PHP und JS aufbaut. Aber es müssen auf der Seite auf der sich der User befindet ohne aktuallisierung der kompletten Zeite zeitnah updates geladen werden.
Ich habe das ganze schon mit NodeJS und SSE gelöst, also der Server pusht updates der datenbank direkt an den Browser. Dennoch habe ich nur mal so zum Spaß überlegt wie man ein einigermaßen performantes Poll System mit PHP und JS baut, würde mich mal Interessieren was ihr so zu meinen Ideen sagt.

Idee 1:

Datensätze die mich interessieren bekommen eine "updated_at" spalte die mit einem index versehen ist und der browser fragt z.B. alle 10 Sekunden an ob veränderte Daten seit der letzten abfrage vorliegen.

Könnte aber bei vielen anwendungen recht "Teuer" werden, oder sehe ich das falsch? Ist es vlt. sogar kontropruktiv die spalte zu indizieren weil zu viel gewuselt wird in der DB?

Idee 2:

Auf dem Server liegt eine datei "updated_rows", die ist z.B. immer 30 Zeilen lang. Ändert ein User etwas wird die der neue datensatz in diese datei geschrieben und der älteste entfernt. Bzw. man fügt immer eine neue ein und löscht die erste.

Man könnte auch nur die IDs der betroffenen Datensätzte speichern und sich diese dann aus der DB hohlen, vlt. im CSV Format.
Hier sehe ich aber das Problem, wenn 2 User etwas gleichzeitig updaten ist die Datei für einen der User gesperrt, man müsste da also ggf. warten, was die Antwort des Servers verzögert. Außerdem habe ich massiven overhead weil ich immer alle daten lade. Auch hier könnte man dann natürlich vorfiltern welche am Ende zum clienten geschickt werden, aber dann wird das update script wirklich ziemlich kompliziert.

Zudem sehe ich in dem Zeilen Verfahren das problem das ich ja nicht einfach die erste Zeile löschen kann, sondern jedesmal die gesamte Datei neu schreiben müsste?

Wenn man nur die IDs im CSV speichert bleibt das problem, zwar aber die Menge an Bytes ist wesentlich geringer.

Idee 3:

Wie idee 2 nur mit einer Datenbank und ggf. kombiniert mit Idee 1 um den overhead zu minimieren.

Das PHP für sowas nicht die Sprache der Wahl ist weiß ich, ist halt nur ein gedanken experiment weil ich vor Jahren mal mit so einem Problem beschäftigt war und dann habe ich SSE und NodeJS kennen gelernt. (Übrigens hier im Forum :D)
Seitdem denke ich da immer mal wieder drüber nach.

Würde mich freuen eure Meinungen zu hören.
 
Du musst doch nur bestimmte Daten aktualisieren ..
Die kannst du auf dem Server in unformatierter, jedoch funktionaler Form bereits vorliegen haben (z.B. ein einfaches Textfile/CSV, welches nach einer Änderung automatisch bereit gestellt wird = Aktualisierung nach Server-Seitiger Änderung, nicht nach Client-Request).
Lokal kannst du dieses Textfile mit JS alle 10s abholen und ggf. mit der Größe des letzten abgeholten Textfiles vergleichen, um nicht benötigte Aktualisierungen zu vermeiden.

Das sind dann nur ein paar Bytes Overhead.

Formatierung dann natürlich am Client.

mfg,
Max
 
Du brauchst definitiv irgendeine geordnete Spalte, um zu wissen welche Datensätze neu bzw. aktualisiert sind. Und diese Spalte wird auch maßgeblich für das Query sein: "... WHERE updatedAt >= lastPollingTimestamp". Von daher ist ein Index eigentlich unverzichtbar.
Auch wenn du eine extra Tabelle mit max. 30 Zeilen aufsetzt, willst du nur die Einträge, die neu/aktualisiert sind. Okay, bei 30 Zeilen kann man auf 'nen Index verzichten, aber die Spalte brauchst du trotzdem.

Mit Idee #2/#3 denormalisierst du natürlich deine Daten und musst eigenhändig für Konsistenz und Aktualität sorgen. Hier sollte man eigentlich einfach abwägen, ob die Daten öfter gelesen oder geschrieben werden. Weil #2/#3 einen Overhead bei Schreiboperationen haben, dafür aber beim Lesen besser abschneiden sollten.

Also grundsätzlich würd ich zwischen #1 und #3 entscheiden. Wenn du schon eine Datenbank hast, die sich um Konsistenz, Zugriffsschutz, Netzwerkanbindung, etc. kümmert, ist es nicht gerade sinnvoll für Solche kleinen Dinge auf Dateien auszuweichen, das bringt im Zweifelsfall nur Probleme mit sich und ist fehleranfälliger.
 
Zuletzt bearbeitet:
Sieht eigentlich ganz gut aus mmn, sind aber alle sehr viel Rechen-/Schreibaufwand.

Sowas hier wäre wahrscheinlich die beste Lösung, allerdings auch nur, wenn du die "Live-Verbindung" wirklich brauchst. Für einfache Textsachen lohnt sich das nicht :)

Lg, Franz
 
Wenn du es wirklich nur in PHP lösen willst, ist Idee 1 die einzig wirklich zuverlässige. Idee 3 ist nur eine andere Variante von 1.
Was den overhead angeht, du schreibst ja beim Polling nicht in die Datenbank. Da kannst du locker (mit Index) paar 10.000 Anfragen pro Sekunde machen, wärst also bei ca. 100k Nutzer gleichzeitig am Limit.
Du solltest für hohe Performance die Abfrage einfach halten und die Tabelle auch, auch musst du gute Indices setzen. Indices sind das A & O in dem Fall.

Idee 4:
Für jeden Nutzer eine 0-byte-Datei anlegen (mglw. in verschachtelte Verzeichnisse). Wenn der Webserver ein Last-Modified-Header ausliefert, kannst du den in JS abfragen. Falls etwas passiert, einfach die Datei touchen (1 Byte schreiben z.B.). Dann wird der Last-Modified Header angepasst, das erkennst du und fragst die Datenbank ab.

Vorteil:
Keine Locking-Probleme
Minimaler realisierbarer Overhead

Nachteile:
Viele kleine Dateien, Inode-Limit
 
Also wie im ersten Post erwähnt setzte ich es schon mit websockets um. SSE ist ja nur eine abart davon. Der Client wartet bis über die verbindung ein event gesendet wird, was daten enthält und dann kann JS damit machen was es will.
Es läuft so ab, ein user ändert etwas, php teilt dann dem Node Server mit das es Datensatz XY verändert wurde und schickt diesen dann an alle wartenden clients.

Das ist hier nur ein reines gedanken Spiel ;)

zur größe (im aktuiellen projekt):
Zur tabelle kommen jeden Tag zwischen 50 und 200 neuen Datensätze, da sie das ganze Jahr benötigt werden wächst sie 365 Tage, zum Jahresbaschluss wandern sie dann in eine seperate Archiv DB.

Im worstcase hat die tabelle zum Schluss also 365 * 200 = 73.000 Zeilen.

Ja #3 ist nur eine abart von #1 aber der gedanke war halt das in z.B. der Zeit X zwischen 2 Polls nie mehr als Y updates vorliegen. Das kann man ja anhand der benutzter näherungsweise berechnen. Bei 10 Usern würden, wenn man ganz ans untere Limit geht, 10 Zeilen reichen, dann es unwahrscheinlich ist das die in 10 Sekunden mehr als einen Datensatz ändern. Es geht um Personaldisposition, d.h. die haben immer jemanden am Telefon. Zur sicherheit könnte man den Wert ja verdreifachen, dann müssten nur 30 Datensätze nach updates durchsucht werden, statt 73.000, wovon in 99% der fälle eh nur die letzten 1000 betroffen sind.

Wenn es aber ohnehin kaum einen unterschied macht braucht man sich diese Mühe ja nicht machen, dann wäre aber meine frage, ab wann würde sich das lohnen?
 
Zuletzt bearbeitet:
Der Datenbank ist es ziemlich egal, ob du 30 oder 73000 Datensätze durchsuchst, wenn du einen Index auf dem entsprechenden Feld hast. Durch einen Index erhältst du Zugriff auf die Datensätze mit einem kleinen Lookup. Das sollte sogar schneller sein als eine 30 Zeilen Tabelle ohne Index zu durchsuchen. Allein das Einfügen neuer Datensätze bzw. das Indizieren dieser Datensätze ist hier relevant. Aber mal ehrlich: bei 200 Einträgen pro Tag? Selbst wenn es 200 pro Minute wären, würd ich mir da keine Gedanken machen. Das juckt einen aktuellen Server nicht mal ansatzweise.
 
ich schreib hier gor nix, das ding ist ja schon fertig :p

wie gesagt, ist alles reine theorie (und nochmal schreibe ich das nicht).

das problem mit simplen varianten die ausreichen ist, das sie oftmal schlecht skalieren, was dann aber hauptsächlich an der schlechten spezifikation liegt. Hatte aber selber den Fall mal ein programm geschrieben zu haben was für 3-5 User ausgelegt war. Auf einmal hat der dann angefangen zu expandieren und plötzlich musste man mit 50 usern arbeiten, da war die simple variante maßlos überfordert. War gut für mich weils einen neuen Auftrag gab, aber auch viel arbeit weil ein nicht zur gänze optimiertes system neu geschrieben werden musste und alleine das mirgieren der daten ewig gedauert hat. Seitdem plane ich lieber 2 Schritte weiter als die Kunden das von mir verlangen, denn die wissen eh NIE was sie eigentlich wollen.
 
Zurück
Oben