記事の一覧

Zabbix で DB 監視する方法 (MySQL・PostgreSQL・ODBC)

Zabbix で MySQL と PostgreSQL を監視する方法を、Zabbix agent 2 の公式テンプレート、ODBC 監視、カスタムクエリに分けて説明します。主なアイテムとトリガー、注文数のような業務データを監視する工夫と限界もまとめました。

Zabbix でデータベースを監視しようとすると、テンプレート、Zabbix agent 2 のプラグイン、ODBC と方法がいくつもあり、どれを使えばよいか迷います。この記事では MySQL と PostgreSQL を例に、それぞれの方法の設定手順、テンプレートが見ている主なアイテムとトリガー、注文数やジョブの滞留のような業務データを監視するときの工夫と限界をまとめます。

内容は 2026 年 11 月時点で最新の LTS (長期サポート版) である Zabbix 7.0 の公式ドキュメントとテンプレートで確かめています。次の LTS の 8.0 はリリース候補の段階で、キーや設定の名前が変わる可能性があるので、8.0 を使う場合はそのバージョンのドキュメントも見てください。

Zabbix でデータベースを監視する 3 つの方法

Zabbix でデータベースの値を取る方法は、大きく 3 つです。

方法 どこから DB に接続するか 向いている用途
Zabbix agent 2 のプラグインと公式テンプレート Agent 2 を入れたホスト 接続数、スロークエリ、レプリケーションなど DB 自体の状態
ODBC 監視 (Database monitor アイテム) Zabbix サーバーまたはプロキシ 自分で書いた SQL の結果 (業務データなど)
Agent 2 のカスタムクエリ Agent 2 を入れたホスト 自分で書いた SQL を Agent 側で実行したいとき

DB 自体が元気かどうかを見るなら、まず 1 つ目の公式テンプレートを入れます。テンプレートには、よく使うアイテム (取得する値) とトリガー (障害と判定する条件) が最初からそろっています。業務データを見たいときは 2 つ目か 3 つ目で SQL を足します。

Zabbix agent 2 は Go で書き直された新しいエージェントです。従来の Zabbix agent (C で書かれたもの) と違い、MySQL や PostgreSQL に接続するプラグインを持っています。Agent 2 は DB サーバーに入れてもかまいませんし、別のホストに入れてネットワーク越しに DB へ接続させることもできます。RDS や Cloud SQL のように OS にログインできない DB は、後者の形になります。

MySQL を Zabbix agent 2 で監視する

監視用のユーザーを作る

公式の手順では監視専用のユーザーを作り、必要な権限だけを与えます。

CREATE USER 'zbx_monitor'@'%' IDENTIFIED BY '<password>';
GRANT REPLICATION CLIENT, PROCESS, SHOW DATABASES, SHOW VIEW ON *.* TO 'zbx_monitor'@'%';

'%' はどのホストからでも接続できるという意味です。Agent 2 を動かすホストが決まっているなら、そのアドレスに絞るほうが安全です。MariaDB 10.5.9 以降でレプリケーションの値も取る場合は、SLAVE MONITOR の権限も必要です。MySQL 8.4 以降を監視するときは、Zabbix agent 2 を 7.0.22 以降にするようテンプレートの説明に書かれています。

ホストにテンプレートをリンクする

Zabbix の画面でホストを作り、テンプレート「MySQL by Zabbix agent 2」をリンクします。そのうえで、ホストのマクロ (テンプレートの中で使う変数) に接続情報を設定します。

マクロ 設定する値
{$MYSQL.DSN} 接続先。例: tcp://localhost:3306、または Agent 2 の設定ファイルで定義したセッション名
{$MYSQL.USER} zbx_monitor
{$MYSQL.PASSWORD} 作ったユーザーのパスワード

パスワードを Zabbix の画面に置きたくない場合は、Agent 2 の設定で名前付きセッションを定義し、{$MYSQL.DSN} にはそのセッション名だけを書きます。

Plugins.Mysql.Sessions.prod.Uri=tcp://10.0.1.20:3306
Plugins.Mysql.Sessions.prod.User=zbx_monitor
Plugins.Mysql.Sessions.prod.Password=<password>

パラメータ名の先頭は Plugins.Mysql で、MySQL ではない点に気をつけてください。

設定できたら、「Monitoring → Latest data」(最新データ) の画面で値が入っているかを確かめます。公式の手順では、{$MYSQL.USER} をわざと違う名前にして「MySQL: Service is down」の障害が出ることを確かめ、元に戻す方法が紹介されています。

主なアイテムとトリガー

テンプレートには多くのアイテムがありますが、まず押さえておきたいのは次のトリガーです (Zabbix 7.0 のテンプレートの README より)。

トリガー 何を見ているか 既定の閾値 (マクロ)
Service is down mysql.ping が 0 (接続できない) なし
Service has been restarted 稼働時間が 10 分未満 なし
Server has aborted connections 5 分間の異常切断の頻度 {$MYSQL.ABORTED_CONN.MAX.WARN} = 3
Refused connections max_connections による接続拒否 なし
Server has slow queries 5 分間のスロークエリの頻度 {$MYSQL.SLOW_QUERIES.MAX.WARN} = 3
Buffer pool utilization is too low InnoDB のバッファプールの使用率 {$MYSQL.BUFF_UTIL.MIN.WARN} = 50 (%)
Replication lag is too high レプリケーションの遅れ {$MYSQL.REPL_LAG.MAX.WARN} = 30m

「Refused connections」が出たら接続数が上限に達しています。原因の調べ方は Too many connections の原因と対処 で説明しています。「Server has slow queries」は MySQL の Slow_queries (long_query_time を超えたクエリの数) をもとにしているので、どのクエリが遅いかはスロークエリログで調べます。手順は MySQL のスロークエリの見つけ方 にまとめています。

閾値はマクロで変えられます。テンプレートの値をそのまま使うと、自分の環境では鳴りすぎたり鳴らなすぎたりすることがあるので、数週間のデータを見てからホストのマクロで上書きします。閾値の決め方は アラートの閾値の決め方 も参考にしてください。

PostgreSQL を Zabbix agent 2 で監視する

プラグインを入れる

Zabbix 7.0 では、PostgreSQL のプラグインは Agent 2 本体とは別の「ロード可能なプラグイン」です。Zabbix の公式リポジトリからインストールしている場合は、zabbix-agent2-plugin-postgresql のパッケージを追加で入れます。入れ忘れると、テンプレートをリンクしてもアイテムが取得できません。

監視用のユーザーと接続の許可

テンプレートの README の手順では、次のようにユーザーを作り、PostgreSQL に用意されている監視用のロール pg_monitor を与えます。

CREATE USER zbx_monitor WITH PASSWORD '<PASSWORD>' INHERIT;
GRANT pg_monitor TO zbx_monitor;

pg_monitor は、統計情報のビューや設定値を読むための組み込みのロールです。テーブルのデータを書き換える権限は含まれていません。

続いて pg_hba.conf に、このユーザーの接続を許す行を足して、設定を読み込み直します。

host  all  zbx_monitor  127.0.0.1/32  scram-sha-256

Agent 2 を別のホストで動かすなら、アドレスはそのホストのものにします。

テンプレートとマクロ

ホストにテンプレート「PostgreSQL by Zabbix agent 2」をリンクし、マクロを設定します。

マクロ 既定値 意味
{$PG.CONNSTRING.AGENT2} tcp://localhost:5432 接続先、またはセッション名
{$PG.USER} zbx_monitor 監視用ユーザー
{$PG.PASSWORD} (要設定) パスワード
{$PG.DATABASE} postgres 最初に接続するデータベース

主なアイテムとトリガー

トリガー 何を見ているか 既定の閾値 (マクロ)
Service is down pgsql.ping が 0 なし
Total number of connections is too high 接続数が max_connections に占める割合 (5 分間の最小値) {$PG.CONN_TOTAL_PCT.MAX.WARN} = 90 (%)
Oldest xid is too big もっとも古いトランザクション ID の年齢 18,000,000
Deadlock occurred データベースごとのデッドロックの頻度 {$PG.DEADLOCKS.MAX.WARN} = 0
Too many slow queries 実行中で時間がかかっているクエリの数 {$PG.SLOW_QUERIES.MAX.WARN} = 5
Too many recovery conflicts スタンバイでのリカバリの競合 {$PG.CONFLICTS.MAX.WARN} = 0

「Too many slow queries」で「遅い」とみなす時間は {$PG.QUERY_ETIME.MAX.WARN} (既定 30 秒) です。「Oldest xid is too big」は、VACUUM が追いついていないときに出やすいトリガーです。背景は PostgreSQL の VACUUM で説明しています。デッドロックが出たときの調べ方は デッドロックの原因と対処 を見てください。

このほか、レプリケーションの遅れ (pgsql.replication.lag.sec)、キャッシュのヒット率 (pgsql.cache.hit)、idle in transaction の接続数なども取れます。グラフで推移を見ておくと、障害のときに「いつから変わったか」を追いやすくなります。

ODBC で SQL の結果を監視する

テンプレートの値は DB 自体の状態です。「直近 1 時間の注文数」や「処理待ちのジョブの数」のような業務データは、自分で SQL を書いて取ります。そのとき使いやすいのが ODBC 監視 (Database monitor アイテム) です。

ODBC 監視では、Zabbix サーバー (またはプロキシ) が ODBC ドライバ経由で DB に接続し、SQL を実行します。DB サーバーに何かを入れる必要はありません。公式の ODBC テンプレートとして「MySQL by ODBC」「PostgreSQL by ODBC」もありますが、ここでは業務データのアイテムを自分で作る手順を書きます。

読み取り専用のユーザーを用意する

監視用の SQL を実行するユーザーは、テンプレート用の zbx_monitor とは分け、見たいテーブルの SELECT だけを与えます。PostgreSQL なら次のようにします。

CREATE USER zbx_query WITH PASSWORD '<password>';
GRANT CONNECT ON DATABASE shop TO zbx_query;
GRANT USAGE ON SCHEMA public TO zbx_query;
GRANT SELECT ON orders, payments, jobs TO zbx_query;

MySQL なら GRANT SELECT ON shop.orders TO 'zbx_query'@'<Zabbix サーバーのアドレス>'; のようにテーブルごとに与えます。誤って書き込む SQL を登録しても、権限で止まります。

ドライバと DSN を設定する

Zabbix サーバーに ODBC ドライバを入れます。公式ドキュメントに載っているパッケージ名は次のとおりです。

# Debian / Ubuntu
apt install odbc-postgresql   # PostgreSQL
apt install odbc-mariadb      # MySQL / MariaDB

# RHEL 系
dnf install postgresql-odbc
dnf install mariadb-connector-odbc

登録されたドライバの名前は odbcinst -q -d で確かめられます。その名前を使って、/etc/odbc.ini にデータソース (DSN) を書きます。

[shopdb]
Description=Shop DB (read only)
Driver=PostgreSQL Unicode
Servername=10.0.1.30
Port=5432
Database=shop
ReadOnly=Yes
SSLmode=require

Driver には odbcinst -q -d で表示された名前を書きます。ユーザー名とパスワードは、ファイルに書かずに Zabbix のアイテムの設定で渡せます。

Zabbix に登録する前に、isql で接続できるかを確かめておくと、問題の切り分けが楽になります。

isql -v shopdb zbx_query '<password>'

「Connected!」と出れば接続できています。もう 1 つ、Zabbix サーバーの設定 StartODBCPollers (ODBC の処理を行うプロセスの数、既定は 1) が 0 になっていないかも確かめます。0 だと Database monitor のアイテムはすべて取得不可 (unsupported) になります。

アイテムを作る

ホストに、タイプ「Database monitor」のアイテムを作ります。キーは次の 3 種類です。

キー 返すもの
db.odbc.select[<説明>,<dsn>] 1 行目の 1 列目の値 (1 つの値)
db.odbc.get[<説明>,<dsn>] 結果全体を JSON の配列で
db.odbc.discovery[<説明>,<dsn>] ローレベルディスカバリ用の JSON

数値を 1 つ取って推移を見たいなら db.odbc.select が手軽です。たとえば、直近 1 時間の注文数は次のように取ります。

  • キー: db.odbc.select[orders_1h,shopdb]
  • データ型: 数値 (整数)
  • 監視間隔: 5m
  • ユーザー名 / パスワード: zbx_query とそのパスワード
  • SQL クエリ:
SELECT count(*)
FROM orders
WHERE created_at >= now() - interval '1 hour';

アイテムの「タイムアウト」は ODBC のログインとクエリ実行のタイムアウトとして使われます。重い集計を短い間隔で回すと本番の DB に負荷がかかるので、条件の列にインデックスがあるかを確かめ、間隔は必要な細かさに合わせます。

トリガーを作る

注文数は時間帯や曜日で大きく変わるので、「10 件を下回ったら」のような固定の閾値は夜中に鳴りやすくなります。Zabbix のトリガー関数には期間をずらす書き方 (タイムシフト) があり、先週の同じ時刻と比べられます。

last(/Shop DB/db.odbc.select[orders_1h,shopdb])
  < avg(/Shop DB/db.odbc.select[orders_1h,shopdb],1h:now-1w) * 0.5
and avg(/Shop DB/db.odbc.select[orders_1h,shopdb],1h:now-1w) >= 20

1 つ目の条件は「今の値が、1 週間前の同じ 1 時間の平均の半分を下回った」、2 つ目は「1 週間前のその時間に、比べる意味がある程度の件数があった」です。2 つ目を入れておくと、件数がもともと少ない深夜の小さな揺れで鳴るのを防げます。比べるには、そのアイテムのヒストリを 1 週間分以上残しておく必要があります。

処理待ちのジョブなら、一定時間以上たっても処理されていない件数を数えます。

SELECT count(*)
FROM jobs
WHERE status = 'pending'
  AND created_at < now() - interval '15 minutes';
min(/Shop DB/db.odbc.select[stuck_jobs,shopdb],10m) > 0

10 分間ずっと 0 より大きいときだけ障害にするので、一瞬の滞留では鳴りません。

もう 1 つ忘れやすいのが、値が取れなくなったことの検知です。接続できなくなったり SQL がエラーになったりすると、アイテムは取得不可 (unsupported) になり、上のトリガーは評価されなくなります。nodata() で、一定時間データが来ないことを別のトリガーにしておきます。

nodata(/Shop DB/db.odbc.select[orders_1h,shopdb],30m)=1

Agent 2 のカスタムクエリを使う場合

Agent 2 側で SQL を実行したい場合は、カスタムクエリを使います。.sql のファイルをディレクトリに置き、そのディレクトリを設定で指定して、ファイル名をキーに書きます。

# MySQL プラグイン
Plugins.Mysql.CustomQueriesPath=/etc/zabbix/mysql/sql
# PostgreSQL プラグイン
Plugins.PostgreSQL.CustomQueriesPath=/etc/zabbix/postgresql/sql
mysql.custom.query[<接続先>,<ユーザー>,<パスワード>,stuck_jobs]
pgsql.custom.query[<接続先>,<ユーザー>,<パスワード>,<DB 名>,stuck_jobs]

SQL の中では ? をプレースホルダに使い、キーの後ろに引数を並べて値を渡せます (MySQL プラグインの README より)。結果は JSON で返るので、数値として扱うには依存アイテムを作り、前処理の JSONPath で値を取り出します。ODBC のドライバを Zabbix サーバーに入れられない場合や、DB に近いところで実行したい場合に向いています。

業務データを Zabbix で監視するときの限界

ここまでの方法で、業務データもかなりの範囲を Zabbix で見張れます。ただ、運用を続けると次のような手間が出てきます。

まず、何を監視するかを人が決め、SQL を書く必要があります。テーブルの構成を知っている人がいないと始められず、テーブルや列が変わったときに SQL を直すのも人です。

次に、閾値の調整です。タイムシフトで先週と比べても、セール、祝日、月末のように先週と条件が違う日は外れます。閾値を緩めれば見逃しが増え、締めれば誤報が増えます。誤報が続くと通知が読まれなくなります。この問題は アラート疲れの原因と対策 で詳しく扱っています。

最後に、障害が出たあとの調査は人が行います。「注文数が半分になった」という通知だけでは、決済の失敗が増えたのか、特定の商品だけなのか、そもそもアクセスが減ったのかは分かりません。調べるための SQL を、その場で書くことになります。

DB の中身の監視を続けるには

小さく始めるなら、ODBC のアイテムを 2〜3 個だけ作り、注文数とジョブの滞留のように「止まったらすぐ困る数字」から見張るのが現実的です。閾値は 1〜2 週間の値を見てから決め、誤報が出たらそのたびに条件を見直します。Zabbix を使わない場合も、同じ SQL を cron で定期的に実行して結果をチャットに送るだけで、最低限の監視にはなります。業務データの監視全体の考え方は データベース監視とは にまとめています。

SQL や閾値を書く部分を AI に任せる方法もあります。Scandock は、接続文字列を登録すると AI がテーブルの構成と実データを読み、注文数や決済の成否、ジョブの滞留など何を監視するかと、取得と判定の間隔を決めます。固定の閾値ではなく、値の推移や過去の発火の結末を踏まえて異常かどうかを判断し、異常のときは読み取り専用のクエリで関連するデータを調べて、原因・影響・根拠・対処案をつけて通知します。監視と調査は読み取り専用のユーザーで行い、DB サーバーにエージェントを入れる必要はありません。

参考

関連する記事