write conflict vs commited 错误

今天遇到一个错误,在事务写的的时候(乐观锁,事务中包含2个put动作),第一次发生了resolve lock错误: [There was a write conflict or resolve lock error: Failed to resolve lock],乐观锁冲突的时候很正常,那我就重试嘛,然后第二次碰到了这个错误:

[There was a problem when accessing the underlying store: KeyError { locked: None, retryable: "", abort: "Error(Txn(Error(Mvcc(Error(Committed{ start_ts: TimeStamp(461847508362986035), commit_ts: TimeStamp(461847508362986058), key: [116, 0, 0, 0, 15, 95, 114, 1, 53, 55, 97, 98, 102, 55, 56, 97, 255, 45, 100, 50, 99, 48, 45, 52, 55, 255, 57, 54, 45, 97, 50, 55, 54, 45, 255, 52, 52, 98, 102, 49, 97, 53, 50, 255, 99, 100, 50, 102, 46, 53, 52, 53, 255, 56, 54, 55, 52, 46, 49, 46, 114, 255, 103, 119, 46, 109, 97, 105, 110, 0, 254, 1, 49, 54, 52, 51, 0, 0, 0, 0, 251] })))))", conflict: None, already_exist: None, deadlock: None, commit_ts_expired: None, txn_not_found: None, commit_ts_too_large: None, assertion_failed: None, primary_mismatch: None }]

Committed这个错误我是第一次见,之前都是resolve lock error 和 write conflict错误,不太能理解committed错误到底是什么意思,和write conflict (start_ts < committed_ts) 相比,committed代表了什么呢?

可能要检查一下 存储完整性,看看是否之前出现服务器掉电或者存储异常,这个问题不是常规逻辑问题,可能是 mvcc 版本一致性问题,最好通过对应的 region 检查一下 table 的状态,可以通过 admin check table 检查 table 数据完整性等问题。

我看了一下admin check table,这个命令似乎是检查主表和其索引的一致性(index条目数量以及对应列的值是否正确),我的问题可能与此无关,我补充下我们的问题场景:我们没有用tidb,而是直接用的tikv_client,向tikv写入kv对,使用了tikv_client 提供的事务接口(不是raw),如tx.set, tx.commit等,上层也没有实现索引相关的东西。另外我想问一下,committed错误报错的场景是什么?是哪一步检查没能通过导致了该问题?

你补充的真好 :+1: 我就说没有遇见过类似问题,可以把这个标签增加一个 TiKV 或者 Raw TiKV 模式了。

Slack @米波五兄弟 来这里看看有没有 TiKV 的社区专家可以帮助到你

1 个赞

感谢,我需要 tikv-wg 的工作区管理员邀请才能登陆这个网站,如果可以的话,请邀请下这个email:ytypy9348@gmail.com

有请大佬登场~~

再次补充:
我们尝试通过tikv_rust_client进行一个乐观事务请求(包含一个删除和一个更新)

  1. 第一次请求发生resolve_lock error
  2. 第二次重试发生committed错误,并且在tikv日志中我们也发现了这个错误的日志!日志如下:

[2025/10/30 07:16:31.509 +00:00] [ERROR] [errors.rs:487] [“txn aborts”] [err_code=KV:Storage:Committed] [err=“Error(Txn(Error(Mvcc(Error(Committed { start_ts: TimeStamp(461847508362986035), commit_ts: TimeStamp(461847508362986058), key: [116, 0, 0, 0, 15, 95, 114, 1, 53, 55, 97, 98, 102, 55, 56, 97, 255, 45, 100, 50, 99, 48, 45, 52, 55, 255, 57, 54, 45, 97, 50, 55, 54, 45, 255, 52, 52, 98, 102, 49, 97, 53, 50, 255, 99, 100, 50, 102, 46, 53, 52, 53, 255, 56, 54, 55, 52, 46, 49, 46, 114, 255, 103, 119, 46, 109, 97, 105, 110, 0, 254, 1, 49, 54, 52, 51, 0, 0, 0, 0, 251] })))))”] [thread_id=7]
按理来说committed错误表示这个事务已经提交了?也就是说此时这个事务实际上应该执行成功了?但是后续我们发现,需要删除的数据依然存在,但是更新命令似乎生效了?

我现在有点怀疑是客户端侧的代码我们写的可能有些问题,比如在tikv反错后(timeout,grpc error, connection refused等等),我们主动执行了rollback命令,按理来说,乐观锁似乎并不需要额外的rollback操作?
但是在rollback tikv_rust_client实现中,除了没有任何mutation的场景,哪怕是乐观锁,依然会发送new_batch_rollback_request命令。
我的问题是,async write 乐观锁在tikv反错后,是否需要rollback操作?

提交写一致

不能强一致,对数据都不安全

要保证数据的强一致

检查一下完整性

事务一致性?

ACID。永久性

两者均属于乐观锁机制下的并发冲突,核心解决方式都是重试事务,通过新的 start_ts 避开冲突窗口

Committed错误是指你重试的事务,其start_ts(事务启动时间戳)早于某个已提交事务的 commit_ts,且两者修改了同一 key—— 相当于你的事务启动后,目标 key 已被其他事务成功提交修改,此时重试的事务因数据已被覆盖,无法再提交