如何实现检测到PostgreSQL阻塞时自动发送通知?
绝对有可行的方案!我来给你拆解几种实用的实现方式,从PostgreSQL原生的NOTIFY机制到更简单的外部定时脚本方案都有,你可以根据自己的运维习惯选:
方案一:用PostgreSQL原生NOTIFY + 定时函数实现实时检测
如果你想利用PostgreSQL本身的能力来触发告警,这个方案很合适。核心思路是写一个定时执行的函数,检查阻塞情况,一旦发现问题就通过NOTIFY发送消息,再用一个外部脚本监听这个消息并触发邮件/Slack通知。
第一步:创建检查阻塞的函数
把你现有的阻塞查询SQL嵌入到这个PL/pgSQL函数里,当检测到阻塞时发送通知:
CREATE OR REPLACE FUNCTION check_lock_blocking() RETURNS void AS $$ DECLARE blocking_records integer; BEGIN -- 替换成你自己的阻塞查询语句,这里用一个通用示例 SELECT COUNT(*) INTO blocking_records FROM pg_locks l JOIN pg_stat_activity a ON l.pid = a.pid WHERE l.granted = false AND a.wait_event_type = 'Lock'; IF blocking_records > 0 THEN -- 发送通知,带上具体的阻塞数量(也可以传更详细的信息) PERFORM pg_notify('lock_blocking_alert', '发现' || blocking_records || '起锁阻塞事件'); END IF; END; $$ LANGUAGE plpgsql;
第二步:设置定时执行
用PostgreSQL的pg_cron扩展(需要先安装启用)来每分钟执行一次这个检查函数:
-- 启用pg_cron扩展(首次使用时执行) CREATE EXTENSION IF NOT EXISTS pg_cron; -- 每分钟检查一次阻塞情况 SELECT cron.schedule('check-lock-blocking', '* * * * *', 'SELECT check_lock_blocking();');
第三步:写监听脚本接收通知并告警
用Python(或其他语言)写一个长运行的脚本,监听lock_blocking_alert频道,收到通知后就发送Slack/邮件:
import psycopg2 from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT import requests # 替换成你的PostgreSQL连接信息 conn = psycopg2.connect("dbname=你的数据库名 user=用户名 password=密码 host=数据库地址") conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT) cur = conn.cursor() # 监听通知频道 cur.execute("LISTEN lock_blocking_alert;") print("已启动锁阻塞告警监听...") while True: conn.poll() while conn.notifies: notify = conn.notifies.pop(0) print(f"收到告警: {notify.payload}") # 示例:发送Slack消息(替换成你的Webhook地址) slack_webhook = "https://hooks.slack.com/services/你的SlackWebhookID" requests.post(slack_webhook, json={"text": f"⚠️ PostgreSQL锁阻塞告警\n{notify.payload}"}) # 示例:发送邮件(需要配置SMTP信息) # import smtplib # from email.mime.text import MIMEText # msg = MIMEText(f"发现锁阻塞情况:{notify.payload}") # msg['Subject'] = 'PostgreSQL锁阻塞告警' # msg['From'] = 'alert@yourdomain.com' # msg['To'] = 'your@email.com' # with smtplib.SMTP('smtp.yourdomain.com', 587) as server: # server.starttls() # server.login('smtp用户名', 'smtp密码') # server.send_message(msg)
可以把这个脚本做成systemd服务,确保它后台持续运行,不会因为服务器重启而中断。
方案二:外部定时脚本直接查询+告警(更简单易维护)
如果不想折腾PostgreSQL的内部函数和监听机制,直接用系统定时任务(比如crontab)跑脚本查询阻塞情况,有结果就发通知,这个方案更直观。
第一步:写Shell查询脚本
创建check_postgres_blocking.sh脚本,嵌入你的阻塞查询:
#!/bin/bash # 替换成你的数据库连接信息 DB_NAME="你的数据库名" DB_USER="用户名" RESULT_FILE="/tmp/postgres_blocking_result.txt" # 执行阻塞查询并保存结果 psql -d $DB_NAME -U $DB_USER -c "SELECT pid, query, wait_event FROM pg_stat_activity WHERE wait_event_type = 'Lock' AND state = 'active';" > $RESULT_FILE # 统计结果行数(跳过SQL表头) ROW_COUNT=$(tail -n +2 $RESULT_FILE | wc -l) if [ $ROW_COUNT -gt 0 ]; then # 发送Slack通知(替换成你的Webhook) curl -X POST -H 'Content-type: application/json' \ --data '{"text":"⚠️ PostgreSQL锁阻塞告警\n```'"$(cat $RESULT_FILE)"'```"}' \ https://hooks.slack.com/services/你的SlackWebhookID # 或者发送邮件 # mail -s "PostgreSQL锁阻塞告警" your@email.com < $RESULT_FILE fi
第二步:设置定时任务
给脚本加执行权限,然后用crontab设置每分钟执行一次:
chmod +x check_postgres_blocking.sh crontab -e # 添加以下内容(替换成脚本的实际路径) * * * * * /path/to/check_postgres_blocking.sh
注意事项
- 不管用哪种方案,都要确保你的阻塞查询语句是高效的,避免查询本身给数据库带来额外压力
- 如果用pg_cron,要确认你的PostgreSQL版本支持(通常9.6+可用),并且已经在
postgresql.conf里启用了这个扩展 - 告警内容可以更详细,比如加上阻塞事务的ID、等待时长、涉及的表名等,方便快速定位问题
内容的提问来源于stack exchange,提问作者Johnny Metz




