悲观事务模式下出现大量的write conflict

【TiDB 版本】v4.0.8
【问题描述】新上线一个业务:在使用500 并发写入的时候tidb.log 出现大量的write conflict .部分日志如下


冲突的表结构如下:

根据官方文档中分析:应该是并发插入的时候唯一键冲突
有以下几个疑问:


1.在autocommit 模式下优先采用乐观锁。
是否是在第一次遇到冲突的时候就立即返回write conflict 写入到tidb.log 中?
后续重试的逻辑是先backoff ,然后继续尝试加锁 ?

2.如果遇到write conflict ,反应在监控指标上主要是哪几个 ?应该如何解读 ?
我的理解是应该是wirte conflict 那个,但是实际上监控的这个指标值很小。

3.在发生冲突比较严重的时候为何duration 比transaction duraiton 高很多,具体是如何计算的 ?


4.在使用dm 的时候下游tidb 中也会遇到大量的write conflict ? 这个该如何调整 ?
我的理解是在上游mysql中是正常写入的顺序,在dm 中消费的时候只是进行了并发执行,不知为何会出现这么多冲突

5.在排查写入性能时,发现一个指标有些疑惑。下图中的commit 对应的是写入流程图的哪个阶段?
是否有其他更具体的指标能定位出来 ?


更新 ----
1.对于写入冲突的状态,业务侧进行了改造后,写入耗时降低很多。
但是其他监控指标相关的问题希望能给一些具体的指导。

可以先看一下这个:http://andremouche.github.io/tidb/transaction_in_tidb.html

对于整体的读取流程和写入流程已经阅读过相关文档。现在就是有些 监控指标对不上。

疑问点比较多,我这里尝试回答下:

  • autocommit 隐式事务

    write conflict 出现的原因是因为在 2PC 事务提交的过程中 ,Prewrite 时发现数据有新的提交 (commit_ts > txn.start_ts)。

    autocommit 模式下确实会默认使用乐观锁,当出现 write conflict 时,隐式事务会根据 tidb_retry_limit 参数来决定是否进行重试。并向 TiDB Server 的 log 中写入一条写写冲突的日志。根据上面参数的截图。可见,TiDB 后端自动的进行了重试。

    如果 autocommit 的事务开始进行重试,整个重试的过程和一般事务的执行过程没有差别,会获取新的 tso ,并进行 2PC 提交。

    当 autocommit 的事务重试的次数达到 tidb_retry_limit 参数的定义的值仍未 retry 成功,则会向客户端返回报错,客户端需要捕获异常,并进行相应的处理~

如果遇到了写写冲突,建议查看下,下面的监控面板的情况:TiDB 监控面板 → KV Errors → KV Backoff OPS 监控指标项,查看 TiKV 中返回错误信息的数量。

理论上,DM 会对接收到的数据进行了并发执行,但是在并发的过程是以一个个 batch 的方式来进行的。而 batch 是一个显示事务,当集群的事务模型是悲观锁时,显示事务会以悲观锁的方式进行提交。

悲观事务在遇到 write conflict 时,理论上不用过多的关注,虽然在 TiDB 的 log 中出现 pessimistic write conflict, retry statement ,但是会根据 [pessimistic-txn] 类别下的 max-retry-limit 定义的参数来进行重试。

悲观事务相关文档见TiDB 悲观锁实现原理

这个 commit 表示的是 commit 提交操作的耗时,这个耗时是 2PC 的过程,包括两部分内容 prewrite 和 commit ,TiKV-Details → gRPC → gRPC message duration 中可以看到提交阶段的耗时~

这个 commit 操作和上面的 TiKV 写入流程的截图的功能模块都会走一遍,即不管是 prewrite 和 commit 都会走 TiKV 数据写入的流程。相关文档见 TiDB 写入慢流程排查系列(四)— TiKV Server 写入流程

1 个赞

十分感谢老师回复。我再好好梳理下这块内容,感觉马上就要站起来了:grinning:

:+1: