メトリクス
Metrics ・ めとりくす
システムの状態を、ラベル付きの数値の時系列として記録したもの。監視の基本の素材。
✦ 30秒で試す — 航海ラベルを1つ足しただけで、監視の仕組みが落ちる利用者のIDを足すと、時系列の本数は?予想してみる概要
メトリクスは、システムの状態を「時刻付きの数値」として一定間隔で記録し続けたデータです。毎秒のリクエスト数、CPU使用率、応答時間、エラー件数 — どれも「名前 + ラベル + 時刻 + 数値」という小さな組の連なり、つまり時系列データとして表現されます。運用のダッシュボードに並ぶ折れ線グラフの正体は、ほぼすべてこのメトリクスです。
出来事を一件ずつ文章として残すログと比べると、メトリクスは最初から集計された数値なので圧倒的に軽く、何か月分でも安価に保存でき、「先週と比べてどうか」「異常な傾向はないか」という問いに即座に答えられます。その代わり、集計の過程で個別のリクエストの事情は失われます。この「軽くて俯瞰に強いが、詳細は語らない」という性格が、監視や可観測性の中でメトリクスが担う役割を決めています。
なぜ生まれたか
数値による計測そのものは、SNMP(ネットワーク機器の状態を読み出す標準の手順)で機器の状態を取っていた時代からありました。当時の監視の関心は「サーバやルータという機械が生きているか」でした。Webサービスの規模が拡大し、分散システム化が進むと、問いは「機械が生きているか」から「サービスとしてユーザーに価値を提供できているか」へ移ります。数百台のサーバの1台が落ちても誰も困らないが、決済のエラー率が0.1%から2%に上がったら大問題です。この問いに答えるには、機械ではなくアプリケーション自身が「リクエスト数・エラー数・処理時間」を数値として吐き出し、それを横断的に集計・保存・検索できる基盤が必要でした。
さらに、コンテナやKubernetesの普及で「観測対象が数分で生まれては消える」環境になると、ホスト名ベースの旧来の監視は破綻します。対象をラベル(サービス名・環境・バージョンなど)で多次元的に識別し、任意の軸で集計し直せるデータモデルが求められ、Google 社内の Borgmon に着想を得た Prometheus(2012年に SoundCloud で開発が始まり、2016年に CNCF へ参加)がこのモデルを広めました。現在の「ラベル付き時系列」というメトリクスの標準形は、この系譜の産物です。
詳細
データモデル — 名前・ラベル・時刻・値
いまのメトリクスの基本形は、Prometheus の書き方で書くと次の1行です。http_requests_total{method="POST", status="500", region="tokyo"} 1027 のように、メトリクスの名前に「ラベル」(キーと値の組)が付き、そこに数値が入ります。監視サーバはこれを15秒ごとなどに読み取り、時刻と値の組として積み上げます。大事なのは、名前とラベルの値の組み合わせが1つ違えば、それは別の1本の時系列になることです。method が4種類、status が5種類、region が3種類なら、このメトリクスは最大で 4×5×3=60本の時系列になります。
ラベルがあるおかげで、「全体のエラー率」も「東京リージョンの POST だけのエラー率」も、同じデータから集計のしかたを変えるだけで取り出せます。一方で、ラベルの付け方しだいで時系列の本数が掛け算で増える、というのがメトリクスの設計のいちばんの急所です(後述のカーディナリティ)。
3つの基本型 — カウンタ・ゲージ・ヒストグラム
メトリクスには、数値の性質による基本型があります。カウンタは「増える一方の累積値」で、リクエストの総数やエラーの総数などです。値そのものではなく、時間あたりの増分(レート)に直して「毎秒何件か」を見ます。プロセスの再起動でゼロに戻っても、増分で見ていれば影響を受けません。ゲージは「上下する現在値」で、CPU 使用率・メモリ使用量・キューの長さなど、その瞬間の値に意味があるものです。
ヒストグラムは「値の分布」で、応答時間のように1つの数に潰すと嘘になるものに使います。応答時間を平均で見ると、大多数の速いリクエストに隠れて、一部の極端に遅いリクエストが見えなくなります。そこで実務では「p99(99パーセンタイル)= リクエストの99%がこれより速く終わる値」のような分位点で語ります。p99 は分布の上の1点で、100人に1人が味わっている遅さです。ヒストグラムの型は「100ms 以下が何件、250ms 以下が何件」というバケツごとの件数を持ち、分位点はそこから計算します。各サーバで計算済みの p99 どうしを平均しても全体の p99 にはなりませんが、バケツの件数は足し合わせられるので、全台ぶんの p99 を正しく出せます。
収集と保存 — Pull/Push と時系列データベース
メトリクスの集め方には二派あります。Pull 型は、監視サーバの側が定期的に各対象の公開エンドポイント(Prometheus なら /metrics)へ取りに行く方式です。監視対象の一覧を監視側が持っているので、「取りに行ったのに応答がない=死んでいる」という死活の判定が自然にできます。Push 型は各対象がメトリクスを送りつける方式で、実行が終わると消えてしまうサーバレスの関数やバッチ処理のように、「取りに行く時にはもう存在しない」対象に向きます。実際の基盤は両方を併用することが多く、OpenTelemetry のコレクタのような中継役を置いて、どちらの経路も受けられるようにします。
集めたデータの保存先が時系列データベース(TSDB)です。「時刻順に追記され、ほとんど更新されず、直近ほど頻繁に読まれる」という時系列特有の使われ方に合わせてあり、汎用の RDBMS より桁違いに高い圧縮率と書き込み性能を出します。古いデータほど解像度を落として持つ(直近は15秒ごと、1年前は1時間ごと)ダウンサンプリングも典型的な機能です。代表的な実装に Prometheus、InfluxDB、長期保存と水平分散を担う Thanos や Mimir などがあります。
何を測るか — RED と USE
「メトリクスは何百種類も取れるが、まず何を見るべきか」への定番の答えが2つのメソッドです。RED メソッドはリクエストを受けるサービス向けで、Rate(毎秒のリクエスト数)・Errors(失敗の数)・Duration(処理時間の分布)の3つを見ます。ユーザー体験に直結し、マイクロサービスの各サービスに同じ形で当てはめられるのが強みです。USE メソッドは CPU・メモリ・ディスクといった資源向けで、Utilization(使用率)・Saturation(飽和。処理しきれずに待たされている量)・Errors(エラー)を見ます。
「サービスの健康は RED で、資源の健康は USE で」と覚えておくと、ダッシュボードの設計の出発点になります。RED の Duration はレイテンシとスループットのうちのレイテンシの分布そのものです。ここで決めたエラー率や応答時間はそのまま SLO の計測の材料になり、アラートを鳴らす条件式の入力にもなります。
落とし穴 — カーディナリティ爆発
メトリクスの設計でいちばんの落とし穴が、カーディナリティ(ラベルの値の組み合わせの数)の爆発です。時系列はラベルの値の組み合わせごとに1本作られ、TSDB は直近の時系列を1本ずつメモリに載せて受け付けます。そこへユーザー ID やリクエスト ID、生の URL のパス(/users/12345 のような ID 入りのもの)のように、値の種類が際限なく増えるものをラベルにすると、時系列の本数が爆発して TSDB のメモリと保存領域を食い潰します。下の部品で、ラベルを1つずつ付けて本数の増え方を確かめてください。
いま http_requests_total は1本の時系列です。下のラベルの札をドラッグして、メトリクス名の { } の中に付けてください(札を押しても付け外しできます)。
ラベルには、サービス名・環境・ステータスコード・ルートのテンプレート(/users/:id)のような、値の種類が有限なものだけを使います。「ユーザー42の決済だけが遅い」のような個別の事情を追いたいときは、その属性をログや分散トレーシングのスパンに書きます。ログやトレースは1件ずつの記録なので、属性の種類がいくら多くても、本数が掛け算で増えることはありません。メトリクスは「決まった問いを安く・長く見張る」、ログとトレースは「後から個別の事情を掘る」。この住み分けが、メトリクスを長く安く運用するための基本原則です。
試問
Web サービスのリクエスト数をメトリクスとして記録します。時系列はラベルの値の組み合わせごとに1本でき、1本ずつメモリに載ります。リクエストに付いてくる9つの情報を、メトリクスのラベルにするか、ログやトレース(1件ずつの記録)に書くかに振り分けてください。
リクエストに付く9つの情報を、メトリクスのラベルにするものと、ログ・トレースに書くものに仕分けよ
項目を選んでから、入れる箱を選びます
