contao / core

Contao 3 → see contao/contao for Contao 4
GNU Lesser General Public License v3.0
492 stars 213 forks source link

Synchronisation häppchenweise um Abbrüche zu vermeiden #5446

Closed NinaG closed 11 years ago

NinaG commented 11 years ago

Sobald man wirklich viele & große Dateien in der Dateiverwaltung hat, ist die Chance sehr groß, dass die Verbindung bei der Synchronisation abbricht, weil die Maximum Execution-Time o.ä. erreicht wird. Bei durchschnittlichen Hosted-Webspaces kann das ziemlich fix geschehen, da dieses Hosted Spaces alle nicht so arg stark sind, selbst wenn es größere Pakete sind.

Ich habe hier z.B. einen Kunden der unter anderem ca. 500 MP3-Dateien in der Dateiverwaltung hat (die auf unterschiedlichsten Seiten innerhalb der Website eingebunden sind), die eine Gesamtgröße von ca. 1.5 GB haben. Leider tritt das Problem des Abbruchs bei der Synchronisation aber auf, so dass die Dateiverwaltung praktisch unnutzbar ist, weil die Seite bei jeder Synchronisation hopps geht.

Daher meine Bitte: Bitte baut die Synchronisation so um, dass sie häppchenweise synchronisiert. Ich kenne das von anderen Programmen so, dass man dort festlegen kann, nach wievielen Sekunden die Aktion automatisiert (glaub via JS?) kurz unterbrochen und neu gestartet wird (ab dem Punkt, an dem sie zuvor bewusst nach der Zeit unterbrochen wurde).

Ich denke, das wäre eine sehr wichtige Sache um die eigentlich gute Idee der Synchronisation auf Hosted Webspaces gut nutzbar zu machen, denn so wie das derzeit ist, kann ich Contao 3 niemandem empfehlen, der auf seiner Website aktiv eine größere Anzahl von Audio oder Video-Dateien in Inhaltselementen nutzen will.

ghost commented 11 years ago

+1 Ich kämpfe zur Zeit mit ca. 1800 Fotos, die sich auch nicht synchronisieren lassen (neben anderen Problemen dabei).

Man braucht aber keine große Anzahl. Bei mir (lokaler Ubuntu Server) reicht ein einzelnes 1.5GB Video zum Abbruch (ok, die Webhosting-Server sind schneller, aber max_execution_time oft knapper). Da reicht die Zeit nicht einmal, um einen (1) Hash zu bilden. Eine häppchenweise Synchronisation würde das Problem erstmal nach hinten verschieben, aber nicht sicher beheben, es sei denn man baut ein Größenlimit (abhängig vom Webspace!) ein.

leofeyer commented 11 years ago

Siehe #5009, #4982, #5100.

NinaG commented 11 years ago

Hm, ist aber nicht gerade beruhigend, wenn alle referenzierten Tickets geschlossen sind, also anscheinend nichts an diesem Problem getan wird?

Im Ticket #5009 schlägt Thyon auch eine häppchenweise-Abarbeitung vor und du meintest, dass du mal schaust, aber das Ticket wurde ebenso geschlossen.

Es handelt sich hier um einen essentiellen Part eines Content Management Systems - da ist es doch ein fatales Signal, wenn die Synchronisation die ganze Geschichte abrauchen lässt, sofern die Leute nicht gerade einen eigenen Server haben. Ich halte das für ein ganz wichtiges Problem.

leofeyer commented 11 years ago

Es wird nicht "nichts an dem Problem getan", sondern es gibt für das Problem keine Lösung (wie in den Tickets erklärt). Wir haben das Thema auf der Agenda der AG Core und sollte uns eine Lösung einfallen, würde ich #5009 wieder öffnen.

NinaG commented 11 years ago

Danke.

BugBuster1701 commented 11 years ago

Das Prinzip bei mysqldumper abschauen? (bzw. das Konzept) Mal als Tipp, aber sicher schon bekannt. Das Teil peilt sich beim Backup automatisch auf Speicher und Zeit Begrenzungen ein.

xchs commented 11 years ago

Ja, das BYSU Backup-Skript macht IMHO auch was Ähnliches, nämlich Speicherlimit und Skriptlaufzeit dynamisch anzupassen.

leofeyer commented 11 years ago

Das Prinzip ist mir klar (hab ich ja u.a. beim Versenden von Newslettern so implementiert). Der Unterschied ist nur, dass es hier so nicht geht, da die Datenkonsistenz während der Synchronisierung nicht gewährleistet ist!

andreasisaak commented 11 years ago

Wir arbeiten nach dem selben Prinzip bei syncCto und dort haben wir es bis zu einer bestimmten Grenze auch geschafft. Auch wenn da das Problem noch nicht ganz behoben ist, da wir ab und zu immer noch die Speicherlimits sprengen.

Eine Lösung ist aber vorhanden.

tristanlins commented 11 years ago

Der Unterschied ist nur, dass es hier so nicht geht, da die Datenkonsistenz während der Synchronisierung nicht gewährleistet ist!

Dann musst du alle Datenoperationen während der Synchronisation sperren. Low-Level Änderungen via FTP/FS kann man natürlich nicht sperren, aber damit muss man leben.

leofeyer commented 11 years ago

Wie soll das denn über mehrere Request hinweg funktionieren? Soweit ich weiß, hebt PHP automatisch Table-Locks auf, wenn das Skript abgearbeitet wurde. Außerdem dürfte man während der Synchronisation eigentlich auch nicht lesend zugreifen, denn die Pfade könnten ja noch falsch sein.

Eine partielle Abhilfe schafft sicher der geplante Wartungsmodus, aber auch der löst das Problem nicht vollständig.

bekanntmacher commented 11 years ago

Mit Transaktionen glaube ich, musste man arbeiten: http://dev.mysql.com/doc/refman/5.1/de/custom-engine-transactions.html

leofeyer commented 11 years ago

Transaktionen == InnoDB und leider (noch) nicht MyISAM.

bekanntmacher commented 11 years ago

Und mit einer Kopie: zuerst tl_files kopieren und dann die Kopie synchen und schliesslich wieder zurückkopieren

leofeyer commented 11 years ago

Auf jeden Fall eine gute Idee. Aber klappt das mit richtig vielen Datensätzen?

ghost commented 11 years ago

Ich komme mehr aus der Datenbankecke (20+ Jahre Oracle, 10+ Jahre db-driven Web), denke vielleicht mal anders, hier meine Überlegungen:

Ein Ansatz:

Die Umsetzung dürfte nicht so schlimm sein wie es zunächst aussieht. Es gibt dabei natürlich noch ein paar nickelige Details (challenges not problems...). Ob man es anschließend auch im FE erlauben kann (ich habe irgendwo dazu ein issue gesehen), wäre dann zu prüfen. Ebenso Sync von file subtrees.

Für Anwender mit eigenem Server (real cron oder inotifywait Möglichkeit) sollte idealerweise ein (kompatibles) Batchverfahren existieren, das den Sync automatisch im Hintergrund erledigt (ideal mit inotifywait bzw. icrond).

Wenn hier der Ansatz als lohnenswert gesehen wird und sonst keiner richitg aktiv ist, versuche ich mich gerne an der Umsetzung.

tristanlins commented 11 years ago

@thomaspahl 's Ansatz klingt echt gut. Ich würde auch über ein Lockfile gehen, einfach einen timestamp in system/tmp/sync.lock oder so schreiben, solange der Timestamp < max_execution_time (*2) ist, ist der Lock gültig (um deadlock bei unerwarteten Abbrüchen zu vermeiten). Solange innerhalb von Contao keine files spezifischen Operationen, mit Ausnahme von READ erlauben. Sollte wie @thomaspahl schon sagt ein Record bereits zu diesem Zeitpunkt invalid sein, ist es sowieso egal ob ein Lesezugriff auf den Sync wartet oder nicht. Invalider Record ist invalider Record, da hilft nur ein Sync ;-)

Eine Prüfmethode könnte so aussehen:

class Files
{
    public static function isLocked()
    {
        if (!file_exists('system/tmp/sync.lock')) {
            return false;
        }
        $maxExecutionTime = ini_get('max_execution_time');
        if ($maxExecutionTime <= 0) {
            $maxExecutionTime = 120; // fallback, 2 minutes timeout
        }
        $expire = file_get_contents('system/tmp/sync.lock') + ($maxExecutionTime * 2);
        if ($expire > time()) {
            return true;
        }
        unlink('system/tmp/sync.lock');
        return false;
    }
}
bekanntmacher commented 11 years ago

Ich nehme an, dass md5_file() zum Abbruch führt, resp. die Zeit frisst. Ich kann mir jetzt aber nicht erklären, wozu wir den Hash überhaupt brauchen. Es geht doch "nur" darum, die Folder-/File-Struktur in der DB abzubilden. Ob die Prüfsumme aus irgend einem Grund ändert, kann doch dem System egal sein.

Somit sehe ich den Ablauf wie folgt:

  1. Schreibzugriff auf die Dateiverwaltung sperren
  2. Dateiverwaltung mit scandir() in ein array schreiben
  3. Array in der DB abbilden
  4. Schreibzugriff freigeben

Die Synchronisation gehört meiner Meinung nach ins Menu Systemwartung.

Die Sperre würde ich nicht anhand einer maxEcutionTime entfernen. Ich würde die Sperre aber durch eine Meldung angezeigen (Analog "abgesicherter Modus"). Im Fehlerfall kann die Sperre manuell entfernt werden (Checkbox analog dem abgesicherten Modus).

tristanlins commented 11 years ago

@bekanntmacher nein, der Hash ist notwendig um Verschiebungen erkennen zu können.

Wenn du die Sperre nicht automatisch aufhebt, wie gehst du damit um, wenn z.B. über einen Redakteur oder im FE die Sperre zu einem Dead-Lock führt, weil weder ein Redakteur und erst recht kein FE Besucher die Sperre entfernen darf? Vor allem wenn der Sync von extern getriggert wird, z.B. via cron ist ein automatisches Aufheben notwendig!

bekanntmacher commented 11 years ago

@tristanlins nein, ist er nicht:

  1. Verschiebungen in der Contao-Dateiverwaltung werden in der DB erfasst > hash nicht nötig
  2. Verschiebungen per FTP unterstehen der Eigenverantwortung und müssen durch das System nicht als Verschiebung wahrgenommen werden. Eine Verschiebung per FTP gilt für das System als delete (Ursprungsort) und add (Zielort) > hash nicht nötig.
tristanlins commented 11 years ago
  1. Verschiebungen per FTP unterstehen der Eigenverantwortung und müssen durch das System nicht als Verschiebung wahrgenommen werden. Eine Verschiebung per FTP gilt für das System als delete (Ursprungsort) und add (Zielort) > hash nicht nötig.

Also soweit ich die definition im Kopf habe, sollten vor allem Verschiebungen via FTP/FS durch den Sync erkannt werden. Deine Aussage ist also falsch. Aber vielleicht kann uns @leofeyer hier aufklären wie die Definition ist.

BugBuster1701 commented 11 years ago

Ist mir auch so bekannt, dass u.a. genau die Erkennung der Verschiebungen außerhalb von Contao erkannt werden können eines der Features ist.

bekanntmacher commented 11 years ago

Das ist schon möglich. Es ist als Input meinerseits zu verstehen, das Konzept nochmals genauer anzuschauen...

ghost commented 11 years ago

Wenn sich das wie oben von mir beschrieben umsetzen lässt, ist auch eine zusätzliche (Performance-)Option einfach zu ergänzen:

backbone87 commented 11 years ago

@thomaspahl die 3 stufen sind inkonsistenz: mv b a; mv c b <- fail bei detect moves; edit: oder auch nicht, kp grad, aber die ganze sache ist mMn eh zu verwurschtelt, deswegen:

Ich finde den sync für FTP/native FS unnötig, wer sowas brauch muss halt auf native inode listener zurückgreifen... (oder alternativ ein manuelle nachträgliche eingabe im BE) Wenn jemand was renamed im BE via FS Manager -> alles gut.

Vorallem zu zeiten von JS-Uploadern ist FTP zugang gar nicht mehr so notwendig. Da würde ich lieber mehr arbeit in eine bessere Bedienung des Contao Datei Managers stecken (direct D&D in den Filetree und so sachen)

NinaG commented 11 years ago

@backbone87 Deinen letzten Eintrag finde ich irritierend, da mir nicht klar, ist ob ich dich richtig verstehe. Willst du sagen, dass man deiner Meinung nach FTP-Uploader komplett ignorieren soll und Redakteure einen Massenupload oder sehr großen Dateien über den Core-Uploader im Backend versuchen sollen?

Meiner Erfahrung nach, kann man das total vergessen.

Situation 1 - viele neue Daten die in diversen Unterordnern stecken: Schon mal versucht über den aktuellen Core-Uploader von Contao 3 in der Dateiverwaltung mehrere hundert Bilder in diversen Unterordnern auf einen Satz hochzuladen? Via FTP ist das ein Klacks.

Situation 2 - große Dateien: Schon mal versucht im Core-Uploader von Contao 3 auf einem durchschnittlichen Webspace eine große Datei hochzuladen? Sagen wir mal, eine mehrseitige Broschüre mit großflächigen Bildern (~ gerne mal 50 MB), ein etwas längeres Video oder größere Audiodateien? Bilder in Druckqualität für einen Pressebereich? Via FTP kein Problem.

Solange wir also in Contao CORE selbst keinen Uploader haben, der beide Situationen locker und mit entsprechendem Zwischen-Feedback an die Redakteure beherrscht, sollten wir entweder schleunigst eine Lösung für die Probleme rund um die Synchronisation haben oder aber aufhören damit zu werben, dass der Core für größere Websites (mit entsprechenden völlig marktüblichen Anforderungen) geeignet ist.

ofriedrich commented 11 years ago

Auf php.net gibt es noch einige Alternativvorschläge bzgl. Performance: http://php.net/manual/de/function.md5-file.php Dort werden als Alternativen zu md5_file() zwei Verfahren genannt, die je nach Dateigröße schneller sind. Sie funktionieren jedoch über exec(), sind also keine Lösung:

Wenn ein File-Hash unbedingt benötigt wird und man es nicht ganz so genau nimmt, wäre es vielleicht ein Weg, den Hash nur über einen Teil der Datei und die Dateigröße zu bilden: $fh = fopen($file, 'r'); $str = fread($fh, 127); fclose($fh); $hash = md5(filesize($file) . '#' . $str); Die Wahrscheinlichkeit, dass zwei Dateien exakt gleich groß sind und in den ersten x Bytes identisch sind, ist meiner Meinung nach relativ gering.

Wie NinaG schon schrieb: Upload über FTP muss weiterhin gewährleistet sein. Ich denke da nur an Seiten mit einer Vielzahl an kleinen Bildern oder eben großen Videos oder Druckvorlagen.

Nachtrag: Habe eben mit openssl md5 und md5_file getestet und konnte die auf php.net genannten Geschwindigkeitsvorteile bei großen Dateien nicht nachvollziehen. Wer es ausprobieren möchte, sollte die Tests mehrfach laufen lassen, da sonst u. U. die Geschwindigkeit des Massenspeichers (HDD oder SSD) ungleich in die Messung mit einwirkt.

backbone87 commented 11 years ago

@NinaG Ich schrieb

Da würde ich lieber mehr arbeit in eine bessere Bedienung des Contao Datei Managers stecken ...

... denn, ja, der Standarduploader ist noch kein annähernd gleichwertiger Ersatz für FTP. FTP hat einfach das Problem, das die ausgeführten FS-Commands (move, copy, touch, etc.) nicht an ein externes Script weitergeleitet werden können. Das kann man dann erst auf OS-Ebene wieder (mit einem inode-Listener oder anderen FS-Layern). Deshalb ist eine Software immer "blind auf dem FTP Auge".

ghost commented 11 years ago

Die derzeitige Dateiverwaltung in der DB ist schick für Dateibestände mit wenigen und kleinen Dateien (was wohl die Mehrzahl der Installationen trifft). Für größere Dateimengen oder große Dateien ist die Architektur der Dateiverwaltung derzeit offenbar unausgereift. Auch meine Krücke zum Sync (weiter oben) dürfte da nur teilweise helfen. Bei großen Dateien ist der Hash kritisch, aber das Problem ist nicht auf den Hash beschränkt:

Testcase: 3.0.6 (core master) update über 3.0.5 Music Academy install. files/testmany/ neu mit 3000 text files je 93bytes:

files/testmanygif/ neu mit 1000 gifs (music_adacemy/admin.gif)

Weitere Beobachtungen:

Ich habe mal die sources von Drupal, Joomla, Papaya, Typo3, Wordpress auf md5_file() und md5() gescannt, um zu sehen was die so machen. md5_file() kommt überhaupt nur noch in Typo3 vor, die md5() Auswertung ist wegen der Menge etwas mühsam, zumindest in Joomla werden da auch file hashes berechnet Bei Typo3 gibt es einen interessanten Hinweis im changelog: * Fixed bug #12232: [Performance] md5_file() to check if a file has been changed is very expensive

Meine Schlussfolgerungen (supporting Nina, bekanntmacher, ..)

Damit ihr mich jetzt prügeln könnt, bin ich auf der Konferenz im Entwickler-Workshop...

ofriedrich commented 11 years ago

@thomaspahl Super! Danke für die ausführliche Analyse. Ähnliches hatte ich bereits befürchtet, ohne den Quelltext gesichtet zu haben.

Die Geschichte mit den Thumbnails ist ein alter Hase, gegen den ich in früheren Versionen von Contao bereits zu kämpfen hatte. Die einzige Lösung damals war: Thumbnail-Preview ausschalten. Nachdem die Thumbnails aus waren, war das System wieder bedienbar. Vermutlich liegt es also an den Bildern. Vielleicht wäre es ein Lösungsansatz, das src-Attribut erst bei Sichtbarkeit per JS mit Inhalt zu füllen. Damals war jedoch die Devise: Das Backend muss auch ohne JS funktionieren...

Jedes Bild erzeugt einen Request. Ist die Frage, was hier wirklich passiert, was den Browser in die Knie zwingt, wenn mehrere Tausend Bilder geladen werden sollen...

btw. Was ich nicht sonderlich gelungen finde, ist, dass file-sync nur als Admin möglich ist. Damit müsste ich einem Kunden, der seine Dateien per ftp bereit stellt, Adminrechte geben. Wozu soll diese nicht konfigurierbare Einschränkung gut sein?

ghost commented 11 years ago

@ofriedrich Die Display-Problematik des Dateimanagers bei vielen Dateien hängt nicht an Bildern und evtl. 1000 Nachlade-Request. Bei Anzeige von 3000 .txt Dateien wird nur 1 Request an den Server geschickt (der für die Seite), die Icons sind gecacht, ebenso CSS etc. Hier kommt der Browser beim Rendern ins Schwitzen (der HTML Quellcode ist fast 7MB). Bei den 1000 kleinen Bilddateien sieht man zwar das Laden, aber eigentlich stecken Server und Browser das im erwarteten Umfang weg, auch hier ist das anschließende Rendern der Schwerpunkt (man kann den Sprung in CPU sehr genau sehen). Müssen Thumbnails erst generiert werden, ist der Server erst lange am Rödeln bevor er den ersten Output produziert - wenn er es denn schafft, da häufen sich die HTTP 500 errors.

leofeyer commented 11 years ago

In 3a57b90033af6e17e9446e32e6c570ef12d559dd wurden umfangreiche Änderungen am DBAFS vorgenommen.

xchs commented 11 years ago

DBAFS := Database Assisted File System

oder

DBAFS := Database Aided File System

?

leofeyer commented 11 years ago

Beides ist möglich. "aided" ist ein bisschen technischer (es gibt z.B. "computer-aided" oder "machine-aided") und "assisted" ist ein bisschen allgemeiner (wobei es auch "computer-assisted" gibt).