深入浅出 TiDB MVCC:揭秘分布式数据库中的多版本并发控制

目录

一、简介

二、TiDB MVCC

        2.1 MVCC 流程

        性能问题与优化

        数据清理和归档

        2.2 MVCC 出现冲突如何解决

三、TiDB ACID 实现原理


一、简介

        TiDB 是开源的分布式数据库,是一款同时支持在线事务处理与在线分析处理的融合型分布式数据库产品,具备水平扩容或缩容、金融级高可用、实时 HTAP、云原生分布式数据库、兼容MySQL5.7 协议和 MySQL 生态等重要特性。目标是为用户提供一站式 OLTP、OLAP、HTAP 解决方案。

        很多数据库都会实现多版本并发控制(MVCC),TiKV也不例外。设想这样的场景,两个客户端同时去修改一个 Key 的 Value,如果没有多版本控制,就需要对数据上锁,在分布式场景下,可能会带来性能及死锁问题。

        想要了解 TiDB 的 KV 存储请先查阅以前的文章:TiDB内核解密:揭秘其底层KV存储引擎如何玩转键值对_tidb 的key value是如何做到的-CSDN博客

二、TiDB MVCC

        TiKV 的 MVCC 实现是通过在 Key 后面添加版本号实现的,简单来说,没有 MVCC 之前,可以把 TiKV 看成:

Key1 -> Value
Key2 -> Value
……
KeyN -> Value

        有了MVCC之后,TiKV的Key排列是这样的:

Key1_Version3 -> Value
Key1_Version2 -> Value
Key1_Version1 -> Value
……
Key2_Version4 -> Value
Key2_Version3 -> Value
Key2_Version2 -> Value
Key2_Version1 -> Value
……
KeyN_Version2 -> Value
KeyN_Version1 -> Value
……

        注意,同一个 Key 的多个版本,版本号较大的会被放在前面,版本号小的放在后面,这样当用户用户通过一个 Key + Version 来获取 Value 时,可以通过 Key 和 Version 构造出 MVCC 的Key,也就是 Key_Versoin。然后可以通过 RocksDB 的 SeekPrefix(Key_Version) API,定位到第一个大于等于这个 Key_Version 的位置。

        2.1 MVCC 流程

        TiDB 实现 MVCC(多版本并发控制)的主要目的是为了支持高并发读写场景下的事务处理,同时保持数据的一致性。以下是 TiDB 中 MVCC 实现的简化流程概述:

  1. 启动事务获取事务 ID:当一个事务开始时,TiDB 的 PD 组件会分配一个全局唯一的事务ID,也称为 Start Timestam(StartTs),这是事务在整个生命周期内的版本基础。
  2. 读操作:读操作根据其所在事务的快照读(Snapshot Read)原则,看到的是在事务开始时刻所有已提交事务的数据版本。读取时会按照版本号找到最新的,但找到的是低于当前事务时间戳的有效版本进行读取。
  3. 写操作:当事务进行写操作时,不会直接覆盖原有数据,而是生成一个新的键值对,其中key 包含原始数据的键以及事务的 StartTS 作为版本号。更新操作会在 MVCC 视图下创建新的版本,同时旧版本的数据得以保留。删除操作也是生成一个新的标记删除的版本,而非立即物理删除。
  4. 并发控制与隔离级别:TiDB 实现了 Snapshot Isolation (SI) 隔离级别,这意味着事务内的读操作不会看到其他未提交事务的修改。由于每个事务有自己的快照,因此避免了脏读和不可重复读的问题。
  5. 死锁检测与处理:若多个事务间存在锁冲突且形成死锁,则事务系统会自动检测并回滚其中一个事务,以解除死锁状态。
  6. 垃圾回收:随着事务不断提交和更新,MVCC 会产生多个数据版本,为了节省存储空间,TiDB 通过垃圾回收(GC)机制定期清理不再需要的历史版本,以释放存储空间。GC 过程会根据 TTL(Time To Live)策略,删除超过指定生存时间且不再被任何未提交事务引用的旧版本。对于 delete 或 update 后的历史版本,在没有活跃事务依赖的情况下,可以通过 compaction 过程将其移除。
  7. 生命周期管理:TiDB 的 MVCC 还涉及到了事务结束时的提交或回滚操作,提交意味着将事务的所有更改应用到全局可见的状态;回滚则撤销事务期间的所有变更。

        使用 TiDB 并涉及其 MVCC 机制时,需要注意一些问题:

        性能问题与优化

        版本堆积:频繁的写操作可能导致数据项上积累大量版本,尤其是在高并发场景下,这不仅消耗存储资源,还可能影响查询性能,因为查询需要遍历更多的历史版本。通过合理的 GC 策略(如调整 tikv_gc_life_time 参数)、优化写密集型工作负载、减少不必要的更新或使用更细粒度的分区来缓解版本堆积问题。

        大事务:若事务过大(例如涉及大量数据变更),可能会触发“Transaction is too large”错误。应遵循最佳实践,尽量保持事务短小,或者调整 performance.txn-total-size-limit 参数以适应特定业务需求。

        数据清理和归档

        直接使用 DELETE 语句在特定场景下可能会因 MVCC 版本管理而导致删除速度变慢。可以通过按主键或更细粒度的范围进行批量删除,并确保每次操作的范围尽量小,以减少 MVCC 版本扫描和清理的负担。

        由于 TiDB MVCC 的特性,无法像传统单机数据库那样简单地删除或归档某一时间范围内的数据。需要结合业务需求设计合适的数据生命周期管理策略,可能包括定期迁移冷数据到低成本存储、使用 TTL(Time To Live)自动删除过期数据,或者开发专门的数据归档流程。

        2.2 MVCC 出现冲突如何解决

        在 TiDB 的 MVCC(多版本并发控制)机制下,写冲突通常指的是不同事务对同一数据项进行并发修改时发生的冲突。TiDB 通过以下方式处理写冲突:

        乐观事务(默认)

  • TiDB 默认采用乐观事务模型,即在事务开始时并不立即获取任何锁,而是在事务提交时才进行冲突检测。当事务试图提交时,TiDB 会检查事务期间修改的数据项是否存在其他未提交事务的并发修改。
  • 写写冲突:如果检测到有其他未提交事务对同一数据项进行了修改(即写写冲突),TiDB 会回滚当前事务并抛出一个错误,如 “Write conflict, txnStartTS=xxx”。应用程序收到错误后,通常需要重新尝试事务(可能需要根据业务逻辑调整重试逻辑以避免无限循环)。
  • 写读冲突(仅在 SERIALIZABLE 隔离级别):在 SERIALIZABLE 隔离级别下,TiDB 会检查事务期间读取的数据是否存在其他未提交事务的并发修改。如果发现写读冲突,也会回滚当前事务并抛出类似错误。

        悲观事务

  • TiDB 也支持悲观事务模型,即在事务开始时就对即将修改的数据项加锁,以防止其他事务并发修改。如果两个事务同时试图对同一数据项加锁,其中一个会因为锁竞争而等待,直到持有锁的事务提交或回滚释放锁。
  • 写写冲突:当两个事务同时尝试修改同一数据项时,其中一个事务的加锁请求会被阻塞,直到另一个事务完成并释放锁。如果锁等待超时(可配置),被阻塞的事务将回滚并抛出错误。
  • 写读冲突:在悲观事务模式下,读操作也会申请共享锁,从而阻止其他事务对已读取数据进行修改。如果有事务试图修改已加共享锁的数据,其写请求会被阻塞,直到读事务结束释放锁。

        总结:TiDB MVCC 通过维护数据的不同版本,实现了高效的并发控制和数据一致性,支持高并发的读写操作。其核心思想是利用时间戳来区分不同事务对数据的访问权限,使得事务能够在不影响彼此的前提下并发执行。通过垃圾回收和 Compaction 机制,TiDB 能够有效地管理存储空间,确保系统长期稳定运行。这种设计使得 TiDB 成为一款适用于大规模分布式环境的高性能、强一致性的数据库系统。

三、TiDB ACID 实现原理

        TiDB 作为一款分布式数据库,实现了完整的 ACID(原子性、一致性、隔离性、持久性)特性,尤其是在复杂的分布式环境中。以下是 TiDB 如何实现这些特性的简要说明:

        原子性:在 TiDB 中,通过两阶段提交(2PC, Two-Phase Commit)协议保证事务的原子性。当事务跨越多个 TiKV 节点时,TiDB 的事务协调器负责发起预提交请求和正式提交请求。如果所有参与的 TiKV 节点都同意提交,事务才会真正生效;如果有任何一个节点无法提交,整个事务都将回滚。

        一致性:一致性主要通过严格遵循 SQL 标准以及事务的正确执行来保证。TiDB 的 SQL 引擎确保了数据操作符合业务逻辑和约束条件。此外,TiDB 还支持分布式事务中的强一致性,利用 Raft 或者 Multi-Raft 协议(具体取决于 TiDB 版本)在存储层保证数据复制的一致性,从而达到跨节点数据的强一致性。

        隔离性:TiDB 默认采用 Snapshot Isolation(快照隔离)级别,它能够防止脏读和不可重复读问题。在 MVCC(多版本并发控制)机制的支持下,每个事务在执行期间会看到一个快照,即事务开始时数据库的一个一致状态,这样不同的事务就可以并发执行而不互相干扰。

        持久性:TiDB 的持久化由底层的 TiKV 存储引擎实现。TiKV 利用 Raft 日志复制来保证数据的安全性和持久性,每一份数据在集群中的多个副本之间同步,只有当数据成功写入多数派节点后才会返回确认,确保即使在部分节点失效的情况下数据也不会丢失。写入 TiKV 后,数据会被异步刷盘(flush)到磁盘,并且 Raft Group 中的日志也会持久化,从而保证在服务器重启后数据仍然存在。

        TiDB 能够在分布式环境下有效地模拟单机数据库的 ACID 特性,为用户提供了一个可靠且高性能的事务处理平台。

往期经典推荐:

TiDB内核解密:揭秘其底层KV存储引擎如何玩转键值对_tidb 的key value是如何做到的-CSDN博客

你真的了解Tomcat一键启停吗?-CSDN博客

实战揭秘:深入解析SSE结合EventBus实现消息定向推送-CSDN博客

揭开Spring Bean生命周期的神秘面纱-CSDN博客

Redis分布式锁:保障微服务架构下的并发控制与数据一致性实战指南-CSDN博客

MySQL为什么会选错索引-CSDN博客

  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超越不平凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值