色んな事を書く

シンプルさを極めたエンジニアになりたい

【読書メモ】オブザーバビリティエンジニアリング

動機

  • 関わっているプロダクトのオブザーバビリティが低いなぁと思うが、オブザーバビリティって何だっけとなったため言語化したい
  • プロダクトのオブザーバビリティを高めるためには何をすれば良いのか言語化したい
  • プロダクトのオブザーバビリティというコンテキストで建設的な議論を行えるようになりたい

 

オブザーバビリティ・エンジニアリング | Charity Majors, Liz Fong-Jones, George Miranda, 大谷 和紀, 山口 能迪 |本 | 通販 | Amazon

 

前書き

モニタリングとオブザーバビリティは本質的には別物。

 

オブザーバビリティは技術的観点よりも社会技術的な概念と言うべき。したがって、組織の文化なども含まれてくる。

例えばだけど

  • ログメッセージとして何を書くべきか
  • ログレベルはどう使い分けるべきか
  • ログを見てどう追っていけば良いのか

などの基準が開発チームにあるか、みたいな話か。

 

状態空間という単語がイメージしづらい。システムというオブジェクトがあって、それにはメソッドがある、みたいなイメージを持とう。開発プロセスの中でその状態が変わっていくのはしっくりくる。実装してわかることもあるし、テスト時にバグ見つかるだろうし、ユーザからのフィードバックを経て変わっていくのだろうし。

オブザーバビリティの本質はこういった状態空間を丁寧にマッピングし、探索を容易にすること。モニタリングは健全性を大まかに把握するにすぎない。

 

Azure Appinsights は構造化ログとかイベントの種類とかあって汎用的なツールとしてはわりと探索は容易なのではないか。※イベントの種類はどっかで調査しておきたいな。

 

アラートの閾値とかダッシュボードはオブザーバビリティの最大化に役に立つわけではない。どゆことだってばよ???


1 章 オブザーバビリティとは

数学的定義によると、オブザーバビリティとは外部の入力からシステム内部の状態がどれほど推測可能かという尺度。

推測ってのはブラックボックステストで期待される出力を予測する、期待な話とは違うと思う。ある入力を元にシステム内部の状態がどう変わり、その後その状態を元にシステムはどんな振る舞いをするのか、といったところまで見てるんじゃなかろうか。

可観測とはどこにかかっているのか。あくまでみたいのはシステム内部の状態なんですよね。ログはその時に何が起きたかを示すってのがあるが、メッセージによってはシステムがどんな状態になっているか推測出来るようにもなりそう。

なぜそれが起きたのかを推測できること、か。これから起きること、すでに起きたこと、それぞれに対して推測する必要があるか?

 

アプリケーションがどういうシステム状態に陥っているのかを理解する

Deadletter 頻発に起きてるけど、それが発生した時にどんな状態になっているかって話だよなぁ。何かに失敗した時ってそれがわからないからなぁ。

Elasticsearch の queue が詰まってあるとかはある種どんな状態かの解にはなると思うが、そこに辿り着くまでがむずい。

システム全体をオブジェクトと捉えた時、あるデータ不整合によりある機能が使えませんはメソッドの Invalid Operation として捉えられるなぁ。そのデータのどういう状態にはどのメソッドのみが責任を持つ、という設計がされていれば、Invalid Operation 時にどのメソッドに問題があったかを伝えられるわけで、それは良い洞察を与えられると思うの。そういう情報とプロダクト全体の構造がマッピングされていれば、どのドメインのどの処理に問題があったかを特定するのは容易か?

 

何故そうなったかってデータとシステムの振る舞いから推測するしかなくて。ドメイン知識があればそれは容易いが、どのタイミングでそれが不具合であると気づけるか。やはりモニタリングのツールだけでなく自プロダクトへの理解と、理解しやすさが必要だなぁ。

C4 があれば解決するかと言われると微妙だなぁと思う。プロダクトへの理解が必要となる以上ツールだけで解決するのは無理だな。

 

メトリクスやモニタリングツールで理解出来るシステムの複雑さには上限がある

確かになぁ。あるデータベースの負荷が高くなっている時に、メトリクスからはそれ以上の情報得られなくない?その事実しかなくて、その背景を探るには別の調査が必要となってくる。しんどい。

複数の小さなアプリケーションで構築していると、それぞれのアプリケーションとその結果生まれるデータの状態の相関が見れなくてきつい。

 

モニタリングは既知の未知を扱うが、オブザーバビリティは未知の未知を扱う。

閾値を使ったモニタリングはその閾値を超す場合にシステムに未知の不具合が起きているということを見つけるために行う。

対してオブザーバビリティとは、何かが発生した時に何が起きていたのかそのコンテキストを提供する。

 

メトリクスの異常に来した時、それをさらに調査するために別のメトリクスが必要になったりとかね。あとそもそもだけど問題に気づくためにどんなメトリクスが必要かを知らないといけないのが厳しい。リリースして気づいてメトリクス導入して〜だとどうしても後手になるよね。

 

カーディナリティの高さが重要になるのは感覚的だけどすげえわかる。

 

ディメンションという考え方ね。構造化ログを使って問題のありそうな処理の特定が容易くなる。というか絞り込みを行える。

 

予測不能な出来事に対しあらかじめソフトウェアで何が起きたのか説明するための判断材料を提供し、対応工数を減らしていこうってことかな。

 

2 章 オブザーバビリティとモニタリングにおけるデバッグの違い

メトリクスは、記録された特定の時間間隔におけるシステムの状態を数値で表したものです。

メトリクスベースの運用をしてて困るなぁと思うのは、ある時点の数値を見た時やそれを時系列に沿ってみた時に問題として対処すべきかどうか判断に迷うこと。その変化の仕方からシステムがおかしな状態になっているというのは属人的なもので、スケールさせずらいなあと思う。ただ判断やフォローだと、同じもしくは似たような事象でない限り常にフォロワーがついておかなきゃいけなくなる。

 

アラート使う時はその閾値を超えた時にしか反応できない事。その数値が瞬間的なものであっても調査が必要だし、継続的に高めの数値を示していても気付けるのは閾値を超えた時。常にダッシュボードと睨めっこは論外だし。

 

メトリックから何が起きているかは超能力ゲーになっているよなぁ。トラブルシューティング能力がそのプロダクト固有なものになってしまってはいかんやなぁ。

 

あるエンジニアが、誤ってデータを消してしまうバグを発見し、その影響が全ユーザに及んであるのか、一部のシャードに及んでいるのか知りたいとします。しかし、ダッシュボードに表示されているのは、たった1つのデータシャードのディスク容量が減少している様子だけです。

数値ってその時々のスナップショットでしかないから、裏で何が起きているのかまだ説明出来ないんよな。削除と同じタイミングで同容量の作成が行われると、表面的には問題が無いように思えてしまう。

 

直感的にある解決策に飛びつき、それが正しいことを確認し、その通りに進めても、その確認した前提が原因ではなく、症状や結果にすぎなかったために、実は本当の問題を見逃していることがよくあるのではないでしょうか。

めっちゃある。ある処理の遅延によってみに行くのが特定のデータベースプールになっていたりする。解決策も大体一緒。ただし根本原因がわかっておらず、中自傷が発生した時に似た対策を行い事なきを得る、ということを繰り返している。直感とか経験ベースにトラブルシュートしている節が多々ある。システムがより複雑になってくるとこのようなアプローチは限界を迎えるよなぁ。

 

オブザーバビリティツールでは、チーム内の最高のデバッガーはもっとも好奇心の強いエンジニアである。

自分で質問を投げかけ、その答えがどこにあるのか明示的であり、それを繰り返すことで原因の特定が出来るってのが大切なんだろう。

 

3 章 オブザーバビリティを用いないスケーリングからの教訓

 

1,2 章の内容を著者の実体験ベースにまとめた章。まぁそうだよねって内容だった。

 

 

4 章 オブザーバビリティとDevOps、SRE、クラウドネイティブとの関連性

テスタビリティと同様に、オブザーバビリティも、システムの理解を深めるための特性

そうね。テスタビリティは特にインプットに対するアウトプットや副作用の理解しやすさとかあるしね。プロダクトの仕様が丁寧にまとめられているかとかもありそう。何をするとどうなるかという意味での可視性ってことかなぁ。

テスタビリティも社会技術的な側面が強そうだ。

 

クラウドネイティブへのシフトのためには、新しいテクノロジーをひと揃い採用するだけでなく、人々の働き方を変える必要がある。

オブザーバビリティを得たいのだって結局のところプロダクトの状態の説明容易性を上げてエンジニアの作業負荷を減らしたいってことだと思う。だからこれまでやってきた直感頼りの調査や地道で時間をかけた作業を当たり前としてるマインドを変えるとこからだよね。それでヒーロー感を得たり働いてる感を得てる人は一定いるだろうし、それらを否定せずにシフトしていくって組織に依ってはめっちゃむずそう。

 

異常な問題のデバッグには、エンジニアがシステムの内部から問題を検出し、理解するための機能が必要です。分散トレースのようなツールは、特定のイベントが発生した時のシステム内部の状態を把握するのに役立ちます。

うちも分散トレースを使ってるけど、確かにリクエストの結果が意図したものになりませんという時に関連するイベントを追いどこで何が起きていたかを特定するのは楽。それをもとに結果の説明をすることも。

だけど何かしらのデータの不整合が起きた時に、それがどのイベントと関連しているのかを追うのがむずい。あるイベントが起きた時にデータがどんな状態になったのかって記録してないし。結局は一つずつイベントを遡りながらデータをもとに各イベントで何が起きたのかを調査することしかできないからねぇ。それをするためにはシステム全体の相互関係を知っておかなきゃいけないし。

あるデータの不整合が別ドメインがきっかけってこともよくあるし、全てが一調査者の仮説・検証能力によっちゃってる。全てが遅くなると似てるけど、事情から原因を遡るのに作業時間の大半を使ってるとこがある。

 

5 章 構造化イベントはオブザーバビリティの構成要素

イベントとは、本番環境のサービスへの影響を理解するために、ある特定のリクエストがそのサービスとやり取りしている間に発生したすべての記録です。

これって例えばストレージの負荷状況とかもログに出した方が良いのだろうか。例えばだけどストレージに Cosmos DB とか使ってると C# SDK には RequsetCharge ってプロパティがある。このプロパティはリクエストで消費した RU が入っている。こういうのもきちんとログに出してたりすると、RU の消費が著しく激しいデータの特徴を見出せたりするのだろうか。Cocmos DB のメトリックだけ見ると、実際にどんなデータを処理しているときに RU を消費するのかわからないからなぁ。

 

しかし、メトリクスの基本的な限界は、事前に集計された測定値であるということにあります。

ある特定の時間帯の状態を数値で表している (ex. Database の負荷状況、実行時間...)。それらの状態がどのリクエストに関連しているかや、どんなデータを処理しているときなのか、処理の過程でデータがどんな状態になってしまっているのかなどが読み取れないってのはメトリックの弱点かもね。開発しているプロダクトでもパフォーマンスを著しく下げるようなゴミデータがある。これは処理の遅延やタイムアウトに気づいてデータの中身を調査して傾向を掴んで、という対策をしていたのだけれども、処理中のデータをログに出していると調査が楽になったりしたのだろうか。

  • 遅延の原因となっている処理
  • その時のデータの状態
  • 処理の実行時間
  • リソースへの負荷状況

これらが関連した一つのイベントの中に集約していると、調査が楽だったかなぁとか。データを直接見て傾向を掴むのは作業時間もかかるし権限も必要だしリスクも付きまとうからあんまりやりたくないんだよね。んで、もちろんそんなデータが入ってくるって前提は置けないから (置けるなら前段で弾け)、可能な限り情報はログに出しておこうって感じか。

 

成熟した計装では、生成されるイベントは300から400のディメンションを含むことが一般的です。

そんなに必要なの?と思ってしまったなぁ。今のプロダクトで分散トレーシングを導入してはいるが、いまいち使いこなせていないなぁっていうのがありまするが。。。「こういう調査をするからこういう情報が必要だよね」じゃなくて「どんな調査にも耐えられるように取れる情報は全て構造化ログに出そう」ってスタンスなのかな。

最近監査ログをプロダクトに導入したのだけれども、「どういう情報が欲しいのか」ってのはクエリでいくらでもカバーできるように作んないといけないんだろう。「ある期間内にある操作をした全ユーザ」「あるユーザがある期間内に行った操作」とかクエリをいじるだけで取れるようにしたい。欲しい情報が変わるたびにログに出す内容を変えるリリースはしたくないしなぁ。

 

6 章 イベントをトレースに繋ぐ

分散トレースの簡単な実装をコードベースで見ていく章。

 

7 章 OpenTelemetry を使った計装

Appliaction InsightsとOpenTelemetry - 技術的な何か。

普段使っている Azure は裏側では OpenTelemetry を使ってたみたい。この辺りの標準規格はまだ弱い。どんなときに Event を使い分けるとかもあんま頭使ったことがない。

 

8 章 オブザーバビリティを実現するためのイベント解析

おそらく、手順書は技術的負債に一時的に対処するためのものです。繰り返し発生するひとつの問題があり、手順書は、それが最終的に解決される次のスプリントまで、問題を軽減する方法を他のエンジニアに指示するのです。

これはめちゃくちゃわかる。全ての手順書がそうだというわけではないけど。運用目線を持つことは大事だけど、運用ありきを前提にするのは違うよね。技術的負債をエンジニアの工数を使って返済している形になってるんだよねぇ。手順書のメンテナンスをしていくって聞こえはいいけど、技術的負債の上に新しい負債を重ねている可能性もあるんだよね。手順書を作るってのは新しい仕事が生まれるってことだろうしね。ちょっと本書とは話が逸れるけど。

 

オブザーバビリティがあればシステムを第一原理からデバックできます。

第一原理とは、ある物事を理解するための最初の基礎とされているもの。オブザーバビリティのあるシステムの良いところは、直感とか経験則に基づいた推論ではなくて、体系的にステップを踏んで答えを見つけるために進んでいけるということ。この考え方を実践しているのがコア分析ループって手法。らしい。

第一原理は何が起きているのか知るための基礎ってことなので、この考え方をベースにしてコア分析ループを回していく。収集されるメトリックやログはそのときに何が起きたのか真に表すものと考えることができるんだね。それをグラフ化するなりして変化が顕著に現れる部分を探したり。見つからなければ新しい仮説を立ててディメンションを変えてグラフ化したりを繰り返すと。

カーディナリティの高い値だと散らばって変化を表しやすそう。パーセンタイルで表すのは基礎中の基礎かね。

 

9 章 オブザーバビリティとモニタリングの関係

考察:システム vs ソフトウェア

ソフトウェアとは市場の問題を解決するためにビジネスが求めているもの。システムとはビジネスのために動かしたいソフトウェアをサポートするために動かさなければいけないもの。システムにはインフラストラクチャが該当するが、クラウドサービスにより提供されている場合にはこれにカウントしないらしい。

 

オブザーバビリティはソフトウェアレベルの問題を理解するのに役立ち、モニタリングはシステムレベルの問題を理解するのに役立つ。

ん〜なるほど。でもクラウドサービスに提供されていようがメトリックは需要だからシステムになるんじゃないの。自社でインフラを構築している会社と比較すると重要度は落ちるってだけかも。

構造化ログはシステムレベルの問題とソフトウェアレベルの問題を混同させて出していいもんだっけかってのが気になる。コードがシステムの過負荷やリソースを食い潰す原因になることは多々あるし、それらを相互に扱うログはオブザーバビリティの観点でも大事だと思うけどな。定義にもシステムの状態を〜、って書いてあったし。

というかインフラストラクチャと呼ばれるようなものたちも、ビジネスの根幹がそれらに支えられていればどうなんのって話もあるしね。

 

10 章 オブザーバビリティへの取り組みをチームへ適用する

オブザーバビリティをチームに導入していくためにまずは何からやっていけば良いのかの章。ツールを導入するために最も問題となっている部分を見極めたり、コミュニティを活用したり、反復して改善させていこうみたいな話。

いやぁ、でも完了と呼ばれる状態にするまでにはかなりの難易度がありそう。実際にシステムの状態が理解出来るよねって何か問題が発生してからじゃないとわからないし、そういうのも含めて反復していこうねってことなんだろうけどさ〜。

 

11 章 オブザーバビリティ駆動開発

オブザーバビリティはより良いコードを書き、リリースするのに役立ちます。なぜなら、それはエンジニアがコードのバグを素早く発見するためのツール、プロセス、文化の一部だからです。

プロダクトを運用している最中にデータがどんな状態になっているのか、どんなデータがインプットされうるのか、リソースがどんな状態になっているのか、これらは実際に本番環境にデプロイしないとわからないこと。TDD はコードが仕様通りに動いているのかを保証するものであり、これらはカバーしきれない部分。オブザーバビリティは本番環境で何が起きているのかを検証するために必要なこと。

 

プルリクエストをサブミットしたりアクセプトする前に、「この変更が意図した通りに動いているかどうか、私はどうやって確認できるだろうか?」と自分自身に問いかけてみましょう。

これは良いアイディアだと思う。モニタリングツールだとある処理が正常に成功したから失敗したかくらいしか読み取れない。その処理の主作用や副作用が意図した通りになっているのかをどうやって把握すれば良いかを考えるのは、オブザーバビリティを高めるためも日々意識できることだと思う。何かを更新する処理だったら、更新前の状態と更新後の状態を出力したり。

 

エンジニアリングチームは、新機能のリリース中に問題が発生した場合、直感的にデプロイをロールバックするのではなく、何が本当に起こっているのかを、さらに深く調査するためのツールを得られるでしょう。

本番リリース直後に意図していない挙動が発覚してすぐに切り戻す、ってのは何度かみたことがある。結局実際に何が起きていたのかを把握する術がないと開発環境での再現もできないし、本当に問題であったのかどうかすらわからない。調査すればいずれわかるかもしれないけど、その時間を短縮したいよねって話。

 

12 章 サービスレベル目標の信頼性向上への活用

なぜ CPU 使用率のような静的な閾値ベースのアラートでは不十分なのか。昨今のシステムの特徴的に、インフラストラクチャレベルのものであってもパフォーマンスは様々なワークロードの下で動的に変化をする。CPU の使用率が閾値を超えるのは様々な要因があり、ユーザ体験に紐づかない場面もありうる。一時的に何かが調子悪かったりとか。結果としてアラートを無視したりすることが常態化してしまう。ただのノイズでしかないし、本当に問題があったときに気づけなくなってしまう。

アラートに対して取るべき行動が不明確ってのもあるのだろうね。とりあえず再起動〜とか。

 

「何」を「なぜ」から切り離すことは最大限のシグナルを最小限のノイズでモニタリングを行う上で、最も重要なことの一つです。

最大限のシグナルってのは「ユーザにどんな体験を与えてしまっているのか」ってこと。ページのロード時間が極端に長くなってしまったり、ユーザの操作に対して意図しない挙動になってしまっていたりなど。ノイズってのは CPU の使用率は閾値を超えたとか、メモリの使用量が〜とかの話。根本原因をアラートとして出すとノイズになりやすいし、調査の起点としては弱い。ユーザの体験したことがシステムがどんな状態になっているのかを最も表しているし、そこを起点にした方が実際の問題へアプローチしやすい。