• Jeder User im Forum verpflichtet sich zur Akzeptanz und zur Einhaltung dieser Regeln:
    1. Umgangston
      Ein angemessener höflicher Umgangston, ohne Beleidigungen, Beschimpfungen und aggressive Postings ist für jedes Mitglied Pflicht.
    2. Beiträge
      Jedes Mitglied sollte sich bemühen nur sinnvolle Beiträge zum Thema zu posten. Dabei ist unbedingt vorher zu prüfen, ob das Thema vorher schon einmal diskutiert wurde und daher fortgesetzt werden kann
      • Suchfunktion benutzen!
      • offizielle Doku lesen!
    3. Haftung
      Jeder Beitragsersteller übernimmt die alleinige Verantwortung seiner Inhalte.
    4. Werbung
      Wir erlauben keine Beiträge, Signaturen, Private Nachrichten oder eMails an Benutzer, die Werbung enthalten. Ausgenommen
      sind Stellengesuche /-angebote, welche ausschließlich im Forum "Stellengesuche" veröffentlicht werden dürfen.
    5. Verstöße
      Regelwidrige Beiträge sollten dem Team gemeldet werden. Nach deren Überprüfung werden wir schnellstmöglich
      entsprechend handeln.
    6. Authorität
      Den Anweisungen der Team-Mitglieder (Administratoren und Moderatoren) sind in diesem Forum Folge zu leisten.
      Bei Fragen oder Beschwerden bitte an diese wenden.
    Wir möchten Euch darauf aufmerksam machen, dass es bei Verstößen gegen einen oder mehreren der oben genannten
    Punkte dem Team frei steht entsprechend zu handeln. Dies kann z.B. das Löschen eines Beitrags, das Ausschliessen bzw.
    Sperren von Mitgliedern oder aber lediglich eine Verwarnung sein.

    In diesem Zusammenhang sollte erwähnt werden, dass das Forum automatisch die IP-Adresse jedes Beitrag-Erstellers
    speichert. Bei schweren Vergehen, behalten wir es uns vor, die IP-Adresse zur Strafverfolgung weiterzugeben.
  • Willkommen im Zend Framework Forum

    ZF1 Zend Framework 1 + ZF2 Zend Framework 2

    Das Zend Framework Forum ist seit 2006 die erste Anlaufstelle für Zend Framework Entwickler in Deutschland. Mit über 70.000 Beiträgen und einer steigenden Nutzerzahl bietet das Forum hilfreiche Themen und ZF-Tutorials für professionelle Entwickler, fortgeschrittene Programmierer sowie Zend Framework Einsteiger.
    Wenn dies Dein erster Besuch in der Zend Framework Community ist, lies bitte zuerst die Hilfe - FAQ durch. Du musst Dich registrieren, bevor Du Beiträge verfassen kannst. Klicke oben auf 'Registrieren', um die Registrierung zu starten. Du kannst auch jetzt schon Beiträge lesen. Hier im Forum findest Du die Zend Framework Hilfe, die Du suchst!

    Grüße an alle Zend Framework Entwickler. Das Team vom Zend Framework Forum!

    Drupal Agentur

Synchronisierungsprobleme mit Cache

klaus24

New member
Hallo

Ich habe da ein Problem und würde gern mal wissen, wie ich dies vielleicht lösen kann.

In einen Projekt wird Memcached als Backend verwendet.
Es gibt insgesamt 2 Memcache Server (lokal und ein Ausweich, falls mal zu viele connections offen und der 1. abriegelt, was öfters vorkommt)

Das projekt hat sehr viele Zugriffe pro Sekunde und die Daten im Cache werden auch öfters aktualisiert.

Aktuell ist der cache so implemeniteiert.

Cache-Server 1: es wird geprüft, ob die Verbindung möglich ist und wenn ja, wird dieser in den jeweilligen PHP-Durchlauf genutzt.
Wenn nicht, verbinde dich zu den 2 und nutze diesen.

Da ist das Grundproblem schon offensichtlich, das es vorkommen kann, das Server 1 unterschiedliche Daten haben kann als Server2 und somit die Website mit unterschiedlichen Daten arbeiten kann.

Doch wie kann man dies nun besser machen.
An der Tatsache, das ein Memcache-Server mal ans Limit kommt, kann ich wenig ändern, da es in Spitzenzeiten einfach sehr viele Zugriffe gibt.

Mein Problem ist, wie ich am besten die 2 Server synchron halten kann ohne extra spezielle Tools laufen zu lassen.

In einer Sekunde, wo einer der beiden Server klemmt, muss ich ja schnell reagieren, damit ein User davon nix mitbekommt.

In Grunde ist das ja eine Art konkurrierendes Verhalten.

Ich habe mir Twolevel Cache angesehen, was vielleicht das Problem lösen kann, das im Falle einer Überlastung erstmal die Daten im File-Cache speichert, aber das Problem, das Cache-Server 1 und 2 dann immer noch nicht synchron sind, das löst es nicht wirklich.

In der Save Methode vom Cache zu reagieren und einfach eine zusätzliche Verbindung zum 2. Cache-Server aufzubauen, und die Daten immer auf 2 Server zu ändern löst zwar das synchronisationsproblem, aber sichert mich nicht ab, wenn einer der beiden gerade überlastet ist.

Wer hat sich mit so eteas schon mal etwas genauer auseinander gesetzt und kann mir vielleicht einen Denkanstoß geben oder vielleicht sogar eine Lösung vorschlagen?

Mutex und ähnliches hilft glaube genau so wenig wie den Einsatz eines anderen Cache-Server.
Bei zuvielen Connections kann das immer wieder pasieren.
Und ich hätte die Daten gern synchron beziehungsweise so, das es nicht zu komischen Verhalten durch nicht aktuelle Daten kommt.

Hoffe mir kann jemmand helfen.

Liebe Grüße

Klaus
 

st0ffel

New member
Mal ein paar Fragen:

Wieviel Server greifen denn auf den Memcache zu?
Wie häufig werden die Daten geändert?
Warum wird erst versucht, ob eine Verbindung aufgebaut werden kann und warum werden nicht gleich die Daten geladen?
Kann man die Anzahl der Backendanfragen (also an PHP) nicht noch reduzieren / welcher Art ist die Anwendung?
 

klaus24

New member
Hallo

Also zugreifen tun 2 Websites (Server).
Die Art der Seiten - community mit Stoßsteigen,welche auch das eigentliche Problem sind.

Wie oft ändern sich Daten?
Immer dann, wenn zb. mit einen User etwas passiert.
Gecacht wird z.B. Anzahl neuer Nachrichten, die Userdaten selbst, also auch die der anderen, also wenn ein user seine Liste der Kontakte anklickt, kommen die Daten wie Username oder Foto aus den Cache.

View helper, die häufig aufgerufene Daten anzeigen nutzen ebenfalls cache.

In Grunde alles das, was oft vorkommt.

Das bedeutet eigentlich, das in der Bootstrap die Verbindung zu Memcache aufgebaut wird, und entweder im controller, plugins oder view helpern mehrfach auf cache->load zugegriffen wird bis alles im Layout ausgegeben wird.

Warum geprüft wird, ob Cache-Server 1 verfügbar ist bevor man diesen nutzt?
Es wird mitgelogt, wie oft es vorkommt, das Server 1 beim Backend initialisieren in den Catch Fall rutscht, und das passiert in den Stoßzeiten oft.

Cache Server 1 ist der lokale, schlägt die Verbindung fehl, geht es in den 2. Versuch, den 2. Cache Server zu nutzen.
Dies durch 2 getrnnte Verbindungen.
Es wird also nicht ein Backend mit 2 Serververbindungen verwendet, da dies ebenso unsicher ist.
Denn angenommen, man hätte dies und in der Bootstrap will man sich nun verbinden, aber es gibt in dieser Sekunde zu viele Verbindungen:
- Das Fallback würde greifen (Blackhole), Anwendung läuft weiter, und nun würde im weiteren Code ein delete oder update gemacht werden.
Im Memcache wären die Daten dann veraltet und eigentlich unbrauchbar.

Allerdings ist man vor diesen Problem mit der jetzigen Version auch nicht auf der sicheren Seite.

Ansich gilt es ja, in solchen Momenten etwas kleveres zu schaffen, denn Fakt ist, jeder der mal genauer drüber nachgedacht hat, sollte wissen, das dies immer passieren kann. Allein schon, wenn der Server selbst mal stakr ausgelastet ist, oder andeere Gründe dafür sorgen.

Das Problem ist ja bekannt und benannt. Nicht nur bei Memcache sondern auch bei anderen Bereichen wie extrem vielen Datenbankzugriffen.

Z.b. : es gibt eine Art Statistik Tabelle, in der gezählt wird, wieviele Hits, SQL Anfragen usw pro Stunde eines Tages es gibt.

Greifen nun zu begin einer vollen Stunde in fast den selben Bruchteil einer Sekunde auf die Seite zu, schreibt der 1. ein Insert für die Stunde, der 2. überschreibt es. Weil!

der Code sagt:

select .... where tag=X and stunde=jetzt
wenn 0 Treffer
Insert
else
update


wenn zwischen abfrage und insert genau die 2 User gleich liegen (und ja, exakt das passiert hin und wieder), passiert genau das.

Codeseitig kann man dies abfangen, aber es bleibt ein genauigkeitsproblem.

Mutex wäre eine Lösung. Doch so weit ich weiß, ist das nur über ein selbst zu kompilierendes Modul realsisierbar oder über andere Wege wie seperate Dateien schreiben,was aber inperformant ist.

Diese Probleme gibt es ja in allen Programmiersprachen.

Wüsste jemmand, wie man da vielleicht etwas anders ran gehen kann?

Meine bisherige Idee ist, einen File-Cache hinzuzufügen, der immer dann greift, wenn der Master und/oder Slave in Prooblemen steckt.
Dieser speichert erstmal nur alles was nicht in Memcache geschickt weden kann.
Sollte eine Sekunde später wieder eine Verbindung kommen und Memcache wieder erreichbar sein, wird noch mal geschaut, ob im File-Cache etwas ist und dies dann an die Memcache Server übertragen und aus den File-Cache gelöscht.
Wenn nicht weiter gesammelt.
Solang bis es wieder geht.
Das Problem was ich sehe ist, das man somit die Performance drückt, auch dann, wenn alles ok ist.

Aber vielleicht habt Ihr ja noch bessere Ideen?

lg

Klaus
 

st0ffel

New member
So von außen eine Anwendung zu beurteilen und sinnvolle Tipps zu geben, ist IMHO sehr schwierig. Zu versuchen die zwei Caches irgendwie synchron zu halten, kommt mir etwas umständlich vor.

Gecacht wird z.B. Anzahl neuer Nachrichten, die Userdaten selbst, also auch die der anderen, also wenn ein user seine Liste der Kontakte anklickt, kommen die Daten wie Username oder Foto aus den Cache.
Ein statisches Bild hat IMHO nix im Cache zu suchen. Entweder die entsprechenden Header setzen und den Browsern das Cachen überlassen oder soetwas wie Varnish einsetzen, damit die Requests nicht auf's Backend durchschlagen.

Meine bisherige Idee ist, einen File-Cache hinzuzufügen, der immer dann greift, wenn der Master und/oder Slave in Prooblemen steckt.
Den File-Cache würde ich bei Maschinen die unter Dampf stehen auch nicht unbedingt verwenden wollen. Ich würde hier APC bevorzugen.

Das SQL-Beispiel würde ich auch nicht im Code lösen. Bei einer Statistik-Tabelle ist es eigentlich ziemlich wurscht, aber bei sensibleren Daten würde ich alles in eine Transaktion packen. Das nur so nebenbei :)

Anyway...

Hast Du schonmal überlegt beide Caches gleichmäßig auszulasten, anstatt erst umzuschalten, wenn es schon zu spät ist? Zum Beispiel könntest Du die Daten der User mit geraden UserIds auf Server 1 und die mit ungeraden UserIds auf Server 2 speichern. Evtl. kann man andere Daten auch noch entsprechend aufteilen, so dass sich die Anfragen gleichmäßig auf beide Server verteilen und das Lastproblem gar nicht erst entsteht.
 

klaus24

New member
Hallo,

Die Idee mit den aufsplitten klingt erstmal ganz gut.
Aber lässt sich wahrscheinlich schwer realisieren, da mehrere dinge dagegen sprechen.
- Das initialisieren des Backends passiert ja bereits in der Bootstrap, einmal und in den Controllern oder Helpern wird auf die Instanz zugegriffen, und da weiss man erst, ob es eine gerade oder ungerade ID ist.
- man könnte 2 2 verbindungen aufbauen, und im controller entscheidet man dann, ob backend 1 oder 2, doch das senkt ja nicht die Verbindungen.
Da es ja z.B. eine Seite mit 10 aufgelisteten Usern gibt (z.b. Wer ist gerade online),
würde dies ja bedeuten, das es verschiedene Cacheanfragen gäbe.
Und dann gibt es noch ein paar View Helper, die an speziellen Stellen der Website eingesetzt werden um ebenfalls user-Daten anzuzeigen.
Auch dort müsste ich dann entweder erst eine neue Verbidung zu Memcache aufbauen (je nach gerade oder ungerade), oder ich bräuchte die Instanz der beiden bereits offenen Instanzen des Backends.

Ich sag es mal so, wir verwenden einige Hilfsmittel, die uns ZF zur verfügung stellt, auch gern mit Helpern. Und ich muss auch sagen, das die Anwendung sehr performant ist.
Aber wir sehen eben durch die Logs,das diese Dinge oft passieren und Memcache abriegelt.
Wir speichern keine riesen Datenmengen pro Element, aber dafür viele Elemente ansich. Also um einfach mal ein Zahlenbeispiel zu nennen, bei 100.000 Usen und angenommen, alle wären Online oder hätten Zugriffe auf deren Daten, könnte es sein, das 100.000 seperate Einträge im Cache wären. Allerdings ist Memcache genau dafür geschaffen.

Mit den Bild meinte ich auch nicht das Bild (Dateiseitig) sondern den Pfad, welcher aus einer Tabelle kommt für eine User id (gibt viele Bilder für einen User), also ich meinte damit Infos, die sich selten ändern und man sie nicht erst aus der db holen muss. Alsp perfekte Cache-Einsatzgebiete.
Wir reden hier vielleicht von insgesamt 20 Eigenschaften eines Users.

APC einsetzen, damit meinst du, meine Idee, aber anstatt den File-Cache und dafür APC?
Das wären dann aber trotzdem 2 Verbindungen pro Skript-Ausführung.
Zwar auf verschiedene Protokolle aber trotzdem.

Bezüglich den SQL Problem: Bist du dir sicher, das Transaktionen da helfen?
Ich glaube eher nicht.
Wenn wirklich 2 Skript-Ausführungen so paralell laufen, das Sie an der kritisfhen Stelle fast paralell landen und..
- der erste ein Select macht, welchess ein leeres Result bringt,
- dieser in den INSERT Fall geht
- zur selben Zeit der 2. PHP Thread mit der 2. Anfrage nun auch das SELECT ausführt, ebenfalls ins Insert geht, weil der 1. noch nicht fertig war,

dann würde die 1. Transaktion des 1. Requests sauber laufen,
die des 2. Requests aber nicht, da dann schon ein Duplicated Entry zurück kommt.
Der Zähler dann aber auch nicht erscheint.
Ja, in diesen ganz konkreten fall kann man das noch abfangen und macht noch mal ein SELECT, bekommt jetzt Daten und führt ein UPDATE aus,
aber sicherlich gibt es auch bessere Beispiele, wo das nicht so einfach und unproblematisch geht.
Wenn man mal ein wenig danach googlet, findet man ja auch diverse Beiträge dazu. Es ist nicht untrivial ebenso wie das Cache Thema.
Doch so richtig trott es erst bei Zeitkritischen Anwendungen auf.
Manche Ansätze dies zu umgehen find ich halt bisschen unschön (z.b. bei den DB Problem, einfach eine Art Look-Datei zu erstellen für diesen Augenblick, und der 2. Client wird kurz in einen Sleep geschickt)...

Meine Hoffnung war, das es halt auch andere hier gibt, die ebenfalls mal an solche Dinge gestoßen sind und vielleicht noch cleverrere Lösungen gefunden haben.
PHP ist da leider etwas eingeschränkt.

LG
Klaus
 

st0ffel

New member
Mit den doppelten Verbindungen hast Du wahrscheinlich Recht :rolleyes:

Da es ja z.B. eine Seite mit 10 aufgelisteten Usern gibt (z.b. Wer ist gerade online), würde dies ja bedeuten, das es verschiedene Cacheanfragen gäbe.
IMHO ist das ist eigentlich genau eine Anfrage an den Cache ;) Die Information würde ich nämllich für alle User gleich speichern (kenne aber die Anforderungen ja nicht).

Wir speichern keine riesen Datenmengen pro Element, aber dafür viele Elemente ansich. Also um einfach mal ein Zahlenbeispiel zu nennen, bei 100.000 Usen und angenommen, alle wären Online oder hätten Zugriffe auf deren Daten, könnte es sein, das 100.000 seperate Einträge im Cache wären. Allerdings ist Memcache genau dafür geschaffen.
ACK. Trotzdem müssen die vielen Verbindungen ja irgendwie zustande kommen :confused: Wieviele Web-Server greifen auf den Memcache-Server zu (wieviele gleichzeite PHP-Prozesse gibt es)? Wieviele Verbindungen lässt Memcache zu?

Das klingt bei Dir alles sehr dynamisch, aber gibt es nicht doch Seiten, die man zumindest für ein paar wenige Sekunden (5-10) gecacht ausliefern könnte (z.B. die Onlineliste)? Das kann die Anzahl der Backend-Requests dramatisch reduzieren. Ohne Varnish könnten wir unsere Seiten gar nicht betreiben :cool:

APC einsetzen, damit meinst du, meine Idee, aber anstatt den File-Cache und dafür APC?
Das wären dann aber trotzdem 2 Verbindungen pro Skript-Ausführung.
Zwar auf verschiedene Protokolle aber trotzdem.
APC ist Shared Memory und damit um einiges schneller als auf die Platte zugreifen zu müssen (wenn Du bei Deinem Ansatz bleiben möchtest).

Bezüglich den SQL Problem: Bist du dir sicher, das Transaktionen da helfen?
Ich glaube eher nicht.
Die Transaktion verhindert zumindest, dass irgendwelche Daten verloren gehen. Natürlich muss man dann in der Applikation noch den entsprechenden Code einbauen, der zwischen INSERT/UPDATE unterscheidet. Auf Dein Statistik/Log-Beispiel bezogen, könnte man in MySQL gleich "INSERT INTO ... ON DUPLICATE KEY UPDATE ..." (sofern man überhaupt MySQL verwendet) benutzen.

Meine Hoffnung war, das es halt auch andere hier gibt, die ebenfalls mal an solche Dinge gestoßen sind und vielleicht noch cleverrere Lösungen gefunden haben.
PHP ist da leider etwas eingeschränkt.
Man muss nicht auf Gedeih und Verderb alles in PHP lösen :p
 
Oben