Netflixは、汎用のAPIゲートウェイとして、Zuulの再構築を発表した。Zuul[1]は、元々ブロッキングで同期するソリューションだった。Zuul2と呼ばれる新たな試みは、ノンブロッキングで非同期なソリューションである。Zuul2とZuul1の主要なアーキテクチャ上の違いは、Zuul2がNettyを使って非同期でノンブロッキングなフレームワークで動くことである。Zuulにおいてスループットを増やすためにマルチスレッドに頼っていた代わりに、NettyフレームワークはZuul2に同じことをするためにイベントループとコールバックを活用する。
InfoQは、Netflixの新たな試みの責任者であるエンジニアリングマネージャーのMikey Cohen氏に話を聞いた。
InfoQ: あなたは、Zuul2の新たな試みを旅のように述べている。長い旅のように思う?旅の全体像や動機付けを教えてくれる?なぜ、そんなに長くかかるのか?
Cohen氏: Zuul2への主な動機は、デバイスへの永続的な接続のためにスケールできるシステムを構築することだった。8,300万を超えるメンバー、それぞれの複数の接続したデバイス、どうやったら大規模なチャレンジへの帳尻をあわせることができるかを目撃できる。永続的な接続、デバイスとクラウド上の制御システムの間で、プッシュと双方向なコミュニケーションを可能にする。それによって、プッシュ通知を伴うデバイスからのポーリングリクエストを置き換えることができる。ポーリングリクエストは、我々のマイクロサービスへのデバイスからのリクエストの可也の部分を占める。これはコストを減らして、より良いユーザーエクスペリエンスを提供する。加えて、よりリッチなユーザーエクスペリエンスから遥かに優れたデバッグ機能まで、それらの機能を使って多くの面白いフィーチャーを開発することができる。最後に、大規模でWebSocketやHTTP/2といった多くのプロトコルをサポートできる。
実際、これは旅であった。孤立しながらZuul2を構築していたら、素晴らしい小旅行ではなかっただろう。Netflixにおけるこのような変更の複雑さは巨大である。Zuul上のクラウドゲートウェイは、Netflixのクラウドサービスのフロントドアである。我々は、1000種類を超えるデバイスをサポートしている。これらのデバイスの多くが持つ微妙な差異、前提、そして制約は大きく変わる。これらの奇妙な特徴のすべては、Zuulにおいて標準化され、サポートされることが必要である。 例えば、幾つかのデバイスはヘッダーの順番に関心がある。幾つかはヘッダーのサイズに制限がある。幾つかはchunked encodingをサポートしていない。そして、幾つかの特性はTomcatとNettyで異なる対処がされている。これらの違いを認識して、互換性を作り出すことが、このプロジェクトの大きなチャレンジである。これらの問題の多くは、現実のトラフィックを使うことだけで見つけることができる。本番環境でカスタマーに影響を与えずに問題を検出することは、巨大なリスクと影響を緩和するためのエンジニアリングスキルの間の細い道を歩くことを伴う。ここでの失敗は、8300万人のメンバーの一部か全てが、Netflixコンテンツを配信することがどうやってもできないことを意味する。
我らのスタックの深いところに話を向けると、非同期環境で実行する必要があるゲートウェイとプラットフォームインフラストラクチャの全ての機能がある。ZuulフィルタだけでなくNetflixのプラットフォームインフラストラクチャの全ては、ブロッキング環境で実行されるという根深い前提で作られている。リクエストにスコープされることで引き継がれるスレッド変数は、我らがサポートするライブラリやプラットフォームコードで普遍的に使われている。ブロッキングI/Oは、プラットフォームにおける2つ目の特性である。これらのコンセプトは、非同期でノンブロッキングなアーキテクチャでは働かない。このアーキテクチャで動く互換性のあるソリューションを構築するだけでなく、これらの領域を特定することは、ときどき難しく、時間を食うものであった。
この旅の一部は、Netflixでのゲートウェイの適切な役割として私たちが考えているものを理解することである。簡単に言えば、この役割はNetflixに来るリクエストのルーティング、判定、正規化をすることである。Zuul2への迂回路は、Zuulに持っている多くのビジネスロジックを削除して、起点となるシステムにロジックを移動した。ゲートウェイの役割について明確に説明するだけでなく、多くのコードを削除したため、ブロッキングコードの移行も簡単なった。
Zuulフィルタを構築し、非同期なフィルタ解析を行うことは、進行中のもう一つの大きなプロジェクトだった。ブログで述べたように、我々はZuul2を構築する前にこれを行い、Zuul1とZuul2で実行するZuulフィルタのセットを同じにすることができた(非同期コードは同期環境で実行できるが、それ以外の方法では動作しない)。これによって、1セットのフィルタでゲートウェイ機能を引き続き開発することができた。フィルタ連鎖の何回かのイテレーションだけでなく、Zuulフィルタのインターフェースの変更の数回のイテレーションがあった。Zuulフィルタを連鎖させるためにRxJavaを使った。100を超えるZuulフィルタを移行することは、細かいことにまで神経を使う時間の掛かる作業であることが証明済みである。
最後に、Zuul2を実行するためのフレームワークを構築するには、幾つかのイテレーションが必要だった。最初はNettyの初期バージョンで書かれたプロトタイプから移転した。そこからRxNettyプロジェクトを使って移転した。Zuul2を構築するある時点で、RxNettyが抽象化していたコアNetty機能が必要であることが分かったので、Nettyに代わってRxNettyに切り替えた。これらの様々な道を歩み、我々が行った訂正と学習をすることで、より強力なプロダクトを作り上げた。
InfoQ: あなたのブログに書かれていることだが、マルチスレッドシステムは、バックエンドの待ち時間、リトライなど、何かが上手くいかないことを除いて、殆どの場合で機能する。新しいアーキテクチャに移行することの他の理由はあるか?
Cohen氏: 我々は、CPU効率の大幅な向上と回復力の改善が見られるとの信念を持っていた。我々は、確かに一部のクラスター(すべてではない)の効率(10・5%)の改善を見ているが、この領域ではひどくがっかりさせられた。我々の誤算は、ゲートウェイ内で行うCPUの作業量に起因しているようだ。そして、非同期nioのアーキテクチャ効率をCPU作業が上回るポイントを解明することである。私は、Zuul2(それがリリースされたとき)のオープンソース版を使っている他の人たちが、NetflixのZuul2ゲートウェイで行う殆どの仕事がNetflixスタックに特に関係しているため、大幅な効率の向上が見られると考えている。多くの人が10-25%のパフォーマンス向上といった数字を見て、それを大きな成功と考えるだろう。成功を実現するための時間と労力を考慮に入れると、非同期nioシステムがもたらした運用とデバッグにおける他の問題と、パフォーマンスの考慮事項は、労力を正当化するには十分ではない。そうは言っても、コネクション管理やプッシュ通知といった他の便益や回復力の向上は、我々にとってますます重要である。
・また、いくらかの回復力の向上が期待されていた。私がブログで言及したように、我々はこれが実現するのを見ることになると思うが、無料ではない。我々は、より回復力の向上を実現するためにコネクションの再利用やロードバランシングアルゴリズムを調整すること、スロットルの変更や、エラーが発生したときの例外のロギングやインスタンスの減少のようなことを積極的に調査する。
InfoQ: ZuulフィルタはZuulの重要な部分である。あなたは、フィルタを使って再構築の試みをはじめました、間違いない?フィルタの再構築について説明して、大規模システムの再構築において、同じアプローチを使う開発者に幾つかの助言を提供できる?
Cohen氏: 非同期に実行するためにゲートウェイのビジネスロジック部分を変更することが適切な方向になるという認識はとても洞察力があり、長期的には時間を節約できた。これにより、同等に保つ必要があった2組のフィルタ(Zuu1用とZuul2用)を持つことが不要になった。これは、Zuul2を構築するための前提となる、6ヶ月かそれ以上の可也大きな初期投資だった。私は、多くのエンジニアリングチームはこれを本末転倒だと見るだろうと想像していた。しかし、これは多くの理由から非常に有益であることがわかった。まず、前述したように、フィルタの開発が1つのコードベースで扱われ、ビジネスロジックが同一性が保証された。なぜなら、ビジネスロジックが確固たるものであると知っていたので、問題の原因として取り除くことができ、最後にシステムと運用の観点からZuu1とZuul2をどのように比較されるかを確認する素晴らしいツールになった。
InfoQ: 同期でブロッキングなソリューションから非同期でノンブロッキングなソリューションに移行することにおいて、開発者とアーキテクトを助けるような戦記はあるか?RxNettyは?あなたの努力においてどれくらい重要だった?
Cohen氏: 非同期システムへの移行において多くの戦いがあった。それらの多くは互いに混ざり合っているが、確かに一般的なテーマとパターンがある。多少のリーク、ByteBuf、セマフォ、ファイルディスクリプタなどがあることに気づくことから始まる。これらは滅多に起きないエッジケースである。デバッグが続く。原因を特定するには1週間かかることもあるが、普通なら数日かかることもある。解決方法は色々あるが、エラー発生時にイベントを伝播させないことがよくある。我々が得た経験を基に、我々が構築した幾つかのツールを寄付しようとしている。例えば、Nettyにプラグインできるリソースリーク検出器を提供した。これによって、モニタリングツールでリソースリークを検出できる。我々は、これらのパターンに関係する問題を素早く解決するのに役立つチェックポイントのようなものを提供したいと考えている。
これらの戦いは、全てが孤独と戦うことではない。これをテストするために構築したテストフレームワークは、実際のメンバーや起点システムと並行実行されて大規模である本番環境では非常に多くの問題を表示させることになり、その程度のものである。ゲートウェイが壊れたり、誰もストリームできないといった、変更のリスクは高い。素早く移行することは、多くを学ぶことを意味する。しかし、顧客に影響する高いリスクがある。そして、より慎重になるということは、漸増的な学びを意味する。メンバーへのリスクは少ない。従って、リスクを取りながら素早く移行することと、より慎重なアプローチを取ることの間に微妙なバランスと格闘がある。
InfoQ: あなたは意図的にベンチマークから距離を置いていると言っている。非同期とノンブロッキングが一般的にパフォーマンスに関係づけられているとして、全体的なパフォーマンス改善の詳細を含めることができるか?
Cohen氏: 我々のゲートウェイでZuu1とZuu2(ブロッキング対ノンブロッキング)を比較する一般的なパフォーマンスの話は、本当にコネクションのスケーリングが大幅に改善されたことである。しかしながら、スループットの改善は、我々がゲートウェイで行うCPUに集中した処理によって妨げられる。この処理の多くは、メトリクス集計、ロギング、分析、暗号処理、そして圧縮のようなものである。私が言及したように、Zuu2をオープンソースにした後で、沢山の処理をしない他の実装では、恐らく大きなスループットの向上が見込まれると考えている。
InfoQ: Zuul2のオープンソースの計画と、一般的なZuulのロードマップについて詳しく説明できるか?
Cohen氏: 我々は、年末までを対象にした、Zuul2のオープンソース化に積極的に取り組んでいる。WebSocketやHTTP/2のサポートなど、幾つかの新しい機能を追加する予定である。ロードマップの視点から、我々が開発した幾つかのフィルタとルーティングツールとコンセプトのオープン化を始めるつもりである。この作業の殆どは、汎用ロジックからNetflix固有のロジックを分離することである。WebSocketとプッシュ機能を開発するとして、これらの学びとインフラストラクチャをオープンソースに引き渡したいと考えている。
Zuul2のドキュメントは途中のようである。ZuulのWikiには、Zuulの一般的な情報とはじめ方が掲載されてる。
Rate this Article
- Editor Review
- Chief Editor Action