Mackerelにおけるカスタマイズグラフ / 式による監視の典型的なパターンを紹介します

こんにちは。CRE(Customer Reliability Engineer)のid:syou6162です。普段は主にカスタマーサクセスを支えるデータ基盤の構築や、データ分析を担当しています。

Mackerelでは様々な機能を提供していますが、中でも自由度が高い機能として「カスタマイズグラフ」と「式による監視」があります。関数を使って自分で自由に式を定義し、グラフにしたりそれを監視ルールとして使える機能です。

このエントリでは、自由度が高いがゆえに「式をどう使うと便利なのかイマイチ想像できない」という方向けに、カスタマイズグラフ / 式による監視を使った典型的なパターンを紹介します。

この記事はMackerel Advent Calendar 2020の12日目の記事です。

ロール内のメトリックをまとめて見たいケース

一つ目がロール内のメトリックをまとめて見たいケースです。例えばproxyロールにnginxが乗っているホストがたくさんあるとして、そのアクセス数の合計やエラー数の合計を出すといった具合です。nginxに関するメトリックはnginxプラグインを使うと簡単に取得できます。式で書くと以下のように書けます。

alias(
  sum(
    role(
      '<YOUR_SERVICE_NAME>:<YOUR_ROLE_NAME>',
      'custom.nginx.requests.requests'
    )
  ), 
  'Requests of Nginx'
)

ロールグラフの積み上げでも同じようなグラフを出せますが、監視ルールにしたい場合はこちらのほうが使いやすいケースがあるかと思います。各ホストで処理しているリクエスト数には特に関心があるわけではなく、ロール全体での数字に関心がある場合に便利です。

傾向予測をしたいケース

過去の傾向から将来予測を行なうパターンです。以下は、AWSのマネージドRDBサービスであるAmazon RDSのディスクの残りの容量が5GBを切るまでの日数を予測するための式です。これを元に監視を仕込んでおいて、アラートが出たらディスクを拡張するなり、不要なデータを消すといったオペレーションをする、といった具合で活用できます。

scale(
  timeLeftForecast(
    host(
      <YOUR_RDS_HOST_ID>,
      'custom.rds.disk.free'
    ),
    '3mo', 
    5000000000
  ), 
  1/86400
)

このグラフは私が個人で管理しているRDSの例ですが、半年以内にディスクの残りの容量が5GBを切ってしまうということが分かります。年末の大掃除をしないといけないですね...。

式の細かいオプションや読み方については、以下のエントリやヘルプページをご参照ください。

使用割合を見たいケース

特定のメトリックを監視することを考えたときに、絶対的な数字自体に興味はなくて、相対的な割合を監視したい場合は多いです。uwsgiプラグインを例に取り説明します。このプラグインでは、uWSGIのworkerの各状態(busyidleなど)数を取得できますが、uWSGIの設定を変更やサーバーのスケールアップをした場合、busyなworker数は変化します。設定を変更する度に監視設定も変更して回るのは大変です。そこで、worker数全体に占めるbusyなworker数の割合で監視すると、イチイチ監視設定を変更せずに済むので楽です。以下のような式を書くと、簡単にbusyなworkerの割合を出すことができます。

scale(
  divide(
    sum(
      role(
        '<YOUR_SERVICE_NAME>:<YOUR_ROLE_NAME>',
        'custom.uWSGI.uWSGI.workers.busy'
      )
    ),
    sum(
      role(
        '<YOUR_SERVICE_NAME>:<YOUR_ROLE_NAME>,
        'custom.uWSGI.uWSGI.workers.*'
      )
    )
  ),
  100
)

スクリーンショット 2020-12-05 16.35.11.png (103.9 kB)

uWSGIに限らず、apache2プラグインやunicornプラグインなどでも同様の監視を行なうことができます。元CREのid:Soudaiさんがプラグインのインストール方法やその他のメトリックなどについても詳しく説明してくださっているので、合わせて参照してください。

過去の値と比較したいケース

監視をする場合、ときどき単純な閾値の監視では不十分な場合があります。例えば

  • 平日の昼間はユーザーさんからのアクセスが多いが、今日はあまりにも多すぎる。botからのアクセスが多くなっていないか
  • 週末の夜はユーザーさんからのアクセスは少なめだが、今日はあまりにも少なすぎる。金曜に入れた設定変更が間違っていないか

といった具合です。こういった監視をしたい場合、過去の値(例: 一週間前の同時刻)を比較して監視すると役に立つことがあります。例として、一週間前のALBへのアクセス数との比率を出す式を書いてみましょう。

divide(
  sum(
    host(
      <YOUR_ALB_HOST_ID>,
      custom.alb.httpcode_count.*
    )
  ),
  timeShift(
    sum(
      host(
        <YOUR_ALB_HOST_ID>,
        custom.alb.httpcode_count.*
      )
    ),
    1w
  )
)

比率が1に近ければいつもと同じ状態ということを意味しているので、比率が極端に大きな値(例: 10以上)や小さな値(例: 0.1以下)を指定して監視ルールを作れば、いつもと異なるアクセスのパターンを検知することができます。

この式を私が個人で管理しているサイトに適用してみると、以下のようなグラフになりました。Advent Calendarとしては都合のよいことに(?)、12/3あたりで通常の10~20倍近くのアクセスがきていることが分かります。アクセスログの生ログを見てみると、海外のbotからのアクセスが殺到していることが分かりました。

カウンター値のような累積値を差分値にばらしてグラフにしたい場合にも、timeShift関数は便利なので、是非ご利用ください。

SLIを見たいケース

SRE(Site Reliability Engineering)の普及から、SLI(Service Level Indicator)について考えたり、SLO(Service Level Objective)を設定されるチームも増えてきていると思います。SLIやSLOはサービスやシステムの特性から様々な定義がありますが、ここでは可用性に着目しSLIを式で表わしてみることにしましょう。可用性はここでは単純にALBのメトリックを対象として(2xxと返したアクセス数) / ((2xxと返したアクセス数 + (5xxと返したアクセス数))と定義します。式は以下のようになります(ローリングタイムウィンドウを2週間とした場合、2週間をウィンドウサイズとした移動平均を取るのもいいかもしれません)。

scale(
    divide(
      host(
        <YOUR_ALB_HOST_ID>,
        custom.alb.httpcode_count.target_2xx
      ),
      sum(
        group(
          host(
            <YOUR_ALB_HOST_ID>,
            custom.alb.httpcode_count.target_2xx
          ),
          host(
            <YOUR_ALB_HOST_ID>,
            custom.alb.httpcode_count.target_5xx
          )
        )
      )
    ),
    100
)

以下は私が趣味で運用しているサイトのグラフの例です。7月頃にSLIが大きく100を割っています。5xxを返していることは分かっていたのですが、復旧作業に時間を取れなかったためこのようになってしまいました。

スクリーンショット 2020-12-05 17.37.07.png (82.0 kB)

SLI/SLO を設定してこれを監視することでサービス継続リスクをコントールしつつ「エラーバジェットがこれだけまだあるから、多少のリスクは許容しつつ開発速度を上げていこう」といったSREの活動のさらなる加速に式をうまく利用してもらえればと思います。