phil: Cronjob o.ä. welcher auf APC zugreifen kann und Datenbank

Hi.

Bei einem Klick auf einen Biete-Button wird der Wert einer in APC gespeicherten Variable um 1 reduziert. Dies soll auch in der Datenbank passieren.
Da aber x-tausende Klicks pro Sekunde auf diesen Button gemacht werden soll das Datenbank-Update nicht bei jedem Klick ausgeführt werden, sondern einmal pro Sekunde.

D.h. es gibt 2 Methoden. Entweder, in einer APC-Variable wird gespeichert wann das letzte update war per time(), jedes mal wird überprüft, "sind wir schon eine sekunde weiter? (time()>apc_fetch('lastupdate')), wenn ja, führe query aus. Das wäre aber eine Weitere Rechnung die bei jedem Query gemacht werden müsste und würde den Rechner wieder unnötig belasten.

Also wäre meine nächste Idee ein Cronjob welcher jede Sekunde einmal aufgerufen wird und die DB updatet.

Wie denkt ihr darüber?
Gäbe es eine Alternative?
Wie lässt sich so ein Cronjob einrichten?

Sprache PHP 5.3
Datenbank PostgreSQl 8.4
Ebenfalls zur Verfügung stehen APC und Memcached

Lg, Phil

  1. Hi,

    Also wäre meine nächste Idee ein Cronjob welcher jede Sekunde einmal aufgerufen wird und die DB updatet.

    Cronjobs bekommst du nicht in dieser zeitlichen „Auflösung“, Minimal-Interval ist eine Minute.

    D.h. es gibt 2 Methoden. Entweder, in einer APC-Variable wird gespeichert wann das letzte update war per time(), jedes mal wird überprüft, "sind wir schon eine sekunde weiter? (time()>apc_fetch('lastupdate')), wenn ja, führe query aus. Das wäre aber eine Weitere Rechnung die bei jedem Query gemacht werden müsste und würde den Rechner wieder unnötig belasten.

    Wenn du eine bestimmte Logik implementieren willst - dann wirst du das nicht hinbekommen, ohne den Rechner damit zu „belasten“, die Bedingungen deiner Logik auszuwerten.

    Wenn dir das Speichern von Timestamps und vergleichen dieser zu aufwendig erscheint, musst du dir was anderes suchen.
    Du könntest bspw. bei jedem Tausendsten Klick ein Update der DB machen - dazu braucht du nur den Zählerstand der APC-Variablen abfragen, und keinen zusätzlichen Wert (Timestamp) mitschleppen; das Verfahren hat aber natürlich seinen Nachteil, wenn die Tausend Klicks mal doch nicht in einer Sekunde stattfinden, sondern vielleicht auch mal fünf Minuten lang kein Nutzer klickt - Server-Crash zwischendurch, APC-Daten futsch.

    Oder du gehst analog vor, wie PHPs Sessionhandler bei der Garbage Collection - machst den Start von entsprechenden Zufallswerten abhängig (die natürlich im Laufe der Zeit noch Feintuning erfahren können), und „würfelst“ damit bei jedem Request aus, ob in die DB gespeichert werden soll oder nicht. Ggf. auch nicht performanter, als die Timestamp-Geschichte.

    Der Cronjob im 1-Minuten-Interval könnte als „Backup“ dienen. Wenn mit einem der obigen Verfahren eine ganze Minute lang nicht in DB gespeichert wurde, dann holt der Cronjob das auf jeden Fall nach. Ob du dabei noch irgendein Kriterium prüfst, oder auf jeden Fall Daten wegschreibst, wäre noch zu überlegen.

    MfG ChrisB

    --
    “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
    1. Hi!

      Oder du gehst analog vor, wie PHPs Sessionhandler bei der Garbage Collection [...]

      Bei PHPs Session-Mechanismus liegen die Daten in Dateien auf Festplatte vor. Ein Serverabsturz macht diesen weniger aus als dem ungesicherten APC-Wert. Da muss also auch noch ein zweiter Mechanismus auf eine abgelaufene Zeit schauen. Das bringt weitere Komplexität ins System.

      Lo!

  2. Hi!

    Da aber x-tausende Klicks pro Sekunde auf diesen Button gemacht werden soll das Datenbank-Update nicht bei jedem Klick ausgeführt werden, sondern einmal pro Sekunde. [...]
    Also wäre meine nächste Idee ein Cronjob welcher jede Sekunde einmal aufgerufen wird und die DB updatet.
    Wie lässt sich so ein Cronjob einrichten?

    Der handelsübliche Cronjob unter Unix/Linux hat eine Auflösung von minimal einer Minute. Abgesehen davon würde ich einem sowieso schon hochbelasteten System nicht mit einer Lösung kommen wollen, die in recht kurzen Zeitabständen immer wieder einen Prozess starten muss inklusive der dabei anfallenden Initialisierungsarbeit. Da (klassische) Cronjobs sowieso nicht in Frage kommen und das Prozess-Starten ungünstig ist, wäre mein Lösungsfavorit ein ständig laufendes Programm, das seine Arbeit erledigt und sich dann für den Intervallzeitraum schlafen legt.

    Lo!

  3. Hallo Namensvetter

    D.h. es gibt 2 Methoden. Entweder, in einer APC-Variable wird gespeichert wann das letzte update war per time(), jedes mal wird überprüft, "sind wir schon eine sekunde weiter? (time()>apc_fetch('lastupdate')), wenn ja, führe query aus. Das wäre aber eine Weitere Rechnung die bei jedem Query gemacht werden müsste und würde den Rechner wieder unnötig belasten.

    Das ist unnötig. Speicher nur einen Wert z.B. den boolschen Wert "true" mit apc_store.
    apc_store bietet dir den Parameter ttl.
    Den setzt du auf 1 Sekunde und damit verfällt die Variable nach einer Sekunde.
    Dein Skript macht dann folgendes:

    if(!apc_exists('lastupdate')){
     // update db
    }

    Beste Grüße,
    Philipp Zentner

    1. Hi!

      if(!apc_exists('lastupdate')){
      // update db

      Auch bei deiner Lösung bleibt das Problem, dass der letzte Wert vor einem großen Schweigen nur im RAM steht bis der nächste Request oder ein Absturz kommt.

      Lo!

      1. if(!apc_exists('lastupdate')){
        // update db

        Auch bei deiner Lösung bleibt das Problem, dass der letzte Wert vor einem großen Schweigen nur im RAM steht bis der nächste Request oder ein Absturz kommt.

        Naja es scheint mir aber weniger aufwendig einen einzigen Wert zu haben und den zu überprüfen oder einen Random-Wert zu erstellen und zu überprüfen, als ein Programm dauerthaft laufen zu lassen mit einem Interval.

        Ein einzelner True-Wert im APC-Cache, macht den Braten auch nicht fett. Er möchte ja die Datenbank komplett updaten und nicht für jeden der klickt einzelnd oder habe ich das falsch verstanden?

        1. Hi!

          Naja es scheint mir aber weniger aufwendig einen einzigen Wert zu haben und den zu überprüfen oder einen Random-Wert zu erstellen und zu überprüfen, als ein Programm dauerthaft laufen zu lassen mit einem Interval.

          Es kommt darauf an, was man möchte. Wenig Aufwand oder Sicherheit? Und wo ist der beste Kompromiss zwischen beiden? Wir können ihm nur die verschiedenen Ideen vorstellen, die wir haben und darüber diskutieren, welche Eigenschaften sie haben und wann diese positiv und negativ sind. Aufsetzen und betreiben muss er das Ding letztlich selbst, weswegen auch die Entscheidung bei ihm liegt.

          Ein einzelner True-Wert im APC-Cache, macht den Braten auch nicht fett. Er möchte ja die Datenbank komplett updaten und nicht für jeden der klickt einzelnd oder habe ich das falsch verstanden?

          Ja, er hantierte schon in einem früheren Posting mit extrem hohen Zugriffszahlen zu bestimmten Zeiten und sinnierte, wie man diese so effizient wie möglich bedienen kann, inklusive theoretischer Überlegungen, welches DBMS wohl schneller sei und ob man mit anderen Methoden den Verarbeitungsaufwand reduzieren kann. "Erstmal APC und später DBMS" scheint sein derzeitiger Favorit zu sein. Inwieweit er praktisch geprüft hat, ob seine Überlegungen und Annahmen stimmen, weiß ich nicht.

          Lo!

          1. Ja, er hantierte schon in einem früheren Posting mit extrem hohen Zugriffszahlen zu bestimmten Zeiten und sinnierte, wie man diese so effizient wie möglich bedienen kann, inklusive theoretischer Überlegungen, welches DBMS wohl schneller sei und ob man mit anderen Methoden den Verarbeitungsaufwand reduzieren kann. "Erstmal APC und später DBMS" scheint sein derzeitiger Favorit zu sein. Inwieweit er praktisch geprüft hat, ob seine Überlegungen und Annahmen stimmen, weiß ich nicht.

            Ja das stimmt.
            "Erstmal APC und später DBMS" ist mein derzeitiger Favorit.
            So ist die Datenbelastung, was der Flaschenhals der früheren Plattform war genommen. Jede Sekunde ein Query ist auf jeden Fall weniger Belastung.
            Zuerst wollte ich nur einen einzigen Query am Ende der Auktion machen.
            Das heißt aber das wenn sich jemand in der Auktion aus und wieder einloggt, er den alten Wert aus der Datenbank wieder hat.

            Okay mir kommt gerade ein Gedanke, das muss ja gar nicht so sein. Ich lasse den Wert dauerhaft im Cache und update erst am Ende der Auktion, falls jemand seine "Coins" wieder aufläd, werden diese auch im Cache erhöht. Das scheint doch ganz gut zu sein.

            So habe ich nur einen Datenbank-Query am Ende der Auktion und beim Login wird nur erneuert falls der Wert nicht mehr im Cache vorhanden ist.

            Entweder mache ich jetzt nur einen Query am Ende der Auktion oder ich werde einfach Philipp Zentners Prinzip übernehmen und diesen Wert dann auf 10 Minuten setzen anstatt auf 1 Sekunde.

            Dedlfix Vorschlag klingt aber auch nicht schlecht, wie würdest du dieses Programm den schreiben? Als PHP CLI oder wie? Und wer ruft es auf?

            1. Hi!

              Dedlfix Vorschlag klingt aber auch nicht schlecht, wie würdest du dieses Programm den schreiben? Als PHP CLI oder wie? Und wer ruft es auf?

              Wenn du sowieso ein Hochlastsystem betreibst und der einzige Grund, das in PHP zu machen der ist, dass du PHP aber nichts anderes kannst, dann ist das vermutlich schon die größte Bremse. Wie auch immer, dieses Programm in PHP zu schreiben, liefe auf ein CLI-Programm hinaus. Wie es aufgerufen wird, hängt von deinen konkreten Bedingungen ab. Das kann in einem für allgemeine Zwecke vorgesehenen Startscript deines Systems eingetragen sein, ein eigenes Startscript haben, beim Webserver-Start mit eingebunden werden, ... irgendwo, wo es automatisch gestartet wird. Außerdem muss es so robust sein, dass ihm Fehlerbedingungen möglichst nichts ausmachen. Denn wenn es einmal abstürzt ist es weg. Eine Überwachung wäre auch angebracht. Möglicherweise kann man ja gleich den Überwacher dazu verwenden, es auch schon beim Systemstart zu starten. Da musst du aber mal jemanden mit profunden Unix/Linux-Kenntnissen auf dem Gebiet befragen.

              Lo!

              1. Moin!

                Wie auch immer, dieses Programm in PHP zu schreiben, liefe auf ein CLI-Programm hinaus.

                APC funktioniert prima - nur nicht mit CLI zusammen, sondern nur als Apache-Modul für/mit PHP.

                Steht übrigens so in der Doku - sollte man mal lesen, bevor man irgendwelche Hochlastpläne macht.

                - Sven Rautenberg

                1. Hi!

                  Wie auch immer, dieses Programm in PHP zu schreiben, liefe auf ein CLI-Programm hinaus.
                  APC funktioniert prima - nur nicht mit CLI zusammen, sondern nur als Apache-Modul für/mit PHP.
                  Steht übrigens so in der Doku - sollte man mal lesen, bevor man irgendwelche Hochlastpläne macht.

                  Abgesehen davon, dass ich dazu nichts finde - aber wenn du das so sagst, ist das auch irgendwie logisch. APC ist eine PHP-Erweiterung, läuft also nur mit einem laufenden PHP. Und das gibt es nur als Apache-Modul. Alle anderen Versionen werden ja immer wieder neu gestartet. Und solange APC nicht noch eine weitere Schnittstelle nach außen bietet, ist es damit unbrauchbar. Das Updatescript müsste dann auch im Rahmen des Apachen laufen, der aber nicht als Host für dauerhaft laufende Programme ausgelegt ist. Sicher könnte man ihm ein entsprechendes Modul schreiben - wenn man dazu die notwendigen Fähigkeiten oder Leute mit diesen hat. Einfacher wird es, auf einen unabhängig von PHP laufenden Cache zu setzen (Shared Memory oder was es auch immer dafür gibt), der dann von mehreren Seiten anwählbar ist. Nachteil ist, dass bei Zugriffen ein Prozesswechsel stattfinden muss, es also vom Prinzip her langsamer sein müsste als ein eingebetteter Cache. Ich stelle mir vor, dass ein externer Cache mit Zugriffen aus dem Apachen und aus dem CLI-Script her immer noch performanter ist, als von außen her ein im Apachen laufendes Script anzustoßen.

                  Lo!

                2. APC funktioniert prima - nur nicht mit CLI zusammen, sondern nur als Apache-Modul für/mit PHP.

                  Jein.
                  CGI Modus in der php.ini anschalten und es läuft ebenfalls mit anderen Webservern wie Lighttpd.

                  1. Moin!

                    APC funktioniert prima - nur nicht mit CLI zusammen, sondern nur als Apache-Modul für/mit PHP.

                    Jein.
                    CGI Modus in der php.ini anschalten und es läuft ebenfalls mit anderen Webservern wie Lighttpd.

                    Auf welchen Konfigurationsparameter beziehst du dich da genau? apc.enable_cli

                    Lies die Doku. APC benötigt einen durchgehend reservierten RAM-Bereich, in dem die schon erstellten Opcodes von Dateien abgelegt und wieder aufgerufen werden können.

                    Beim Starten von PHP auf der Kommandozeile gibt es so einen Speicherbereich nicht. Und auch bei CGI habe ich da so meine argen Zweifel, da CGI ja auch gerade darauf basiert, dass der Webserver einen externen Prozess anstößt, der nach der Ausführung auch wieder verschwindet - es gibt also keine Chance, einen persistenten Speicher zum Caching zu benutzen.

                    - Sven Rautenberg

                    1. Lies die Doku. APC benötigt einen durchgehend reservierten RAM-Bereich, in dem die schon erstellten Opcodes von Dateien abgelegt und wieder aufgerufen werden können.

                      Getan.

                      Beim Starten von PHP auf der Kommandozeile gibt es so einen Speicherbereich nicht.

                      Davon war nicht die Rede, ich sagte lediglich das es auch auf anderen Webservern läuft, ich habe nicht behauptet, es würde bei CLI funktionieren.

                      Und auch bei CGI habe ich da so meine argen Zweifel, da CGI ja auch gerade darauf basiert, dass der Webserver einen externen Prozess anstößt, der nach der Ausführung auch wieder verschwindet - es gibt also keine Chance, einen persistenten Speicher zum Caching zu benutzen.

                      Ich kenne einige Leute, sogar wirklich extrem große Seiten bei denen APC in Kombi mit Lighttpd super läuft, ohne Beschwerden und denen einen guten Geschwindigkeitsschub gibt. Zumind. als Opcode Cache. Da sie alle mehrere Webserver geschaltet haben kommt für das meiste aufgrund der skalierbarkeit nur Memcache in Frage.

                      1. Moin!

                        Beim Starten von PHP auf der Kommandozeile gibt es so einen Speicherbereich nicht.

                        Davon war nicht die Rede, ich sagte lediglich das es auch auf anderen Webservern läuft, ich habe nicht behauptet, es würde bei CLI funktionieren.

                        Wir reden hier aber von CLI, nicht CGI.

                        - Sven Rautenberg

                        1. Wir reden hier aber von CLI, nicht CGI.

                          Sorry hatte mich da wohl falsch artikuliert. Das CGi war lediglich darauf bezogen das PHP bei Lighttpd unter fastcgi läuft, nicht auf das apc. Aber APC funktioniert halt ebenfalls auf anderen Webservern, das war der Ausganspunkt was ich klarmachen wollte.

                          1. Hi!

                            Wir reden hier aber von CLI, nicht CGI.
                            Sorry hatte mich da wohl falsch artikuliert. Das CGi war lediglich darauf bezogen das PHP bei Lighttpd unter fastcgi läuft, nicht auf das apc. Aber APC funktioniert halt ebenfalls auf anderen Webservern, das war der Ausganspunkt was ich klarmachen wollte.

                            Das nützt nur nicht viel, weil es hier um ein Problem geht, das möglichst effizient und ohne den Overhead eines Webrequests gelöst werden soll.

                            Aber auch um APC unter FastCGI als gemeinsamen Speicher verwenden zu können, müssen einige Voraussetzungen erfüllt sein, egal welcher Webserver dahintersteckt. Es darf nämlich nur einen PHP-Prozess (mit APC darin) geben, denn der Zugriff auf APC kann nicht prozessübergreifend erfolgen (hab ich gelesen).

                            Lo!

                            1. Aber auch um APC unter FastCGI als gemeinsamen Speicher verwenden zu können, müssen einige Voraussetzungen erfüllt sein, egal welcher Webserver dahintersteckt. Es darf nämlich nur einen PHP-Prozess (mit APC darin) geben, denn der Zugriff auf APC kann nicht prozessübergreifend erfolgen (hab ich gelesen).

                              Hey, hast du ebenfalls gelesen, wie sowas zu schaffen ist? Wo stelle ich was richtig ein? Kannst du mir mal den Link geben?

                              Lg

                              1. Hi!

                                Aber auch um APC unter FastCGI als gemeinsamen Speicher verwenden zu können, müssen einige Voraussetzungen erfüllt sein, egal welcher Webserver dahintersteckt. Es darf nämlich nur einen PHP-Prozess (mit APC darin) geben, denn der Zugriff auf APC kann nicht prozessübergreifend erfolgen (hab ich gelesen).
                                Hey, hast du ebenfalls gelesen, wie sowas zu schaffen ist? Wo stelle ich was richtig ein? Kannst du mir mal den Link geben?

                                Nicht mit APC.

                                Eine Datenhaltung, die für alle Anwender gleich ist, muss entweder singulär sein oder sich 1:1 auf mehrere Systeme verteilen. Letzteres setzt einen Abgleichmechanismus zwischen den Systemen voraus. APC ist weder dafür ausgelegt, sich zwischen mehreren Instanzen auszugleichen, noch hat es eine Schnittstelle, über die man es von außen anzapfen kann. Der einzige Zugriffsweg ist über die PHP-Instanz, in der es läuft.

                                Das bedeutet nun für dich, dass du, auf APC setzend, immer nur einen Server für deine Aufgabe haben kannst und sich alles immer nur innerhalb des Webservers mit dem eingebauten PHP stattfinden kann. Dinge, die du von außen steuern willst - weil du noch weitere Auslöser neben den unregelmäßig eintrudelnden Requests benötigst - musst du per Request an den Webserver herantragen.

                                Natürlich kannst du dir auch was bauen, was den Webserver "von der Seite her anspricht", um an den APC-Inhalt zu gelangen.

                                Wenn du requestunabhängige Zugriffe auf einen gemeinsamen Speicher verwenden möchtest, solltest du dich nach Alternativen zu APC umsehen, die unabhängig vom Webserver und der eingebauten PHP-Instanz laufen und außerdem auch von PHP aus angesprochen werden können.

                                Lo!

                                1. Moin!

                                  Wenn du requestunabhängige Zugriffe auf einen gemeinsamen Speicher verwenden möchtest, solltest du dich nach Alternativen zu APC umsehen, die unabhängig vom Webserver und der eingebauten PHP-Instanz laufen und außerdem auch von PHP aus angesprochen werden können.

                                  Ob Phil schon mal davon  gehört hat?

                                  MFFG (Mit freundlich- friedfertigem Grinsen)

                                  fastix

                                  1. Hi!

                                    Wenn du requestunabhängige Zugriffe auf einen gemeinsamen Speicher verwenden möchtest, solltest du dich nach Alternativen zu APC umsehen, die unabhängig vom Webserver und der eingebauten PHP-Instanz laufen und außerdem auch von PHP aus angesprochen werden können.
                                    Ob Phil schon mal davon gehört hat?

                                    Die Memory-Engine von MySQL ist schonmal eine Idee, aber mit shmop und Konsorten sollte sich doch sicher noch eine Menge (SQL-)Overhead einsparen lassen.

                                    Lo!

                                    1. Nene ich mache das ganz anders.
                                      Habe ja noch memcached im Einsatz, größeres wird dort gecached. Für die Auktionen bietet sich APC an weil es schnelleren Zugriff ermöglicht. Ich werde es echt so machen das erst am Ende in die DB geschrieben wird, das wenn ein Server abstürzt dann alles weg ist, ist nämlich völlig okay.
                                      Denn 1. ist die Auktion dann eh gelaufen und 2. wurde dann den Leuten nicht unnötig Coins abgezogen.

                                      Generell wird fast alles in Memcached gespeichert. Nur die Auktion läuft über APC, alles andere über memcached, was mir später auch horizontale Skalierung ermöglicht. Das ist schon durchdacht.
                                      Und ich kenne ebenfalls MySQLs Speicher-Engine, ich nutze allerdings PostgreSQL.

                                      Ich baue in den Javascript-Counter noch ein das beim ablaufen der Zeit einmal sofort das Skript aufgerufen wird "hole aus dem Cache, schreibe in die DB, bereinige Cache". Fertig.

                                    2. Hi.

                                      mit shmop und Konsorten sollte sich doch sicher noch eine Menge (SQL-)Overhead einsparen lassen.

                                      Okay, _das_ wäre für mich echt etwas neues, damit habe ich in PHP noch nie rumhantiert. Kannst du mir ein bisschen erzählen was es mir bringen soll? Ist es eine Art Cache? Kann ich es als Cache verwenden oder ist es schneller als APC? Was bringt es mir?

                                      Lg, phil

                                      1. Hi!

                                        shmop und Konsorten

                                        Okay, _das_ wäre für mich echt etwas neues, damit habe ich in PHP noch nie rumhantiert. Kannst du mir ein bisschen erzählen was es mir bringen soll? Ist es eine Art Cache? Kann ich es als Cache verwenden oder ist es schneller als APC? Was bringt es mir?

                                        Ich weiß nur den Namen, das grobe Funktionsprinzip und das bisschen, was ich auf die Schnelle darüber gelesen habe. Memcached macht im Prinzip etwas Vergleichbares, nur ein paar Nummern größer.

                                        Shared Memory. Der Name sagt eigentlich schon alles. Ein Speicherbereich, den sich verschiedene Prozesse teilen können. Als Cache lässt sich jeder Speicher verwenden. Ob schneller oder nicht, hängt von einigen Faktoren ab. Generell ist ein Zugriff über Prozessgrenzen mit mehr Aufwand verbunden. Wie (in)effizient/aufwendig die Vorbereitung und Auswertung des Zugrifs auf der einen und die Ausführung des Zugriff auf der anderen Seite implementiert ist, entscheidet auch über die Geschwindigkeit. Ob es dir was bringt, sagen dir deine damit gesammelten Erfahrungs- und Messwerte. Ich würde sie aufgrund meiner Nichtnäherkenntnis sowohl dieses als auch deines Systems nicht vorhersagen wollen.

                                        Lo!

            2. Hi,

              Ich lasse den Wert dauerhaft im Cache und update erst am Ende der Auktion, falls jemand seine "Coins" wieder aufläd, werden diese auch im Cache erhöht. Das scheint doch ganz gut zu sein.

              Dann darfst du aber nicht vergessen, den Nutzern abgezogene „Coins“ auch erst nur im Cache abzuziehen. Denn wenn du das schon beim Bieten in der DB machst, und dann deine Auktion aber im worst-case-Szenario gar nicht zum Ende kommt, weil der Server abschmiert/neu gestartet werden muss/... - dann fühlen sich die Nutzer vermutlich schnell verarscht, wenn du ihnen bereits Coins abgezogen hast dafür.
              (Oder du musst dann den Abbruch der Auktion ebenfalls bemerken, und die bereits darauf gezahlten Coins dann auch in der Datenbank per „Rollback“ wieder zurückgeben. Das wird aber vermutlich aufwendiger.)

              MfG ChrisB

              --
              “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
              1. Dann darfst du aber nicht vergessen, den Nutzern abgezogene „Coins“ auch erst nur im Cache abzuziehen. Denn wenn du das schon beim Bieten in der DB machst, und dann deine Auktion aber im worst-case-Szenario gar nicht zum Ende kommt, weil der Server abschmiert/neu gestartet werden muss/... - dann fühlen sich die Nutzer vermutlich schnell verarscht, wenn du ihnen bereits Coins abgezogen hast dafür.
                (Oder du musst dann den Abbruch der Auktion ebenfalls bemerken, und die bereits darauf gezahlten Coins dann auch in der Datenbank per „Rollback“ wieder zurückgeben. Das wird aber vermutlich aufwendiger.)

                Also erst zum Ende der Auktion alles in die DB schreiben, wie ich es mir eigentlich von vorne rein dachte. Dann muss mein CLI also nicht alle 2 Minuten cache mit DB abgleichen sondern alle 2 Minuten erstmal checken "mensch, irgendeine auktion vorbei und noch nicht in der DB?"

  4. hi,

    Wie denkt ihr darüber?

    Kein Cronjob.

    Gäbe es eine Alternative?

    Diese Frontlast auf dem Webserver belassen, der Prozess der dazu eine Datei schreibt (1000 IO / Sekunde gänge noch), macht einen Abgleich mit der DB nicht zeitgesteuert, sondern nach einer bestimmten Anzahl Klicks.

    Hotti

  5. Moin!

    Da aber x-tausende Klicks pro Sekunde

    Ich frage mich immer noch, ob PHP die richtige serverseitige -Technologie ist. Weil ich zweifle. Stark zweifle. Hinsichtlich der von der benötigten Echtzeitreaktion (Auktion) sogar weiß, dass es nicht gehen kann. Binnen weniger Sekunden wäre bei dieser hohen Anzahl von http-Requests allein schon der Webserver überlastet, da brauchst Du über den daran hängenden Rest (PHP, APC, Datenhaltung) gar nicht mehr nachdenken. "x-tausende Klicks pro Sekunde" kommen da schon nicht mal mehr an.

    auf diesen Button gemacht werden soll das Datenbank-Update nicht bei jedem Klick ausgeführt werden, sondern einmal pro Sekunde.

    Warum nimmst Du nicht einfach etwas nichts kann und deswegen eigentlich schnell sein muss wie z.B. dbase für die nicht-permanente Haltung der stark volatilen Daten und überlässt das Caching zwischen Arbeitspeicher und Platte dem Betriebssytem? Die dbase-Dateien kannst Du sogar auf einer SSD ablegen... Die stark volatilen Datenmengen sollten ja übersichtlich sein, vor allem wenn Du für einen Datentransfer (Synchronisation) zum Dauerspeicher dann eine externe Lösung bemühst. Die kann man sogar in die Start-Stop-Skripte des Apache einbauen.

    Da aber x-tausende Klicks pro Sekunde

    Die wirst Du gewiss nicht von Anfang an haben, auch nicht wenn Du die schon mal erwähnten 15 oder 50.000 Euro für Werbung ausgeben kannst. Wenn Du diese Klicks aber hast, dann hast Du schon weit vorher auch den finanziellen Background (Du willst ja pro Click einen Coin abkassieren...) Dir eine geeignete Lösung in einer geeigneteren Programmiersprache als PHP schreiben zu lassen. Es spricht nichts dagegen hierfür einen kleinen Server zu schreiben, diesen eventuell an den xinet-Daemon zu hängen und/oder je nach Last auf einem eigenen Port oder einem eigenen Server (jetzt gemeint: Hardware) zu betreiben. Es kann sogar ein spezieller http-Server geschrieben werden, bei der Auswahl an freien Servern die nicht den Funktionsumfang eines Apache haben (und nicht soviel nachdenken müssen) und openSource sind sollte sich einer finden in welchen man die von Dir gewünschten Funktionen quasi direkt hineinkompilieren kann. Der kann dann eben auf Deine "Clicks" reagieren aber nicht einmal statischen HTML-Dateien ausliefern...

    Da aber x-tausende Klicks pro Sekunde

    Du musst sowieso über Lastverteilung nachdenken. Das zieht automatisch einen ganzen Rattenschwanz von Überlegungen bis hin zum Einsatz mehrerer Webserver und Datenbankserver nach sich.

    Da aber x-tausende Klicks pro Sekunde

    Wie ich schon sagte, ich bezweifele diese Zahl und das ziemlich ernsthaft. Ich denke, wir machen hier heiße Luft zum Thema "heiße Luft".

    MFFG (Mit freundlich- friedfertigem Grinsen)

    fastix

    1. Moin!

      Da aber x-tausende Klicks pro Sekunde

      Ich frage mich immer noch, ob PHP die richtige serverseitige -Technologie ist. Weil ich zweifle. Stark zweifle. Hinsichtlich der von der benötigten Echtzeitreaktion (Auktion) sogar weiß, dass es nicht gehen kann. Binnen weniger Sekunden wäre bei dieser hohen Anzahl von http-Requests allein schon der Webserver überlastet, da brauchst Du über den daran hängenden Rest (PHP, APC, Datenhaltung) gar nicht mehr nachdenken. "x-tausende Klicks pro Sekunde" kommen da schon nicht mal mehr an.

      Im Detail würde ich das mal näher untersuchen, aber meiner Erfahrung nach ists mit Perl problemlos möglich, mehrere Tausend Lese- und Schreibvorgänge an einer Datei in nur einer Sekunde zu machen. Geeignete HW vorausgesetzt.

      Horst von der Werra

      1. Hi!

        Im Detail würde ich das mal näher untersuchen, aber meiner Erfahrung nach ists mit Perl problemlos möglich, mehrere Tausend Lese- und Schreibvorgänge an einer Datei in nur einer Sekunde zu machen. Geeignete HW vorausgesetzt.

        Geeignet wofür konkret? Mit geeigneter Hardware kannst du jede beliebige Programmiersprache verwenden, wenn du definierst, dass "geeignet" ausreichend schnelle Hardware für die jeweilige Lösung bedeutet.

        Lo!

      2. Moin!

        Im Detail würde ich das mal näher untersuchen, aber meiner Erfahrung nach ists mit Perl problemlos möglich, mehrere Tausend Lese- und Schreibvorgänge an einer Datei in nur einer Sekunde zu machen.

        Mag sein. Aber kann der Apache mehrere tausend mal pro Sekunde HTTP-Requests beantworten?
        Kann er das noch wenn z.B. mod_rewrite (wegen anderer Requests) aktiv ist?
        Kann er das noch, wenn zusätzliche Logik (perl, PHP, ggf. Datenbank ausgeführt werden muss?

        Vergiss bitte auch nicht, dass die Anzahl der Ports begrenzt ist. Persistene Verbindungen nach HTTP 1.1 verbieten sich dann (wahrscheinlich!) auch, dafür entsteht wieder Overhead durch den immer wieder neu erfolgenden Verbindungsaufbau.

        Schafft der Server also nicht den einzelnen Request nicht so schnell abzuarbeiten bis der (durchschnittlich) nächste Request eintrifft also in Bruchteilen von tausenstel Sekunden, dann wird ein "Auftragsstau" auftreten, der irgendwann die knappste Ressource verbraucht.

        Also: Wieviele gleichzeitige Netzwerkverbindungen (jeder Art!) kann eine Linux-Kiste überhaupt offen haben?

        Wieviele "Worker" kann der Oberindianer starten, wieviele gleichzeitige Threads verwalten?

        MFFG (Mit freundlich- friedfertigem Grinsen)

        fastix

        1. Moin!

          Mag sein. Aber kann der Apache mehrere tausend mal pro Sekunde HTTP-Requests beantworten?

          Wenn man ihn tuned.

          Kann er das noch wenn z.B. mod_rewrite (wegen anderer Requests) aktiv ist?

          Vermutlich. "ab" dürfte es zeigen (Apache Benchmark).

          Kann er das noch, wenn zusätzliche Logik (perl, PHP, ggf. Datenbank ausgeführt werden muss?

          S.o.

          Vergiss bitte auch nicht, dass die Anzahl der Ports begrenzt ist. Persistene Verbindungen nach HTTP 1.1 verbieten sich dann (wahrscheinlich!) auch, dafür entsteht wieder Overhead durch den immer wieder neu erfolgenden Verbindungsaufbau.

          Die Zahl der Ports gilt aber pro konnektierter IP, nicht global. Ist also kein echtes Limit. Außer ein riesiges NAT-Netzwerk stürzt sich auf den Server - dann hat aber der NAT-Router sowieso ein Problem, denn dem gehen ebenso die Ports aus.

          Schafft der Server also nicht den einzelnen Request nicht so schnell abzuarbeiten bis der (durchschnittlich) nächste Request eintrifft also in Bruchteilen von tausenstel Sekunden, dann wird ein "Auftragsstau" auftreten, der irgendwann die knappste Ressource verbraucht.

          Definitiv, aber der Apache wird ohnehin die Zahl der maximal möglichen Prozesse, Threads, Worker o.ä. begrenzt halten. Deshalb geht die Ressource am Ende nicht aus, sondern wird einfach unverfügbar. Was für den User den gleichen Effekt hat, aber nicht für den Admin.

          - Sven Rautenberg

    2. Hallo fastix.
      Diese Tausenden Klicks pro Sekunde hatten wir schon, deswegen muss das System ja neu gecoded werden.

      Es war prozedualer Schrottcode auf der Infrastruktur: Apache, PHP (5.1), MySQL one Chaching-Lösungen und es hat alles standgehalten bis auf die Datenbank. (war auch nicht von mir)

      Das neue System ist extrem anders aufgebaut.
      Als Frontend dient NGINX als Reverse-Proxy, damit wird Lighttpd entlastet welcher an sich schon schneller ist als Apache2.

      Skriptsprache bleibt zwar PHP, allerdings 5.3 welches wesentlich schneller sein soll laut PHP und diversen Gerüchten, welche sich aber aus meiner Erfahrung schon als bestätigt zeigen.

      Die Datenbanklast wird völlig weggenommen. Größere Daten wie die fertigen Views(alles OOP auf einem kleinen MVC Framework aufgebaut) von abgelaufenden Auktionen lagern in Memcached, ebenso wie Userdaten.

      Die Auktionen laufen dann weder über die DB noch über Memcached, sie laufen über APC weil es schneller schreiben kann als Memcached und APC wird in PHP 6 standartisiert sein.

      Ebenfalls wird darauf geachtet PHP Overhead zu vermeiden. Während das alte System 8 Sessions mit sich rumschleppte, wird dieses hier maximal 1 brauchen.

      Ich denke das dieses System ausreicht. Die Datenbank hat kaum noch Belastung, natürlich ist das nur eine Lastverteilen, das ist mir klar, aber eine wesentlich effizientere.

      Jetzt werde ich denke ich ein  PHP CLI erstellen. Ich möchte das dieses alle 2 Minuten die Daten aus dem Cache schreibt.

      Wie ist dies am elegantesten zu lösen?
      Meine Idee wäre das Skript beim Webserverstart mit zu starten und es per sleep(120); ruhen zu lassen.

      Habt ihr andere Vorschläge? Und kann mir die maximale Ausführungszeit eines Skriptes zum Verhängnis werden? Muss ich auf irgendwas achten? Wie sorge ich dafür das das Skript dauerhaft läuft?
      Zusätzlich würde ich ein weiteres Skript laufen lassen welchen alle 10 Min checkt ob das andere Skript noch läuft. Auch hier frage ich euch wie das machbar ist.

      Lg, phil

      1. Du könntest auch eine URL deines Projektes aufrufen lassen, diese hat dann Zugriff auf APC und kann dann die gewünschte Synchronisation vornehmen.

        Lg

      2. Moin!

        Meine Idee wäre das Skript beim Webserverstart mit zu starten und es per sleep(120); ruhen zu lassen.

        ~> man at

        atd sollte gestartet sein  (auf SuSE einmalig: insserv atd, /etc/init.de/atd start)

        <~~~php ?php
        print "Hallo Welt!\n";

        Neustart in (etwa) 2 Minuten:

        $min=date('i')+2;
        $hour=date('h');
        if ($min > 59) {
          $min=$min-60;
          $hour++;
          if ($hour > 23) {
              $hour = 0;
          }
        }

        function zweistellig($str) {
            if ($str > 9)  {
               return $str;
            } else {
               return '0'.$str;
            }
        }

        exec ('echo skript.php | at '.zweistellig($hour).zweistellig($min));

        ?>

          
          
        batch ist auch sehr interessant.  
          
          
          
          
        MFFG (Mit freundlich- friedfertigem Grinsen)  
          
        fastix  
        
        -- 
        [Des fastix kleines CMS](http://www.fastix.org/fastix-cms/)
        
        1. Na Mensch, super danke, das ist ja schonmal was gutes.
          Kann ich von da aus das machen was Philipp Zentner mir vorgeschlagen hat und eine URL aufrufen welche dann Zugriff auf APC hat?

          Und was sagst du zu dem Rest den ich geschrieben habe was sie Serverausstattung und verwendete Technik angeht(vorrausgesetzt sie wird richtig angewendet).

          Lg

          1. Moin!

            Na Mensch, super danke, das ist ja schonmal was gutes.
            Kann ich von da aus das machen was Philipp Zentner mir vorgeschlagen hat und eine URL aufrufen welche dann Zugriff auf APC hat?

            Aber ja doch. Wie wäre es mit so was einfachem wie:

            readfile('http://localhost/aufraeumen.php');
            statt
            print "Hallo Welt!\n";

            Und was sagst du zu dem Rest den ich geschrieben habe was sie Serverausstattung und verwendete Technik angeht(vorrausgesetzt sie wird richtig angewendet).

            "Ihr kloppt euch mit hochkomplizierten Zeug um und kennt nicht mal auf die Basics."
            (Ich bin ungern unhöflich, aber Du hast es ja wissen wollen.)

            MFFG (Mit freundlich- friedfertigem Grinsen)

            fastix

            1. Moin!

              Moin!

              Na Mensch, super danke, das ist ja schonmal was gutes.
              Kann ich von da aus das machen was Philipp Zentner mir vorgeschlagen hat und eine URL aufrufen welche dann Zugriff auf APC hat?

              netcat muss natürlich installiert sein.

              als shell-Skript:

                
              #! /bin/sh  
              while true; do  
              echo "GET /aufraeumen.php" | netcat localhost 80;  
              /bin/sleep 120;  
              done
              

              netcat muss natürlich installiert sein.

              MFFG (Mit freundlich- friedfertigem Grinsen)

              fastix

            2. [Code lang=php]readfile('http://localhost/aufraeumen.php');[/code]
               Stimmt, danke

              Und was sagst du zu dem Rest den ich geschrieben habe was sie Serverausstattung und verwendete Technik angeht(vorrausgesetzt sie wird richtig angewendet).

              "Ihr kloppt euch mit hochkomplizierten Zeug um und kennt nicht mal auf die Basics."
              (Ich bin ungern unhöflich, aber Du hast es ja wissen wollen.)

              Ehrlichkeit waehrt am laengsten. Dennoch hatte ich bei meiner Bitte das noetige knowledge vorrausgesetzt. Ich bitte dich also noch einmal zu der 'softwareauswahl' stellung zu nehmen in bezug auf hochlast und die verwendung von PHP in dieser konstelation.

              Danke fuer deine unterstuetzung!

        2. Moin!

          » $hour=date('h'); # falsch  
          $hour=date('H'); # richtig
          

          MFFG (Mit freundlich- friedfertigem Grinsen)

          fastix

        3. Hi!

          Warum einfach, wenn es auch umständlich geht? :-)

          Neustart in (etwa) 2 Minuten:

          $min=date('i')+2;
          $hour=date('h');
          if ($min > 59) {
            $min=$min-60;
            $hour++;
            if ($hour > 23) {
                $hour = 0;
            }
          }

          Ersetzbar durch strtotime('+ 2 minutes')

          function zweistellig($str) {
              if ($str > 9)  {
                 return $str;
              } else {
                 return '0'.$str;
              }
          }

          Wäre ersetzbar durch number_format() oder sprintf(), aber ...

          exec ('echo skript.php | at '.zweistellig($hour).zweistellig($min));

          ... das strtotime()-Ergebnis ist ein Unix-Timestamp, der sich auch mit date() formatieren lässt.

          Lo!