pgsentinel 用来保存活动会话历史,也就是 ASH(Active Session History)。它按周期采样 pg_stat_activity,把活跃会话保存到共享内存中。问题发生后,即使会话已经结束,也可以在缓冲区中回看一段时间内的现场。支持版本
PostgreSQL 版本 | 最早支持版本 | 插件版本 |
PostgreSQL 18 | v18.6_r1.15 | pgsentinel 1.4.1 |
说明:
本文适用于云数据库 PostgreSQL 18集成版本。
插件简介
pg_stat_activity 只能看当前时刻。很多线上问题持续时间很短,等 DBA 登录时,现场已经没有了。pgsentinel 解决的是这类问题。它可以记录:采样时间;
会话 PID、用户、数据库、应用名;
会话状态和等待事件;
当前 SQL 和顶层 SQL;
阻塞者数量、阻塞者 PID、阻塞者状态;
长事务、空闲事务相关信息。
典型用途:
回看某个时间点哪些会话在运行;
排查锁等待和阻塞链;
抓取偶发慢 SQL 的真实参数;
分析存储过程内部实际执行的 SQL;
给
pg_profile 提供 ASH 数据。环境准备
配置预加载
pgsentinel 需要共享内存和后台进程,必须预加载。建议同时加载 pg_stat_statements。shared_preload_libraries = 'pg_stat_statements,pgsentinel'track_activity_query_size = 2048pg_stat_statements.track = allpgsentinel.db_name = 'postgres'pgsentinel_ash.sampling_period = 1pgsentinel_ash.max_entries = 1000pgsentinel_ash.track_idle_trans = offpgsentinel_pgssh.enable = offpgsentinel_pgssh.max_entries = 10000
说明:
pgsentinel.db_name 必须是已经存在的数据库。后台进程会连接这个库。修改后重启数据库:
pg_ctl -D $PGDATA restart
创建扩展
pgsentinel 需要管理员创建:CREATE EXTENSION pg_stat_statements;CREATE EXTENSION pgsentinel;
可以指定 schema:
CREATE SCHEMA ash;CREATE EXTENSION pgsentinel SCHEMA ash;
授权
GRANT pg_monitor TO monitor_user;
普通用户没有
pg_monitor 时,只能看到自己的会话历史。常用查询
检查后台进程
SELECT pid, backend_type, application_name, datnameFROM pg_stat_activityWHERE backend_type = 'pgsentinel'OR application_name = 'pgsentinel';
如果没有结果,先检查
shared_preload_libraries 和 pgsentinel.db_name。回看最近活动会话
SELECT ash_time, pid, usename, datname, application_name, state,coalesce(wait_event_type, 'ON CPU') AS wait_type,wait_event, substring(query, 1, 80) AS queryFROM pg_active_session_historyWHERE ash_time > now() - interval '10 minutes'ORDER BY ash_time DESC, pidLIMIT 50;
wait_event_type 为空时表示当时没有等待事件。查看等待分布
SELECT coalesce(wait_event_type, 'ON CPU') AS wait_type,coalesce(wait_event, 'ON CPU') AS wait_event,count(*) AS samplesFROM pg_active_session_historyWHERE ash_time > now() - interval '30 minutes'GROUP BY 1, 2ORDER BY samples DESCLIMIT 15;
因为采样周期固定,
samples 可以近似理解为活跃秒数。查看阻塞链
SELECT ash_time,pid AS blocked_pid,usename AS blocked_user,wait_event_type, wait_event,blockers, blockerpid, blocker_state,substring(query, 1, 80) AS blocked_queryFROM pg_active_session_historyWHERE blockers > 0AND ash_time > now() - interval '1 hour'ORDER BY ash_time DESCLIMIT 30;
查看阻塞次数最多的进程:
SELECT blockerpid, blocker_state,count(*) AS times_blocking,count(DISTINCT pid) AS victimsFROM pg_active_session_historyWHERE blockers > 0GROUP BY 1, 2ORDER BY times_blocking DESCLIMIT 10;
查看活跃时间最多的 SQL
SELECT queryid, cmdtype, count(*) AS active_samples,count(DISTINCT pid) AS sessions,substring(min(query), 1, 80) AS sample_queryFROM pg_active_session_historyWHERE ash_time > now() - interval '30 minutes'AND queryid IS NOT NULL AND queryid <> 0GROUP BY queryid, cmdtypeORDER BY active_samples DESCLIMIT 15;
查看存储过程内部 SQL
SELECT substring(top_level_query, 1, 80) AS top_sql,substring(query, 1, 80) AS inner_sql,cmdtype, count(*) AS samplesFROM pg_active_session_historyWHERE top_level_query IS DISTINCT FROM queryAND ash_time > now() - interval '30 minutes'GROUP BY 1, 2, 3ORDER BY samples DESCLIMIT 20;
查看 SQL 统计历史
需要先开启:
pgsentinel_pgssh.enable = on
该参数需要重启。
查询:
SELECT ash_time, queryid, calls, total_exec_time, rows, wal_bytesFROM pg_stat_statements_historyORDER BY ash_time DESCLIMIT 20;
说明:
pg_stat_statements_history 保存的是 pg_stat_statements 的核心字段快照,不是完整字段快照。函数和视图
对象 | 说明 |
pg_active_session_history() | 返回 ASH 环形缓冲区中的记录 |
pg_active_session_history | ASH 视图 |
pg_stat_statements_history() | 返回 SQL 统计历史 |
pg_stat_statements_history | SQL 统计历史视图 |
get_parsedinfo(int) | 查看指定 PID 当前解析出的语句,传 -1 表示所有进程 |
参数说明
参数 | 默认值 | 生效方式 | 说明 |
pgsentinel.db_name | postgres | 重启 | 后台进程连接的数据库 |
pgsentinel_ash.sampling_period | 1 | reload | ASH 采样周期,单位秒 |
pgsentinel_ash.max_entries | 1000 | 重启 | ASH 环形缓冲区条数 |
pgsentinel_ash.track_idle_trans | off | reload | 是否记录 idle in transaction |
pgsentinel_pgssh.enable | off | 重启 | 是否采集 SQL 统计历史 |
pgsentinel_pgssh.max_entries | 10000 | 重启 | SQL 统计历史缓冲条数 |
track_activity_query_size 会影响 SQL 文本长度,也会影响共享内存占用。调大前要估算内存。常见问题
Q1:创建扩展为什么报权限错误?
A:
pgsentinel 需要管理员创建。Q2:视图为什么一直为空?
A:先确认后台进程存在,再确认有活跃会话。空闲数据库没有 ASH 记录是正常的。还要检查
pgsentinel.db_name 指向的数据库是否存在。Q3:为什么只能回看很短时间?
A:ASH 存在环形缓冲区中。可回看时长约等于
max_entries / 平均活跃会话数。可以增大 pgsentinel_ash.max_entries,但会占用更多共享内存并需要重启。Q4:数据库重启后历史为什么没了?
A:这是预期行为。ASH 在共享内存中。需要长期保留时,用
pg_profile 定期采样落盘。Q5:看不到
idle in transaction 怎么办?A:需要开启参数 pgsentinel_ash.track_idle_trans,设置该参数的值为 on,设置后 reload 配置即可开始记录这类会话,之后就可以看到
idle in transaction 了。Q6:普通用户为什么看不到别人的 SQL?
A:这是权限隔离。需要全量视角时授予
pg_monitor。卸载
DROP EXTENSION pgsentinel;
然后从
shared_preload_libraries 中移除 pgsentinel 并重启数据库。卸载或重启后,共享内存中的 ASH 和 SQL 统计历史会丢失。