Performance-Engpass bei der Verarbeitung von GIFs

  • Betroffene App
    WoltLab Suite Core

    Im Dateianhang befindet sich eine Gif-Datei, welche ich von einem Nutzer erhalten habe und die nicht besonders groß ist, nur 237,27 KB. Jedoch scheint das WSC mit dem Upload dieser Datei große Probleme zu haben. Nachdem eine ganze Weile nach dem Start des Uploads nur der Ladekreis zu sehen ist, erscheint die Meldung "Es ist ein Fehler bei der Verarbeitung aufgetreten, bitte versuche es später erneut.", die Konsole zeigt, dass es einen 503er Server-Fehler gegeben hat. Der wird auch im ACP geloggt:

    Aufgerufene URL
    /forum/index.php?ajax-upload/&t=32968a0d920bf6f43078edff3e70c236c8961fa7
    Referrer
    WoltLab Suite
    5.2.9
    PHP
    7.4.5
    Fehlermeldung
    Could not prepare statement 'DELETE FROM wcf1_attachment WHERE attachmentID = ?'
    Art
    wcf\system\database\exception\DatabaseQueryException
    Datei (Zeile)
    /www/htdocs/w0175a4b/camp-firefox.de/lib/system/database/Database.class.php (284)
    Stacktrace
    1. /www/htdocs/w0175a4b/camp-firefox.de/lib/data/attachment/AttachmentEditor.class.php (31): wcf\system\database\Database->prepareStatement(…)
    2. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/upload/DefaultUploadFileSaveStrategy.class.php (264): wcf\data\attachment\AttachmentEditor->delete(…)
    3. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/upload/UploadHandler.class.php (107): wcf\system\upload\DefaultUploadFileSaveStrategy->save(…)
    4. /www/htdocs/w0175a4b/camp-firefox.de/lib/data/attachment/AttachmentAction.class.php (148): wcf\system\upload\UploadHandler->saveFiles(…)
    5. /www/htdocs/w0175a4b/camp-firefox.de/lib/data/AbstractDatabaseObjectAction.class.php (205): wcf\data\attachment\AttachmentAction->upload(…)
    6. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AJAXProxyAction.class.php (75): wcf\data\AbstractDatabaseObjectAction->executeAction(…)
    7. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AJAXInvokeAction.class.php (94): wcf\action\AJAXProxyAction->invoke(…)
    8. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AbstractAction.class.php (47): wcf\action\AJAXInvokeAction->execute(…)
    9. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AJAXInvokeAction.class.php (61): wcf\action\AbstractAction->__run(…)
    10. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/request/Request.class.php (83): wcf\action\AJAXInvokeAction->__run(…)
    11. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/request/RequestHandler.class.php (107): wcf\system\request\Request->execute(…)
    12. /www/htdocs/w0175a4b/camp-firefox.de/forum/index.php (9): wcf\system\request\RequestHandler->handle(…)
    Fehlermeldung
    SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
    Art
    PDOException
    Datei (Zeile)
    /www/htdocs/w0175a4b/camp-firefox.de/lib/system/database/Database.class.php (279)
    Stacktrace
    1. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/database/Database.class.php (279): PDO->prepare(…)
    2. /www/htdocs/w0175a4b/camp-firefox.de/lib/data/attachment/AttachmentEditor.class.php (31): wcf\system\database\Database->prepareStatement(…)
    3. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/upload/DefaultUploadFileSaveStrategy.class.php (264): wcf\data\attachment\AttachmentEditor->delete(…)
    4. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/upload/UploadHandler.class.php (107): wcf\system\upload\DefaultUploadFileSaveStrategy->save(…)
    5. /www/htdocs/w0175a4b/camp-firefox.de/lib/data/attachment/AttachmentAction.class.php (148): wcf\system\upload\UploadHandler->saveFiles(…)
    6. /www/htdocs/w0175a4b/camp-firefox.de/lib/data/AbstractDatabaseObjectAction.class.php (205): wcf\data\attachment\AttachmentAction->upload(…)
    7. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AJAXProxyAction.class.php (75): wcf\data\AbstractDatabaseObjectAction->executeAction(…)
    8. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AJAXInvokeAction.class.php (94): wcf\action\AJAXProxyAction->invoke(…)
    9. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AbstractAction.class.php (47): wcf\action\AJAXInvokeAction->execute(…)
    10. /www/htdocs/w0175a4b/camp-firefox.de/lib/action/AJAXInvokeAction.class.php (61): wcf\action\AbstractAction->__run(…)
    11. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/request/Request.class.php (83): wcf\action\AJAXInvokeAction->__run(…)
    12. /www/htdocs/w0175a4b/camp-firefox.de/lib/system/request/RequestHandler.class.php (107): wcf\system\request\Request->execute(…)
    13. /www/htdocs/w0175a4b/camp-firefox.de/forum/index.php (9): wcf\system\request\RequestHandler->handle(…)

    Offensichtlich schießt die Datei die Datenbank ab. Der Upload selbst scheint aber zu klappen, denn wenn der Beitrag abgesendet wird, ist die Datei trotzdem da.

    Das ist in diesem Forum insofern reproduzierbar, als dass es auch hier ziemlich lange dauert, die Datei hochzuladen. Allerdings überlebt die Datenbank es hier und es kommt nicht zum Fehler.

    • Offizieller Beitrag

    Das Problem ist einfach, dass die GIF-Verarbeitung sehr zeitaufwändig ist und in deinem Fall die Datenbank-Verbindung auf Grund eines Timeouts vorzeitig geschlossen wird. Die Datenbank selbst ist nicht beeinträchtigt, die Meldung ist einfach nur etwas irreführend.

  • Was gibt es denn so aufwändig zu verarbeiten beziehungsweise gibt es hier Möglichkeiten zur Optimierung? Denn man sollte ja meinen, dass eine 237 KB kleine Grafik in einem gängigen Format problemlos hochgeladen werden kann. Ich kann den Nutzern schlecht erzählen, dass das so eine Schwierigkeit sei. Die halten mich dann ja für bekloppt. ;)

    • Offizieller Beitrag

    Die Dateigröße ist hier irrelevant, das Problem ist die Skalierung. Ein GIF ist im Prinzip nichts anderes als ein Bild gefolgt von den Teilbildern in Form der Veränderungen in jedem weiteren Frame.

    Um ein GIF zu skalieren passiert das folgende:

    1. Gegeben ist ein fiktives GIF mit 50 Frames
    2. Berechnung von 50 Einzelbildern
    3. Skalierung von 50 Einzelbildern auf das gewünschte Format
    4. Berechnung der Unterschiede der 50 Einzelbilder, um daraus das endgültige GIF zu erzeugen

    Die Dateigröße sagt leider überhaupt nichts über den Rechenaufwand aus.

    Das Bottleneck wird hier ImageMagick sein, wir werden uns damit mal befassen und sehen, welche Optimierungsmöglichkeiten wir da haben.

  • Alexander Ebert 4. September 2020 um 19:49

    Hat den Titel des Themas von „Gif-Datei von kleiner Dateigröße überlastet Datenbank beim Upload“ zu „Performance-Engpass bei der Verarbeitung von GIFs“ geändert.
  • Danke, das leuchtet soweit ein.

    Die Frage ist, wieso überhaupt Einzelbilder berechnet werden müssen, und man die Grafik nicht einfach nehmen kann, wie sie ist. Geht es um die Bildskalierung, damit keine zu großen Bilder hochgeladen werden, bzw. um das Erzeugen eines Vorschaubilds, und weil die Bildfolge nicht verloren gehen soll, müssen alle Bilder berechnet werden?

    Jedenfalls Danke für's damit Befassen.

    • Offizieller Beitrag

    Geht es um die Bildskalierung, damit keine zu großen Bilder hochgeladen werden, bzw. um das Erzeugen eines Vorschaubilds, und weil die Bildfolge nicht verloren gehen soll, müssen alle Bilder berechnet werden?

    Bei der Datei dürfte es sich um die Erzeugung der Vorschaugrafik ("Thumbnail") handeln, denn die Grafik selbst ist nicht groß genug um herunterskaliert zu werden. Bildverarbeitung ist und bleibt leider eine der mit Abstand aufwändigsten Prozesse bei Web-Applikationen (Video-Verarbeitung lasse ich mal ganz raus, das ist eine andere Geschichte).

    • Offizieller Beitrag

    Ein Zwischenstand: Wir sind eher zufällig auf ein Issue zu ImageMagick auf GitHub gestoßen, in dem ein ähnliches Problem besprochen wurde. Die Empfehlung im letzten Kommentar durch den Ersteller ist der Aufruf von quantizeImages() vor dem Speichern der Frames als Einzelgrafik.

    Ich habe das mal experimentell lokal umgesetzt und kam zu dem folgenden Ergebnis.

    Originaldatei aus dem Startbeitrag:

    Test.gif (998x438 Px, 237 kB)

    Erzeugung einer Thumbnail-Grafik mit 684x300 Px:

    25,38 Sekunden, 14,1 MB Dateigröße

    Erzeugung einer Thumbnail-Grafik mit 684x300 Px in Kombination mit quantizeImages():

    8,3 Sekunden, 202 kB Dateigröße

    Optisch ist kein Unterschied zwischen den beiden Grafiken erkennbar.

    Testsystem:

    PHP 7.4.13

    imagemagick 7.0.10-48

    macOS 11.0.1

    Intel Core i7-7820HQ @ 2,9 GHz (mit deaktiviertem Turbo)

  • Verzeihung, wenn ich mich in die Diskussion einmische.

    Könnte es sein, dass damit auch das Problem aus diesem Thread gelöst würde?

    ImageMagick wirft Fehler

    Dies wäre sehr hilfreich, da wir dadurch wieder animierte GIFs für Schulungszwecke verwenden könnten.

    Danke im Voraus.

    Grüsse aus Wien, Regards from Vienna

    Saccil

  • Bei der Datei dürfte es sich um die Erzeugung der Vorschaugrafik ("Thumbnail") handeln

    Muss es denn sein, dass die Thumbnails auch wieder "bewegte" GIFs mit allen Frames sind? Könnte man dafür nicht einfach (zumindest als Option im ACP) den ersten Frame als Standbild verwenden?

    Gruß aus Südhessen

    • Offizieller Beitrag

    Cadeyrn Ich habe die Änderung hier online bereits vorab vorgenommen, der PR mit den Änderungen findest du auf GitHub, solltest du dies selbt ausprobieren wollen: https://github.com/WoltLab/WCF/pull/3807

    Saccil Möglicherweise ist das ein Nebeneffekt. Eventuell macht es Sinn, dies nach einer entsprechenden Änderung von uns erneut auszuprobieren, um so mögliche Fehlerquellen auszuschließen. Bitte nutze dann dafür ein neues Thema, um keine Inhalte zu vermischen.

    Donner Das wäre unsere Notlösung gewesen, aber erst einmal versuchen wir Probleme ohne funktionelle Einbußen zu lösen. Denkbar wäre auch die Erzeugung der Vorschaugrafik als Standbild in Kombination mit einer asynchronen Erzeugung der "richtigen" Grafik. Das sprengt aber den Rahmen dieses Themas. Das Standbild zu erzeugen ist übrigens auch ziemlich aufwändig, grob geschätzt würde die in meinem obigen Beispiel auch ca. 2-3 Sekunden dauern, denn zur Ermittlung des ersten Frames muss das gesamte GIF dekonstruiert werden.

  • Alexander Ebert 14. Dezember 2020 um 14:14

    Hat das Label 5.3.2 hinzugefügt.
  • Alexander Ebert 14. Dezember 2020 um 14:14

    Hat das Label Behoben hinzugefügt.
    • Offizieller Beitrag

    Der Fix stimmt schon, Grafikverarbeitung ist und bleibt aber unglaublich rechenintensiv, das lässt sich nicht magisch beschleunigen. Durch die Korrektur ist die Laufzeit aber nicht mehr "astronomisch hoch" sondern nur noch das erwartete "bäh, es ist ein GIF"-hoch. Und die resultierende Grafik hat eine realistische Dateigröße.

    Das Bild sind 120 Frames à 800x600 die es zu skalieren gilt, bevor das GIF neu zusammengesetzt und komprimiert werden kann…

    Code
    $> time convert 53c6d53c0a420d130ea23d645533c934.gif -coalesce -resize 256x256 -quantize transparent +dither -colors 256 -deconstruct result.gif
    convert 53c6d53c0a420d130ea23d645533c934.gif -coalesce -resize 256x256     25  29,02s user 2,65s system 579% cpu 5,466 total

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!