- Gotenberg(Chromium)とwkhtmltopdfの技術的な特性と得意分野の違い
- ユースケース別のエンジン選定基準
- 2つのエンジンを並行運用する「デュアルエンジン」のアーキテクチャ
- フォールバック設計の考え方と実装パターン
- PDF生成エンジンの運用・監視で押さえるべきポイント
PDF生成エンジン選定の難しさ
WebアプリケーションやSaaSでPDFを生成する場合、「どのエンジンを使うか」は避けて通れない設計判断です。世の中にはHTML→PDF変換ツールが多数存在しますが、すべてのユースケースに万能なエンジンは存在しません。
FUNBREWでは自社SaaSプロダクト「FUNBREW PDF」の開発において、Gotenberg(Chromium)とwkhtmltopdfの2つのエンジンを並行運用する「デュアルエンジン戦略」を採用しました。本記事では、この設計に至った背景と実践的なパターンを解説します。
最初はGotenberg一本で始めましたが、実際の運用で「Chromiumでは過剰な場面」と「Chromiumでなければ再現できない場面」の両方に遭遇しました。1つのエンジンに依存するリスクと、ユースケースごとの最適化を考えた結果、デュアルエンジン方式に行き着きました。
2つのエンジンの特性比較
まず、Gotenberg(Chromium)とwkhtmltopdfの技術的な特性を整理します。
Gotenberg(Chromiumベース)
GotenbergはDockerコンテナとして動作するPDF変換APIサービスです。内部でヘッドレスChromiumを使用しており、ブラウザのレンダリングエンジンをそのままPDF生成に活用します。
| 項目 | 特性 |
|---|---|
| CSS対応 | Flexbox、Grid、カスタムプロパティ等、最新CSSをフルサポート |
| JavaScript | 完全に実行可能(チャート描画、動的レンダリング等) |
| Webフォント | Google Fonts等を含め完全対応 |
| 処理速度 | やや遅い(Chromium起動・レンダリングのオーバーヘッド) |
| メモリ消費 | 大きい(Chromiumプロセスがメモリを占有) |
| デプロイ | Docker必須。コンテナ化環境と相性が良い |
| メンテナンス | 活発に開発が続いている |
wkhtmltopdf
wkhtmltopdfは、Qt WebKit(古いバージョンのWebKitエンジン)をベースにしたPDF変換ツールです。
| 項目 | 特性 |
|---|---|
| CSS対応 | CSS2.1 + 一部のCSS3。Flexbox/Grid非対応 |
| JavaScript | 限定的(基本的なDOM操作は可能) |
| Webフォント | 一部対応(環境依存あり) |
| 処理速度 | 高速(Chromiumより軽量) |
| メモリ消費 | 小さい(Chromiumの数分の1) |
| デプロイ | バイナリ1つで動作。Docker不要 |
| メンテナンス | 公式メンテナンス終了(セキュリティパッチ・バグ修正ともに提供されない) |
性能比較の目安
同一のHTMLテンプレートをPDFに変換した場合の、一般的な性能差の目安です。
| 指標 | Gotenberg | wkhtmltopdf |
|---|---|---|
| シンプルなPDF(テキスト+テーブル) | 1〜3秒 | 0.3〜1秒 |
| リッチなPDF(画像+チャート+複雑レイアウト) | 3〜8秒 | 2〜5秒(レイアウト崩れの可能性あり) |
| メモリ使用量(1リクエスト) | 100〜300MB | 30〜80MB |
| 同時処理能力(4GBサーバー) | 5〜10並列 | 15〜30並列 |
ユースケース別のエンジン選定
2つのエンジンの特性を踏まえ、PDF生成のユースケースごとに最適なエンジンを選定します。
Gotenbergが適するユースケース
- レポート・ダッシュボード:グラフ、チャート、複雑なレイアウトを含むビジュアルリッチなPDF
- マーケティング資料:ブランドフォント、グラデーション、Flexboxレイアウトを使用するデザイン重視のPDF
- Webページのスクリーンショット:実際のブラウザ表示と同一のPDF出力が求められる場合
- 動的コンテンツ:JavaScriptで描画されるコンテンツを含むPDF
wkhtmltopdfが適するユースケース
- 請求書・納品書:テーブルベースのシンプルなレイアウト
- 契約書・規約文書:テキスト中心で装飾が少ないPDF
- バッチ処理:大量のPDFを短時間で生成する場合(メモリ効率が重要)
- 軽量環境:Dockerが使えない、またはリソースが限られた環境
デュアルエンジンのアーキテクチャ
デュアルエンジン戦略の核心は、エンジン選択の判断を1箇所に集約し、呼び出し側のコードを単純に保つことです。
設計のポイント
アーキテクチャの設計で重要なのは、以下の3つの原則です。
- 統一インターフェース:どのエンジンを使っても、呼び出し側は同じ方法でPDFを生成できる
- 設定による切り替え:テンプレートやリクエストの属性でエンジンを自動選定する
- フォールバック:プライマリエンジンが失敗した場合に、自動的に別エンジンで再試行する
エンジン選定ロジック
リクエストごとにどのエンジンを使うかを判定するロジックは、以下の順序で評価します。
- 明示指定:リクエストやテンプレートで特定のエンジンが指定されていればそれを使う
- テンプレート属性:テンプレートにFlexbox/Grid/JSが含まれていればGotenbergを選択
- デフォルト:指定がなければ、テナントやプランに応じたデフォルトエンジンを使用
この設計により、新しいエンジンを追加する場合も既存コードの変更が最小限で済みます。たとえば将来、Playwrightベースのエンジンを追加する場合も、統一インターフェースに沿って実装するだけです。
Strategyパターンの活用
デュアルエンジンの実装には、Strategyパターン(デザインパターン)が有効です。各エンジンの処理を「戦略」として抽象化し、実行時に切り替え可能にします。
Strategyパターンを採用することで得られるメリットは以下の通りです。
- 拡張性:新しいエンジンの追加が容易
- テスタビリティ:各エンジンの処理を独立してテスト可能
- 保守性:エンジン固有のロジックが分離され、変更の影響範囲が限定される
フォールバック設計
フォールバックは、PDF生成SaaSのサービス継続性を支える重要な仕組みです。
フォールバックが必要な場面
| 障害シナリオ | 原因 | フォールバック動作 |
|---|---|---|
| タイムアウト | 複雑なHTMLのレンダリングに時間がかかりすぎ | wkhtmltopdfで再試行(レイアウト簡略化あり) |
| メモリ不足 | Chromiumプロセスがメモリ上限に到達 | wkhtmltopdfで再試行 |
| エンジン障害 | Gotenbergコンテナのクラッシュや応答停止 | wkhtmltopdfに自動切替 |
| レンダリングエラー | 特定のCSS/HTMLがエンジンで正しく処理されない | 別エンジンで再試行 |
フォールバックの設計原則
- 自動リトライ:プライマリエンジンの失敗を検知し、ユーザーの操作なしにセカンダリエンジンで再試行
- リトライ上限:無限リトライを防ぐため、最大試行回数を設定(通常は2回:プライマリ+フォールバック1回)
- タイムアウト設定:エンジンごとに適切なタイムアウト値を設定(Gotenberg: 30〜60秒、wkhtmltopdf: 15〜30秒)
- 品質劣化の通知:フォールバックで生成されたPDFは品質が異なる可能性があるため、メタデータに使用エンジンを記録
フォールバック時の品質管理
GotenbergからwkhtmltopdfにフォールバックしたPDFは、見た目が異なる可能性があります。この差異にどう対処するかも設計の一部です。
- 許容する場合:「PDFが生成されないよりは、多少レイアウトが崩れても出力された方がいい」という判断。バッチ処理や社内文書向け
- 許容しない場合:フォールバックせずにエラーを返し、ユーザーにリトライを促す。デザイン品質が重要な外部向け資料向け
この判断はテンプレートやユースケースごとに異なるため、テンプレートレベルでフォールバック許可/禁止を設定できる設計が理想的です。
運用・監視のポイント
デュアルエンジンの運用では、単一エンジン時とは異なる監視ポイントがあります。
監視すべきメトリクス
| メトリクス | 確認ポイント |
|---|---|
| エンジン別の成功/失敗率 | 特定エンジンの失敗率が上昇していないか |
| フォールバック発生率 | フォールバックが頻発する場合、プライマリエンジンの調査が必要 |
| エンジン別の処理時間 | p50/p95/p99で処理時間の分布を監視 |
| メモリ使用量 | Gotenbergコンテナのメモリ使用量推移 |
| キュー待機時間 | PDF生成リクエストがキューに滞留していないか |
CJKフォントへの対応
日本語を含むPDFを生成する場合、フォントの取り扱いはエンジンを問わず注意が必要です。
- Gotenberg:コンテナ内にフォントファイルをインストールするか、CSSで
@font-faceを指定 - wkhtmltopdf:システムにフォントがインストールされている必要あり。Dockerの場合はマルチステージビルドでフォントを追加
どちらのエンジンでも、フォントが見つからない場合は文字化けやトーフ(□)表示になります。本番環境と同じフォント設定をステージング環境でも再現し、事前に検証することが重要です。
リソース管理とスケーリング
PDF生成はCPU・メモリ集約型の処理です。マルチテナントSaaSでは、テナント間の公平性を保つためのリソース管理が重要になります。
- 並行処理数の制限:エンジンごとに同時処理数の上限を設定し、リソース枯渇を防止
- キューによる制御:PDF生成リクエストをキューイングし、順次処理
- プラン別の優先度:有料プランのリクエストを優先処理
- 水平スケーリング:Gotenbergコンテナを複数起動し、ロードバランシング
エンジン選定のディシジョンツリー
新しいPDF生成要件が出たときのエンジン選定を、ディシジョンツリーで整理します。
- FlexboxやCSS Gridを使用する → Gotenberg
- JavaScriptによるレンダリングが必要 → Gotenberg
- 大量バッチ処理(100件以上/時)→ wkhtmltopdf(またはGotenbergの水平スケーリング)
- テーブルベースのシンプルなレイアウト → wkhtmltopdf
- どちらでも対応可能 → Gotenberg(将来性とCSS対応の広さで優先)
迷った場合はGotenbergをプライマリに選択し、wkhtmltopdfをフォールバックとして配置するのが安全な選択です。Chromiumベースのエンジンは今後も進化が続くため、長期的な保守性の点でも有利です。
wkhtmltopdfの将来性とエンジン移行の展望
wkhtmltopdfは2023年に公式メンテナンスが終了し、セキュリティパッチも提供されない状態です。ユーザーが提供するHTMLを処理するSaaSでは、パッチ未適用のWebKitエンジンがセキュリティリスクとなり得ます。
FUNBREWでは現在、wkhtmltopdfをフォールバック用途として運用していますが、中長期的にはPlaywright(Chromiumベース)やWeasyPrint(Pythonベース)への移行を視野に入れています。Strategyパターンで設計しておけば、新しいエンジンへの切り替えは既存コードへの影響を最小限に押さえられます。
デュアルエンジン戦略の最大のメリットは、このようなエンジンの世代交代を段階的に進められる点にもあります。新エンジンをまずフォールバックとして導入し、安定性を確認した後にプライマリに昇格させる、というアプローチが取れるためです。
まとめ:デュアルエンジン戦略の設計指針
PDF生成エンジンの選定は「どちらが優れているか」ではなく、「どう組み合わせるか」が重要です。デュアルエンジン戦略のポイントをまとめます。
- 特性を理解して使い分ける:Gotenberg=リッチなレイアウト、wkhtmltopdf=軽量・高速
- 統一インターフェースで抽象化:Strategyパターンで呼び出し側をシンプルに保つ
- フォールバックで耐障害性を確保:プライマリ失敗時に自動切替、品質管理はテンプレートレベルで制御
- 監視と運用を設計に組み込む:エンジン別の成功率・処理時間・フォールバック率を継続監視
この設計パターンは、PDF生成に限らず「複数の処理エンジンを持つシステム」全般に応用可能です。画像変換、動画エンコード、文書変換など、エンジンの特性に応じた使い分けとフォールバックの考え方は共通しています。
FUNBREWでは、自社SaaSプロダクト「FUNBREW PDF」の開発で培ったPDF生成基盤の知見をもとに、システム開発をご支援しています。PDF生成やSaaS開発でお悩みの方は、ぜひお気軽にご相談ください。
この記事をシェア