1. 理解PostgreSQL会话机制
PostgreSQL的会话(Session)是指客户端与数据库服务器建立的连接上下文环境。每个会话都包含独立的事务状态、临时表、会话变量等资源。当会话异常卡住或占用关键资源时,数据库管理员需要手动终止这些会话以释放系统资源。
会话与连接(Connection)在PostgreSQL中是紧密关联但不同的概念。连接是物理层面的TCP/IP链路,而会话是逻辑层面的工作环境。一个连接可以承载多个会话(通过SET SESSION AUTHORIZATION切换),但通常我们说的"会话"就是指单个连接的工作状态。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 识别需要终止的会话
2.1 查询活跃会话列表
要终止会话,首先需要定位目标会话的进程ID(PID)。PostgreSQL提供了pg_stat_activity系统视图来查看当前所有会话:
sql复制SELECT
pid,
usename,
application_name,
client_addr,
backend_start,
state,
query,
query_start
FROM pg_stat_activity
WHERE state = 'active';
关键字段说明:
pid:会话的进程ID,终止会话时需要此值usename:连接的用户名application_name:客户端应用名称state:会话状态(active/idle/idle in transaction等)query:正在执行的SQL语句query_start:查询开始时间
2.2 识别问题会话的特征
需要特别关注的异常会话包括:
- 执行时间过长的查询(通过
now() - query_start计算) - 处于"idle in transaction"状态的会话(可能持有锁)
- 占用大量CPU或I/O资源的会话(需结合系统监控)
- 来自异常客户端的连接(如非常见IP或应用名称)
3. 终止会话的多种方法
3.1 使用pg_terminate_backend函数
这是最常用的终止会话方法:
sql复制SELECT pg_terminate_backend(pid);
其中pid是要终止的会话进程ID。该函数会向目标后端进程发送SIGTERM信号,请求其优雅退出。
注意:如果会话正在执行关键操作(如事务提交),强制终止可能导致数据不一致。建议先尝试取消查询(见3.2节),仅在必要时使用终止。
3.2 使用pg_cancel_backend函数(更温和)
如果只是想取消正在执行的查询而不终止整个会话:
sql复制SELECT pg_cancel_backend(pid);
这会发送SIGINT信号,通常会导致当前查询中止但保持连接。适用于长时间运行的查询占用了资源但连接本身仍需保留的场景。
3.3 通过操作系统命令终止
在数据库服务器上,也可以直接使用操作系统命令终止PostgreSQL进程:
bash复制# 查找PostgreSQL进程
ps aux | grep postgres
# 发送TERM信号
kill -TERM <pid>
# 强制终止(不推荐)
kill -9 <pid>
警告:kill -9可能导致数据损坏,仅在其他方法无效时作为最后手段使用。
4. 会话终止后的影响与验证
4.1 终止操作的影响
终止会话会产生以下影响:
- 任何未提交的事务将回滚
- 临时表将被删除
- 会话级别的设置(如SET命令)将失效
- 客户端将收到连接中断错误
4.2 验证终止是否成功
执行终止操作后,应验证目标会话是否确实已消失:
sql复制SELECT pid FROM pg_stat_activity WHERE pid = <目标PID>;
如果查询无返回结果,说明会话已终止。也可以检查客户端应用是否收到断开连接的通知。
5. 高级场景与特殊处理
5.1 终止复制槽会话
复制槽会话有特殊处理要求。直接终止可能导致复制中断,应先检查复制状态:
sql复制SELECT * FROM pg_replication_slots;
如果确定需要终止,建议先删除复制槽:
sql复制SELECT pg_drop_replication_slot('slot_name');
然后再终止相关会话。
5.2 处理卡死的空闲事务
"idle in transaction"状态的会话可能持有锁阻塞其他操作。可以组合查询锁定情况:
sql复制SELECT blocked_locks.pid AS blocked_pid,
blocking_locks.pid AS blocking_pid,
blocked_activity.usename AS blocked_user,
blocking_activity.usename AS blocking_user,
blocked_activity.query AS blocked_statement,
blocking_activity.query AS blocking_statement
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.GRANTED;
5.3 批量终止会话
需要终止多个会话时,可以使用以下模式:
sql复制-- 终止所有非超级用户会话
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE usename != 'postgres';
-- 终止所有空闲时间超过1小时的会话
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND now() - state_change > interval '1 hour';
6. 预防性措施与最佳实践
6.1 配置连接超时
在postgresql.conf中设置:
code复制idle_in_transaction_session_timeout = '10min' # 自动终止空闲事务会话
statement_timeout = '30min' # 单条SQL执行超时
lock_timeout = '5min' # 获取锁等待超时
6.2 使用连接池管理
推荐使用PgBouncer或PgPool-II管理连接:
- 限制最大连接数
- 自动回收空闲连接
- 提供连接排队机制
6.3 监控与告警设置
配置监控系统关注以下指标:
- 活跃会话数
- 长时间运行查询
- 锁等待
- 连接池使用率
7. 常见问题排查
7.1 会话无法终止的可能原因
如果pg_terminate_backend()返回false或似乎无效,可能因为:
- 目标会话正在启动或关闭
- 会话是PostgreSQL系统进程(如checkpointer)
- 权限不足(需要超级用户或相同角色)
- 操作系统级别限制
7.2 终止会话后连接立即恢复
如果发现终止的会话立即重新连接,可能因为:
- 客户端配置了自动重连
- 连接池在维持最小连接数
- 恶意或异常客户端行为
解决方法:
- 在客户端或中间件调整配置
- 使用防火墙规则临时阻止问题IP
- 修改数据库密码(如果是认证问题)
7.3 终止会话导致的应用异常
应用可能遇到:
- 事务中断错误
- 连接池失效
- 序列化异常
建议应用实现:
- 适当的重试逻辑
- 连接健康检查
- 事务边界明确处理
在实际生产环境中终止会话前,最好先通知相关应用团队,或在低峰期操作。对于关键业务系统,建议先在测试环境验证影响。
