暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

PostgreSQL大事务拦截保障系统稳定

原创 梧桐 2025-03-11
73

大事务是指影响数据库性能、存储、并发的事务,而不是单纯指 SQL 长语句,大事务拦截可根据实际需要,结合pg_stat_activity, pg_stat_statements等监控工具、合理设置超时、自动清理机制,防止或降低大事务对系统稳定性的影响。

以 PostgreSQL 17(CentOS 7.9)为例,上实现大事务拦截,有以下几种方法:

方案1:使用 pg_stat_activity + 触发 pg_terminate_backend

原理:定期监控正在执行的事务,发现大事务(如占用大量资源、运行时间过长)后终止它。

步骤

  1. 创建一个定时任务,定期扫描 pg_stat_activity 视图。

  2. 设定阈值,例如:

    • 事务执行时间超过N秒。

    • 事务占用 work_mem 或 temp_file 过大的话(可结合 pg_stat_statements)。

  3. 终止超过阈值的事务。

示例脚本(每分钟执行一次,终止运行超过 10 分钟的事务):

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND now() - query_start > interval '10 minutes' AND pid <> pg_backend_pid();
复制

使用cron 定时任务自动部署 :

*/1 * * * * postgres psql -d yourdb -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND now() - query_start > interval '10 minutes' AND pid <> pg_backend_pid();"
复制

方案2:使用 pg_stat_statements 监控资源消耗

pg_stat_statements 可用于检测高资源消耗的 SQL。

编辑 postgresql.conf ,启用 pg_stat_statements:

shared_preload_libraries = 'pg_stat_statements' pg_stat_statements.track = all pg_stat_statements.max = 10000
复制

重启PostgreSQL:

systemctl restart postgresql-17
复制

创建扩展:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
复制

查询高消耗 SQL

SELECT query, calls, total_time, rows, mean_exec_time FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
复制

可以结合 pg_terminate_backend 终止异常 SQL。

方案3:使用 statement_timeout 限制 SQL 运行时间

statement_timeout 设定单条 SQL 最大执行时间,超时自动终止。

修改 postgresql.conf(全局生效):

statement_timeout = ‘10min’

或对特定用户/会话生效:

ALTER ROLE someuser SET statement_timeout = '5min'; SET statement_timeout = '5min';
复制

方案4:使用 pg_wal 监控 WAL 大事务

PostgreSQL WAL 记录大事务,可结合 pg_stat_bgwriter、pg_stat_database 监测 WAL 写入速率。

监测 WAL 写入过快的数据库

SELECT datname, blks_written, buffers_alloc FROM pg_stat_database;
复制

当 blks_written 快速增长,可能是大事务。

拦截大事务: 配合 pg_terminate_backend 终止长时间占用 WAL 的事务:

SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'active' AND now() - xact_start > interval '10 minutes';
复制

方案5:使用 event trigger 拦截 BEGIN 事务

可以通过事件触发器(Event Trigger)防止特定事务执行。

步骤

  1. 启用pg_event_trigger:
CREATE FUNCTION block_large_transactions() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN IF (SELECT count(*) FROM pg_stat_activity WHERE state = 'active' AND now() - xact_start > interval '10 minutes') > 0 THEN RAISE EXCEPTION 'Transaction too large!'; END IF; END; $$;
复制
  1. 绑定到BEGIN事件:
CREATE EVENT TRIGGER prevent_large_tx ON ddl_command_start EXECUTE FUNCTION block_large_transactions();
复制

方案6:使用外部工具(pgbouncer / pg_kill)

  • pgbouncer:限制最大事务时长,超时自动断开连接。
  • pg_kill:第三方工具,可自动终止 PostgreSQL 长事务。

总结

  • 轻量级方案:statement_timeout(简单易用)
  • 自动化拦截:pg_stat_activity + pg_terminate_backend
  • SQL 级分析:pg_stat_statements
  • 防止大 WAL 事务:监控 pg_wal
  • DDL 级防护:event trigger

您可以根据不同场景,使用单独的方案或组合多个方案。

最后修改时间:2025-03-13 12:47:14
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

暂无图片
获得了230次点赞
暂无图片
内容获得68次评论
暂无图片
获得了594次收藏
TA的专栏
与PostgreSQL对话
收录100篇内容
目录
  • 方案1:使用 pg_stat_activity + 触发 pg_terminate_backend
  • 方案2:使用 pg_stat_statements 监控资源消耗
  • 方案3:使用 statement_timeout 限制 SQL 运行时间
  • 方案4:使用 pg_wal 监控 WAL 大事务
  • 方案5:使用 event trigger 拦截 BEGIN 事务
  • 方案6:使用外部工具(pgbouncer / pg_kill)