一次postgresql锁事件:找到有影响的进程pid并杀掉进程的3种方法

背景:某一个功能测试时发现执操作数据库某张表报错,具体报错信息记不住了。可以查到该数据库中该功能进程的事务信息,该事务操作被其他事务给阻塞了。

以杀掉锁表的进程为例

1) 查询待操作数据库表锁表的进程id

方法1.1)

select oid from pg_class where relname='可能锁表了的表';

select pid from pg_locks where relation='上面查出的oid';

方法1.2)

2) 死锁进程查看pg_stat_activity

方法2.1)

SELECT * FROM pg_stat_activity WHERE datname='数据库名称' and waiting=true;

方法2.2)

3) 杀掉锁表进程,在确认以上pid不影响系统的情况下

select pg_cancel_backend(上面查到的pid);

pg_stat_activity

pg_stat_activity是一个非常有用的视图,可以分析排查当前运行的SQL任务以及一些异常问题。pg_stat_activity 每行展示的是一个“process” 的相关信息,“process”可以理解为一个用户连接。

几个重要的字段:

datname 后端连接到的数据库的名称

procpid  后端的进程id(4.3版本)

pid  后端的进程id(6.0版本)

current_query当前正在执行的查询(4.3版本)

query 如果state为active,为当前正在执行的查询(6.0版本)

state 后端目前的状态包括 active、idle、idle in transaction、idle in transaction  (aborted)、fastpath function call、disabled (6.0版本)。active:后端正在执行一个查询。idle:后端正在等待一个新的客户端命令。idle in transaction:后端在一个事务中,但是当前没有正在执行一个查询。idle in transaction (aborted):与idle  in transaction相似,在该事务中的一个语句导致了一个错误。fastpath function call:后端正在执行一个fast-path函数。 disabled:如果后端中track_activities被禁用,则报告这个状态。

state_change 上次状态切换的时间点(6.0版本)

waiting True当前SQL在锁等待,否则false

waiting_reason 当前执行等待的原因,可能是等锁或者等待节点间数据的复制

client_addr 连接到后端的客户端的IP地址。如果这个域为空,表示客户端通过服务器机器上的一个 Unix 套接字连接或者这是一个内部进程。

client_port 客户端和后端通信的TCP端口号,如果使用 Unix 套接字则为-1

应用场景

1) 查看当前运行中的耗时较长的SQL语句

4.3 版本

select current_timestamp - query_start as  runtime, datname, usename, current_query

    from pg_stat_activity

    where current_query != ''

    order by 1 desc;

6.0 版本

select current_timestamp - query_start as  runtime, datname, usename, query

    from pg_stat_activity

    where state != 'idle'

    order by 1 desc;

2) 异常SQL诊断及修复

4.3 版本

SELECT datname,usename,current_query

  FROM pg_stat_activity

  WHERE waiting;

6.0 版本

SELECT datname,usename,query

  FROM pg_stat_activity

  WHERE waiting;

只能获取当前block的SQL,但找不到原因。相互block的SQL信息

SELECT

      w.current_query as waiting_query,

      w.procpid as w_pid,

      w.usename as w_user,

      l.current_query as locking_query,

      l.procpid as l_pid,

      l.usename as l_user,

      t.schemaname || '.' || t.relname as tablename

    from pg_stat_activity w

    join pg_locks l1 on w.procpid = l1.pid and not l1.granted

    join pg_locks l2 on l1.relation = l2.relation and l2.granted

    join pg_stat_activity l on  l2.pid = l.procpid

    join pg_stat_user_tables t on l1.relation = t.relid

    where w.waiting;

session是query,杀掉阻塞的进程id: SELECT pg_cancel_backend(pid);

session是idle,杀掉阻塞的进程id:SELECT pg_terminate_backend(pid);

pg_locks

pg_locks提供了数据库服务器上打开事务中保持的锁的信息。pg_locks是对每一个活动可锁对象、请求锁模式和相关事务的组合。如果多个事务持有或正在等待一个可锁对象上的锁,同一个可锁对象可能出现很多次。

有多种不同类型的可锁对象:整个关系(如表)、关系的单个页、关系的单个元组、事务ID(包括虚拟和永久ID)和普通数据库对象(由类OID和对象OID标识,和pg_description或pg_depend中的相同方式)。扩展一个关系的权力也被表示为一个独立的可锁对象。"咨询"锁可以具有用户定义的意义。

几个重要的字段:

locktype:可锁对象的类型: relation,  extend, page, tuple, transactionid, virtualxid, object, userlock, or advisory

relation:pg_class.oid 锁目标的关系的OID

pid :保持这个锁或者正在等待这个锁的服务器进程的PID

pg_class

pg_class记载表和几乎所有有字段或者是那些类似表的东西。 包括索引、序列、视图、物化视图、 复合类型和一些特殊关系类型。

几个重要字段:

oid:  行标识符(隐藏属性; 必须明确选择)

relname:表、索引、视图等的名字。

relfilenode:这个关系在磁盘上的文件的名字,0表示这是一个"映射的"关系, 它的文件名取决于行级别的状态。

relpersistence : p = permanent table(永久表), u = unlogged table(未加载的表), t = temporary table (临时表)

relkind :r = ordinary table(普通表) ,  i =  index(索引), S = sequence(序列),  v =  view(视图), m = materialized view (物化视图), c = composite type(复合类型), t =  TOAST table(TOAST 表), f = foreign table(外部表)

pg_cancel_backend和pg_terminate_backend

pg_cancel_backend() 取消后台操作,回滚未提交事物

pg_terminate_backend() 中断session,回滚未提交事物

pg_cancel_backend(pid)杀掉某条sql,是温柔的杀,向后台发送sigint信号,关闭当前后台进程,用户只能关闭自己的后台进程,事务回滚。

pg_terminate_backend(pid)杀掉某条sql,是强杀,向后台发送sigterm信号,关闭当前后台进程,需要有超级用户权限,超级用户可以关闭所有后台进程,事务回滚。

使用pg_cancel_backend杀不掉的进程,但是其实pg_terminate_backend有时也无法杀掉某条sql,笔者在生产环境遇到过,这时我们可能会抓一下该连接的堆栈,然后我们可能想尽快杀掉该sql,问题原因后面再分析,这时我们就要从操作系统层面使用kill命令来杀掉连接了。通过上面查到的pid,在操作系统上ps -ef |grep pid查看当前连接的状态,然后kill -9 pid杀掉该连接。

参考

PostgreSQL死锁进程及慢查询处理

PostgreSQL锁查询与杀掉进程说明

通过pg_stat_activity分析诊断正在执行的SQL

不同版本的pg_stat_activity

pg-locks

pg_cancel_backend和pg_terminate_backend

你可能感兴趣的:(一次postgresql锁事件:找到有影响的进程pid并杀掉进程的3种方法)