LinkedInは先頃、同社がJavaベースのマイクロサービスで採用しているオーバーロードの検出と対処の方法を公開した。同社のソリューションであるHodorは、設定不要で機能する"適応型ソリューション"として、監視対象プロセス内部でオーバーロード検出機能とロードシェダ(load shedder)を実行し、アプリケーション処理チェーン内でロードのサンプリングと削減をシームレスに行う、プラットフォーム非依存のメカニズムを提供する。
Hodorは"Holistic Overload Detection and Overload Remedoiation"の略で、プラットフォーム非依存のアダプタを経由してプロセス内で動作する、Javaベースのコンポーネントである。複数の要因から発生するサービスのオーバーロードを検出し、適切な量のトラフィックをドロップして自動的に問題を軽減を行うことにより、サービスの回復を可能にするとともに、適切なトラフィックレベルを維持してオーバーロードの再発を防止する。
LinkedInシニアスタッフエンジニアのBryan Barkley氏は、Hodorを開発した動機を次のように述べている。
LinkedInが原型をローンチしたのは18年以上前です。テクノロジの世界では"永遠の昔"ですね。当時のサイトは、単一のモノリシックなJavaアプリケーションでした。サービスが人気を集めて、ユーザ数が増えつつある中、その基盤となるテクノロジも成長を続ける必要がありました、当社では現在、1,000を越える独立したマイクロサービスをJVM上で運用しています。オペレーションの拡大に際しては、それぞれ独自の運用的問題を抱えているのですが、各サービスが直面する共通的な問題のひとつが、サービスが過負荷になることによって、合理的なレイテンシでトラフィックが提供できなくなることなのです。
以下の図は、Hodorの内部アーキテクチャを表したものだ。
オーバーロードディテクタ(Overload Detecror)は、サービスが過負荷状況にあることを判断する。複数のディテクタを登録することが可能(アプリ特有のものを含む)で、それぞれに対してインバウンド要求毎に問い合わせが行われる。ディテクタがシステムの過負荷状態を判断すると、ロードシェダがトラフィックを抑制するべきかどうかを判断する。そして最後に、各プラットフォーム専用のアダプタが、要求の固有データを、ディテクタやシェダが理解可能なプラットフォーム非依存なフォーマットに変換するのだ。要求がリジェクトされても、すべてのアプリケーションがそれを処理するロジックを備えているため、クライアントには何の問題もない。
"Hodorの開発にあたっては、当初はオーバーロードの最も一般的なシナリオを対象としていました。その後、可能性のあるさまざまな原因へと、段階的にスコープを広げていったのです"、とBarkley氏は述べている。その結果、まず最初に開発されたのがCPU過負荷のオーバーロードディテクタであった。
長期間にわたる実験の結果、彼らがCPU稼働率の測定に採用したアプローチは、バックグラウンドデーモンスレッドをループ実行した上で、一定時間スリープするようにスケジュールする、というものだった。実際にスリープした時間を記録し、スレッドが起動した時に、期待していたスリープ時間との比較を行う。これらのサンプルを一定の時間枠で収集した後、データから特定のパーセンタイルを見て、それがしきい値を越えているかどうかを確認する。しきい値を越えた時間枠が多過ぎる場合に、サービスCPUが過負荷であると判断するのだ。
この時点で、ロードシェダがトラフィックのドロップを開始する。ただしこの時点ですべてのトラフィックをドロップするのではなく、既定のストラテジでは同時要求数の制限を行う。サービスが同時要求数の制限を越えた時に、ロードシェダがそれ以上のトラフィックを遮断するのだ。制限値未満に戻れば、すべてのトラフィックを許可する。
このメカニズムの中核にあるのは、オーバーロードディテクタからのフィードバックに基づいて同時要求数を決定し、必要に応じてその値を上下させるという、適応型のアルゴリズムである。この制限値を、過負荷が発生する間、継続的にチューニングすることによって、トラフィックロスの最小化 — サービスが運用を続ける上で十分な値であること — を保証するのだ。
トラフィックを削減している間、Hodorはクライアントに対して、リジェクトされた要求を別インスタンスで再試行するように指示する。"盲目的な再送要求は問題を発生させたり、クラスタ全体が過負荷な場合にはリトライストームに陥る可能性があります"、とBarkley氏は述べている。そのためHodorでは、GoogleのSRE Bookに強く影響されたアプローチを使って、クライアントとサーバの両面において、いくつかの再試行バジェット(retry budget)を管理している。バジェットを超過すると、要求はフェールして、全体的な状況が解決されたと思われるになるまで、サーバからのクライアントに対する再送指示は停止される。