sumirenです。
ヘンリーではオブザーバビリティに投資をし、開発生産性と品質を高める取り組みをしています。 この記事では、ヘンリーが考えるオブザーバビリティ成熟度を解説し、最後にヘンリーの現状と今後について解説します。
オブザーバビリティ成熟度
全体像
筆者は、オブザーバビリティの成熟度について、以下のように考えています。 これはあくまで一般的な概念ではなく、筆者が説明のために考えた便宜上のモデルになります。
- なにもない
- インフラメトリック
- アプリケーションログ
- 非構造化ログ
- 構造化ログ
- リクエストに紐づくログ
- アプリケーションメトリック(ログベース)
- トレース
- トレース単体
- システム固有の共通的な計装
- ドメイン/機能カットの計装
- トレースの分析と集計
- トレースの相関分析
オブザーバビリティ成熟度が低い状態〜中程度の状態
1. なにもない〜 2. インフラメトリック
なにもない状態は、オブザーバビリティがない状態です。この状態では、システムで問題が起きてもトラブルシュートはできません。
そこから1つ進んだ段階に、インフラメトリックのみ存在する状態があります。この状態では、アプリケーションやDBのCPUやメモリ利用率などが確認できます。大半の組織では、インフラメトリックは取れているのではないでしょうか。一方で、アジリティの高いエンジニアリング組織では障害の大半はアプリケーションレイヤで発生するため、依然としてオブザーバビリティが低い状態と言えます。
3. アプリケーションログ
アプリケーションレイヤの障害に備えてログが取れている状態です。3.2.の構造化ログまで進むと、JSON等の形式に対するクエリや集計が可能になり、生産性が高まります。
Webサービスの場合、並行して複数のサービスでリクエストが処理されるため、ログが混在して問題のリクエストを追うのが難しくなります。マイクロサービスをまたいでリクエストにIDを割り振り、構造化ログに出力することで、システム全体でリクエストが何を行ったかを把握できるようになります(3.3.)。
4. アプリケーションメトリック
例えば「過去2時間に最も実行されたAPIはなんでしょうか」という質問に答えることはできるでしょうか。これはアプリケーションのメトリックと言えます。
オブザーバビリティ成熟度が3.2.の構造化ログの段階を超え、ロギングサービスが高速なクエリや集計に対応していれば、これに答えることができます。しかし、そうでなければ難しいでしょう。
代替アプローチとして、ログからメトリックを非同期で生成して保存しておくというものがあります。この方法では、サマリ情報を保存するため、データ量やクエリ速度の観点で効果的です。ただし、事前に決めた形式でメトリックを保存するため、生データがないため、新たな問いにすぐに答えられないというデメリットもあります。
オブザーバビリティ成熟度が高い状態
分散トレーシングが活用できている組織はオブザーバビリティ成熟度が高いと考えられます。トレースの可視化により、システムで何が発生したかを視覚的に表示でき、トラブルシュートが容易になります。
一方で、トレースの活用段階にもいくつかの成熟度があると筆者は考えています。
5.1. トレース単体
まずはトレース単体が利用されている状態です。例えばシステムで例外が発生したらSentry経由で通知され、トレースIDでトレーシングサービスを検索するといったオペレーションができている状態です。
パフォーマンスを定期的に分析している組織であれば、遅い懸念のあるエンドポイントの名前でトレーシングサービスを検索し、トレース単体を見てN+1やスロークエリの問題を判断することもできます。アプリケーションメトリックが運用されていれば、遅いエンドポイントを特定してトレーシングサービスを検索することも可能です。
5.2. システム固有の共通的な計装
上記のアプローチでN+1など技術的なトラブルを解決することはできますが、アプリケーションのトラブルの大半はロジックの問題です。例えば、もしPOST /user エンドポイントのエラーレートが10%で、そのエラーがフィーチャーフラグに依るとしたらどうでしょう。
もちろん、トレースからシステムの振る舞いの全体像を掴むことは可能で、それ自体に十分価値があります。しかし、例えばBFFや個別マイクロサービスでリクエストのペイロードやフィーチャーフラグなどの情報が(個人情報の取り扱いに注意しつつ)スパンに記録されていれていたらどうでしょうか。ソースコードを読むまでもなくトレースだけでトラブルシュートが完結する場合さえあるはずです。
5.3. ドメイン/機能カットの計装
アプリケーションレイヤの障害で最も厄介なのはドメインロジックの問題です。例えばPUT /user
で、DBに保存されているユーザーとフィーチャーフラグの組み合わせでエラーが発生するとします。ドメインレイヤでifに入ったかelseに入ったかで後々エラーが発生するとしたら、共通的な計装だけでトラブルシュートを完結することは難しいでしょう。
こうしたトラブルに対処するためには、個別機能で重要な情報をトレースのスパンに記録する文化が必要です。
多くの組織では、オブザーバビリティ成熟度の5.1.〜5.3.の段階を理想として目指しているか、その段階にあるのではないでしょうか。
5.4. トレースの分析と集計
筆者は、トレースの活用において、より進んだ段階として「トレースの分析と集計」があると考えています。
例えば5.2.〜5.3.の成果で、PUT /user
はDBに保存されているユーザーとフィーチャーフラグの組み合わせでエラーを起こす可能性があると分かったとします。しかし、これは「可能性がある」だけです。なぜ断定できないのでしょうか。それは、見ているのがトレース単体であり他のトレースも同じ問題を持っているかの確証がないからです。
例えば、トレースをデータベースのテーブルのように扱い、当該フィーチャーフラグとユーザーの属性で全てのトレースをGROUP BYしてグループごとのエラーレートを可視化したらどうでしょうか。特定のグループが高いエラーレートを示せば、仮説に確証が持てます。
実のところ、5.2.や5.3.はログに情報を記録するという手もありました。しかし、筆者はトレースのスパンへの記録が望ましいと考えています。それは、スパンに記録したものはトレース単体の確認とトレースの分析集計の両方で活用できるからです。
5.5. トレースの相関分析
筆者が現時点で最も先進的だと考えているのは、トレースの相関分析が利用できている状態です。
5.4.では、トレースの分析集計により、立てた仮説の検証をトレーシングサービスで完結できる可能性を説明しました。しかし、そもそも最も難しいのは良い仮説を立てることです。なぜ数あるスパンの属性の中から、特定のフィーチャーフラグやDB上の項目がエラーレートと相関している可能性が高いと思いついたのでしょうか。その仮説は、その機能を開発した人でなくても立てられる仮説でしょうか。
結局のところ、やりたいことは「PUT /user
のトレース/スパンの全ての属性全てから、エラーレートと相関性の高いものをピックアップする」ということです。これは、トレーシングサービス側で全属性を突合してくれれば自動化できます。こうしたトレース属性の相関分析を活用し、誰でも良質な仮説を立てられる世界観を、筆者は目指しています。
ヘンリーのオブザーバビリティ成熟度の過程とこれから
2022年
2022年時点では、ヘンリーのオブザーバビリティ成熟度は3.3.の段階にありました。インフラメトリクスやアプリケーションログについては十分に活用できていましたが、分散トレーシングやアプリケーションメトリックはまだ導入されていませんでした。この段階では、インフラの監視とアプリケーション構造化ログの収集が中心でした。
2023年
2023年から、ヘンリーでは本格的にオブザーバビリティに投資を始めました。4のアプリケーションメトリックの成熟度が大きく高まり、5.1のトレース単体の活用にも着手しました。この年は多くの取り組みが行われ、大きな転機となりました。
OpenTelemetryの導入
OpenTelemetryを導入し、OpenTelemetry Collectorをデプロイしました。これにより、5.1.のトレース単体について技術的な整備が進み、一部のエンジニアがCloud Traceを使い始めるようになりました。
インフラに強いSREが入社
インフラに強いSREが入社しました。様々な成果を上げられていますが、オブザーバビリティに関しては、特に4. のアプリケーションメトリックの生成や運用が進みました。これにより、システムの全体感に対する可観測性が大きく向上しました。
2024年〜現在(7月)
2024年開始時点の課題は、5.1のトレース単体の技術的な成熟度が十分でなく、一部のエンジニアしか活用できていなかったことです。また、5.2〜5.3についても手つかずで、N+1などの技術的障害の解決と、システムの処理の全体感を掴むことのみが可能でした。
2024年は、上記の課題に取り組んできました。それに加え、あるべき姿を見据え、5.4.と5.5.のトレースの分析集計・相関分析にも取り組みました。その結果、成熟度は以下のような状態にあります。
- 5.1 トレース単体の成熟度:完全
- 5.2. システム固有の共通的な計装:高い
- 5.3. ドメイン/機能カットの計装:着手済み
- 5.4. トレースの分析と集計:完全
- 5.5. トレースの相関分析:着手済み
5.1. Context Propagatorの自作
以前記事で紹介したとおり、ヘンリーではCloud Runの不具合でCloud Run間の通信でトレースが切れるという課題がありました。dev.henry.jp
この問題に対処するために、JVMとNode.jsそれぞれでContext Propagatorを自作し、Cloud Runが知る由もないHTTPヘッダでトレースコンテキストをやりとりするように改善しました。これにより、5.1.のトレース単体の技術的な整備が完全となりました。
5.2.〜5.3. トレース情報の充実化とEmbedded SREing
5.2.の共通的な計装でトレースの情報を充実させ、フィーチャーフラグ・認証情報・バージョン・エンドポイントのメタデータなど、多くの情報を共通的にトレースに含めるようにしました。また、新しいフィーチャー開発においてはEmbedded SREとして支援に入り、5.3.の個別機能の計装のイネーブルメントを進めています。
特に個別機能の計装は1つ1つの取組みの範囲こそ狭いですが、その機能でトラブルが発生したときのインパクトは絶大だろうと考えており、強く期待をしています。
5.4.〜5.5. Honeycombの導入
5.4.と5.5.の達成に向けて、トレースの分析と集計が強力なHoneycombを試験的に導入しました。Honeycombではスパンに対して柔軟に集計や可視化を行うことができ、導入しイネーブルメントすることで5.4.の成熟度が完全なものとなりました。
また、HoneycombにはBubbleUpというスパン間の相関分析もあり、5.5.についても技術的なケイパビリティがあります。ただし、これは使いこなすのが難しく、実運用で再現性が得られないと成熟度が高いとは言えないとも考えています。
今後の展望
今後は、現在低い成熟度の部分を高めていくことを目指します。当然ながら難しいテーマや時間のかかるテーマが残っている認識ですので、腰を据えて取り組んでいきたいです。加えて、上記成熟度の整理に含んでいない技術的テーマや、文化のイネーブルメントにも取り組んでいく必要があります。
5.3.の個別機能の計装、5.5.の相関分析
先述のとおり、5.3.の個別機能の計装は非常に期待の大きいテーマです。まだ始めたばかりなので、プロダクトエンジニアと密に関わりながら、腰を据えて進めていきたいと考えています。また、5.5.の相関分析についても、実運用で再現性を確立できれば、銀の弾丸といっても過言ではないほど強力な武器になりうると考えています。HoneycombのBubbleUpを実運用で利用し、ナレッジを蓄積して勝ちパターンを増やすことで、トラブルシュートにおいて誰でも良質な仮説を立てられる世界観を実現したいです。
フロントエンドオブザーバビリティ
これはOpenTelemetryにベットしていることの反動でもあるのですが、フロントエンドオブザーバビリティについては手つかずです。Sentryの導入によるトレース取得はできていますが、パフォーマンス改善のPDCAが運用されていません。この分野の整理と強化も進めていきたいです。
オブザーバビリティ文化の醸成
最後に、オブザーバビリティで最も重要な目標は、全エンジニアがオブザーバビリティを活用できることであり、イネーブルメントが肝要と考えています。ツール活用や計装のイネーブルメントの他にも、例えばオブザーバビリティ成熟度が高まったことで、既存機能でパフォーマンスの問題が多数見つかっています。そうして見つけた既存機能の問題を改善するサイクルを根付かせていくことなどにも取り組んでいきたいです。
最後に
この記事では、ヘンリーが考えるオブザーバビリティ成熟度と、現状および展望について解説しました。この記事が皆さまの組織においてオブザーバビリティの議論の役に立ったり、トレース単体活用の先にあるオブザーバビリティの世界観を知るきっかけになれば幸いです。
また、Honeycombについては、国内事例が少ないかもしれません。Honeycombを使った5.4.や5.5.の達成方法や活用事例についても、今後発信していきたいと考えています。
ヘンリーでは各種エンジニア職を積極的に採用しています。医療ドメインに興味がある方も、オブザーバビリティに興味がある方も、ぜひカジュアル面談でお話させていただければと思います。