You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何实现检测到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

火山引擎 最新活动