T-CREATOR

MySQL アラート設計としきい値:レイテンシ・エラー率・レプリカ遅延の基準

MySQL アラート設計としきい値:レイテンシ・エラー率・レプリカ遅延の基準

MySQL の運用において、適切なアラート設計は障害の早期発見と予防に不可欠です。この記事では、レイテンシ・エラー率・レプリカ遅延の 3 つの重要な監視項目について、実践的なしきい値設定とアラート設計を解説します。これから MySQL の監視体制を構築する方、既存のアラートを見直したい方に向けて、具体的な基準と実装例をご紹介しますね。

背景

MySQL のパフォーマンス監視は、サービスの安定稼働に直結する重要な課題です。しかし、どの指標をどのようなしきい値で監視すべきか、明確な基準を持つことは簡単ではありません。

データベースの負荷やトラフィックパターンはサービスごとに異なり、適切なしきい値も環境によって変わります。また、アラートが多すぎると重要な通知を見逃してしまい、逆に少なすぎると障害の兆候を捉えられないというジレンマがあります。

以下の図は、MySQL 監視における主要な指標の関係性を示しています。

mermaidflowchart TB
    client["クライアント<br/>アプリケーション"] -->|クエリ実行| mysql["MySQL<br/>プライマリ"]
    mysql -->|レスポンス| client
    mysql -->|レプリケーション| replica["MySQL<br/>レプリカ"]

    subgraph monitoring["監視項目"]
        latency["レイテンシ<br/>クエリ応答時間"]
        error["エラー率<br/>失敗率・接続エラー"]
        replication["レプリカ遅延<br/>データ同期遅延"]
    end

    mysql -.->|計測| latency
    mysql -.->|計測| error
    replica -.->|計測| replication

この図から、クライアントとデータベース間のやり取りにおいて、3 つの異なる側面から健全性を監視する必要があることがわかります。

課題

MySQL の監視設計では、以下のような課題に直面することが多いでしょう。

まず、しきい値の妥当性の判断が困難です。レイテンシ 100ms は遅いのか、エラー率 1%は許容範囲なのか、初めて監視を設計する場合は判断基準がないため悩みます。

次に、**アラート疲れ(Alert Fatigue)**の問題があります。しきい値を厳しく設定しすぎると、些細な変動でもアラートが発生し、本当に対応すべき障害を見逃してしまうリスクが高まるのです。

さらに、監視レベルの設定も重要な課題となります。警告レベルと緊急レベルをどう分けるべきか、どの時点でエスカレーションすべきかの基準が曖昧だと、適切な対応が遅れてしまいます。

また、環境差の考慮も必要です。開発環境・ステージング環境・本番環境では、求められるパフォーマンス基準が異なるため、一律のしきい値では対応できません。

以下の図は、これらの課題がどのように相互作用するかを示しています。

mermaidflowchart LR
    threshold["しきい値設定"] -->|厳しすぎる| fatigue["アラート疲れ"]
    threshold -->|緩すぎる| miss["障害見逃し"]

    fatigue -->|重要度判断困難| response["対応遅延"]
    miss -->|発見遅延| response

    env["環境差"] -->|基準不明確| threshold
    level["監視レベル"] -->|区分曖昧| threshold

    response -->|サービス影響| impact["ユーザー体験低下"]

このように、適切なバランスを見つけることが監視設計の鍵となります。

解決策

これらの課題に対して、段階的なアラートレベルと具体的なしきい値基準を定義することで、効果的な監視体制を構築できます。

アラートレベルの定義

アラートは以下の 3 段階で設計することをお勧めします。

#レベル対応時間対応者目的
1INFO(情報)営業時間内開発チーム傾向監視・予防保守
2WARNING(警告)1 時間以内オンコール担当早期対応・悪化防止
3CRITICAL(緊急)即時(15 分以内)オンコール担当 + マネージャー即時対応・サービス復旧

この段階的なアプローチにより、重要度に応じた適切な対応が可能になります。

レイテンシのしきい値設計

クエリ応答時間は、ユーザー体験に直結する最も重要な指標の一つです。

平均レイテンシ(avg_latency)の基準:

#レベルしきい値継続時間理由
1INFO50ms 以上10 分間通常より遅い状態の検出
2WARNING100ms 以上5 分間ユーザー体験への影響開始
3CRITICAL500ms 以上1 分間深刻なパフォーマンス劣化

P95 レイテンシ(95 パーセンタイル)の基準:

#レベルしきい値継続時間理由
1INFO200ms 以上10 分間一部のクエリが遅延
2WARNING500ms 以上5 分間多くのユーザーに影響
3CRITICAL1000ms 以上1 分間サービス品質の著しい低下

平均値だけでなく P95 を監視することで、一部のユーザーに発生する問題も見逃さずに対応できます。

エラー率のしきい値設計

接続エラーやクエリエラーは、アプリケーションの障害に直結します。

接続エラー率の基準:

#レベルしきい値継続時間理由
1INFO0.1% 以上5 分間散発的なエラーの検出
2WARNING1% 以上3 分間接続プールの問題可能性
3CRITICAL5% 以上1 分間データベース接続障害

クエリエラー率の基準:

#レベルしきい値継続時間理由
1INFO0.5% 以上5 分間アプリケーションバグの兆候
2WARNING2% 以上3 分間データ不整合やスキーマ問題
3CRITICAL10% 以上1 分間深刻なアプリケーション障害

エラー率は絶対値が小さくても影響が大きいため、比較的低いしきい値を設定します。

レプリカ遅延のしきい値設計

レプリケーション遅延は、データの一貫性とスケーラビリティに影響します。

レプリカ遅延の基準:

#レベルしきい値継続時間理由
1INFO10 秒以上5 分間通常より遅い同期速度
2WARNING30 秒以上3 分間読み取り一貫性への影響
3CRITICAL60 秒以上1 分間レプリケーション停止の可能性

レプリカ停止の検出:

#レベル条件理由
1CRITICALレプリケーションスレッド停止データ同期完全停止
2CRITICALレプリカ 5 分間応答なしレプリカサーバー障害

以下の図は、アラートレベルと対応フローの関係を示しています。

mermaidstateDiagram-v2
    [*] --> Normal: 正常稼働
    Normal --> Info: しきい値超過<br/>INFO レベル
    Info --> Normal: 自動復旧
    Info --> Warn: 悪化継続<br/>WARNING レベル

    Warn --> Info: 改善傾向
    Warn --> Critical: さらに悪化<br/>CRITICAL レベル

    Critical --> Warn: 一時回復
    Critical --> Incident: 対応開始<br/>インシデント化

    Incident --> Normal: 完全復旧

    note right of Info
        営業時間内対応
        傾向分析
    end note

    note right of Warn
        1時間以内対応
        原因調査開始
    end note

    note right of Critical
        即時対応
        エスカレーション
    end note

この状態遷移により、問題の深刻度に応じた適切な対応フローが実現できます。

具体例

ここでは、Prometheus と Grafana を使った実際の監視設定例をご紹介します。段階的に実装していきましょう。

MySQL Exporter の設定

まず、MySQL のメトリクスを収集するために MySQL Exporter を導入します。

Docker Compose での MySQL Exporter 設定:

yamlversion: '3.8'

services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: myapp
    ports:
      - '3306:3306'
    volumes:
      - mysql_data:/var/lib/mysql

MySQL 本体のコンテナを定義します。本番環境ではパスワードは環境変数やシークレット管理ツールで管理してください。

yamlmysql-exporter:
  image: prom/mysqld-exporter:latest
  environment:
    DATA_SOURCE_NAME: 'exporter:exporterpassword@(mysql:3306)/'
  ports:
    - '9104:9104'
  depends_on:
    - mysql

MySQL Exporter を設定し、MySQL からメトリクスを収集します。ポート 9104 で Prometheus がスクレイプできるようにします。

yamlprometheus:
  image: prom/prometheus:latest
  volumes:
    - ./prometheus.yml:/etc/prometheus/prometheus.yml
    - ./alerts.yml:/etc/prometheus/alerts.yml
  ports:
    - '9090:9090'
  command:
    - '--config.file=/etc/prometheus/prometheus.yml'

Prometheus サーバーを起動し、設定ファイルとアラートルールを読み込みます。

yamlvolumes:
  mysql_data:

データ永続化のためのボリュームを定義します。

Prometheus 設定

次に、Prometheus でメトリクスを収集する設定を行います。

prometheus.yml の基本設定:

yamlglobal:
  scrape_interval: 15s # 15秒ごとにメトリクスを収集
  evaluation_interval: 15s # 15秒ごとにアラートルールを評価

# アラートマネージャーの設定
alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - 'alertmanager:9093'

グローバル設定で収集間隔とアラート評価間隔を定義します。頻繁すぎると負荷が高まるため、15 秒が適切でしょう。

yaml# アラートルールファイルの読み込み
rule_files:
  - 'alerts.yml'

# メトリクス収集対象の設定
scrape_configs:
  - job_name: 'mysql'
    static_configs:
      - targets: ['mysql-exporter:9104']
        labels:
          env: 'production'
          service: 'mysql'

MySQL Exporter からメトリクスを収集する設定です。環境やサービスのラベルを付けることで、後でフィルタリングしやすくなります。

アラートルールの実装

続いて、具体的なアラートルールを定義していきます。

alerts.yml のグループ定義:

yamlgroups:
  - name: mysql_latency_alerts
    interval: 30s # 30秒ごとにこのグループのルールを評価

レイテンシ関連のアラートをグループ化します。グループごとに評価間隔を設定できます。

平均レイテンシの WARNING アラート:

yamlrules:
  - alert: MySQLHighAverageLatency
    expr: |
      rate(mysql_global_status_queries[5m]) > 0
      and
      (rate(mysql_global_status_slow_queries[5m]) / rate(mysql_global_status_queries[5m])) > 0.1
    for: 5m
    labels:
      severity: warning
      component: mysql
    annotations:
      summary: 'MySQL 平均レイテンシが高い (instance {{ $labels.instance }})'
      description: '過去5分間のスロークエリ比率が10%を超えています。現在の値: {{ $value | humanizePercentage }}'

スロークエリの比率を監視します。クエリ実行数に対するスロークエリの割合が 10%を超えた状態が 5 分間継続すると WARNING アラートが発火します。

平均レイテンシの CRITICAL アラート:

yaml- alert: MySQLCriticalAverageLatency
  expr: |
    rate(mysql_global_status_queries[1m]) > 0
    and
    (rate(mysql_global_status_slow_queries[1m]) / rate(mysql_global_status_queries[1m])) > 0.5
  for: 1m
  labels:
    severity: critical
    component: mysql
  annotations:
    summary: 'MySQL 平均レイテンシが非常に高い (instance {{ $labels.instance }})'
    description: '過去1分間のスロークエリ比率が50%を超えています。即座の対応が必要です。現在の値: {{ $value | humanizePercentage }}'

より深刻な状況を検出します。スロークエリ比率が 50%を超えた状態が 1 分間継続すると CRITICAL アラートが発火しますね。

エラー率のアラートグループ:

yaml- name: mysql_error_alerts
  interval: 30s
  rules:
    - alert: MySQLHighConnectionErrorRate
      expr: |
        rate(mysql_global_status_aborted_connects[5m]) > 0.01
      for: 3m
      labels:
        severity: warning
        component: mysql
      annotations:
        summary: 'MySQL 接続エラー率が高い (instance {{ $labels.instance }})'
        description: '接続エラーが発生しています。レート: {{ $value | humanize }}/秒'

接続エラーを監視します。1 秒あたり 0.01 回(1 分あたり約 0.6 回)以上のエラーが 3 分間継続すると WARNING が発火します。

接続エラーの CRITICAL アラート:

yaml- alert: MySQLCriticalConnectionErrorRate
  expr: |
    rate(mysql_global_status_aborted_connects[1m]) > 0.05
  for: 1m
  labels:
    severity: critical
    component: mysql
  annotations:
    summary: 'MySQL 接続エラー率が非常に高い (instance {{ $labels.instance }})'
    description: '大量の接続エラーが発生しています。データベース接続に深刻な問題があります。レート: {{ $value | humanize }}/秒'

深刻な接続エラーを検出します。1 秒あたり 0.05 回以上のエラーが 1 分間継続すると即座に対応が必要です。

レプリカ遅延のアラートグループ:

yaml- name: mysql_replication_alerts
  interval: 30s
  rules:
    - alert: MySQLReplicationLagWarning
      expr: |
        mysql_slave_status_seconds_behind_master > 30
      for: 3m
      labels:
        severity: warning
        component: mysql-replication
      annotations:
        summary: 'MySQL レプリカ遅延が発生 (instance {{ $labels.instance }})'
        description: 'レプリケーション遅延が30秒を超えています。現在の遅延: {{ $value }}秒'

レプリカの遅延を監視します。30 秒以上の遅延が 3 分間継続すると WARNING アラートが発火します。

レプリカ遅延の CRITICAL アラート:

yaml- alert: MySQLReplicationLagCritical
  expr: |
    mysql_slave_status_seconds_behind_master > 60
  for: 1m
  labels:
    severity: critical
    component: mysql-replication
  annotations:
    summary: 'MySQL レプリカ遅延が深刻 (instance {{ $labels.instance }})'
    description: 'レプリケーション遅延が60秒を超えています。データ一貫性に影響があります。現在の遅延: {{ $value }}秒'

深刻なレプリカ遅延を検出します。60 秒以上の遅延が 1 分間継続すると CRITICAL アラートが発火しますね。

レプリケーション停止の検出:

yaml- alert: MySQLReplicationStopped
  expr: |
    mysql_slave_status_slave_io_running == 0
    or
    mysql_slave_status_slave_sql_running == 0
  for: 1m
  labels:
    severity: critical
    component: mysql-replication
  annotations:
    summary: 'MySQL レプリケーションが停止 (instance {{ $labels.instance }})'
    description: 'レプリケーションスレッドが停止しています。IO Running: {{ $labels.slave_io_running }}, SQL Running: {{ $labels.slave_sql_running }}'

レプリケーションスレッドの停止を即座に検出します。IO スレッドまたは SQL スレッドが停止すると、1 分以内に CRITICAL アラートが発火します。

Grafana ダッシュボード設定

最後に、これらのメトリクスを可視化する Grafana ダッシュボードを設定します。

レイテンシパネルの PromQL クエリ:

promql# 平均クエリ実行時間
rate(mysql_global_status_slow_queries[5m]) / rate(mysql_global_status_queries[5m])

スロークエリの比率を計算し、レイテンシの傾向を可視化します。

promql# P95 レイテンシの推定(ヒストグラムがある場合)
histogram_quantile(0.95,
  rate(mysql_query_duration_seconds_bucket[5m])
)

95 パーセンタイルのレイテンシを表示します。大多数のユーザーが体験する応答時間がわかります。

エラー率パネルの PromQL クエリ:

promql# 接続エラー率(1秒あたり)
rate(mysql_global_status_aborted_connects[5m])

接続エラーの発生頻度を時系列で表示します。

promql# クエリエラー率(パーセント)
rate(mysql_global_status_connection_errors_total[5m]) /
rate(mysql_global_status_connections[5m]) * 100

全接続に対するエラーの割合をパーセントで表示します。

レプリカ遅延パネルの PromQL クエリ:

promql# レプリカ遅延(秒)
mysql_slave_status_seconds_behind_master

レプリカの遅延時間をリアルタイムで表示します。

promql# レプリケーション状態
mysql_slave_status_slave_io_running * mysql_slave_status_slave_sql_running

レプリケーションスレッドの稼働状態を監視します。両方が 1 の場合のみ正常です。

アラート通知の設定

アラートを適切な担当者に通知するための設定も重要ですね。

Alertmanager の設定例(alertmanager.yml):

yamlglobal:
  resolve_timeout: 5m # アラート解決の判定時間

# 通知テンプレート
templates:
  - '/etc/alertmanager/templates/*.tmpl'

# ルーティング設定
route:
  group_by: ['alertname', 'severity']
  group_wait: 30s # 初回アラート待機時間
  group_interval: 5m # グループ内の追加アラート間隔
  repeat_interval: 3h # アラート再送間隔

基本的なルーティング設定を行います。同じアラートが頻繁に送信されないよう、適切な間隔を設定します。

yaml# デフォルトレシーバー
receiver: 'default-receiver'

# 重要度別ルーティング
routes:
  - match:
      severity: critical
    receiver: 'critical-receiver'
    continue: true

  - match:
      severity: warning
    receiver: 'warning-receiver'

重要度に応じて異なる通知先にルーティングします。CRITICAL は即座に通知が必要です。

Slack 通知の設定:

yamlreceivers:
  - name: 'default-receiver'
    slack_configs:
      - api_url: 'YOUR_SLACK_WEBHOOK_URL'
        channel: '#mysql-monitoring'
        title: 'MySQL アラート'
        text: |
          {{ range .Alerts }}
          *アラート:* {{ .Labels.alertname }}
          *重要度:* {{ .Labels.severity }}
          *説明:* {{ .Annotations.description }}
          {{ end }}

デフォルトの通知設定です。Slack の Webhook URL を設定してください。

yaml- name: 'critical-receiver'
  slack_configs:
    - api_url: 'YOUR_SLACK_WEBHOOK_URL'
      channel: '#mysql-critical'
      title: '🚨 MySQL 緊急アラート'
      text: |
        @channel
        {{ range .Alerts }}
        *アラート:* {{ .Labels.alertname }}
        *インスタンス:* {{ .Labels.instance }}
        *説明:* {{ .Annotations.description }}
        *対応:* 即座の対応が必要です
        {{ end }}

CRITICAL レベルのアラートは専用チャンネルに @channel 付きで通知します。担当者全員に確実に届きますね。

yaml- name: 'warning-receiver'
  slack_configs:
    - api_url: 'YOUR_SLACK_WEBHOOK_URL'
      channel: '#mysql-warnings'
      title: '⚠️ MySQL 警告'
      text: |
        {{ range .Alerts }}
        *アラート:* {{ .Labels.alertname }}
        *インスタンス:* {{ .Labels.instance }}
        *説明:* {{ .Annotations.description }}
        {{ end }}

WARNING レベルは別チャンネルで通知し、緊急度を分けて管理します。

以下の図は、アラート発生から通知、対応までのフローを示しています。

mermaidsequenceDiagram
    participant M as MySQL
    participant E as Exporter
    participant P as Prometheus
    participant A as Alertmanager
    participant S as Slack
    participant T as 担当者

    M->>E: メトリクス提供
    E->>P: メトリクス収集<br/>(15秒ごと)
    P->>P: ルール評価<br/>(30秒ごと)

    Note over P: しきい値超過検出

    P->>A: アラート送信
    A->>A: グルーピング<br/>待機30秒
    A->>S: Slack通知送信
    S->>T: 通知受信

    T->>M: 調査・対応
    M->>E: 正常化メトリクス
    E->>P: 正常値収集
    P->>A: アラート解決
    A->>S: 解決通知

この一連のフローにより、問題の検出から対応、解決までを追跡できます。

環境別設定の例

開発環境と本番環境で異なるしきい値を設定する方法もご紹介します。

環境別アラートルールの設定:

yamlgroups:
  - name: mysql_latency_production
    interval: 30s
    rules:
      - alert: MySQLHighLatencyProduction
        expr: |
          (rate(mysql_global_status_slow_queries[5m]) / rate(mysql_global_status_queries[5m])) > 0.1
          and on(instance) mysql_exporter_build_info{env="production"}
        for: 5m
        labels:
          severity: warning
          env: production

本番環境専用のアラートルールです。env="production" ラベルでフィルタリングします。

yaml- name: mysql_latency_development
  interval: 30s
  rules:
    - alert: MySQLHighLatencyDevelopment
      expr: |
        (rate(mysql_global_status_slow_queries[5m]) / rate(mysql_global_status_queries[5m])) > 0.3
        and on(instance) mysql_exporter_build_info{env="development"}
      for: 10m
      labels:
        severity: info
        env: development

開発環境では、しきい値を緩く(0.3)、継続時間を長く(10 分)設定します。頻繁なアラートを避けつつ、傾向は把握できますね。

まとめ

MySQL のアラート設計では、レイテンシ・エラー率・レプリカ遅延の 3 つの主要指標を段階的に監視することが重要です。

INFO・WARNING・CRITICAL の 3 段階のアラートレベルを設定することで、問題の深刻度に応じた適切な対応が可能になります。レイテンシは平均値と P95 の両方を監視し、エラー率は低いしきい値で早期検出、レプリカ遅延は 30 秒・60 秒・停止の 3 段階で監視することをお勧めします。

Prometheus と Grafana を組み合わせることで、メトリクス収集・アラート発火・可視化・通知までを一貫して実装できます。環境ごとに異なるしきい値を設定し、アラート疲れを防ぎながら重要な問題を見逃さない監視体制を構築してください。

これらの基準は出発点として活用し、実際のトラフィックパターンやサービス要件に応じて調整していくことで、より効果的な監視システムが完成します。適切なアラート設計により、障害の早期発見とサービスの安定稼働を実現しましょう。

関連リンク