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

前言

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


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

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

通过pg_stat_activity视图查询活动线程

sql 复制代码
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

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

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

查看数据库锁信息

sql 复制代码
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持有锁的情况。

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 秒。如果死锁检测超过该时间,将引发一个错误,并在日志中记录死锁信息。

四、手动关闭线程

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

sql 复制代码
SELECT pg_cancel_backend(<pid>);
-- 或
SELECT pg_terminate_backend(<pid>);

总结

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

相关推荐
IT_陈寒14 分钟前
SpringBoot自动配置没生效?你可能漏了这个注解
前端·人工智能·后端
长明19 分钟前
C#项目组织与概念梳理
后端·c#
xn713324 分钟前
个人网站站外分发怎么做归因?我给 XBSTACK 补了一套 UTM 追踪规则
后端·低代码
用户23307130747927 分钟前
JUC 并发容器与工具
后端
冰暮流星39 分钟前
flask之模版渲染
后端·python·flask
威武的花瓣1 小时前
细说ASP.NET的各种异步操作
后端·asp.net·php
漂亮的摩托1 小时前
如何编写一个SpringBoot项目告警推送的Starter
java·spring boot·后端
任性的芝麻1 小时前
ASP.NET MVC 中的异步方式
后端·asp.net·mvc
雨师@1 小时前
go语言项目--实例化(图书管理)--006
开发语言·后端·golang
kuro-shiro1 小时前
SpringBoot 启动流程
java·spring boot·后端