[SQL allgemein] Onlineliste/letzte Aktion - high performance Lösung gesucht

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [SQL allgemein] Onlineliste/letzte Aktion - high performance Lösung gesucht

    Hallo,

    ich möchte für eine Community Webseite eine Lösung entwickeln in der ich bei möglichst jedem Klick eines Users, die Zeit abspeicher und anderen Usern anzeigen kann. (Heady23 letzte Aktion war am ... um ...) Inklusive einer Liste mit sortierter Reihenfolge.
    Einfach gesagt, nur die Realisierung ist bei hohem Load doch nicht mehr ohne.

    Eine ganz normale MyISAM Tabelle kippt mir hier dank der Table Locks recht schnell aus den Latschen.
    InnoDB kommt nicht in Frage (unperformant), wenn ich auf der Seite die Liste der User in der Reihenfolge ihrer Aktivität anzeigen möchte.

    Ich habe nachgedacht per Memcache die Klicks zu "buffern" und zeitversetzt (ggf per Cron) in eine SQL Tabelle wegzusichern. Die Selects würden erst über den MC laufen und dann erst, wenn dort kein Eintrag gefunden wurde, in der SQL nachschauen.
    Hier bliebe das Problem der "Liste aller User" problematisch und generell wird es sehr schnell sehr komplex vom Code her.

    Kennt jemand hierfür ein geeignetes (Datenbank)Modell?

  • #2
    Wieso brauchst du überhaupt einen Lock auf die Tabelle? Ich würde in der Usertabelle einfach eine Spalte LastAction anfügen und bei jedem Klick des Users das Feld aktualisieren. Kann mir nicht so recht vorstellen für wieviele User du das planst. Aber das einfache Updaten eines Feldes kann imho die DB doch nicht kippen
    Gutes Tutorial | PHP Manual | MySql Manual | PHP FAQ | Apache | Suchfunktion für eigene Seiten

    [color=red]"An error does not become truth by reason of multiplied propagation, nor does truth become error because nobody sees it."[/color]
    Mohandas Karamchand Gandhi (Mahatma Gandhi) (Source)

    Kommentar


    • #3
      Ich glaube er meint, dass MyISAM kein Row Level Locking kann und fürs Update eines Wertes die ganze Tabelle sperrt.

      Kommentar


      • #4
        Original geschrieben von onemorenerd
        Ich glaube er meint, dass MyISAM kein Row Level Locking kann und fürs Update eines Wertes die ganze Tabelle sperrt.
        Genau.

        Kommentar


        • #5
          fürs Update eines Wertes die ganze Tabelle sperrt.
          Aber nur wenn vom Entwickler veranlasst, von daher weiterhin die Frage
          Wieso brauchst du überhaupt einen Lock auf die Tabelle?
          Ich sehe da kein Problem, solange der Datenbankserver die Seite für alle anzeigen kann sollte er auch ein Update pro Aufruf verkraften können (solange die Sekunden uninteressant sind für ich nur ein Update / Minute machen).
          Die Regeln | rtfm | register_globals | strings | SQL-Injections | [COLOR=silver][[/COLOR][COLOR=royalblue]–[/COLOR][COLOR=silver]][/COLOR]

          Kommentar


          • #6
            Original geschrieben von tontechniker
            Aber nur wenn vom Entwickler veranlasst
            Ich rede nicht über LOCK TABLE sondern das interne Locking.

            Kommentar


            • #7
              Ich rede nicht über LOCK TABLE sondern das interne Locking.
              Sollte das bei UPDATE tatsächlich zu einem Problem werden kannst du entweder INSERTS verwenden und eine extra Tabelle verwenden oder du musst dafür tatsächlich eine eigene Verwaltung auf Shared Memory bzw. MEMORY Tabellen Basis aufbauen. Du kannst dann ja in regelmäßigen Abständen die Daten in die User Tabelle übernehmen.
              Die Regeln | rtfm | register_globals | strings | SQL-Injections | [COLOR=silver][[/COLOR][COLOR=royalblue]–[/COLOR][COLOR=silver]][/COLOR]

              Kommentar


              • #8
                Original geschrieben von tontechniker
                Sollte das bei UPDATE tatsächlich zu einem Problem werden kannst du entweder INSERTS verwenden und eine extra Tabelle verwenden oder du musst dafür tatsächlich eine eigene Verwaltung auf Shared Memory bzw. MEMORY Tabellen Basis aufbauen. Du kannst dann ja in regelmäßigen Abständen die Daten in die User Tabelle übernehmen.
                An sowas habe ich auch gedacht. Aber dann inserte ich und sobald ich dann (per cron) da aufräume und in die users merge habe ich (gefühlt) den doppelten overhead.
                MEMORY Tabellen brachten in meinen 1. Benchmarks nur unwesendlich mehr Performance. Das Locking Problem (das hier viele nicht verstehen) bleibt hierbei auch bestehen.

                Ich habe mir jetzt per Memcache was selbst gebastelt, was vom Gefühl her SCHRECKLICH ist, aber scheinbar in 1. Tests 50% mehr Performance als eine MEMORY Tabelle bringt.
                Hier update ich je Klick im Memcache die Zeit des Users in einem Wert und schreibe einen weiteren Wert durchnummeriert mit der user_id.
                Um die letzte Aktualisierung des Users abzurufen muss ich nur auf den Memcache Wert mit der user_id zugreifen. Perfekt.
                Wenn ich allerdings eine Liste aller User abrufen will muss ich nun meine durchnummerierten Einträge manuell durchgehen bis ich xhundert distinct User habe. Klingt schrecklich, scheint aber recht gut zu performen.

                Kommentar


                • #9
                  Klingt schrecklich, scheint aber recht gut zu performen.
                  Warum schreibst du nicht ein assoziatives Array mit den user_id => last_action Zuordnung und nimmst dir dann einfach 100 raus? Die könntest du sortieren und es wäre wesentlich performanter.
                  MEMORY Tabellen brachten in meinen 1. Benchmarks nur unwesendlich mehr Performance. Das Locking Problem (das hier viele nicht verstehen) bleibt hierbei auch bestehen.
                  Das Problem verstehe ich inzwischen schon, ich kann nur noch nicht ganz nachvollziehen warum es solche Probleme mit dem internen Locking gibt.
                  Die Regeln | rtfm | register_globals | strings | SQL-Injections | [COLOR=silver][[/COLOR][COLOR=royalblue]–[/COLOR][COLOR=silver]][/COLOR]

                  Kommentar


                  • #10
                    Original geschrieben von tontechniker
                    Warum schreibst du nicht ein assoziatives Array mit den user_id => last_action Zuordnung und nimmst dir dann einfach 100 raus? Die könntest du sortieren und es wäre wesentlich performanter.
                    Und wie aktualisiere ich das Array? Dazu muss ich es ja auslesen, ändern, speichern. Da muss ich manuell locken wenn 2 User gleichzeitig eine Aktion durchführen.

                    Das Problem verstehe ich inzwischen schon, ich kann nur noch nicht ganz nachvollziehen warum es solche Probleme mit dem internen Locking gibt.
                    Weil meine schöne 32 Core Kiste 32 updates gleichzeitig machen will, dann die mysql sagt "ah, ich sperr mal eben die ganze Tabelle für ein Update" und EIN Update durchführt, während dem zu allem übel auch kein select mehr laufen kann, das sitzt dann auch und wartet bis das update fertig ist. Usw...
                    Vielleicht versteh ich es auch nicht sooo genau, ich weiss nicht wie der Server bitte PARALLEL aus dem Ram/der HDD Daten holen will... das geht doch eh nicht wirklich?
                    Aber dieses gelocke/aufstauen von Querys benötigt performance und mir zerhauts die Server wenn man es "einfach so" macht.

                    Kommentar


                    • #11
                      quote:Original geschrieben von tontechniker Warum schreibst du nicht ein assoziatives Array mit den user_id => last_action Zuordnung und nimmst dir dann einfach 100 raus? Die könntest du sortieren und es wäre wesentlich performanter. Und wie aktualisiere ich das Array? Dazu muss ich es ja auslesen, ändern, speichern. Da muss ich manuell locken wenn 2 User gleichzeitig eine Aktion durchführen.
                      Du darfst halt nur auf bestimmte Speicherbereiche zugreifen, mit ein wenig Aufwand geht das sicherlich, die Daten sind ja im Prinzip immer gleichlang und verändern sich in der Länge auch nicht, sodass du genau an eine bestimmte Stelle schreiben kannst. Die shmop-Funktionen beispielsweise erlauben einen derartigen Zugriff.
                      während dem zu allem übel auch kein select mehr laufen kann, das sitzt dann auch und wartet bis das update fertig ist. Usw...
                      Was du mit Inserts laut MySQL Doku verhindern kannst, bei so hohen Anforderungen ist eine nicht Datenbank basierte Lösung aber wohl doch besser.
                      Zuletzt geändert von tontechniker; 23.05.2008, 02:52.
                      Die Regeln | rtfm | register_globals | strings | SQL-Injections | [COLOR=silver][[/COLOR][COLOR=royalblue]–[/COLOR][COLOR=silver]][/COLOR]

                      Kommentar


                      • #12
                        Oh Vorsicht. Unter bestimmten Bedingungen kann MySQL in MyISAM-Tabellen parallel Lesen und Einfügen, das ist richtig. Diese Bedingung sind aber nur dann zuverlässig gegeben, wenn man ausschließlich INSERTs und SELECTs ausführt.

                        Aber auch dann stauen sich die Writes auf. Das kann man nur mit (noch) besserer Hardware erschlagen.

                        Der Ansatz mit Memcache ist vielleicht wirklich eine gangbare Alternative. Die Liste aller User, die jetzt noch so teuer ist, kannst du als separate Datenstruktur anlegen.

                        Quasi für jeden Zweck eine MEMORY-Tabelle. Dank Memcache ohne den Overhead eines DBMS, dafür auch ohne ACID.

                        Kommentar


                        • #13
                          Schonmal an MyISAM Merge-Tabellen gedacht?
                          Habs selber noch nicht praktisch gemacht aber vom Prinzip her würds doch passen?!
                          Einfach die user nach der userid auf mehrere Tabellen aufteilen, auf die du dann auch die UPDATE-Queries ausführst. Über die Merge-Tabelle kannst du dann deine SELECTs ausführen, oder?
                          Assembler ist eine Methode,
                          Programme, die zu langsam laufen,
                          so umzuschreiben,
                          dass sie überhaupt nicht mehr laufen.

                          Kommentar


                          • #14
                            Original geschrieben von TheFish511
                            Schonmal an MyISAM Merge-Tabellen gedacht?
                            Habs selber noch nicht praktisch gemacht aber vom Prinzip her würds doch passen?!
                            Einfach die user nach der userid auf mehrere Tabellen aufteilen, auf die du dann auch die UPDATE-Queries ausführst. Über die Merge-Tabelle kannst du dann deine SELECTs ausführen, oder?
                            Nachgedacht ja, getestet noch nicht.
                            Irgendwie missfällt mir der Gedanke per Hand viele kleine Tabellen anzulegen, nur damit es dann besser ist als eine. Ich finde, das ist die Aufgabe der mysql :-/
                            Aber kann ich mal testen.
                            Die Shared Memory Variante ist auch interessant, allerdings nicht verteilbar auf mehrere Server.

                            Kommentar

                            Lädt...
                            X