はじめに
オブザーバビリティは監視の世界を変えつつありますが、それには正当な理由があります。
多岐にわたるツールのおかげで、コードをデリバリするのがこれまでになく簡単になりましたが、それはソフトウェア環境がかつてないほど複雑化しはじめていることも意味します。ソフトウェア開発手法が進化するにつれて、システムも進化してます。ソフトウェアに「何か問題が発生しているか?」と尋ねるだけでは不十分です。その問題の理由も同時に尋ねられなければなりません。これは可観測性 (オブザーバビリティ) の基本的な性質です。
システムの可観測性を実現するにはすべてを計測し、すべてのテレメトリデータを1か所で表示できる必要があります。その方法については多くの議論が続いており、確実な定義は未だ現れていませんが、New Relic はメトリクス、イベント、ログ、およびトレース(MELT : Metrics, Events, Logs, Traces)を可観測性実現の基本的なデータタイプだと考えています。すべてを計測し、MELTを使用してシステム内の関係と依存関係、そしてその詳細なパフォーマンスと正常性を維持することが可観測性を実現するために重要です。ただし、MELTの価値はあまり明らかな考え方が明示されていないかもしれません。「その用語を聞いたことがある」という可能性は十分にありますが、それらの違いを自信を持って説明できることが可観測性の実現には重要です。
この MELT を理解するために「自動販売機」のケースを参考に MELT の説明をしてみたいと思います。
(注意)MELT なのでメトリクスが最初にくると想像されるかと思いますが、イベントが可観測性にとって最も重要なデータ型であるため、イベントの説明から始めていきます。イベントはログとは異なります。ログは重要な分析ポイントの個別詳細な記録といえますが、イベントはログで提供される詳細よりも高いレベルの抽象化を提供しています。アラートはイベントです。トランザクションとエラーも同様です。イベントは、きめ細かな分析をリアルタイムで実行する機能を提供しています。
イベント | Events
イベントは、ある瞬間に発生する個別のアクションをさしています。誰かが自動販売機から商品を購入した瞬間をキャプチャする"イベント"をみて見ましょう。 例えば
- 2019年2月21日午後3時34分に、BBQチップのバッグが1ドルで購入されました。
この場合データベースに保存されたイベントデータは次のようになります。
イベントは「いつか何が起こった」ということを説明しています。イベントは送信する情報の属性を選択できます。イベントに含めることができるデータに関する厳格なルールはありません。必要に応じてイベントを定義します。たとえば、New Relicでは、すべてのイベントに少なくとも Timestamp 属性 と EventType 属性を含めています。
イベントはどのように使用されるのか
イベントは、特定の時間に、特定のアクションが発生したことを検証するために使用することができます。たとえば、自動販売機が最後に補充された時間を知りたい、と考えたとします。イベントを使用して、Refilled (補充) イベントタイプから最新のタイムスタンプを確認すれば、「最後に商品が補充されたのはいつか」という質問にすぐに回答できます。イベントは基本的にシステムで発生したすべての個々の事柄の履歴であるため、イベントを集計にまとめればより高度な質問にその場で答えることができます。例えば以下のようなイベントが保存されていることを想像してみてください。
このデータについて以下のような質問をしてみます。
- 今週自動販売機はどのくらい売り上げましたか?
すべての購入イベントの履歴が保存されているので、Value列を合計するだけで、この自動販売機は今週4.25ドルを稼いだことがわかります。メタデータを追加すればイベントデータはより強力になります。たとえば、ItemCategory (商品カテゴリ)やPaymentType(支払い方法)などを追加して、PurchaseEventデータに対してファセットクエリを実行できます。例えば次のような質問をすることができます。
- 各商品カテゴリはそれぞれどれくらい売れていますか?(スナック:$ 2.75、ドリンク:$ 1.50)
- 支払い方法はどの方法がどれくらいの回数発生していますか?(現金:3、CreditCard 1)。
- 1日にどれくらい売り上げましたか?(2/21:2.00ドル、2/22:0.75ドル、2/23:0ドル、2/24:1.50ドル)
New Relicでイベントを使用する場合
たとえば私たちが電話会社であり、複数の顧客からモバイルアプリケーション「ACME Telco-Android」のクラッシュが報告されているとしましょう。New Relic ではいくつかの分析を行うことができます。監視しているアプリのクラッシュデータをキャプチャするNew Relic Mobileエージェントをデプロイしたので、 New Relicの基になるMobileCrashイベントデータにアクセスします。 New Relic One のグラフビルダーで次のクエリを実行します。
SELECT * FROM MobileCrash
次の表の各行は、ある時点で特定のユーザーに対して発生した特定のクラッシュイベントを表示しています。
このイベントデータについてもっと役に立つ質問をしたいとしましょう。たとえば、アプリが特定のメーカーのデバイスで頻繁にクラッシュするかどうかを知りたい場合があります。ここでは、チャートビルダーで次のクエリを実行します。
SELECT count(*) FROM MobileCrash WHERE appName = 'Acme Telco -Android' FACET deviceManufacturer SINCE 1 day AGO
この結果から、特定のアプリケーションが最終日にメーカーAのデバイスラインでほぼ3倍頻繁に失敗したことがはっきりとわかります。
イベントの限界
イベントは素晴らしい、そう思うかもしれません。しかしイベントの収集には費用がかかります。すべてのイベントは、収集と処理にある程度の計算エネルギーを必要とします。またデータベース内のスペース、場合によっては大量のスペースを占有します。そのため、自動販売機での購入のような比較的まれなことについてはイベントは素晴らしく適していますが、自動販売機が行うすべてのイベントを収集したくありません。たとえば、自動販売機の温度の履歴を保持すると変化が頻繁なため最大のデータベースでもすぐにいっぱいになります。そんなことをしたくない、その代わりに定期的に温度のサンプルを採取するという方法が考えられます。この種類のデータはメトリクスと呼びます。
メトリクス | Metrics
簡単に言うと、メトリクスは定期的にグループ化または収集された測定値の集合です。イベントとは異なり、メトリクスは個別ではなく「特定の期間のデータの集計」を表します。 メトリクス凝集の型は多様ですが(例えば、average(平均)、total(合計)、minimum(最小)、maximum(最大)、sum-of-squares(平方和))以下のような共通の特徴があります。
- タイムスタンプ(このタイムスタンプは、特定の時間ではなくタイムスパンを表すことに注意してください)
- 名前
- 特定の集計値を表す1つ以上の数値
- 集約で表されるイベントの数のカウント
メトリクスは例えば以下のようなことを教えてくれます。
- 2019年2月21日の午後3時34分から3時35分まで、合計3回の購入があり、合計で$ 2.75でした。
このメトリクスは、データベースでは単一行のデータとして表されます。
多くの場合、同じ名前、タイムスタンプ、およびカウントを共有するさまざまなメトリクスを表す複数の値が1行で計算されます。この場合、Totalの購入金額とAverageの購入金額の両方を追跡しています。しかしイベントと比較して、メトリクスでは一部のデータが失われていることに注意してください。Count の3つの購入内容が何であるかはメトリクスではわかりません。また、個々の値にアクセスすることもできません。メトリクスは必要なストレージが大幅に少なくなりますし、「特定の1分間の総売上はいくらですか?」などの重要な質問をすることもできます。実際のレベルでは、これがメトリクスとイベントの主な違いですが、それぞれの長所と短所をまとめると以下のようになります。
イベントの得意なところ
- 個別のデータポイントが含まれる
- 様々な質問に答えられる
- 素早く計算できる
イベントの苦手なところ
- イベントデータの保有コストは高い
- イベントデータの収集と送信は帯域を圧迫する
- クエリに時間がかかる
メトリクスの得意なところ
- 保存するデータを少なくできる
- ロールアップ時間を短縮
メトリクスの苦手なところ
- 分析するデータを事前に決める必要がある
メトリクスは大量のデータや事前に問い合わせたいことがわかっている場合に定期的に収集されるデータに対して適切に機能します。イベントは、データが比較的小さいか散発的である場合、または事前に表示する特定の集計がわからない場合に役立ちます。
New Relicでメトリクスを使用する場合
New Relicでのメトリクスデータの最良の例は、エラー率、応答時間、およびスループットです。
上記のスクリーンショットでは、「WebPortal」というアプリケーションの12時間のウィンドウが表示されています。すべての行が非常にぎざぎざになっていることに注意してください。これはデータの忠実度が高いことを意味します。次に2週間前にキャプチャした同じメトリクスの別の12時間のウィンドウを見てみましょう。
線が滑らかになっていることに注目してください。これは、メトリックが時間とともにさらに集約されているためです。データが新しい場合、1分間の平均を取っています。ただし一定の時間が経過した後は、通常このような細かい粒度は必要ありません。そのため、1分間の平均は1時間の平均にロールアップされます。個々のイベントデータは削除されるまで保存されます。イベントデータは事後にロールアップされることはありません。
メトリクスの限界
メトリクスは非常にコンパクトで費用対効果の高い形式で情報を取得します。それではなぜメトリクスを常に使用しないのでしょうか?簡単に言えばメトリクスには慎重な意思決定が必要だからです。たとえば、キャプチャするメトリクスの50パーセンタイル(中央値)および95パーセンタイルを知りたい場合は、それを計測しすべての集計で収集してからグラフ化することができます。しかし、自動販売機の特定のアイテムのデータのみの95パーセンタイルを知りたいとしましょう。事後にそれを計算することはできません。そのためには、すべてのサンプルイベントが必要になります。そのため、メトリクスはデータの分析方法を事前に決定し、その分析をサポートするように設定しておく必要があります。
ログ | Logs
ログは本質的に特定のコードブロックが実行されたときにシステムが生成する単なるテキスト行です。開発者は、コードのトラブルシューティングを行い、コードの実行をさかのぼって検証および調査することをログに大きく依存しています。実際ログはデータベース、キャッシュ、ロードバランサーなどに馴染みのない古い独自システムなどのトラブルシューティングに非常に役立ちます。イベントと同様にログデータは離散的であり(集約されない)、不規則な時間間隔で発生する可能性があります。また、ログは通常イベントよりもはるかにきめ細かくなります。実際1つのイベントが多くのログ行に関係している可能性があります。元の自動販売機イベントを考えてみましょう。
- 2019年2月21日午後3時34分に、BBQチップのバッグが1ドルで購入されました。
対応するログデータは次のようになります。
2/21/2019 15:33:14: User pressed the button ‘B’
2/21/2019 15:33:17: User pressed the button ‘4’
2/21/2019 15:33:17: ‘Tasty BBQ Chips’ were selected
2/21/2019 15:33:17: Prompted user to pay $1.00
2/21/2019 15:33:21: User inserted $0.25 remaining balance is $0.75
2/21/2019 15:33:33: User inserted $0.25 remaining balance is $0.50
2/21/2019 15:33:46: User inserted $0.25 remaining balance is $0.25
2/21/2019 15:34:01: User inserted $0.25 remaining balance is $0.00
2/21/2019 15:34:03: Dispensing item ‘Tasty BBQ Chips’
2/21/2019 15:34:03: Dispensing change: $0.00
ログデータは構造化されていない場合があり、体系的な方法で解析するのが困難です。ただし最近ではマシンによって解析されるように特別にフォーマットされた「構造化ログデータ」に遭遇する可能性が高くなります。構造化されたログデータにより、データの検索とデータからのイベントまたはメトリクスの取得がより簡単かつ迅速になり始めています。たとえば、
2/21/2019 15:34:03: Dispensing item ‘Tasty BBQ Chips’
から
2/21/2019 15:34:03: { actionType: purchaseCompleted, machineId: 2099, itemName: ‘Tasty BBQ Chips’, itemValue: 1.00 }
といった感じです。ログでpurchaseCompletedを検索すれば、アイテムの名前と値をその場で解析することができます。
ログはどんなとき役に立つのか
ログは非常に用途が広く多くのユースケースがあり、ほとんどのソフトウェアシステムはログデータを出力できます。ログの最も一般的な使用例は、特定の時間に何が起こったか、といった詳細な記録を取得することです。たとえば、PurchaseFailed次のようなイベントがあるとします。
このことから、ある特定の時点で予期せぬ理由で購入が試みられ失敗したことがわかりますが購入が失敗した理由についての洞察を提供する追加の属性はありません。ただしログから次のようなことがわかります。
2/21/2019 15:33:14: User pressed the button ‘B’
2/21/2019 15:33:17: User pressed the button ‘9’
2/21/2019 15:33:17: ERROR: Invalid code ‘B9’ entered by user
2/21/2019 15:33:17: Failure to complete purchase, reverting to ready state
これで、何が間違っていたかが正確にわかりました。ユーザーが無効なコードを入力したからのようですね。
New Relicでログを使用する場合
New Relic Logsはエラーが発生するとすぐにトラブルシューティングを行うのに非常に役立ちます。たとえば、「WebPortal」アプリケーションでは、無効な文字の例外に関するエラーメッセージが表示されます。
ここから、[See Logs] をクリックすると、New Relic Oneがその特定のエラートランザクションのログを表示します。この場合ユーザーが間違ったユーザー名を渡したことがわかります。単にユーザーが文字をタイプミスしただけです。
トレース | Traces
トレース(より正確には「分散トレーシング」)は、マイクロサービスエコシステムの異なるコンポーネント間のイベント(またはトランザクション)の因果連鎖のサンプルです。また、イベントやログのようにトレースは離散的で不規則に発生します。自動販売機が現金とクレジットカードを受け入れるとしましょう。ユーザーがクレジットカードで購入する場合、トランザクションはバックエンド接続を介して自動販売機を通過し、クレジットカード会社に連絡してから発行銀行に連絡する必要があります。自動販売機の監視では、次のようなイベントを簡単に設定できます。
このイベントは、特定の時間にアイテムがクレジットカード経由で購入されたことを示しており、トランザクションを完了するのに23秒かかったことを示しています。しかし「23秒では長すぎる」という場合を考えてください。バックエンドサービス、クレジットカード会社のサービス、または発行銀行のサービスが購入完了までの時間を遅くしていたのでしょうか?このような質問はまさにトレースが対処するものです。
トレースはどのように機能するか
トレースは「スパン」と呼ばれる特別なイベントを形成します。スパンは、単一トランザクションのマイクロサービスエコシステムを通じて因果連鎖を追跡するのに役立ちます。これを実現するために各サービスは相互に「トレースコンテキスト」と呼ばれる相関識別子を渡します。このトレースコンテキストはスパンに属性を追加するために使用されます。したがって、クレジットカードトランザクションのスパンで構成される分散トレースの例は次のようになります。
TimestampとDurationデータをみてみると、トランザクション内の最も遅いサービスはクレジットカード会社にあることがわかります (Service ID: Issuing Bank から Credit Card Company までの期間が12秒)。23秒のうち12秒かかっているのです。このトレース全体の半分の時間を占めています。
いつトレースを使用する必要があるか
サービス/エンティティ間の関係を考慮する場合はトレースデータが必要です。各サービスの生のイベントのみを分離していた場合、特定のトランザクションのサービス間の単一チェーンを再構築する方法はありません。さらに、アプリケーションは多くの場合達成しようとしているタスクに応じて複数の他のアプリケーションを呼び出します。また、多くの場合データを並行して処理するため、コールチェーンの一貫性が失われ相関のタイミングが不安定になる可能性があります。一貫したコールチェーンを確保する唯一の方法は、各サービス間でトレースコンテキストを渡し、チェーン全体で単一のトランザクションを一意に識別することです。
New Relicで分散トレーシングを使用する場合
New Relic Oneは分散トレーシング機能を介してトレースデータをキャプチャします。
この特定の例では、「WebPortal」アプリケーションにpurchase / confirmation.jspというページがあります。このページは「Fulfillment Service」を呼び出します。「Fulfillment Service」は「Billing Service」を呼び出し、「Shipping Service」は「Shipping Service」を呼び出します。長方形が長いほどその特定のサービスに費やされる時間が長くなります。
「なぜ」と尋ねる方法を再定義しましょう
MELTデータタイプのユースケースを理解することはオブザーバビリティを実践するために不可欠です。これらのデータタイプを理解すると、New Relicを操作して、オープンソースまたはベンダー固有のテレメトリデータを接続し、関係を理解し、関連するデータを理解する方法を把握できます。依存関係を視覚化し、リアルタイムでドリルダウンすることができれば、システムの問題をより迅速かつ簡単に解決し、アプリケーションやインフラストラクチャでこれらの問題が再び発生するのを防ぐことができます。MELT を理解することは、信頼性を確保する方法を理解することにつながっているのです。
New Relic のフル機能を無料で試したいかたはこちらからアカウントを作成できます。是非 New Relic の力をお試しください。
本ブログに掲載されている見解は著者に所属するものであり、必ずしも New Relic 株式会社の公式見解であるわけではありません。また、本ブログには、外部サイトにアクセスするリンクが含まれる場合があります。それらリンク先の内容について、New Relic がいかなる保証も提供することはありません。