19 ポイント 投稿者 xguru 2020-08-10 | 3件のコメント | WhatsAppで共有

数千万の同時接続、毎秒数百万リクエスト、テラ単位の帯域を使用しているDropboxが、Nginxと比べたEnvoyの利点をうまく説明した記事

従来 : nginx(オープンソース版) + python2 + Jinja2 + YAML

→ 1つだけ変わっても全体の再デプロイが必要

→ 動的な部分はLuaで開発

→ 複雑なロジックはGoベースのプロキシであるBandaidで処理

この10年近くうまく動いていたが、現在の環境にはあまり合っていない

→ 内部および外部(非公開)APIは徐々にRESTからgRPCへ移行中であり、プロキシのトランスコーディング機能が必要

→ Protocol Buffersが内部サービス定義の標準に

→ すべてのソフトウェアは言語に関係なくBazelでビルドおよびテスト

→ 主要インフラプロジェクトのオープンソースコミュニティに社員がかなり積極的に参加中

Nginxは運用面でも維持コストが高い

→ Config生成ロジックが柔軟すぎて、YAML、Jinja2、Pythonに分散している

→ 監視がLua / Log parsing / システムベース監視の混在

→ サードパーティモジュールへの依存が高まるにつれて、安定性/性能に影響し、頻繁なアップグレードによるコストが発生

→ nginx自体のデプロイおよびプロセス管理は他のサービスと大きく異なる。syslog、logrotateなど基本システムとはかなり異なるものに依存

そこで、10年ぶりに初めてNginxを置き換えるものを探すことにした

  • なぜBandaid(Dropboxが独自開発したGoベースのプロキシ)ではないのか?

→ GoはC/C++よりリソースを多く消費する。

→ GoのTLSスタックはFIPS対応ではない(米国連邦情報処理標準)

→ 内部ツールのため外部コミュニティの支援を受けられない

現在 : Envoyベースのトラフィックインフラへ移行中

----- NginxよりEnvoyが優れていた点 ------

  • 性能 *

Nginxのアーキテクチャはイベントドリブン / マルチプロセス。SO_REUSEPORT & EPOLLEXCLUSIVEをサポート

イベントループベースだが完全なノンブロッキングではない。ファイルオープン/ロギング時にはイベントループが停止する可能性がある。(aio、aio_writeおよびThreadpoolを有効化しても)

これによってテールレイテンシが発生し、数秒単位の遅延が生じることもある

Envoyも同様にイベントドリブンアーキテクチャだが、プロセスではなくスレッドベース

SO_REUSEPORTをサポート(BPFフィルタ対応)、libeventによるイベントループをサポート

イベントループでブロッキングI/Oはなく、イベントロギングもノンブロッキング方式で実装。

理論的には似たような性能特性を示しそうで、実際にほとんどのワークロードテストでも似ていた。

ただし、Nginxはロングテールでレイテンシがより大きかった。I/Oが多いときにイベントループが停止したため。

統計収集がなければNginxはEnvoyと近い性能を示すが、内部で使用中のLua統計収集ツールがhigh-RPSテストでNginxを3倍遅くしていた。(これはmutexで同期されるlua_shared_dictのため)。Dropboxの統計収集方式にも問題はあったが、これを効率的に再開発するのは断念した。(Nginx内部にインストルメンテーションすると将来のアップグレードが難しくなると見込んだため)

とにかく、このような問題がEnvoyにはなかったため、移行後は従来Nginxが使っていたサーバーの最大60%を削減できた。

  • Observability *

無料版Nginxはstub statusモジュールで7種類のstatしか提供しない

これでは当然不足していたため、log_by_luaハンドラを付けてさらに多くのstatを提供していた。

また、error.logパーサーを通じてエラー情報を出力し、nginx内部状態値を出力するための別個のexporterも存在。

基本的なEnvoyセットアップはPrometheus形式で数千種類の異なるメトリクスを提供

プロキシトラフィック情報からサーバーの内部状態情報、

クラスタ別/アップストリーム別/仮想ホスト別の統計値や、リスナー別のTCP/HTTP/TLSダウンストリーム統計情報など

このような多様な統計に加えて、EnvoyはTracing Providerをプラグイン可能。

トラフィックチームだけでなく、アプリケーション開発者にも有用。

最後に、EnvoyはgRPCを通じてアクセスログをストリーミング可能。

これにより、トラフィックチームがsyslog-to-hiveブリッジを支える負担が軽減される。

カスタムTCP/UDPリスナーを付けるより、一般的なgRPCサービスを実行するほうがはるかに簡単で安全。

  • Integration *

Nginxの統合は非常にUnix的。Configurationが非常に静的。

configファイルやTLS証明書、allowlist/blocklistなどをファイルに依存。

単純で後方互換性があるため、いくつかのシェルスクリプトで自動化は可能だが、

システムが大きくなるにつれて、テスト可能性と標準化がますます重要になる。

Envoyはこのような統合に対して独自の方法を持っている。

xDSと呼ばれるAPIを提供し、protobufとgRPCの利用を推奨。

EnvoyはこのxDSにクエリを送って動的リソースを見つける。

  • このxDSは今やEnvoyを超えて、Universal Data Place API(UDPA)という名前でL4/L7ロードバランサーのde facto標準になろうと進化しており、私たちの経験ではこれがうまく進んでいる。EnvoyだけでなくKatran eBPF/XDP L4ロードバランサーでもUDPAを使おうとしている。

Dropboxは内部でgRPCを通じてサービスが連携しているため、はるかに都合がよい。

  • Configuration *

Nginxは人間が読みやすい設定ファイルという大きな利点を持っている。

しかしこの利点は、設定が複雑化し自動生成されるにつれて失われていった。

DropboxではPython2、Jinja2、YAMLなどを通じて生成されていたため、データモデルも絡み合って複雑だった。

Envoyは設定に対する統一されたデータモデルを持っている。すべての設定値はProtocol Bufferで定義される。データモデリングの問題が解消され、設定値に型情報が追加される。

Dropbox内部ではprotobufが多く使われているため、統合も容易だった

  • Extensibility *

Nginxの拡張にはCモジュールの作成が必要。安全なモジュールを書くにはシニア開発者が必要。より軽量なモジュール開発のためにPerl / JSインターフェースも提供しているが非常に限定的。そのため最も一般的に使われる方法はlua-nginx-moduleを通すこと。

Envoyの主な拡張メカニズムはC++プラグインだが、ドキュメントはnginxほど充実していないものの非常に単純。これは整理されコメントの行き届いたインターフェース、C++14言語と標準ライブラリのおかげ

Envoyが他のWebサーバーと大きく異なる点は、WebAssembly(WASM)をサポートしていること。

これによりRustのようなさまざまな言語で拡張開発できる。

まだDropboxではWASMを使っていないが、いつかproxy-wasm向けGo SDKがサポートされれば変わるかもしれない

  • Building and Testing *

Nginxは基本的にカスタムシェルベースの設定とmakeベースのビルドを使用。単純で優れているが、これをBazelでビルドされるモノレポに統合するにはかなりの労力がかかる

NginxにはPerlベースのintegration testはあるが、unit testはない。

EnvoyはすでにビルドシステムがBazelベースで、簡単に私たちのモノレポへ統合できた。

gtest/gmockベースのunit testとintegration test frameworkをサポート

  • Security *

Nginxのコードは非常に小さく、外部依存も少ないため、セキュリティ上の脆弱性は多くない。

Envoyはコード量が多いため、そのぶん攻撃面も多く見える。そのためEnvoyは現代的なセキュリティプラクティスに大きく依存している。AddressSanitizer、ThreadSanitizer、MemorySanitizerなどを使用。

  • Features *

この部分は主観的な意見が多いので参考までに

Nginxは当初、ごく少ないリソースで静的ファイルを配信するWebサーバーとして始まった。

つまりstatic serving、caching、range cachingが主機能

プロキシの観点では、Nginxには現代のインフラで求められる機能が多く不足している。

バックエンドとのHTTP/2接続もできず、マルチプレックスされるgRPCプロキシにも対応せず、gRPCトランスコーディングも不可など。

オープンコア型のライセンスモデルのため、いくつかの主要機能は「コミュニティ版」には含まれていない

Envoyはそもそもingress/egress proxyとして始まり、gRPC負荷の高い環境で多く使われている。

Webサービス機能は非常に初歩的なレベル。ファイル配信もできず、キャッシュもまだ開発中で、brotliも未対応など

このような環境向けには、Envoyをアップストリームクラスタとして使うNginxセットアップも使用中

EnvoyがHTTPキャッシュに対応すれば、このような静的配信環境も移行できると見込んでいる

EnvoyはgRPC関連機能を多くサポート

  • gRPC proxying

  • HTTP/2 to backends

  • gRPC → HTTP bridge (+ reverse.)

  • gRPC-WEB

  • gRPC JSON transcoder

またEnvoyはoutbound proxyとしても利用可能

  • Egress Proxy

  • Courier gRPCライブラリによるサードパーティソフトウェアのサービスディスカバリ

  • Community *

Nginxの開発は中央集権的で、その大半が見えない。

Envoyの開発はオープンで分散的。GitHubのissue/PRで進み、メーリングリストやSlackなどでも活発

----- Dropboxの現在のMigration状況 -----

NginxとEnvoyを半年前から並行運用しながら、DNSを通じて段階的にトラフィックを移行中

何の問題もなく移行できたわけではなく、小さな問題はあったが深刻な障害はなかった。

"unusual" または "non-RFC" 的な挙動によって経験した問題に対する解決策も整理している(本文に詳細があるので参照)

** 今後やること **

  • HTTP/3 : Envoyも実験的サポートを開始。UDP高速化のためにLinuxカーネルをアップグレードしたら試してみる予定

  • 内部xDSベースのロードバランサーとOutlier Detection

  • WASMベースのEnvoy拡張

  • Bandaid(Goベースのプロキシ)をEnvoyに置き換え

  • Envoy MobileでモバイルアプリにもEnvoyを適用

3件のコメント

 
baeba 2020-08-13

良い内容を簡潔に

まとめてくださって

ありがとうございます。

 
before30 2020-08-11

ありがとうございます。:)

 
loslch 2020-08-11

詳細な整理と親切なご意見まで添えてくださり、理解にとても役立ちました。ありがとうございます :)