Browser Use: EC2上でFirecracker microVMを実行し、高性能クラウドブラウザを実現する
Browser Useは、クラウドブラウザのインフラを再構築し、ブラウザ1時間あたりのコストを$0.02(以前の$0.06から削減)に抑え、VMのコールドスタート時間を400ms未満に短縮しました。このシステムは、すべてのブラウザセッションに独自のFirecracker microVMを割り当てることで高い隔離性を実現し、コストとスケーリング速度を最適化するために、これらのVMを通常のAmazon EC2インスタンス内でネストして実行しています。
UnikernelsからFirecrackerへの移行
Browser Useは、スケーリングの制限によりUnikraft unikernelsからの脱却を図りました。unikernelsは高速な起動時間と低いアイドルコストを提供していましたが、堅牢な組み込みオートスケーリング機能が不足していたため、トラフィックの急増時に手動のエンジニアリング介入が必要となり、以前の負荷テスト中に45分間の本番環境停止を引き起こしました。
Firecrackerが採用された理由は、軽量な仮想化レイヤーを提供し、各ブラウザをホストおよび他のセッションから隔離しつつ、コントロールプレーンがVMの作成と監視をより効果的に管理できるようにするためです。
自動スケーリングのためのカスタムコントロールプレーン
Unikernelsで直面したスケーリングの問題を解決するために、Browser Useはカスタムコントロールプレーンを開発しました。このコントロールプレーンは、以下の機能を通じてブラウザのフリートをリアルタイムで管理します:
- Host Selection: ユーザーを空き容量のあるEC2ホストに割り当てます。
- Dynamic Scaling: トラフィックが増加したときに新しいマシンを自動的に起動し、削除対象としてマークされたホストへの新しいセッションの送信を停止します。
- Real-time Monitoring: 現在起動中のブラウザを追跡し、新しいセッションを受け入れられないホストを特定することで、標準的なAWS CloudWatchメトリクスよりも高速に動作します。
EC2におけるネストされた仮想化の最適化
Firecrackerは通常、ベアメタル(.metal)インスタンス上で実行されますが、Browser Useは通常のEC2インスタンスを利用しています。このアプローチにより、ホストの起動時間が短縮され(約30秒)、コストも抑えられますが、ネストされた仮想化(VM内でのVMの実行)という課題が生しまいました。
2つのハイパーバイザレイヤーをまたぐページフォールトによるレイテンシを軽減するため、チームはメモリとCPUの最適化を行いました:
メモリ最適化とページフォールトの削減
初期のコールドスタートは9.8秒かかり、VM exitsの72%がページフォールトによるものでした。チームは以下の方法でこれを3.1秒まで短縮しました:
- Increasing Page Size: 4KBページから2MBページに切り替えることで、ページあたりのページフォールトの回数を512倍削減しました。
- Implementing
userfaultfd: LinuxのuserfaultfdAPI用のカスタムハンドラーを使用し、Chromiumが最初にアクセスする可能性が高いメモリページをプリロードします。 - Removing Legacy Checks: 存在しないPS/2キーボードの500msのチェックを無効化しました。
- Optimizing Ready-Signals: HTTPポーリングを
vsock通信チャネルに置き換えることで、ホストがブラウザの準備が整うのを1ミリ秒未満で検知できるようにしました。
CPUスケジューリングとバースト管理
Chromiumの起動はCPU集約型ですが、運用フェーズは比較的静かです。Browser Useは、これを2段階のCPU戦略によって管理しています:
- Launch Phase: 仮想CPU(vCPU)のピン留めを行わず、Linuxが起動時のバーストをすべての利用可能なホストコアに分散させることができます。
- Operational Phase: ブラウザが準備完了になると、干渉を防ぎ、ホストあたりのブラウザの集約密度を高めるために、vCPUを安定したコアにピン留めします。
- Hyperthread Management: 物理コアの競合を防ぐため、各ブラウザには物理コアの兄弟スレッドの両方が割り当てられます。
- Real-time Priority: vCPUにリアルタイム優先度を与えることで即時実行を確保し、1,000ブラウザの負荷テスト中にセッション損失をゼロにしました。
Headless Chromiumのフォークによるステルス性の実現
GPUやディスプレイサーバーのオーバーヘッドなしにボット検知を回避するため、Browser Useは、完全にヘッドレスなアプローチとカスタムのChromiumフォークを組み合わせて使用しています。
- Low-level Patching:
navigator.webdriverのような自動化フラグを隠すためにJavaScriptインジェクションを使用する代わりに、チームはChromiumをソースレベルでパッチ適用し、これらのフラグが露出しないようにしました。 N-level Fingerprinting: システムは、macOS、Windows、およびLinuxにわたる数万種類のリアルなフィンガープリントを利用して、実際のユーザー環境をmimic(模倣)します。
内部ベンチマークによれば、このアプローチにより、ブロックされる確率を81%のケースで回避し、通常のヘッドレスChromium(2%)よりも大幅に高い回避率を実現しています。
パフォーマンス・パフォーマンス・結果と今後のロードマップ
10,000セッションの負荷テストにおいて、システムはp50ブラウザ作成レイテンシを825ms、p99を1.35sとし、信頼性100%を達成しました。VMのコールドスタート自体は400ms未満です。
次のボトルネック:Chromiumの起動
最大の残存レイテンシは、VMが再開された後にChromiumを起動するのに必要な545ms(p50)です。チームは現在、Chromiumがすでに起動した後のVMのスナップショットを作成することに取り組んでいます。これにより、新しいセッションが起動中のブラウザとともに目覚めることが可能になり、ChromきングChromiumの起動時間をクリティカルパスから完全に排除できる可能性があります。