今天压力测试系统告警存在长事务 存在三个长事务。
会话ID:3221491694,事务ID:80186255,事务类型:unknown,事务创建时间:2025-04-15T11:14:01.953+08:00,事务最长持续时长:32 分 22.9 秒。这是三个简单的update语句,连续三个相似sql更新同一行数据,后通过kill会话处理
请问下出现这个问题的原因是什么呢,死锁吗,如果是死锁我该怎么排查呢 我看ocp页面上没有提示有死锁
根据文档库中的信息,以下是对您问题的详细解答:
1. 长事务的原因分析
根据文档片段 10 的描述,长事务是指事务开始后,执行时间超过 60 秒不提交的事务。在您的场景中,三个简单的 UPDATE
语句连续更新同一行数据,导致事务持续时长达到 32 分 22.9 秒,这符合长事务的定义。
可能原因:
- 行锁冲突:根据文档片段 3,当多个事务并发更新同一行数据时,可能会出现行锁冲突。如果前一个事务未提交或未释放锁,后续事务会等待,从而导致事务持续时间变长。
-
业务逻辑问题:如果这些
UPDATE
语句没有及时提交或回滚,可能导致事务长时间挂起。 - 热点行问题:文档片段 3 提到,热点行更新是关系型数据库的通用问题。如果频繁更新同一行数据,可能会引发锁冲突和性能瓶颈。
2. 是否为死锁?
从您的描述来看,OCP 页面上没有提示死锁,因此可以初步判断当前问题并非死锁引起。
死锁排查方法:
尽管当前不是死锁问题,但如果您怀疑存在死锁,可以通过以下步骤排查:
- 检查死锁检测功能是否开启:根据文档片段 4 和 5,OceanBase 社区版 OCP 暂不支持死锁检测功能。但您可以启用 OceanBase 数据库的分布式死锁自动检测功能(从 V3.2 版本开始支持)。
-
查询死锁历史视图:通过查询
DBA_OB_DEADLOCK_EVENT_HISTORY
或CDB_OB_DEADLOCK_EVENT_HISTORY
视图,获取过去发生的死锁事件及其相关信息。示例如下:obclient> SELECT * FROM oceanbase.DBA_OB_DEADLOCK_EVENT_HISTORY; obclient> SELECT * FROM oceanbase.CDB_OB_DEADLOCK_EVENT_HISTORY;
-
超时机制排查:根据文档片段 2,OceanBase 提供了锁超时机制 (
ob_trx_lock_timeout
)、语句超时机制 (ob_query_timeout
) 和事务超时机制 (ob_trx_timeout
) 来解决死锁问题。您可以检查这些参数的配置是否合理。
3. 解决方案
针对当前的长事务问题,建议采取以下措施:
(1) 优化业务逻辑
- 确保每个事务在完成操作后立即提交或回滚,避免事务长时间挂起。
- 如果需要连续更新同一行数据,考虑将多个
UPDATE
语句合并为一个事务,减少锁等待时间。
(2) 调整超时参数
根据文档片段 2,您可以调整以下参数以减少锁等待时间:
-
ob_trx_lock_timeout
:设置锁等待超时时间。 -
ob_query_timeout
:设置语句执行超时时间。 -
ob_trx_timeout
:设置事务执行超时时间。
(3) 使用 SELECT ... FOR UPDATE WAIT
优化锁等待
根据文档片段 3,您可以使用 SELECT ... FOR UPDATE WAIT
语法来控制锁等待时间。例如:
SELECT * FROM your_table WHERE id = ? FOR UPDATE WAIT 1;
上述语句会在等待 1 秒后超时,避免事务长时间挂起。
(4) 监控和告警
- 在 OCP 中监控长事务和悬挂事务的告警信息,及时发现并处理异常事务。
- 根据文档片段 10,OCP 中长事务的告警阈值为 30 秒,悬挂事务的告警阈值为 10 分钟。确保这些阈值符合您的业务需求。
4. 总结
当前问题更可能是由于行锁冲突或业务逻辑问题导致的长事务,而非死锁。建议优化业务逻辑、调整超时参数,并使用 SELECT ... FOR UPDATE WAIT
语法来减少锁等待时间。同时,加强监控和告警机制,及时发现并处理异常事务。
如果仍有疑问,可以联系 OceanBase 的人工答疑团队获取进一步支持。
更多信息请查看:
死锁是会话之间的相互锁是一个环,你这个应该说是出现了一个会话持有了行锁没有提交,导致后面的会话一直在重试,下次可以查询gv$ob_locks看下是否存在锁的争抢select
/+DYNAMIC_SAMPLING(1)/
concat(‘kill ‘,c.svr_ip,’ /’,c.svr_ip,’:2881/’) as kill_sid,
b.database_name,
b.table_name,
a.svr_ip,
case when block = 0 then ‘持有锁会话’ ELSE ‘等待锁会话’ END AS block,
c.id,
a.type,
a.trans_id,
a.id2,
a.lmode,
a.CTIME / 1000000 as CTIME,
c.info,
c.command,
c.time,
c.total_time,
c.user_client_ip,
c.retry_cnt,
c.retry_info,
c.thread_id,
c.trace_id
from
gv$ob_locks a,
cdb_ob_table_locations b,
gv$ob_processlist c
where
a.id1 = b.tablet_id
and a.tenant_id = b.tenant_id
and c.trans_id = a.trans_id
and b.tenant_id = 租户ID
and b.role = ‘LEADER’
and id2 is not null;