この記事は Mackerel プラグインアドベントカレンダー(全部CRE) の25日目です。
それでは25日目は mackerel-plugin-postgres
です。
mackerel-plugin-postgresはRDBMSでもMySQLと同じように広く使われているPostgreSQL専用プラグインです。
インストールと設定手順
PostgreSQLのプラグインはPostgreSQLの統計情報の内容を可視化してくれるプラグインです。
本プラグインはプラグイン集として提供しているパッケージの mackerel-agent-plugins
に含まれています。
インストール名は mackerel-plugin-postgres
です。
次にMackerelのプラグインはコマンドですので実行する事ができます。
※認証を設定している場合はオプションを利用して認証情報を入力しましょう
-- /usr/bin はPATHが通っているので省略出来ます # mackerel-plugin-postgres -user=postgres -password=hogehoge postgres.size.total_size 22330912.000000 1514040349 postgres.iotime.blk_read_time 0.000000 1514040349 postgres.iotime.blk_write_time 0.000000 1514040349 postgres.connections.active 1.000000 1514040349 postgres.connections.active_waiting 0.000000 1514040349 postgres.connections.idle 1.000000 1514040349 postgres.connections.idle_in_transaction 0.000000 1514040349 postgres.blocks.blks_read 2610.000000 1514040349 postgres.blocks.blks_hit 12600.000000 1514040349 postgres.rows.tup_returned 11340.000000 1514040349 postgres.rows.tup_fetched 11280.000000 1514040349 postgres.rows.tup_inserted 0.000000 1514040349 postgres.rows.tup_updated 0.000000 1514040349 postgres.rows.tup_deleted 0.000000 1514040349 postgres.deadlocks.deadlocks 0.000000 1514040349 postgres.tempfile.temp_bytes 0.000000 1514040349 postgres.commits.xact_commit 180.000000 1514040349 postgres.commits.xact_rollback 0.000000 1514040349
設定ファイルであるmackerel-agent.confは標準では /etc/mackerel-agent/mackerel-agent.conf
にインストールされます。
こちらに下記のとおり追記しましょう。
[plugin.metrics.postgres] command = "mackerel-plugin-postgres"
以上を行った上でmackerel-agentを再起動してください。
見れるメトリック
まずこれを見てくれるとこのあとの話はすっと理解できると思います。
各グラフ定義ごとに説明します。
それでは各グラフ定義ごとに説明します。
また表に出てくるdiffとはプラグイン上で差分値計算をするかどうかです。
◯
となっている項目はプラグインで前回の実行時の値と差分値計算して出力しています。
Postgres Connections
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Active | postgres.connections.active | ー | 現在の接続でActive状態の数 |
Active waiting | postgres.connections.active_waiting | ー | 現在の接続でActive waiting状態の数 |
Idle | postgres.connections.idle | ー | 現在の接続でIdle状態の数 |
Idle in transaction | postgres.connections.idle_in_transaction | ー | 現在の接続でIdle in transaction状態の数 |
fast-path function call | postgres.connections.idle_in_transaction | ー | 現在の接続でfast-path function call状態の数 |
Disabled | postgres.connections.disabled | ー | 現在の接続でDisabled状態の数 |
接続の状態ですがこれは統計情報の pg_stat_activity
を見ています。
状態の種類ですが公式ドキュメントには次の通り書いてあります。
引用元:28.2. 統計情報コレクタ
現在のバックエンドの総体的な状態です。 以下のいずれかの値を取ることができます。 - active: バックエンドは問い合わせを実行中です。 - idle: バックエンドは新しいクライアントからのコマンドを待機しています。 - idle in transaction: バックエンドはトランザクションの内部にいますが、現在実行中の問い合わせがありません。 - idle in transaction (aborted): この状態はidle in transactionと似ていますが、トランザクション内のある文がエラーになっている点が異なります。 - fastpath function call: バックエンドは近道関数を実行中です。 - disabled: この状態は、このバックエンドでtrack_activitiesが無効である場合に報告されます。
Active、idle、idle in transactionについては皆さんの想像の通りですし、ここに書いてあるとおりです。 idle in transaction (aborted)は他のRDBMSから来た人にはわかりにくいかもしれません。 PostgreSQLのトランザクションは実行時にエラーが発生するとabortedになり、その後のクエリを受け付けません。 この状態になるとロールバックするしかありません。 abortedは勿論クエリエラーでもなりますがデッドロックが発生した場合はabortedになります(コネクションはPostgreSQL側からは切られない) そのためデッドロックによってクエリが止まっている場合などもここが増えるので覚えておきましょう。 このようにidle in transaction (aborted)はとても大事な指標ですが通常時は0を目指しましょう。
fastpath function callは知らない人からすると意味不明だと思います。
近道関数はPQFnという関数で近道インターフェイスを利用する関数を指します。
基本的にPQFnは公式ドキュメントにもある通り、なかなか使われません。
ではどこで使われているのでしょうか?一般的に目にする機会があるのはラージオブジェクトを利用するときでしょう。
ラージオブジェクトとは他のデータベースではBlob(Binary large object)と呼ばれるモノと同等で大きなデータを扱う仕組みのです。
これにより、画像や動画のような大きなデータでもPostgreSQLに保存することが出来ます。
ちなみに9.3以上では4TBまで保存することが出来るので概ね保存できます。
なおラージオブジェクトは pg_largeobject
に保存されるので興味がある人はそちらもどうぞ。
少し脱線しましたがラージオブジェクトインターフェイスはPQFnを呼び出しています。
そのためラージオブジェクトを使っている仕組みの場合はfastpath function callを意識する必要があります。
逆にそれ以外の時は特に気にしなくても良いでしょう。
https://www.postgresql.jp/document/9.6/html/libpq-fastpath.html
disabledは track_activities
が無効化されている場合のみ出てきます。
track_activities デフォルトは有効になっているのでお目にかかることは無いかもしれません。
Postgres Commits
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Xact Commit | postgres.commits.xact_commit | ◯ | 1分間あたりのデータベースでコミットされたトランザクション数 |
Xact Rollback | postgres.commits.xact_rollback | ◯ | 1分間あたりのデータベースでコミットされたロールバック数 |
これは pg_stat_database
の値を使っています。
データベースの総数なのですがロールバックが多い場合などは要注意しましょう。
アプリケーション側のエラーまたはデッドロックの可能性があります。
デッドロックの場合は後述の Postgres Dead Locks
を見てみて、切り分けしましょう。
特にリリース直後やUPDATEが多い仕組みでの繁忙期などは要注意です。
ロールバックが増える要因の一つに制約にぶつかりまくるというのもあります。
これは制約が守ってくれているので正しい挙動ではありますがアプリケーション側は制約にぶつからない事が本来正しい振る舞いです。
普段はロールバックは0になるように調整しましょう。
Postgres Blocks
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Blocks Read | postgres.blocks.blks_read | ◯ | 1分間あたりのDiskから読み出したブロック数 |
Blocks Hit | postgres.blocks.blks_hit | ◯ | 1分間あたりのキャッシュから読み出したブロック数 |
これは pg_stat_database
の値を使っています。
公式ドキュメントにある通り、blks_hitはOSでのfilesystemのキャッシュは含まれません。
blks_hit : バッファキャッシュに既にあることが分かっているために読み取りが不要だったディスクブロック数です(これにはPostgreSQLのバッファキャッシュにおけるヒットのみが含まれ、オペレーティングシステムのファイルシステムキャッシュは含まれません)。
PostgreSQLのアーキテクチャは良くも悪くもOSの振る舞いには関与しません。 そのため、PostgreSQL がディスクアクセスをしていると思っていてもOS側のキャッシュで返している事があります。 ここはアーキテクチャとして大切なところなので覚えておきましょう。
Postgres Rows
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Returned Rows | postgres.rows.tup_returned | ◯ | 1分間あたりのデータベース内の問い合わせで返された行数 |
Fetched Rows | postgres.rows.tup_fetched | ◯ | 1分間あたりのデータベース内の問い合わせで取り出された行数 |
Inserted Rows | postgres.rows.tup_inserted | ◯ | 1分間あたりのデータベース内の問い合わせで挿入された行数 |
Updated Rows | postgres.rows.tup_updated | ◯ | 1分間あたりのデータベース内の問い合わせで更新された行数 |
Deleted Rows | postgres.rows.tup_deleted | ◯ | 1分間あたりのデータベース内の問い合わせで削除された行数 |
実行されたSQLに対する行数です。
Returned Rows
と Fetched Rows
違いの分からない人もいると思います。
ここは公式ドキュメントも説明が不親切です。
いやまぁ公式ドキュメントは基本的に不親切なんだけど。
ざっくりいうと次のとおりです。
- Returned Rows : 表スキャンでの読み取り行数
- Fetched Rows : インデックススキャンでの読み取り行数
その他はそれぞれ見たまま通り、INSERT/UPDATE/DELETE をされた行数です。
これらは定期的に確認しましょう。
リリース直後に想定通り振る舞っているかどうかを確認するときにも良い指標になります。
テーブルスキャンが疑われるようならその次は pg_stat_user_tables
を見ましょう。
Postgres Data Size
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Total Size | postgres.size.total_size | ー | データベースのトータルサイズ(バイト) |
こちらはシンプルにデータベースで使用されるディスク容量の合計値が見れます。
ただしこれはmackerel-plugin-postgresを実行しているユーザがアクセスできるデータベースのトータルサイズです。
postgresユーザのように全てアクセスできるユーザなら全てのデータベースのトータルサイズですし、一部しかアクセスできないユーザならそのアクセス出来るデータベースの合計になります。
ここは意図しない振る舞いになっていることあると思いますから実行しているユーザで一度 select datname from pg_database where has_database_privilege(datname, 'connect')
を実行して確認しておきましょう。
個人的には別に積上げにしてデータベース名毎のサイズ出してもいいかもなって思っているところです。
またTipsですがpg_size_pretty()を使うとバイトをKBやGBなど人間に優しい表示に変換することができます。 SQLで確認する時は知っておくと便利です。
Postgres Dead Locks
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Deadlocks | postgres.deadlocks.deadlocks | ◯ | 1分間あたりの検知したデッドロックの数 |
その名の通り、デッドロックの数です。Postgres Commits
と併せて確認すると良いでしょう。
通常時は0になるように目指しましょう。
またデッドロックを調査する時は pg_stat_activity
の wait_event
と wait_event_type
を見ると良いでしょう。
その他にも pg_locks
には現状のロックの一覧があります。
下記のクエリをご活用ください。
-- ロック待ちとなっている処理内容と対象のテーブルを確認する -- 表示の関係でqueryを6文字で切っています SELECT l.locktype, c.relname, l.pid, l.mode, substring(a.current_query, 1, 6) AS query, (current_timestamp - xact_start)::interval(3) AS duration FROM pg_locks l LEFT OUTER JOIN pg_stat_activity a ON l.pid = a. procpid LEFT OUTER JOIN pg_class c ON l.relation = c.oid WHERE NOT l.granted ORDER BY l.pid;
Postgres Block I/O time
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Block Read Time (ms) | postgres.iotime.blk_read_time | ◯ | 1分間あたりのデータファイルブロックの読み取り時間(ms) |
Block Write Time (ms) | postgres.iotime.blk_write_time | ◯ | 1分間あたりのデータファイルブロックの書き出し時間(ms) |
こちらはI/Oに関する値です。
回数と併せて時間軸で見るのはとても大切です。
Postgres Blocks
と見比べながら活用しましょう。
Postgres Temporary file
メトリック名(ラベル) | プラグインの出力名 | diff | 説明 |
---|---|---|---|
Temporary file size (byte) | postgres.tempfile.temp_bytes | ◯ | 1分間あたりの検知された一時ファイルのサイズ |
こちらはその名の通り、一時ファイルを作った時のそのサイズです。
pg_stat_database
の temp_files
で個数を見ることが出来るのですがこちらはmackerel-plugin-postgresには含まれていません。
プルリクチャンスポイントの一つです。
また一時ファイルが作られるタイミングですが以下のようなものがあります。
- GROUP BY や ORDER BY やメモリ内で処理できなかった時
- JOINの際にメモリ内で処理できなかった時
- サブクエリなどでクエリの中身を処理する必要があり、それがメモリ内で処理できなかった時
代表的な例を上げましたが、つまりは PostgreSQLがめちゃめちゃ遅くなる時 に一時ファイルは出来ます。
特にORDER BYなどは実行してみないとメモリに乗るかどうかオプティマイザ側では判断出来ませんし、データの肥大化である日突然遅くなる要因の一つです。
メモリをコップだとしたらデータは中身に入れる水です。
コップの中で水を処理できるうちは問題ないのですが溢れるとこぼれ落ち、一時ファイルを必要とします。
そのためついさっきまではめちゃめちゃ早かったのに急に遅くなった時は Postgres Temporary file
を疑ってみてください。
詳細が見たい場合は log_temp_files
を指定することでログとして細かい情報を残すことができます。
調査の時にご活用ください。
PostgreSQLのモニタリングの勘所
前回まとめたので是非呼んで欲しいです。
mackerel-plugin-postgresでやってないこととして、キャッシュヒット率の計算やテーブル単位での集計などがあります。 つまりMackerelのプルリクチャンスです!! 僕もチャレンジしたいと思っています。 それとMackerelのプラグインで扱っていないレプリケーションの監視についても纏めました。
こちらも併せてご愛顧いただければと思います。
それでは25日目はPostgreSQLのプラグインについての説明でした。
なんとか無事走りきることができたMackerel プラグイン アドベントカレンダーですが皆様如何でしたでしょうか?
今回紹介したMackerelのプラグインやモニタリングの知見はほんの一部です。
引き続き、Mackerel User Groupやイベント、そしてMackerel自身を通じて色んなモニタリングの知見を共有していきたいですね。
今度は皆さんの作ったカスタムプラグインを使ったモニタリングの知見のアウトプット、お待ちしています!
それでは皆様、良いお年を。