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

PostgreSQL之“ERROR: deadlock detected”

12972

1、什么是deadlock(死锁)?

你可能会在程序日志中,遇到过类似“ERROR: deadlock detected Detail: Process 1766 waits for ShareLock on transaction 11322; blocked by process 1788. Process 1788 waits for ShareLock on transaction 11321; blocked by process 1766” 这样的报错信息。

含义很明显,即发生了死锁。那么死锁是什么?

死锁是DBMS不能执行在特定时间点运行的所有并发事务的一种情况。

2、为什么会出现死锁?

服务器会尽力确保多个事务可以并发工作而不互相干扰,但是还是会出现互相干扰的情况。为了实现事务的特性,PG为数据库中的每个表和每一行都维护了锁,并且每次只会将锁授予第一个事务。之后出现的所有事务都不得不等待,直到第一个事务完成,并释放它所持有的锁。未没有获取锁的事务被挂起,无法继续执行。因为锁的这种机制,所以在数据库繁忙的场景,是极易发生死锁的。

3、举个死锁的例子?

发生死锁时,一个比较常见的现象就是两个事务互相等待,由于两者都在等待,没有人能取得进展。此时数据库要么无限期等待下去,要么选择终止其中一个,让另一个继续。

举一个死锁发生在行级锁(表级锁发生死锁的概率更大)的情况。

考虑两个并发事务修改一个表的情况。

第一个事务执行:

    UPDATE t_data SET data = data * 10 WHERE id = 1
    复制

    这个语句将获取id=1的行上的行级锁,注意这个时候第一个事务还未提交,然后第二个事务执行:

      UPDATE t_data SET data = data * 10 WHERE id = 2

      UPDATE t_data SET data = data * 10 WHERE id = 1
      复制

      第一个UPDATE语句成功地获取了id=2行上的行级锁,因此它成功地更新了该行。但是,第二个UPDATE语句发现它试图更新的行(id=1的行正在被事务1锁定)已经被锁定,所以它等待获得锁的事务完成。事务2现在等待事务1完成后再继续执行。现在,事务1继续执行:

        UPDATE t_data SET data = data * 10 WHERE id = 2
        复制

        事务1试图获取指定id=2行上的行级锁,此时它已经被事务2持有,因此它等待事务2完成。因此,事务1在事务2上阻塞,事务2在事务1上阻塞。两者互相等待,死锁发生。

        4、deadlock_timeout参数?

        前面我们说过在死锁发生后,数据库要么无限期等待下去(不可能允许这种情况发生),要么选择终止其中一个,让另一个继续。

        那么数据库会在什么时机去终止事务呢?这个就跟deadlock_time参数相关。

        此参数表示,在等待一个lock被释放的时间里,多久可以启动deadlock检查机制。

        死锁检测相对昂贵,因此服务器不会在每次等待锁时都运行这个它。我们乐观地假设在生产应用中死锁是不常出现的,并且只在开始检测死锁之前等待一会儿。增加这个值就减少了浪费在无用的死锁检测上的时间,但是减慢了报告真正死锁错误的速度。 在lock动作比较多的系统里,可以适当增大deadlock_timeout。

        5、怎么预防死锁或减少死锁?

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

        • 另外,想要预防死锁,一般我们要确保使用数据的所有应用程序,以一致的顺序获取多个对象上的锁。比如上面我们提到的死锁的例子,如果两个事务都以相同的顺序更新行,就不会出现互相等待的情况。

        • 同时程序里需要实现重试机制,通过重试来恢复因死锁而中止的事务操作。

        6、查询当前系统中所有活动的锁信息?

          postgres=> SELECT virtualtransaction, relation::regclass, locktype, page, tuple, mode, granted, transactionid
          FROM pg_locks
          ORDER BY granted, virtualtransaction;
          virtualtransaction | relation | locktype | page | tuple | mode | granted | transactionid
          --------------------+----------+------------+------+-------+-----------------+---------+---------------
          16/2062658 | pg_locks | relation | | | AccessShareLock | t |
          16/2062658 | | virtualxid | | | ExclusiveLock | t |
          (2 rows)
          复制

          关于pg中的locktype类型,

          可以参考:https://www.postgresql.org/docs/current/explicit-locking.html。

          参考:http://www.moioli.net/progetti/postgres-deadlocks-debugging-guidelines/

          https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-DEADLOCKS

          文章转载自PostgreSQL运维技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论