postgresql的死锁检测机制

死锁检测,是pg的一种自动检测机制,可以发现两个或者多个session之间对互斥资源的申请造成的死锁,并且可以随机将其中一个事务回滚掉,以解除死锁。

PG的死锁时间由deadlock_timeout参数控制,默认是1s,当发生死锁超时,会随机将一个事务回滚掉,同时记录到数据库日志中。


deadlock_timeout

死锁检测之前在一个锁上等待的总时间。

This is the amount of time to wait on a lock before checking to see if there is a deadlock condition.

deadlock_timeout设置为1s,也即意味着,锁出现的一秒后,系统才会触发死锁检测机制,如果检测到死锁。会随机将其中任一事务回滚掉。

这个值越大,锁触发死锁检测等待的时间越长。这个值一般要超过大多数事务执行的时间。

特殊情况下,如果我们想定位死锁问题,我们可以先调大这个值,让因死锁而“挂起“的会话,维持“挂起”状态的时间更长点,以便我们定位具体SQL。


当死锁发生后,你可能在服务器日志或者会话报错中看到如下形式的日志信息:

ERROR:  deadlock detected
DETAIL:  Process 18446 waits for ShareLock on transaction 976; blocked by process 18478.
Process 18478 waits for ShareLock on transaction 975; blocked by process 18446.
HINT:  See server log for query details.
CONTEXT:  while updating tuple (0,2) in relation "t_data"

从上图中的日志信息中可以看到服务器是产生了循环依赖的,Process 18446 waits for process 18478, Process 18478 waits for 18446,process 18446和process 18478都被挂起,无法向前推进。

当死锁发生后,我们可以从pg_stat_activity表中,获取当前挂起的会话中找到对应的client_addr、client_port,以及具体query等信息。

SELECT client_addr, client_port, query
FROM pg_stat_activity
WHERE state = 'active'
  AND wait_event_type = 'Lock'
ORDER BY state_change

postgresql的死锁检测机制_第1张图片

一般我们希望能找到最初挂起的会话,因此我们按state_change排序pg_stat_activity,因为其他会话稍后可能卡在最初导致死锁的会话后面。

扩展

pg_stat_activity视图中wait_event_type,这字段表示等待事件的类型。 wait_event_type的取值可为:LWLockNamed、LWLockTranche、Lock、BufferPin。其中Lock表示backend后台进程等待重量级的锁,通常是指 relation、tuple、page、transactionid 等子类型锁。

我们知道死锁会带来很多问题:产生死锁的会话无法继续推进,同时它占用的资源无法释放,时间长了之后可能会导致系统中出现更多的锁,进而导致服务雪崩。所以一般来说,我们是不希望在生产环境中发生死锁的。死锁的检测和解除,如上文所示可以通过设置合理的deadlock_timeout来解决。除此之外,我们使用一些预防策略,来防治死锁的产生。

死锁的预防

  1. 死锁只有在锁存在的情况下才会发生,所以缓解死锁的一个策略就是减少锁的使用,比如说避免大事务,尽量减少显式锁的使用,减小锁的粒度等。

  2. 一般我们要确保使用数据的所有应用程序,以一致的顺序获取多个对象上的锁,防止出现互相等待的情况。

另外,业务侧也需要实现重试机制,通过重试来恢复因死锁而中止的事务操作。

参考:

https://www.cybertec-postgresql.com/en/postgresql-understanding-deadlocks/ https://www.cybertec-postgresql.com/en/debugging-deadlocks-in-postgresql/

该篇已首发到公众号PostgreSQL运维技术,欢迎来踩~

悄悄放一张:

PostgreSQL运维技术 

 

 

你可能感兴趣的:(postgresql,数据库,postgresql)