数据库卡死,不要再重启了


前言

说实话数据库卡死,还是比较少见的,我工作六七年也只遇到过两三次。上周就遇到一次,而且上周发生的十分的频繁。可能适合数据库有很大关系,因为我们搞了国产化,用了人大金仓的数据库。今天就讨论一下面临数据库卡死的时候,如何查到问题所在。(ps:本篇文章只是提一个一种排查的思路)


一、查看数据库线程活跃状态

数据库卡死是,先不要重启,我们可以通过查看数据库线程状态,来确定那个线程出现了问题,从而手动关闭线程,把风险降到最低(下面sql用postgre sql)。

通过pg_stat_activity视图查询活动线程

SELECT pid,client_addr,state,query,wait_event,wait_event_type,query_start,state_change FROM pg_stat_activity

当然pg_stat_activity还有很多其他字段,你可以select *,上面列举的是一些关键字段,以下是一些常见的状态值的解释:

  1. pid:会话ID、进程ID。
  2. usename:连接数据库的用户名。
  3. query:正在执行的查询语句。
  4. state:会话状态,active,表示正在执行或正在等待完成;idle,表示处于空闲的状态
  5. wait_event_type:正在等待的事件类型(如果有),如IO、锁等。
  6. wait_event:正在等待的具体事件(如果有)。
  7. query_start:查询开始时间
  8. state_change:状态修改时间

通过这些关键的字段可以查看当前数据库目前在执行的sql,通过state字段可以找到当前正在执行的sql,通过query_start、state_change粗略估计sql执行时间。找到对应会话的pid

二、查看数据库持有锁情况

数据库卡死是,除了通过查看数据库线程状态,来确定那个线程出现了问题,还可以观察数据库目前持有锁的情况,来定位是不是锁没有被释放。

查看数据库锁信息

SELECT * FROM pg_locks;

在 PostgreSQL 的 pg_locks 视图中,以下是常见字段的含义:

  1. locktype:表示锁的类型。常见的锁类型包括 relation(表级锁)、page(页级锁)、tuple(行级锁)等。

  2. database:表示所属的数据库的 OID(对象标识符)。

  3. relation:表示被锁定对象(如表、索引)的 OID。

  4. page:表示被锁定页的位置。如果锁定的是表级锁或行级锁,则该字段为 null。

  5. tuple:表示被锁定行的位置。如果锁定的是表级锁或页级锁,则该字段为 null。

  6. virtualxid:表示虚拟事务 ID。在锁定的是事务级别锁时,该字段表示锁定的事务。

  7. transactionid:表示锁定的事务的 ID。如果锁定的是事务级别锁,则该字段包含事务的 ID。对于其他类型的锁,该字段为 null。

  8. classid:表示锁定的对象的类 ID。对于关系型锁(relation),该字段表示关联的目录(catalog)的 OID。对于其他类型的锁,该字段可能有不同的含义。

  9. objid:表示锁定的对象的 ID。对于关系型锁(relation),该字段表示关联的对象(如表、索引)的 OID。对于其他类型的锁,该字段可能有不同的含义。

  10. objsubid:表示锁定对象的子标识符。对于某些类型的锁,如行级锁,该字段表示被锁定行的位置。

  11. pid:表示持有锁的进程 ID。

  12. mode:表示锁定的模式(如共享锁、独占锁等)。

  13. granted:表示锁是否已被授予。

这些字段提供了关于锁的类型、锁定对象、持有锁的事务或进程等信息。通过查询 pg_locks 视图,并解释这些字段的值,可以获得有关当前数据库中锁的详细信息。

三、查看是否发生死锁

通过查看数据库线程活跃状态,以及线程持有的锁情况可以去初步判断是否是某一个sql执行过长,或者存在长时间持有锁的情况。通过上面两个步骤可以看到两个视图都存在pid,我们也可以通过pid进行关联查询,分析sql持有锁的情况。

SELECT
    p.pid,
    query,
    locktype,
    mode
FROM
    pg_stat_activity p
JOIN
    pg_locks l ON p.pid = l.pid
WHERE
    l.granted = FALSE;

上述查询将返回所有当前存在的会话和锁的信息,其中 pg_locks.granted = FALSE 表示未获得的锁。这样,你可以检查是否有会话在等待锁并导致死锁的情况。

如果查询结果中存在循环等待的锁(即互相等待对方释放锁的情况),则表示发生了死锁。

另外,你还可以使用 PostgreSQL 提供的 pg_deadlock_timeout 参数来设置死锁检测的超时时间。默认情况下,该参数值为 1 秒。如果死锁检测超过该时间,将引发一个错误,并在日志中记录死锁信息。

四、手动关闭线程

如果能确认时某个线程导致数据库卡死,我们就可以手动关闭该线程。

SELECT pg_cancel_backend(<pid>);
-- 或
SELECT pg_terminate_backend(<pid>);

总结

本篇文章主要分析了pg_stat_activitypg_locks的字段含义,以及在排查数据库问题时的应用场景。在面临数据卡死的场景时候,可以查询这两个视图分析问题,而不是直接重启。

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不务专业的程序员--阿飞

兄弟们能否给口饭吃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值