Shopware 5 - Parallele Hochgeschwindigkeits-Miniaturbildererstellung
Shopware 5 - Parallele Thumbnail-Generierung nach dem Verschieben eines Shopware 5-Systems auf einen anderen Server
Wir hatten einen Kunden mit 400k Bildern und 1600k Thumbnails, der von einem alten hdd-basierten Server auf einen neuen ssd-basierten umziehen musste. Das Problem war, dass der alte Server so langsam war, dass er bereits 2 Tage brauchte, um alle Bilder durchzuzählen, ganz zu schweigen vom Kopieren der Bilder.
Also haben wir beschlossen, nur die Originalbilder zu kopieren und die Thumbnails neu zu generieren. Um die Originalbilder zu kopieren, habe ich einen kleinen Konsolenbefehl erstellt, der alle Pfade der Originalbilder, die wir kopieren müssen, exportiert: ExportImagesCommand.php
Diese Dateiliste kann mit den Optionen tar -T oder rsync --files-from= verwendet werden, die diese Tools anweisen, nur die aufgelisteten Dateien zu verarbeiten. Für den anfänglichen Kopiervorgang ist tar sehr zu empfehlen, da es nur die aufgelisteten Dateien abholt, ohne irgendeine "Berechnung" wie bei rsync vorzunehmen.
SW5 Standard-Thumbnails generieren hätte 80 Stunden gedauert
... und würde nur die Hälfte eines Kerns nutzen.
Ich war neugierig, ob ich diesen Generierungsprozess beschleunigen kann. Der Server selbst hat 32 Kerne zur Verfügung, also habe ich den Befehl generate thumbnail aus sw5 kopiert und ihn so modifiziert, dass er mit dem Parameter --batch in Batches arbeitet:
ParallelThumbnailGenerateCommand.php
Damit es funktioniert, habe ich einfach den Shopware-Kern unter engine/Shopware/Models/Media/Repository.php geändert
Ich habe einfach die getAlbumMediaQuery Funktion geändert in:
public function getAlbumMediaQuery($albumId, $filter = null, $orderBy = null, $offset = null, $limit = null, $validTypes = null, $batch = null)
{
$builder = $this->getAlbumMediaQueryBuilder($albumId, $filter, $orderBy, $validTypes);
if (is_numeric($batch)) {
$builder->andWhere('MOD(media.id, 1000) = ?3');
$builder->setParameter(3, $batch);
}
if ($limit !== null) {
$builder->setFirstResult($offset)
->setMaxResults($limit);
}
return $builder->getQuery();
}
Es ist ein optionaler Parameter und wird nichts kaputt machen. Wenn man ein Shopware-Update durchführt, würde dies verschwinden, aber da ich auf der Suche nach einer einmaligen Aufgabe war, um die Dinge zu beschleunigen, habe ich es einfach im Kern geändert, anstatt eine langfristige Lösung zu finden.
Diese Funktion berechnet ein Modulo von 1000 auf der Medien-ID und vergleicht es mit der Chargen-ID. Wir haben also im Grunde 1000 Stapel zu verarbeiten, bis alle Arbeit erledigt ist.
Jetzt müssen wir nur noch alle 1000 Stapel parallel starten. Dazu habe ich das sehr hilfreiche Tool parallel verwendet, das unter Linux verfügbar ist:
Es startet 64 Batches parallel und setzt seine Arbeit fort, bis alle 1000 Batches fertig sind.
Und so sieht es bei htop aus:
parallel -j 64 ./bin/console my:image:generate:thumbnails --batch ::: {0..999}