跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

按场景排查

从症状走到证据,再确认结果。

照场景走之前,先确认连的是目标实例。示例来自测试集群上的故障注入脚本,不需要在生产环境复现。

1 - 找到长时间运行的 SQL

找到跑了一阵的语句,看它在等什么。

采集于 2026-09-27(UTC+08),本地 KingbaseES V008R006C009B0014 主节点,数据库 test。工具是 Go 版源码提交 93bf65d 编译的 ~/kbdiag(linux/amd64 静态二进制)。这是测试环境实测,不代表生产环境验收。PID、计数和时间只属于本次采样。故障注入脚本启动了 select pg_sleep(3600);,一条只睡觉的语句。它测的是能不能发现,不模拟 CPU 或磁盘压力。

kbdiag 2.0 还没有慢 SQL 阈值:长语句会被列出并排序,但本身不报 WARN。它开着事务太久(txn)或让别人等锁(locks)时,才会变成 finding。

1. 现在在跑什么?

~/kbdiag sessions
echo EXIT_CODE=$?
sessions  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:49+08:00)

connected: 4 client sessions (not counting kbdiag), 1 walsender, 7 background
  count  user    database  application            client
  2      esrep   esrep     internal_rwcmgr        192.168.105.10
  1      esrep   esrep     internal_rwcmgr        192.168.105.11
  1      system  test      kbdiag_inj_long_query  local

not idle: 1
  pid      user    database  application            client  state   xact  query  wait             sql
  1049328  system  test      kbdiag_inj_long_query  local   active  13s   13s    Timeout:PgSleep  select pg_sleep(3600);
EXIT_CODE=0
  • connected 按用户、库、应用、客户端给客户端会话计数;walsender 和后台进程只计数(--all 才列出)。
  • not idle 列出在干活或开着事务的会话,事务最久的在前。1049328 在跑 select pg_sleep(3600);,已经 13 秒。query 是当前语句跑了多久,wait 是它在等什么。
  • sql 列截到 60 个字符;session <pid> 显示完整文本。

2. 它在等什么?

~/kbdiag session 1049328
echo EXIT_CODE=$?
session  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:50+08:00)

session 1049328
  user         system
  database     test
  application  kbdiag_inj_long_query
  client       local
  type         client backend
  state        active  (for 14s)
  xact         14s
  query        14s
  wait         Timeout:PgSleep
  xid / xmin   - / 6353

sql
  select pg_sleep(3600);

waiting for: 0

blocking: 0

holds: 0
EXIT_CODE=0

Timeout:PgSleep 说明它是故意在睡。它没在等谁,也没挡住谁,也没有值得列出的锁(每个事务自己的 virtualxid 锁不列)。换成真实语句,你会看到 IO(在读数据)、Lock(在等别的会话),或者没有等待事件(在用 CPU)。

3. 是一条还是一堆?

~/kbdiag waits
echo EXIT_CODE=$?
waits  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:51+08:00)

not idle: 1
  wait             state   sessions  pids
  Timeout:PgSleep  active  1         1049328

not shown: 3 idle, 8 background
EXIT_CODE=0

waits 把在干活的会话按等待事件和状态分组。只有一个 Timeout:PgSleep 会话,说明是单条语句,不是扎堆;idle 的会话和空闲的后台进程只计数。几十个会话等同一个事件时,那个事件就是要查的方向。

4. 决定

这里的睡眠是故意的,没什么可调。真实语句要和应用负责人一起看它的执行计划和涉及的数据。kbdiag 不会取消语句;你决定取消时,在 ksql 里用 select pg_cancel_backend(<pid>);。注入的会话随后被释放,复查时已经没有了。

继续排查锁等待

2 - 排查锁等待

找到谁在等,顺着 verify 行找到挡路者,做决定,再确认等待消失。

采集于 2026-09-27(UTC+08),本地 KingbaseES V008R006C009B0014 主节点,数据库 test。工具是 Go 版源码提交 93bf65d 编译的 ~/kbdiag(linux/amd64 静态二进制)。这是测试环境实测,不代表生产环境验收。PID、计数和时间只属于本次采样。故障注入脚本开了一个事务,对测试表加 ACCESS EXCLUSIVE 锁后停着不动;另一个会话去读这张表。

1. 谁在等?

~/kbdiag locks
echo EXIT_CODE=$?
locks  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:33+08:00)

[WARN] lock.waiting  session 1048829 has waited 13s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1048819
  verify: kbdiag session 1048819  # what the blocking session is doing

blockers: 1
  pid      blocks  holds
  1048819  1       public.kbdiag_inj_lock AccessExclusiveLock

waiting: 1
  pid      object                  wants            waited  blocked by
  1048829  public.kbdiag_inj_lock  AccessShareLock  13s     1048819
EXIT_CODE=1
  • 会话 1048829 等 public.kbdiag_inj_lock 的 AccessShareLock 已经 13 秒,直接挡路者是 1048819。等超过 10 秒报 WARN(用 --lock-wait-warn 调整)。
  • blockers 排在前面,因为第一个问题是谁挡的:1048819 挡住了 1 个会话,持有这张表的 AccessExclusiveLock。一个挡路者挡住几十个会话时,它就是第一行。
  • waiting 逐个列出等锁的会话,等得最久的在前。时长从等待者最后一次状态变化算起,可能略微多报,不会少报。

2. 挡路者在干什么?

照 verify 行跑:

~/kbdiag session 1048819
echo EXIT_CODE=$?
session  WARN  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:34+08:00)

[WARN] lock.waiting  session 1048829 has waited 14s for AccessShareLock on public.kbdiag_inj_lock, blocked by 1048819

session 1048819
  user         system
  database     test
  application  kbdiag_inj_lock_holder
  client       local
  type         client backend
  state        idle in transaction  (for 14s)
  xact         14s
  query        14s
  wait         -
  xid / xmin   6351 / -

last sql
  lock table kbdiag_inj_lock in access exclusive mode;

waiting for: 0

blocking: 1
  pid      object                  wants            waited
  1048829  public.kbdiag_inj_lock  AccessShareLock  14s

holds: 1
  object                  mode
  public.kbdiag_inj_lock  AccessExclusiveLock
EXIT_CODE=1
  • 挡路者是 idle in transaction:最后一条语句是 lock table kbdiag_inj_lock in access exclusive mode;,已经在等客户端 14 秒,事务还开着。它什么都没在跑,锁一直占着只是因为没人提交或回滚。
  • blocking 是它挡住了谁,holds 是对方想要的那把锁。
  • 如果 waiting for 不为空,说明挡路者自己也在等:对它的挡路者再跑 session,直到找到一个没在等的。kbdiag 一次只显示一跳。
  • 如果挡路者显示为 2PC,挡路的是一个没有会话的两阶段事务;到主库跑 kbdiag txn 找它。

3. 决定并处理

kbdiag 不会结束会话。先和应用负责人确认这个事务是干什么的。通常应该由应用提交或回滚;应用做不到时,再自己断开连接,比如在 ksql 里执行 select pg_terminate_backend(1048819);,执行前确认这个 PID 仍然属于同一个用户和应用。断开挡路者会回滚它的事务。

这次测试里,注入脚本释放了持锁会话,事务随之结束。

4. 确认

~/kbdiag locks
echo EXIT_CODE=$?
locks  OK  (KingbaseES V008R006C009B0014, primary, system@local, 2026-09-27T13:36:36+08:00)

waiting: 0
EXIT_CODE=0

没有等待,OK,退出码 0。一次干净的采样只说明现在没有等待;如果反复出现,要去找应用里把事务开着不关的那段逻辑。

回到排查场景 · locks 手册