matrixorigin / matrixorigin/matrixone
lockservice: 长事务持锁无超时机制,孤儿事务可阻塞集群连接
- Dominant language
- Go
- Stars
- 1.9k
- Forks
- 311
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 768
Description
## Parent Issue
- matrixorigin/mocloud-services#2093
## 背景
prod freetier-01 出现一个事务持有行锁 3h+ 未释放(txn 未 commit/rollback),导致 112 个 waiter 排队,CN handshake 超时,集群连接不可用。
## 问题描述
当一个事务获取行级排他锁后,如果该事务既不 commit 也不 rollback(可能因为客户端断连但 session 未被清理),lockservice 没有机制自动释放该锁:
1. **无锁持有超时**:exclusive row lock 可以被无限期持有
2. **waiter 无限排队**:等待锁的事务没有超时自动放弃(只有 "wait too long" 告警日志)
3. **连带影响**:大量 goroutine 阻塞在 `remoteLockTable.lock` → CN 无法 accept 新连接 → proxy handshake timeout
## 复现路径(建议)
```sql
-- Session 1: 获取行锁但不 commit
BEGIN;
UPDATE some_table SET col=val WHERE pk=1;
-- 不执行 COMMIT,保持 session 打开
-- Session 2+: 尝试更新同一行
UPDATE some_table SET col=val2 WHERE pk=1;
-- 将无限期阻塞
```
更极端的复现:
1. Session 1 开启事务并获取锁
2. 客户端网络断连(但 CN 侧 session 未被清理)
3. 观察锁是否会被自动释放
## 期望行为
1. **事务超时**:长时间未活动的事务应被自动 abort(可配置,如 `max_txn_idle_time`)
2. **锁等待超时**:waiter 在超过阈值后应返回错误(如 `lock_wait_timeout`,类似 MySQL `innodb_lock_wait_timeout`)
3. **孤儿事务检测**:session 断连后应及时清理关联事务和锁
## 实际行为
- 事务持锁 3h+ 无任何超时机制
- 112 个 waiter 无限期阻塞
- 唯一的信号是 `lockservice/waiter_events.go:256` 的 WARN 日志,但不触发任何自动处理
## 环境信息
- MO 版本: prod freetier-01(具体版本待确认)
- 涉及代码:
- `pkg/lockservice/lock_table_local.go:166` (doLock → waiter.wait 无超时)
- `pkg/lockservice/waiter.go:220` (waiter.wait)
- `pkg/lockservice/waiter_events.go:256` (只打日志不处理)
## 相关日志
- Gist: https://gist.github.com/xzxiong/a0779bc61387616cfef8e1e459e72c44
- goroutine profile 显示 122 个 goroutine 阻塞在 `remoteLockTable.lock`(CN v9274)
- 5 个 goroutine 阻塞在 `localLockTable.doLock`(CN lzwmw,lock table owner)
Contributor guide
Assessment
This issue has not been assessed yet.