使用 MCP Toolbox 的 postgres-long-running-transactions 工具监控 PostgreSQL 长事务
【免费下载链接】mcp-toolboxMCP Toolbox for Databases is an open source MCP server for databases.项目地址: https://gitcode.com/GitHub_Trending/ge/mcp-toolbox
本指南围绕 MCP Toolbox for Databases 中内置的postgres-long-running-transactions工具展开,讲解它如何通过扫描 PostgreSQL 系统视图pg_stat_activity定位超过指定阈值的长时间运行事务,并输出进程 ID、数据库、用户、事务时长、等待事件与 SQL 文本等完整诊断信息。读完本文,你将掌握该工具的参数用法、YAML 配置方式、返回字段含义与底层查询实现,能够在真实环境中快速发现事务泄漏、空闲事务阻塞与查询卡死等问题。
工具概述:用系统视图捕捉超时事务
postgres-long-running-transactions是 MCP Toolbox 为 PostgreSQL 生态提供的一个只读诊断工具,其核心职责是:报告运行时长超过配置阈值的数据库事务。它不执行任何写操作,只对 PostgreSQL 的系统目录视图pg_stat_activity执行一条只读查询,找出xact_start(事务开始时间)已设置且早于配置间隔的非空闲会话。
工具返回一个 JSON 数组,数组中每个元素对应一个匹配的会话,包含进程 ID、数据库与用户名、应用名、客户端地址、会话状态、多项年龄指标(连接时长、事务时长、查询时长、最后活动时长)、等待事件信息,以及该会话当前关联的 SQL 文本。这些字段组合起来,足以支撑一条完整的长事务排障链路:谁在跑、跑了多久、卡在什么事件上、正在执行什么语句。
在源码层面,该工具注册的资源类型常量为postgres-long-running-transactions,定义于 internal/tools/postgres/postgreslongrunningtransactions/postgreslongrunningtransactions.go,并通过tools.Register在包初始化时注册进工具注册表。
参数说明
工具提供两个可选参数,均不强制要求提供,未指定时使用默认值:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
min_duration | string | 否 | 5 minutes | 只显示运行时长达到该值的交易,采用 PostgreSQL interval 格式,例如'5 minutes'、'30 seconds'、'1 hour'。 |
limit | integer | 否 | 20 | 返回结果的最大条数。 |
这两个参数的默认值在工具初始化代码中有明确对应:min_duration通过parameters.NewStringParameter注册并设置字符串默认值"5 minutes",limit通过parameters.NewIntParameter注册并设置整数默认值20(见 postgreslongrunningtransactions.go)。
参数在运行期会被转换为 SQL 绑定参数:min_duration作为$1::INTERVAL传入,limit作为$2::int传入,二者均通过COALESCE与默认值结合,即使 Agent 不传参也能安全执行。
配置示例
最小工具配置
在 Toolbox 配置文件(YAML)中声明该工具,需要指定kind: tool、唯一的name、type: postgres-long-running-transactions以及指向某个已声明 source 的source字段:
kind: tool name: long_running_transactions type: postgres-long-running-transactions source: postgres-source description: "Identifies transactions open longer than a threshold and returns details including query text and durations."其中source必须指向一个兼容的 source 定义。以官方预置配置 internal/prebuiltconfigs/tools/postgres.yaml 为参照,一个可运行的 PostgreSQL source 示例如下:
kind: source name: postgresql-source type: postgres host: ${POSTGRES_HOST:localhost} port: ${POSTGRES_PORT:5432} database: ${POSTGRES_DATABASE} user: ${POSTGRES_USER} password: ${POSTGRES_PASSWORD}官方预置配置中已包含名为long_running_transactions的工具实例,类型为postgres-long-running-transactions,绑定postgresql-source,并将其编入名为monitor的 toolset(与list_active_queries、list_locks、list_query_stats等监控工具并列),方便一次性暴露整组运维能力。
使用环境变量注入敏感信息
Toolbox 支持在配置中使用${ENV_NAME}形式的环境变量替换,建议用此方式注入数据库密码等敏感信息,而不是明文写入配置文件。上述示例中${POSTGRES_PASSWORD}即采用这一机制;未设置时可用${VAR:default}语法提供回退默认值,例如${POSTGRES_HOST:localhost}。
兼容的 source 类型
该工具通过源码中的compatibleSource接口约束可绑定 source:只要实现PostgresPool() *pgxpool.Pool与RunSQL(context.Context, string, []any) (any, error)两个方法即可(见 postgreslongrunningtransactions.go)。当前仓库中满足该接口的 source 包括:
- PostgreSQL 原生 source(internal/sources/postgres/postgres.go)
- AlloyDB Omni / AlloyDB PostgreSQL(
alloydb-omni、alloydb-postgres预置配置中同样声明了该工具) - Cloud SQL for PostgreSQL(
cloud-sql-postgres预置配置)
它们共享 pgx 连接池与RunSQL查询通道,因此本工具可以在上述任一环境中直接复用。
返回结果字段说明
每个匹配会话对应 JSON 数组中的一个对象,字段如下:
| 字段 | 类型 | 是否可空 | 说明 |
|---|---|---|---|
pid | integer | 否 | 后端进程 ID(backend pid)。 |
datname | string | 否 | 数据库名。 |
usename | string | 否 | 数据库用户名。 |
appname | string | 是 | 客户端应用名,无应用名时为空。 |
client_addr | string | 是 | 客户端 IPv4/IPv6 地址,本地连接(如 Unix socket)可能为 null。 |
state | string | 否 | 会话状态,例如active、idle in transaction。 |
conn_age | string | 否 | 连接年龄:now() - backend_start,以 PostgreSQL interval 字符串序列化。 |
xact_age | string | 否 | 事务年龄:now() - xact_start,interval 字符串。 |
query_age | string | 否 | 当前运行查询的年龄:now() - query_start,interval 字符串。 |
last_activity_age | string | 否 | 距上次状态变更的时间:now() - state_change,interval 字符串。 |
wait_event_type | string | 是 | 后端正在等待的事件类型,无等待时为 null。 |
wait_event | string | 是 | 具体等待事件名,无等待时为 null。 |
query | string | 否 | 会话当前关联的 SQL 文本。 |
典型返回元素示例:
{ "pid": 12345, "datname": "my_database", "usename": "dbuser", "appname": "my_app", "client_addr": "10.0.0.5", "state": "idle in transaction", "conn_age": "00:12:34", "xact_age": "00:06:00", "query_age": "00:02:00", "last_activity_age": "00:01:30", "wait_event_type": null, "wait_event": null, "query": "UPDATE users SET last_seen = now() WHERE id = 42;" }解读要点:
xact_age是判断长事务的核心指标,它直接从xact_start计算而来,即事务真正开启后经过的时间,与query_age区分开——query_age只衡量当前这条查询的耗时,事务可能长时间处于idle in transaction状态(事务开着、语句早已执行完),此时xact_age远大于query_age;state = "idle in transaction"的会话是典型的隐患:事务未提交、锁未释放,会持续阻塞其他会话的写入,也是造成连接池耗尽和 WAL 膨胀的常见来源;wait_event_type/wait_event为 null 表示后端当前未在等待;非空时(如Lock类事件)可以快速定位死锁或锁等待;conn_age与last_activity_age分别帮助判断连接是否长期驻留、会话是否长时间无操作。
底层 SQL 实现
工具实际执行的 SQL 与文档一致,在源码中以longRunningTransactions常量形式存在(见 postgreslongrunningtransactions.go),完整语句如下:
SELECT pid, datname, usename, application_name as appname, client_addr, state, now() - backend_start as conn_age, now() - xact_start as xact_age, now() - query_start as query_age, now() - state_change as last_activity_age, wait_event_type, wait_event, query FROM pg_stat_activity WHERE state <> 'idle' AND (now() - xact_start) > COALESCE($1::INTERVAL, interval '5 minutes') AND xact_start IS NOT NULL AND pid <> pg_backend_pid() ORDER BY xact_age DESC LIMIT COALESCE($2::int, 20);逐条拆解该查询的设计意图:
WHERE state <> 'idle':排除完全空闲的会话,避免把大量休眠连接计入结果;(now() - xact_start) > COALESCE($1::INTERVAL, interval '5 minutes'):核心过滤条件,事务年龄超过阈值才命中;$1未提供时回落为5 minutes;xact_start IS NOT NULL:确保事务确实已开始(xact_start只在事务中才有值),防止对非事务会话计算无意义的年龄;pid <> pg_backend_pid():排除执行本查询自身的后端进程,避免工具把自己误报为长事务;ORDER BY xact_age DESC:按事务年龄降序,最老的事务排在最前,便于优先处理最危险的会话;LIMIT COALESCE($2::int, 20):限制返回条数,$2未提供时默认 20 条。
在调用链上,工具的Invoke方法把解析好的参数(parameters.GetParams提取、AsSlice转为有序参数切片)连同 SQL 一并交给 source 的RunSQL执行,由 pgx 连接池以参数化查询方式运行,返回的行被逐行归一化后组装成 JSON 数组(见 internal/sources/postgres/postgres.go)。由于全程使用绑定参数而非字符串拼接,SQL 文本天然具备注入防护。
调用行为与配置解析验证
从源码实现可以确认以下几点行为:
- 只读工具:工具注册时使用
tools.NewReadOnlyAnnotations作为默认注解(见 postgreslongrunningtransactions.go),声明该工具不会产生副作用,可安全暴露给只读场景; - 描述自动填充:若配置中未提供
description,工具会用默认描述补齐:Identifies and lists database transactions that exceed a specified time limit...; - 可配置认证:
Config结构体支持authRequired字段,可为工具绑定认证服务,YAML 解析测试覆盖了带与不带authRequired两种形态(见 postgreslongrunningtransactions_test.go); - source 兼容性校验:
ValidateSource会在启动阶段检查所绑定的 source 是否实现compatibleSource接口,不兼容时直接报错,避免运行期才发现配置错误。
常见问题与使用建议
- 为什么工具查不到我刚开启的事务?事务必须已经运行超过
min_duration阈值才会被报告;同时阈值计算基于xact_start,未真正开启事务(无BEGIN或没有在事务内的语句)的会话不会命中。 - 为什么有些会话
xact_age很大但query_age很小?这是idle in transaction的典型形态:事务仍保持打开(可能持有锁),但已无语句在执行。此时应优先处理这类会话,因为锁的持有通常比查询本身更危险。 - 如何调高告警粒度?将
min_duration调小(如30 seconds)可以发现更早期的事务,适合在压测或故障演练中观察事务增长速度;生产环境建议保持或调大默认的 5 分钟阈值,减少噪声。 - 与
postgres-list-active-queries的区别:postgres-list-active-queries只关注state = 'active'的正在执行查询,而本工具关注“事务”维度,覆盖包括idle in transaction在内的全部非空闲状态,两者配合可以完整刻画数据库当前的活动全貌。
延伸阅读
- PostgreSQL source 完整配置字段:参见 docs/en/integrations/postgres/source.md,其中包含
queryParams、queryExecMode、sqlCommenter、connectTimeout等扩展配置项; - PostgreSQL 工具全集索引:docs/en/integrations/postgres/tools/_index.md;
- 官方预置配置(含本工具与 monitor toolset):internal/prebuiltconfigs/tools/postgres.yaml;
- 工具实现源码与测试:internal/tools/postgres/postgreslongrunningtransactions/postgreslongrunningtransactions.go 与 postgreslongrunningtransactions_test.go。
通过将本工具接入 MCP Toolbox 的 monitor toolset,配合list_locks、list_active_queries等诊断工具,即可让 Agent 在运维对话中直接回答"当前是否有长事务、谁持有锁、卡在哪条语句"这类问题,把 PostgreSQL 长事务监控变成可编程、可自动化的能力。
【免费下载链接】mcp-toolboxMCP Toolbox for Databases is an open source MCP server for databases.项目地址: https://gitcode.com/GitHub_Trending/ge/mcp-toolbox
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考