-
Notifications
You must be signed in to change notification settings - Fork 0
[GRAFANA] PostgreSQL Slow Query Monitoring dengan Grafana
Panduan instalasi monitoring PostgreSQL Slow Query menggunakan:
- PostgreSQL 15.17
pg_stat_statements-
postgres_exporterv0.20.1 - Prometheus
- Grafana
Target database:
pramuka_gamification_db_prod
┌─────────────────────────────────────┐
│ PostgreSQL Server │
│ │
│ PostgreSQL 15.17 │
│ pramuka_gamification_db_prod │
│ pg_stat_statements │
│ │
│ postgres_exporter :9187 │
└──────────────────┬──────────────────┘
│
│ HTTP :9187
│
▼
┌─────────────────────────────────────┐
│ Monitoring Server │
│ │
│ Prometheus :9090 │
│ │ │
│ ▼ │
│ Grafana :3000 │
└─────────────────────────────────────┘
PostgreSQL Server:
10.130.249.232
Versi:
PostgreSQL 15.17
Ubuntu 22.04
Config:
/etc/postgresql/15/main/postgresql.conf
Data directory:
/var/lib/postgresql/15/main
Cek:
SHOW shared_preload_libraries;Jika kosong, edit:
sudo nano /etc/postgresql/15/main/postgresql.confSet:
shared_preload_libraries = 'pg_stat_statements'Jika sudah ada library lain:
shared_preload_libraries = 'library_lain,pg_stat_statements'Restart:
sudo systemctl restart postgresqlCek:
sudo systemctl status postgresql --no-pagerVerifikasi:
sudo -u postgres psqlSHOW shared_preload_libraries;Harus terdapat:
pg_stat_statements
Masuk ke database:
\c pramuka_gamification_db_prodBuat extension:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;Verifikasi:
SELECT extname, extversion
FROM pg_extension
WHERE extname = 'pg_stat_statements';Test:
SELECT count(*)
FROM pg_stat_statements;Masuk sebagai administrator:
sudo -u postgres psqlBuat user:
CREATE USER postgres_exporter
WITH PASSWORD 'PASSWORD_KUAT';Berikan role monitoring:
GRANT pg_monitor TO postgres_exporter;Beri akses database:
GRANT CONNECT
ON DATABASE pramuka_gamification_db_prod
TO postgres_exporter;psql \
-h 127.0.0.1 \
-U postgres_exporter \
-d pramuka_gamification_db_prodTest:
SELECT current_user, current_database();Test akses:
SELECT count(*)
FROM pg_stat_statements;Jika berhasil, user exporter sudah bisa membaca statistik PostgreSQL.
Versi:
v0.20.1
Cek architecture:
uname -mUntuk x86_64:
cd /tmp
wget https://github.com/prometheus-community/postgres_exporter/releases/download/v0.20.1/postgres_exporter-0.20.1.linux-amd64.tar.gz
tar -xzf postgres_exporter-0.20.1.linux-amd64.tar.gzCopy binary:
sudo cp \
postgres_exporter-0.20.1.linux-amd64/postgres_exporter \
/usr/local/bin/postgres_exporterPermission:
sudo chown root:root /usr/local/bin/postgres_exporter
sudo chmod 755 /usr/local/bin/postgres_exporterCek:
/usr/local/bin/postgres_exporter --versionExpected:
postgres_exporter, version 0.20.1
sudo useradd \
--system \
--no-create-home \
--shell /usr/sbin/nologin \
postgres_exporterCek:
id postgres_exporterBuat directory:
sudo mkdir -p /etc/postgres_exporterBuat file:
sudo nano /etc/postgres_exporter/postgres_exporter.envIsi:
DATA_SOURCE_NAME=postgresql://postgres_exporter:PASSWORD_KAMU@127.0.0.1:5432/pramuka_gamification_db_prod?sslmode=disableJika password memiliki karakter khusus seperti:
@
#
/
:
%
password harus di-URL-encode karena digunakan dalam connection URL.
Amankan:
sudo chown root:postgres_exporter \
/etc/postgres_exporter/postgres_exporter.env
sudo chmod 640 \
/etc/postgres_exporter/postgres_exporter.envBuat:
sudo nano /etc/systemd/system/postgres_exporter.serviceIsi:
[Unit]
Description=Prometheus PostgreSQL Exporter
Wants=network-online.target
After=network-online.target postgresql.service
[Service]
Type=simple
User=postgres_exporter
Group=postgres_exporter
EnvironmentFile=/etc/postgres_exporter/postgres_exporter.env
ExecStart=/usr/local/bin/postgres_exporter \
--web.listen-address=0.0.0.0:9187 \
--collector.stat_statements
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
[Install]
WantedBy=multi-user.targetReload:
sudo systemctl daemon-reloadEnable:
sudo systemctl enable postgres_exporterStart:
sudo systemctl start postgres_exportersudo systemctl status postgres_exporter --no-pagerJika gagal:
sudo journalctl \
-u postgres_exporter \
-n 100 \
--no-pagercurl -s http://127.0.0.1:9187/metricsTest PostgreSQL:
curl -s http://10.130.249.232:9187/metrics \
| grep '^pg_up'Expected:
pg_up 1
curl -s http://10.130.249.232:9187/metrics \
| grep -i 'stat_statements' \
| head -30Cari:
pg_scrape_collector_success{collector="stat_statements"} 1
Metric yang tersedia pada setup ini:
pg_stat_statements_block_read_seconds_total
pg_stat_statements_block_write_seconds_total
pg_stat_statements_calls_total
pg_stat_statements_rows_total
pg_stat_statements_seconds_total
Dari server Prometheus:
curl -s http://10.130.249.232:9187/metrics \
| grep '^pg_up'Expected:
pg_up 1
Port exporter:
9187/TCP
Jangan expose port 9187 ke public internet.
Idealnya:
Prometheus VM
│
│ TCP 9187
▼
PostgreSQL VM
Contoh UFW:
sudo ufw allow from IP_PROMETHEUS to any port 9187 proto tcpCek:
sudo ufw statusCari config:
sudo find /etc/prometheus \
-type f \
\( -name '*.yml' -o -name '*.yaml' \)Biasanya:
/etc/prometheus/prometheus.yml
Backup:
sudo cp \
/etc/prometheus/prometheus.yml \
/etc/prometheus/prometheus.yml.bakEdit:
sudo nano /etc/prometheus/prometheus.ymlTambahkan:
- job_name: 'postgres-gamification'
static_configs:
- targets:
- '10.130.249.232:9187'
labels:
service: 'postgresql'
database: 'pramuka_gamification_db_prod'
environment: 'production'Contoh:
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets:
- 'localhost:9090'
- job_name: 'postgres-gamification'
static_configs:
- targets:
- '10.130.249.232:9187'
labels:
service: 'postgresql'
database: 'pramuka_gamification_db_prod'
environment: 'production'promtool check config /etc/prometheus/prometheus.ymlExpected:
SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax
Reload:
sudo systemctl reload prometheusJika reload tidak tersedia:
sudo systemctl restart prometheusBuka:
http://IP_PROMETHEUS:9090/targets
Cari:
postgres-gamification
Status harus:
UP
Test PromQL:
up{job="postgres-gamification"}
Expected:
1
Query calls:
pg_stat_statements_calls_total{
job="postgres-gamification"
}
Execution time:
pg_stat_statements_seconds_total{
job="postgres-gamification"
}
Rows:
pg_stat_statements_rows_total{
job="postgres-gamification"
}
Block read:
pg_stat_statements_block_read_seconds_total{
job="postgres-gamification"
}
Block write:
pg_stat_statements_block_write_seconds_total{
job="postgres-gamification"
}
Datasource:
grafana-postgresql-datasource-gamification
UID:
afxsibohenv9ce
Database:
pramuka_gamification_db_prod
Host:
10.130.249.232:5432
User:
postgres_exporter
Dashboard menggunakan dua datasource:
Prometheus
│
├── Query Calls/sec
├── Execution Time/sec
├── Rows/sec
├── Block Read
├── Block Write
└── PostgreSQL UP
PostgreSQL
│
├── Top Slow Queries
├── Top Total Execution Time
└── Most Executed Queries
Datasource:
PostgreSQL
Query:
SELECT
queryid,
calls,
ROUND(mean_exec_time::numeric, 2) AS avg_ms,
ROUND(max_exec_time::numeric, 2) AS max_ms,
ROUND(total_exec_time::numeric, 2) AS total_ms,
rows,
query
FROM pg_stat_statements
WHERE dbid = (
SELECT oid
FROM pg_database
WHERE datname = 'pramuka_gamification_db_prod'
)
AND calls > 0
ORDER BY mean_exec_time DESC
LIMIT 20;SELECT
queryid,
calls,
ROUND(mean_exec_time::numeric, 2) AS avg_ms,
ROUND(max_exec_time::numeric, 2) AS max_ms,
ROUND(total_exec_time::numeric, 2) AS total_ms,
rows,
query
FROM pg_stat_statements
WHERE dbid = (
SELECT oid
FROM pg_database
WHERE datname = 'pramuka_gamification_db_prod'
)
AND calls > 0
ORDER BY total_exec_time DESC
LIMIT 20;SELECT
queryid,
calls,
ROUND(mean_exec_time::numeric, 2) AS avg_ms,
ROUND(total_exec_time::numeric, 2) AS total_ms,
rows,
query
FROM pg_stat_statements
WHERE dbid = (
SELECT oid
FROM pg_database
WHERE datname = 'pramuka_gamification_db_prod'
)
ORDER BY calls DESC
LIMIT 20;sum(
rate(
pg_stat_statements_calls_total{
job="postgres-gamification",
datname="pramuka_gamification_db_prod"
}[5m]
)
)
sum(
rate(
pg_stat_statements_seconds_total{
job="postgres-gamification",
datname="pramuka_gamification_db_prod"
}[5m]
)
)
sum(
rate(
pg_stat_statements_rows_total{
job="postgres-gamification",
datname="pramuka_gamification_db_prod"
}[5m]
)
)
sum(
rate(
pg_stat_statements_block_read_seconds_total{
job="postgres-gamification",
datname="pramuka_gamification_db_prod"
}[5m]
)
)
sum(
rate(
pg_stat_statements_block_write_seconds_total{
job="postgres-gamification",
datname="pramuka_gamification_db_prod"
}[5m]
)
)
up{
job="postgres-gamification"
}
PostgreSQL - Gamification Slow Query
│
├── PostgreSQL Status
├── Query Calls / sec
├── Execution Time / sec
├── Rows / sec
│
├── Query Calls / Second
├── Query Execution Time / Second
│
├── Block Read Time / Second
├── Block Write Time / Second
│
├── Top 20 Slow Queries
│
├── Top 20 Queries
│ └── Total Execution Time
│
└── Top 20 Most Executed Queries
Saat analisis awal, query berikut menjadi query paling berat:
Query ID:
-9113787273790285623
Statistik:
Calls : 358
Average : 1903.90 ms
Total : 681597.59 ms
Percentage : 66.32%
Query melakukan aggregation:
WITH aggregated AS (
SELECT
anggota_id,
SUM(total_point) AS total_point,
MAX(updated_at) AS updated_at
FROM gamification_leaderboard
WHERE deleted_at IS NULL
GROUP BY anggota_id
)Tabel:
gamification_leaderboard
Statistik tabel saat analisis:
Live rows : 953,802
Dead rows : 99,441
Total : 601 MB
Table : 108 MB
Indexes : 493 MB
Query ini menjadi kandidat utama untuk optimasi selanjutnya.
Lihat statistik:
SELECT
queryid,
calls,
mean_exec_time,
total_exec_time,
query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;Reset statistik:
SELECT pg_stat_statements_reset();Hati-hati: reset akan menghapus statistik yang sedang dikumpulkan. Sebaiknya reset hanya ketika diperlukan, misalnya setelah optimasi query dan ingin membuat baseline baru.
sudo systemctl status postgres_exporterLog:
sudo journalctl \
-u postgres_exporter \
-n 100 \
--no-pagercurl -s http://127.0.0.1:9187/metrics \
| grep '^pg_up'Expected:
pg_up 1
curl -s http://127.0.0.1:9187/metrics \
| grep 'stat_statements'Cari:
pg_scrape_collector_success{collector="stat_statements"} 1
Dari Prometheus server:
curl -s http://10.130.249.232:9187/metrics \
| grep '^pg_up'Expected:
pg_up 1
sudo ss -lntp | grep 9187Expected:
0.0.0.0:9187
[✓] PostgreSQL 15.17
[✓] pg_stat_statements enabled
[✓] Extension pg_stat_statements
[✓] User postgres_exporter
[✓] GRANT pg_monitor
[✓] postgres_exporter v0.20.1
[✓] Exporter :9187
[✓] pg_up = 1
[✓] stat_statements collector = 1
[✓] Monitoring VM bisa akses :9187
[✓] Prometheus scrape target
[✓] Prometheus target UP
[✓] pg_stat_statements metrics masuk Prometheus
[✓] PostgreSQL datasource Grafana
[✓] Grafana dashboard
PRODUCTION
┌────────────────────────────────────────────┐
│ PostgreSQL Server │
│ 10.130.249.232 │
│ │
│ PostgreSQL 15.17 │
│ │ │
│ ├── pramuka_gamification_db_prod │
│ │ │
│ └── pg_stat_statements │
│ │ │
│ ▼ │
│ postgres_exporter │
│ │ │
│ :9187 │
└────────────────────┼───────────────────────┘
│
│ metrics
▼
┌────────────────────────────────────────────┐
│ MONITORING VM │
│ │
│ Prometheus │
│ │ │
│ ▼ │
│ Grafana │
│ │
│ PostgreSQL Slow Query Dashboard │
└────────────────────────────────────────────┘