Zum Inhalt springen

Dokumenterzeugung in großem Umfang

Spec: ISO 24495-1:2023, §5 Spec: ISO 9241-112:2025, §6.1.2.3 Evidence: Benchmark-backed

Ein einzelnes PDF zu erzeugen ist ein Funktionsaufruf. Hunderttausend davon nach Zeitplan zu erzeugen ist ein Systemproblem: Arbeitsspeicher muss begrenzt bleiben, Arbeit muss parallel laufen, und Zahlen müssen belastbar sein. Diese Seite führt Sie durch das Szenario der Stapelerzeugung – von der Durchsatzfrage bis zu einem Deployment, das standhält. Sie sagt klar: Die ehrliche Antwort lautet „Messen Sie es an Ihren Dokumenten“ und ist keine plakative Zahl.

Die Stapelerzeugung scheitert typischerweise auf zwei Arten. Die erste ist schleichendes Speicherwachstum. Ein langlebiger Worker häuft Dokument für Dokument zurückgehaltenen Zustand an, bis er mitten im Stapel abbricht; der Lauf ist dann weder abgeschlossen noch sauber gescheitert. Die zweite ist eine selbstbewusst präsentierte, aber bedeutungslose Zahl: Ein Benchmark mit einem trivialen Dokument wird verwendet, um eine Flotte zu dimensionieren, die komplexe Dokumente rendert, und erweist sich erst unter Produktionslast als falsch.

Sie können beides vermeiden, aber nur, wenn Sie Speichermodell und Messmethode von Anfang an einplanen, statt sie nach dem ersten Vorfall nachzurüsten.

  • Die Arbeitseinheit ist ein wegwerfbares Dokument, kein gemeinsam genutztes. Halten Sie Daten mit Prozesslebensdauer (Schriften, Bild-Cache) in gemeinsam genutzten Registries; erzeugen und verwerfen Sie das Dokument für jeden Render.
  • Arbeitsspeicher besteht aus zwei Teilen, und nur einer ist für einen langlebigen Worker entscheidend. Ein vorübergehender Spitzenwert während eines Renders ist zu erwarten; zurückgehaltener Speicher, der nicht wieder freigegeben wird, ist das Leck, das einen Stapel beendet.
  • Durchsatz ist Parallelität plus begrenzte Kosten pro Render. Eine belastbare Form ist eine Warteschlange, die zustandslose Worker speist, von denen jeder rendert und wieder freigibt.
  • Eine Zahl ohne ihre Methode ist keine Zahl. NextPDF meldet Messwerte pro Render als Daten, die Sie selbst erheben, und verweigert unqualifizierte Geschwindigkeitsbehauptungen. Die wichtigste Kennzahl ist diejenige, die Sie an Ihren eigenen Vorlagen messen (ISO 24495-1 §5.x11 – stellen Sie die wichtige Botschaft dorthin, wo der Leser sie findet).

Die Architektur ist auf einer einzigen Entscheidung aufgebaut: Zustand, der für die Lebensdauer des Prozesses besteht, ist gemeinsam genutzt und unveränderlich; Zustand, der für die Dauer eines Renders besteht, ist frisch und wird verworfen. Schriften sind strukturelle Daten, die einmal geparst und dann gesperrt werden, sodass kein Render sie verändern und den nächsten verfälschen kann. Der Bild-Cache ist ein begrenzter Least-Recently-Used-Speicher, der niemals gesperrt wird, sodass der Arbeitsspeicher begrenzt bleibt, ohne über Anfragen hinweg zu lecken. Die Dokumentfabrik ist ein zustandsloses Singleton; jedes Dokument, das sie erzeugt, ist wegwerfbar.

Durch diese Trennung kann ein Worker sicher stundenlang unter Octane, RoadRunner oder Swoole laufen. Sie beseitigt den Fehlerfall, in dem „Anfrage N beschädigt Anfrage N+1“, durch Konstruktion – und nicht durch die Hoffnung, dass sich das Dokument selbst zurücksetzt.

Das Szenario hat vier Stufen.

  1. Warm the shared state once On worker boot, parse and lock the font registry and size the image cache. This cost is paid once, not per document.
  2. Enqueue the work A queue holds the render jobs. The queue is the throughput dial — workers scale horizontally behind it.
  3. Render on a disposable document Each worker creates a fresh document from the factory, renders, emits the bytes, and lets the document go.
  4. Measure, then size Collect per-render time and peak memory. Size the fleet from measurements on your own templates, not a generic figure.
Das Hochvolumen-Szenario von Anfang bis Ende: gemeinsam genutzter unveränderlicher Zustand wird einmal aufgewärmt; jeder Auftrag rendert auf einem wegwerfbaren Dokument und gibt frei; der Durchsatz skaliert, indem Worker hinzugefügt werden, nicht indem ein einzelner vergrößert wird.

Die Framework-Brücken machen diese Form zur Voreinstellung, statt sie Ihnen als Eigenbau zu überlassen. Der Laravel-Service-Provider registriert die Schrift-Registry als aufgewärmtes, gesperrtes Singleton und bindet das Dokument bei jeder Auflösung als frische Instanz. Er liefert einen warteschlangenbasierten Job mit begrenzten Versuchen, einem Timeout und exponentiellem Backoff aus. Dieser Job validiert seinen Ausgabepfad auf der Worker-Seite, weil eine serialisierte Warteschlangen-Payload während der Übertragung manipuliert werden kann. Die Symfony- und CodeIgniter-Integrationen folgen derselben Disziplin aus wegwerfbarem Dokument und gemeinsam genutzter Registry.

Das Speichermodell ist codegestützt. Evidence: Code-backed Der Laravel-NextPdfServiceProvider registriert die FontRegistry als Singleton, wärmt sie auf und sperrt sie anschließend mit lock(); die ImageRegistry registriert er als begrenztes LRU-Singleton, das bewusst nicht gesperrt wird, und das Document als Bindung pro Auflösung über eine zustandslose Fabrik. Das Modell des wegwerfbaren Dokuments steckt in der Verdrahtung, nicht in der Prosa. Der GeneratePdfJob enthält tries, timeout und backoff und validiert seinen Ausgabepfad innerhalb von handle() erneut.

Die Messfläche ist benchmarkgestützt. Evidence: Benchmark-backed Die Engine gibt einen unveränderlichen RenderReport pro Render aus, der die Render-Zeit in Millisekunden, den Spitzen- Speicher in Byte, die Seitenzahl, die Anzahl der Warnungen und Fallback-Ereignisse enthält – genau die Eingaben, die Sie zum Dimensionieren einer Flotte benötigen. Ein separater Speicherfragmentierungs- Analysator unterscheidet Spitzen-Speicher (vorübergehend) von zurückgehaltenem Speicher. Diese Unterscheidung zeigt Ihnen, ob ein langlebiger Worker gesund ist oder langsam leckt. Das Benchmark-Harness selbst ist auf wiederholte Durchläufe mit Aufwärmphase konfiguriert, weil eine einzelne Messung Rauschen ist.

Die Disziplin ist ein Designprinzip: Evidence: Design principle NextPDF meldet Performance immer mitsamt Methode und verweigert unqualifizierte Geschwindigkeitsbehauptungen. Das passt dazu, wie diese Dokumentation geschrieben ist – Spec: ISO 24495-1:2023, §5 platziert die Botschaft, die wichtig ist, dort, wo der Leser sie findet. Die Botschaft, die hier wichtig ist, lautet „Messen Sie Ihre eigene Arbeitslast“.

Der folgende Code zeigt die Schleife mit wegwerfbarem Dokument und Messung und veranschaulicht das Modell. Die Engine erzeugt den RenderReport. Die Warteschlange ist Ihre Infrastruktur.

<?php
declare(strict_types=1);
use NextPDF\Contracts\DocumentFactoryInterface;
use NextPDF\Observability\RenderReport;
use Psr\Log\LoggerInterface;
/**
* One batch worker iteration: render, emit, release, measure.
*
* The factory and its registries are process-lifetime singletons; the
* document is disposable. Retained memory must return to baseline between
* iterations or the worker is leaking.
*
* @param iterable<int, callable(\NextPDF\Core\Document): \NextPDF\Core\Document> $jobs
*/
function runBatch(
DocumentFactoryInterface $factory,
LoggerInterface $logger,
iterable $jobs,
): void {
foreach ($jobs as $jobId => $build) {
$startedAt = hrtime(true);
// Fresh, disposable document — shares the warmed registries.
$doc = $factory->create();
$doc = $build($doc);
$bytes = $doc->getPdfData();
// Hand the bytes off to your sink (object store, response, etc.).
unset($doc, $bytes); // let the per-render state go
$elapsedMs = (hrtime(true) - $startedAt) / 1_000_000;
$logger->info('pdf.render.complete', [
'job_id' => $jobId,
'render_time_ms' => round($elapsedMs, 2),
'peak_memory_mb' => round(memory_get_peak_usage(true) / 1_048_576, 2),
]);
}
}

Das unset() ist keine Kosmetik. Der Zustand pro Render soll bei jeder Iteration freigegeben werden, damit der zurückgehaltene Speicher zur Ausgangsbasis zurückkehrt. Ein Worker, dessen Ausgangsbasis von Iteration zu Iteration ansteigt, ist genau das Versagen, das diese Schleife verhindern soll.

Das wichtigste Missverständnis ist „Wie viele PDFs pro Sekunde schafft NextPDF?“ – als gäbe es eine einzige Antwort. Die gibt es nicht, und eine einzelne Zahl zu nennen ist ein sicherer Weg, Flotten falsch zu dimensionieren. Die Render-Kosten werden vom Dokument dominiert, sodass die einzige Zahl, nach der Sie handeln sollten, diejenige ist, die an Ihren eigenen Vorlagen mit dem Engine-eigenen Bericht pro Render gemessen wird. Eine Zahl ohne das Dokument, die Hardware und die Methode dahinter ist Dekoration, keine Daten.

Das zweite Missverständnis lautet, dass Spitzenspeicher die entscheidende Größe sei. Der Spitzenwert ist vorübergehend und zu erwarten – er kehrt zurück. Die Zahl, die einen Stapel beendet, ist zurückgehaltener Speicher, der nicht zurückkehrt. Genau deshalb trennt die Engine die beiden.

  • Es gibt keine universelle Durchsatzzahl, und diese Seite nennt bewusst keine. Die Render-Kosten hängen von Ihren Dokumenten ab; messen Sie mit dem Bericht pro Render.
  • Beschränkter Arbeitsspeicher setzt voraus, dass das Modell des wegwerfbaren Dokuments verwendet wird. Ein Dokument über viele Render hinweg zu halten oder veränderlichen Zustand pro Render zu teilen, hebt die Garantie auf. Die Framework-Brücken nutzen standardmäßig die sichere Form. Selbstgebaute Verdrahtung muss sie nachbilden.
  • Der Bild-Cache ist beschränkt, nicht unbeschränkt. Bei Arbeitslasten mit vielen einzigartigen Bildern greift das LRU. Das ist das Design, keine Regression.
  • Die Dimensionierung des Worker-Pools, die Wahl der Warteschlange und Autoscaling sind Deployment-Entscheidungen außerhalb der Engine. NextPDF liefert die Messwerte und die beschränkten Primitive. Es betreibt Ihre Warteschlange nicht.
  • RenderReport ist ein Datensatz, kein Urteil. Er sagt Ihnen, was bei einem Render passiert ist. Daraus einen Kapazitätsplan zu machen ist Ihre Analyse.
  • Diese Seite ist für die Messfläche benchmarkgestützt und für das Speichermodell codegestützt. Sie behauptet keine bestimmte Rate.
Queued high-volume generation primitives — edition availability
Edition Availability
Core

Das Modell des wegwerfbaren Dokuments, gemeinsam genutzte unveränderliche Registries, der RenderReport pro Render und der Speicherfragmentierungs-Analysator gehören zu Core. Schlichte Hochvolumen-PDF-Erzeugung braucht keine kommerzielle Stufe.

Pro

Dieselben Primitive; kommerzielle Funktionen (Signierung, PDF/A) verursachen Kosten pro Render, die Sie messen und nicht annehmen sollten.

Enterprise

Dieselben Primitive; Arbeit an strukturierten Rechnungen und Validierung verursacht weitere Kosten pro Render, die mit der Payload- und Regelsatzgröße skalieren.

  • Wegwerfbares Dokument – eine Dokumentinstanz, die für einen einzigen Render erzeugt und danach verworfen wird, sodass kein Zustand in den nächsten Render überläuft.
  • Gemeinsam genutzte Registry – Zustand mit Prozesslebensdauer, der nach dem Aufwärmen unveränderlich ist (Schriften, Bild-Cache) und ohne Kosten pro Render über Render hinweg wiederverwendet wird.
  • Spitzenspeicher – die vorübergehende Höchstmarke während eines Renders; sie ist zu erwarten und kehrt zur Ausgangsbasis zurück.
  • Zurückgehaltener Speicher – Speicher, der nach Abschluss eines Renders noch gehalten wird; eine über die Render hinweg steigende Ausgangsbasis des zurückgehaltenen Speichers ist ein Leck.
  • Worker – ein langlebiger Prozess, der Render-Aufträge aus einer Warteschlange zieht; muss speicherbeschränkt bleiben, um einen Stapel zu überstehen.
  • RenderReport – der unveränderliche Metrik-Snapshot der Engine pro Render (Zeit, Spitzenspeicher, Seitenzahl, Warnungen), der dazu dient, die Kapazität aus echten Daten zu dimensionieren.