【ITニュース解説】Architectural Breakdown: We Rendered a HQ Demo Video on a Free Farm Run by Strangers
2026年10月15日に「Dev.to」が公開したITニュース「Architectural Breakdown: We Rendered a HQ Demo Video on a Free Farm Run by Strangers」について初心者にもわかりやすく解説しています。
ITニュース概要
無料の分散型環境で4K動画をレンダリング。不安定な環境で障害が頻発したが、データベースによる状態管理、バックプレッシャー、再試行、中断からの再開機能を実装。これによりデータ損失なく動画を完成させ、信頼できない環境でも安定稼働できるシステム設計の重要性を実証した。
ITニュース解説
このニュース記事は、無料で提供される、信頼性の低い分散型コンピューティング環境を使って、高解像度のデモ動画をレンダリングするという困難な課題に直面し、それをいかに技術的な工夫で乗り越えたかについて解説している。システムエンジニアを目指す皆さんにとって、実際の開発現場で遭遇する可能性のある問題と、それに対する実践的な解決策、そしてシステム設計の根本的な考え方を学ぶ良い機会となるだろう。
物語は、深夜2時に顧客から「90秒の4Kデモ動画」のレンダリング依頼が飛び込んできたところから始まる。手元にあるのはGitHubのリポジトリといくつかのAPIキー、そして「サービス品質保証(SLA)」が一切ない、見知らぬ人々が提供する37台のコンピュータ(ノード)だった。このような信用できない環境で動画レンダリングを試みた結果、すぐに深刻な問題が次々と発生した。
最初の問題は、各ノードでメモリが足りなくなり、プログラムが強制終了する現象(OOM kills)だった。同時に、ディスクへのデータ書き込みが原因で、非同期処理を管理するメインの処理(イベントループ)が最長12秒も停止してしまった。さらに、完成した動画ファイルへの複数のノードからの同時書き込みが激しい競合状態(ロック競合)を引き起こし、処理速度は毎分たった4フレームという絶望的な状況になった。これらはすべて、ノードのメモリやCPU、ネットワーク帯域などに何の保証もない「無料ファーム」に対する楽観的な仮定が裏目に出た結果だった。ノードが途中で停止しても、担当していたフレームが失われ、再試行も行われないという状況は、分散システムにおける基本的な堅牢性の欠如を示していた。
これらの問題の根本原因を特定した結果、以下のような課題が浮き彫りになった。フレームごとの画像データを無制限にキャッシュしようとしたためメモリ不足に陥ったこと、非同期処理中に同期的なディスク書き込みが行われたためイベントループが停止したこと、共有ファイルへの書き込みが単一のロックで直列化されていたため競合が発生したこと、ノードが落ちた際のデータ回復機能が不足していたこと、多数のワーカーが同時にクラウドストレージにファイルをアップロードしようとしてレート制限に引っかかったこと、そして、弱いノードでCPUコア数が不足しているにもかかわらず、4コアを前提とした処理をさせていたためCPU性能が発揮できなかったことなどである。
これらの課題を解決するために、開発チームは「希望任せ」ではなく「バックプレッシャー駆動型」という、システムが処理能力を超過しないように、上流からのデータ流入を制御する仕組みを取り入れた堅牢なアーキテクチャを設計した。
この新しいアーキテクチャは主に三つの部分から構成される。 まず、「Coordinator(調整役)」は、動画を小さな「チャンク」という単位に分割し、それぞれのチャンクの状態を管理する。これはSQLiteという軽量なデータベースを「WALモード」という耐久性の高い設定で使用し、すべての情報(チャンクの識別子、ステータス、チェックサムなど)をメモリだけでなくディスクにも永続的に記録することで、調整役が停止しても情報を失わないようにした。再起動時には、停止前の状態を正確に復元できる。
次に、「Dispatcher(分配役)」は、調整役から受け取ったチャンクを作業を行うノード(ワーカー)に割り当てる役割を担う。ここで重要なのが、collections.deque(maxlen=512)という固定サイズのキューを使って、処理待ちのチャンク数を常に制限することだ。これにより、システム全体が過負荷になるのを防ぎ、メモリの急激な使用量増加も抑える。また、asyncio.Semaphore(MAX_CONCURRENT_UPLOADS=12)という仕組みで、クラウドストレージへの同時アップロード数を最大12に制限し、ストレージ側のレート制限エラーを防いだ。さらに、分配役はワーカーからの定期的な「ハートビート(生存信号)」を監視し、30秒以上応答がないワーカーは故障と判断し、そのワーカーが担当していたチャンクを「再試行待ち」として別のワーカーに再割り当てする。これにより、ノードの故障によるフレーム損失を完全に防ぐ。
そして、「Worker Pool(ワーカー群)」は、実際に動画のチャンクをレンダリングする個々のノードの集まりである。各ワーカーは、「MEMORY_SEMAPHORE」という仕組みを使って、ノードのメモリ容量(例えば8GB RAMの70%)に基づいて、同時に処理できるチャンク数を制限する。これにより、各ノードでのメモリ不足によるプログラムの強制終了を防止した。レンダリングにはFFmpegのようなツールを使用し、CPUスレッド数を2に固定することで、弱いノードでも安定したパフォーマンスを確保した。レンダリングが完了すると、生成された動画ファイルのチェックサム(データの完全性を確認するための符号)を計算し、調整役に報告する。同じチャンクが複数回処理されても、データベースがすでに完了していることを確認するため、無駄な処理を避ける「冪等性」も確保された。
さらに、これらのコンポーネントを補完する「Watchdog(監視役)」という仕組みも導入された。これは、分配役が監視するハートビートに加えて、定期的にアクティブなワーカーの状態を確認し、長時間応答がないワーカーが担当しているチャンクを失敗としてマークし、再試行キューに戻す役割を果たす。これにより、データ損失の可能性を最小限に抑えることができた。
ハードウェア面では、さまざまなノードタイプでのパフォーマンスとメモリ使用量を測定し、最適な構成を見つけ出した。その結果、2コア8GBのノードが最も効率的であることが判明した。これは、FFmpegのレンダリングが2スレッドで性能の頭打ちになることや、それ以上のコア数だと他のテナントとのCPU競合により性能が不安定になるためだった。最終的に、1チャンクあたり30フレーム、256MBのメモリを割り当てることで、どのノードでも安定して動作させることができた。
動画の最終的な保存には「マルチパートアップロード」という技術が大きく貢献した。これは、大きなファイルを小さな部分に分割し、それぞれを並行してクラウドストレージにアップロードする仕組みである。各部分にはチェックサムが付与されており、もしワーカーがアップロード中に停止しても、次にそのチャンクを担当するワーカーは、最後に正常にアップロードされた部分から再開できる。これにより、途中でノードが停止しても、最初からレンダリングやアップロードをやり直す必要がなく、時間とリソースの無駄を大幅に削減できた。実際に、47分かかるアップロード中にノードが消失しても、途中の94番目の部分から再開できたという事例が紹介されている。
この一連の経験から、彼らは三つの重要な教訓を得た。「無料で提供されるファームは決して信頼してはならない」「監視は常に不完全である」「最初の設計は必ず失敗する」という真実である。そして、楽観的な進捗表示を信用するのではなく、実際に転送されたデータ量を測定することの重要性、各ノードを一時的で状態を持たないものとして扱うべきこと、そしてバックプレッシャーはシステムの性能向上だけでなく、システムが優雅に障害を処理し、データの破損を防ぐための不可欠な要素であることを学んだ。
結果として、2台のノードが作業中に停止したにもかかわらず、94秒の4K動画はフレームを一切失うことなくレンダリングされた。費用は0ドル、投入されたエンジニアリング工数は約180人時間だったが、この困難な挑戦は完全に成功した。