LINE株式会社は、2023年10月1日にLINEヤフー株式会社になりました。LINEヤフー株式会社の新しいブログはこちらです。 LINEヤフー Tech Blog

Blog


【インターンレポート】サービス依存関係の有向グラフでの管理による障害影響範囲の可視化

はじめに

こんにちは。この度、Verda Reliability Enginneringチームにて技術職就業型インターンシップに参加させていただきました、慶應義塾大学政策・メディア研究科修士1年の上田です。この記事では私の担当した業務の内容についてご紹介します。

Verda Reliability EngineeringチームはLINEのプライベートクラウドであるVerdaのSRE業務を行なっているチームです。そのため今回のインターンシップでは、次節で述べるVerdaにおける運用上の課題を解決することを目指しました。

課題

Verda上ではOpenStackをベースに、VMやベアメタルマシン、Kubernetes、ロードバランサ、ストレージ、DBなどをはじめとした多くのサービスが提供されています。そして、これらのサービスを提供するためにVerdaの内部では多くのソフトウェアが動作していますが、その依存関係は非常に複雑なものとなっています。

そのため、あるサービスの特定の部分に障害が発生した場合、どれだけの範囲に影響が及ぶのか瞬時に判断することが難しいという問題がありました。例えばVerdaで提供されるMySQLサービスはVMサービスに依存していますが、L4LBは依存していません。また、OpenStack自体も非常に複雑なソフトウェア群であり、例えばOpenStackを構成するコンポーネントの特定のプロセスがダウンした場合に、その影響が及ぶ範囲を判断することは容易ではありません。

さらに障害影響範囲を推定することが困難であれば、適切なサービスレベルの設定が困難になる、あるサービスに何らかの変更を加える際のリスク推定が困難になるなどの問題も付随して発生し、ユーザがVerdaのサービスをどのように使用するかの意思決定にも悪影響を与えます。

アプローチ

そこでVerda内におけるサービスの依存関係を有向グラフとして管理するソフトウェアを実装することで、この問題を解決することを目指しました。この有向グラフにはService、Function、Process Group、Processの4種類のノードを配置することが出来ます。以下に簡単な例を示します。各ノードを色分けをした丸、依存関係をそれらを繋ぐ矢印で表現しています。なお本構成はあくまで例であり、サービスの依存関係を忠実に表現する場合はより多くのノードが必要です。

ServiceはVerda上で提供される、またはVerdaを構成するサービスを表すノードです。先の図ではnova、neutron、rabbitmq_nova、openstack_dbなどが該当します。Functionはサービスが提供するAPIなどの機能を表します。Novaが提供する機能であるcreate_server(VMの作成)やNeutronのget_metadata_from_server(VMのメタデータ取得)などが該当します。Process Groupはサービスを構成するプロセスそのものを表す、Processは各Functionが依存しているプロセスの機能を表すノードです。これらを分離して表現する理由は、例えばあるFunction AとFunction BがあるProcess Pに依存している場合を考えたときに、 それぞれのケースでProcess Pの依存するノードが異なる場合がある、つまり、サービスの各機能はサービスを構成するプロセスの有する機能全てを使用するわけではないからです。これをシンプルな実装で、かつ、有向グラフとして視覚化した際にわかりやすく表現するためにProcess GroupとProcessの二種類のノードを用いています。

この様な有向グラフでVerda内におけるサービスの依存関係を表現した上で、各ノードにメトリクスなどのメタデータを付加すれば、Verda上のサービスを提供する特定のプロセスがダウンした場合、ハードウェアの故障などにより特定の機能のみがダウンした場合など、想定される様々な障害についてその影響範囲を可視化し、先述の問題を解決することが出来ます。また、有向グラフを用いて依存関係を管理しているため、循環依存のような好ましくない構成を発見することや、メトリクス的に異常が発生しているが障害の原因がわからない際に、メトリクスに異常のあるノードから依存先を辿っていくことで障害の原因となったノードを把握することも可能です。

実装

上述のアプローチをSDG(Service Dependency Graph)というプロジェクト名で実装しました。実装にはGolangを用い、各コンポーネントはDockerを用いてコンテナ上で動作させることでポータビリティを確保しました。以下にSDGの構成図を示します。

SDGはService、Function、Process、Process Groupなどの依存関係、メトリックスなどのメタデータをMariaDB上で管理します。ユーザはsdg_serverが提供するGraphQL APIを通じてサービスの依存関係を有向グラフとしてDBに登録し、任意のデータソースから各ノードのメトリクスを定期的に更新していきます。以下にSDGが提供するGraphQL APIのスキーマの一部を示します。

ユーザはMutation createSdgNodesを用いて各ノードを登録し、サービスの依存関係を現す有向グラフを構築していきます。メトリクスの更新にはMutation updateSdgNodesを用います。getSdgNodes、getSdgNodesAll、getSdgNodesGql、getSdgNodesGqlAllなどのQueryを用いてノードのオブジェクトを取得し、ノードの依存関係やメトリクスなどのメタデータを取得することが出来ます。

sdg_serverの提供するGraphQL APIにおいて、QueryやMutationの引数は多くの場合ノードのIDの配列となります。これはSDGというソフトウェアの特性上、GraphQL APIにおいて発生しがちなN+1問題にユーザ側で大きな労力をかけることなく対処することが可能であり、そうした方がSDGの実装をシンプルに保つ上で有効であると判断しているためです。

一般的に、GraphQL+RDBの構成において特定のオブジェクトの単一のIDを引数とするリゾルバを実装すると、そのリゾルバが実行される度にSQLを発行することになりがちです。取得するオブジェクトが他のオブジェクトへのRelationを定義している場合にはこの数はさらに膨れ上がるだけでなく、発行されるSQLごとのパフォーマンスに与える影響がより深刻になります。このような場合、GraphQL API server側に複数の問い合わせをまとめて実行するDataloaderを実装して負荷を軽減するというアプローチが一般的です。

しかし、SDGというソフトウェアの特性上、主な処理はノードの依存関係、メトリクスの取得、更新を行うものに集中すると考えられます。取得処理はGrafanaなどの可視化ツール、更新処理はSDGを利用するユーザが実装する、何らかのメトリクスのデータソースから定期的にメトリクスを取得し、sdg_serverにメトリクス更新のリクエストを送信するアプリケーションと想定されます。これらの処理はいずれもバッチ処理であるため、ユーザはまとめてリクエストを送信することになります。相互に時系列的な依存関係もない処理であるため、GraphQL APIのインタフェースさえ複数のノードへの処理をまとめてリクエストできる様になっていれば、RDBは処理を相対的に少数のSQLに纏めることができます。その他の処理を担当するAPIについても極力発行されるSQLの数を減らすよう、基本的にオブジェクトのIDの配列を引数に取るデザインとしてあります。

作成されたグラフはgrafana_exporterが提供するREST APIをGrafanaのデータソースとして用いて可視化することが出来ます。以下は先に挙げた例の構成をGrafanaで可視化したものです。

障害が起きた場合、各ノードのメトリクスの変化から影響範囲が明確に可視化されます。以下に先の構成でNeutron用のRabbitMQがダウンした場合にGrafanaにて表示される有向グラフを示します。障害の範囲が可視化されただけでなく、任意のメトリクスに異常のあるノードから依存先のノードを辿っていくことで障害の原因となったノードを突き止めることも可能になっています。

Redis Pub/Subを用いて各ノードの登録、更新、削除、メトリクスをはじめとするメタデータの変更などを通知するSubscription APIも実装されています。これによりSlack等のオフィスツールとの連携も容易に行えます。

data_inputterはyamlファイルで記載されたサービスの依存関係を登録するためのツールです。sdg_serverが提供するGraphQL APIは各ノードの登録、更新、削除をサポートしています。そのため、構成の変更などの変化にユーザ側で追従することは出来ますが、これは頻繁に発生する事象ではないと考えられます。そこで、依存関係を示す有向グラフはツールを用いて先に入力してしまい、ユーザ側ではデータソースからのメトリクスの取得、更新処理のみを実装するといった簡便な使用方法を可能にするために、このツールを作成しています。以下にyamlファイルの一例を抜粋したものを示します。

おわりに

今回のインターンシップでは、Verda内のサービスの依存関係を有向グラフ上で管理するソフトウェアであるSDGを開発し、各サービスの依存関係を明確に表現することで、障害影響範囲の正確な把握、適切なサービスレベル設定、サービスに変更を加える際のリスク推定などへの貢献を目指しました。

最後にインターンシップを終えての感想を記しておきます。

私はインターンシップ開始前にインフラの経験はありましたが、OpenStackの運用、開発の経験はなく、Golangでのプロダクト開発経験もありませんでした。そのため、当初はメンターの話を理解することに苦労することもありましたが、手厚いサポートを頂き開発を進めることが出来ました。

LINEの様な大きな組織で就業するという経験も初めてのものでしたが、社員の方の働き方、共通する価値観、福利厚生など様々な面でとても働きやすい組織であると感じました。このブログをきっかけに一人でも多くの方がLINEでのインターンシップへ興味を持っていただけたらなと思っております。