はじめに:午前3時のページャー
マイクロサービスアーキテクチャが普及するにつれ、障害対応の複雑さは増す一方です。午前3時、重要なサービスのエラー率上昇を知らせるアラートを受信したと想像してください。数千のサービスが絡み合う環境では、「何が壊れたか?」よりも「何に影響があるか?」「どこから問題が始まったか?」という問いが重要になります。
Netflixのエンジニアたちはまさにこの問題に直面しました。従来のメトリクス、ログ、トレースはそれぞれサービスの断片的な情報しか提供せず、全体の接続関係を一目で把握できるツールは存在しませんでした。本記事では、Netflixがこの課題を解決するために構築したService Topologyシステムの設計思想とアーキテクチャを詳細に分析します。
本記事はNetflix Tech Blogの原文を基に、日本の開発者向けに再構成しています。

本論1:3つのデータソースで構築する「生きた」マップ
Netflixが導き出した核心的な結論は、単一のデータソースでは完璧な依存関係マップは描けないということです。そこで彼らは、3つの相補的なソースを活用して個別のグラフを作成し、それらを統合するアプローチを採用しました。
1. eBPFネットワークフロー(ネットワーク層)
取得方法: eBPF技術を使用してカーネルレベルでネットワーク接続情報をキャプチャします。どのサービスがどのサービスのIPに接続しているかが記録されます。
強み: すべてのサービスをカバーします。アプリケーションのインストルメンテーション有無に関わらず、実際のネットワークトラフィックを収集するため、計装されていないサービスも見逃しません。
限界: アプリケーションコンテキストが不足します。「サービスAがサービスBに接続した」ことはわかりますが、/api/v1/usersなのか/api/v1/ordersなのかはわかりません。
2. IPCメトリクス(アプリケーション層)
取得方法: インストルメンテーションされたサービスがgRPC、GraphQL、RESTなどで他のサービスを呼び出す際に発行するメトリクスを収集します。
強み: 豊富なアプリケーションコンテキストを提供します。呼び出された特定のエンドポイント、エラー率、レイテンシ分布、プロトコル情報がわかります。
限界: インストルメンテーションされたサービスでのみ動作します。メトリクスを出力しないサービスは見えません。
3. End-to-Endトレーシング(リクエスト層)
取得方法: 分散トレーシングシステムを通じて、個々のリクエストがシステムを通過する経路を収集し集約します。
強み: 実際のリクエストパスを表示します。「サービスAがサービスBを呼び出せる」ではなく、「サービスAがこの特定のリクエストを処理するためにサービスBを呼び出した」という事実を示します。条件付きロジックやフィーチャーフラグの影響も捉えます。
限界: サンプリングベースです。すべてのリクエストを追跡できないため、稀にしか使用されないコードパスは集約ビューで欠落する可能性があります。
統合の力
これら3つのグラフは物理的に分離して保存されますが、ユーザーは統合ビュー(Unified View)をリクエストできます。システムはすべてのレイヤーで同時に探索クエリを実行し、結果をマージすることで、サブセカンドの応答時間を維持します。
# 擬似コード: 統合グラフクエリの例
# 実際の実装はgRPC APIと分散グラフDBに基づく
def get_unified_dependencies(service_name):
# 1. ネットワーク層グラフのクエリ (eBPFベース)
network_edges = query_network_graph(service_name)
# 2. アプリケーション層グラフのクエリ (IPCメトリクスベース)
app_edges = query_application_graph(service_name)
# 3. トレーシング層グラフのクエリ (分散トレーシングベース)
trace_edges = query_tracing_graph(service_name)
# 4. 3つのグラフのノードとエッジをマージ (重複除去、属性マージ)
unified_graph = merge_graphs([
network_edges, # すべての接続 (漏れなし)
app_edges, # エンドポイント、プロトコル詳細情報
trace_edges # 実際のリクエストパターン
])
return unified_graph

本論2:日本での適用コンテキストと注意点
日本の開発現場での示唆
Netflixのアプローチは、その規模とインフラが異なる日本の環境にそのまま適用するのは困難です。しかし、核となるアイデアは十分に参考になります。
-
マルチレイヤーアプローチの重要性: 日本では多くの企業がAPMツール一つに依存しているケースが少なくありません。Netflixの事例は、ネットワーク層、アプリケーション層、リクエスト層のすべてを俯瞰する必要があることを示しています。
-
eBPFの活用可能性: 最近のLinuxカーネルではeBPFが徐々に普及しています。CiliumやPixieなどのオープンソースプロジェクトを通じて、日本でもeBPFベースのオブザーバビリティを導入する事例が増えています。
-
タイムトラベル機能: 「昨日は正常だったのに…」という疑問に答えるため、Netflixは過去の時点のトポロジーを照会できる機能を提供しています。これは障害原因の分析に非常に有用です。
この技術の限界と注意点
- インフラコスト: eBPFフローログをリアルタイムで収集し、分散ストリーム処理パイプラインを運用するには、相当なインフラコストが発生します。Netflixはこれを負担できる規模の企業です。
- データ品質: 誤った依存関係情報は障害対応をむしろ妨げます。Netflixは3つのソースをクロスチェックすることでこの問題を解決しましたが、データパイプラインの正確性を維持するには継続的な努力が必要です。
- 複雑さ: 3つのグラフを維持管理し、統合ビューを提供するシステム自体が複雑です。日本の中小規模チームであれば、オープンソースソリューション(例:Jaeger + Prometheus + Grafana)を組み合わせて類似の効果を得ることを最初に検討するとよいでしょう。
合わせて読みたい記事

まとめ:実務適用のためのアドバイス
NetflixのService Topologyは、単なる可視化ツールではなく、分散システムの「真実の情報源(Source of Truth)」 として機能します。エンジニアは複数のツールを行き来して情報を組み立てる必要がなくなり、一つのマップで依存関係を把握し、ブラストレーダー(Blast Radius)を計算し、問題の根源を追跡できます。
次のステップとしての学習方向
-
eBPFの基礎学習: LinuxカーネルのeBPF技術がどのように動作するかを理解すると、ネットワークレベルのオブザーバビリティをより深く理解できます。
bcc(BPF Compiler Collection)プロジェクトを調べてみてください。 -
分散ストリーム処理の実践: NetflixはApache Pekko Streams(Akkaのフォーク)を使用しました。Kafka StreamsやApache Flinkなどの代替技術を実践し、ストリーム処理パイプラインの概念を習得することをお勧めします。
-
グラフデータベースの探索: Neo4j、Amazon Neptune、DgraphなどのグラフDBを使用して、小規模な依存関係グラフを実際に構築してみてください。Netflixのアプローチを縮小規模で体験できます。
障害対応のパラダイムは「何が壊れたか?」から「何に影響があり、どこから問題が始まったか?」へと進化しています。Netflixの事例は、この進化の方向性を明確に示しています。日本の開発者の皆さんも、このインサイトを基に、ご自身のサービスに適したオブザーバビリティ戦略を考えてみてはいかがでしょうか。