051、事务设计之TiDB事务实现方式

事务在TiDB中的存储

在这里插入图片描述

分布式事务

在这里插入图片描述
提交的第一阶段,会用三个CF 来存放这些数据信息,
一类列簇对应一类键值对, 第一个CF(default)存放的是数据 的键值对。第二个存放的是锁信息。 第三个对应的是提交信息。

put<3_100,Frank> 3_100: primary_tso 表示是在事务时间戳100的时候对3这个主键进行修改。 注意增删改的操作,里面放的都是新数据。

< 3,(W,pk,3,100 …)> : 写锁,主键,事务相关信息. 注意一点,在TiDB当中,一个事务只有一个主锁,也就是分布式事务中的第一行加锁,这个锁就是主锁pk

put<3_110,100> : 会用第三个CF来存储提交信息,包含主行的标识,开始和提交的时间戳。

< 3,(D,PK,3,100 …)> < 3,(W,pk,3,100 …)> : 提交后,需要清理CF当中索的信息,它不是直接在里面删除这一行,而是新增一行, 告诉主键3上已经删除了锁(D)

读取的时候:它会先到write 的CF中查看 最近一次修改是什么时候,本例是110,并且通过110找到对应的事务开始是100,继而就能找到Frank
如果通过write中找不到,则表示这个记录正在被上锁,处于修改中,则这个记录不能直接读取。

  • Write列: 当用户写入了一行数据时,如果该行数据长度小于255个字节,否则该行的数据会被存入到default列中。当然它更要用于存储 提价的信息
  • default列: 用于存储超过255字节长度的数据。
    在这里插入图片描述

在这里插入图片描述
< 1,(W,PK,1,100 …)>: 注意一点,在TiDB当中,一个事务只有一个主锁,也就是分布式事务中的第一行加锁,这个锁就是主锁pk

< 2,(W,@1,2,100 …)> :这是第二行,就不是主锁,@1 表示 我不是主,我的主锁在1那里。存的是锁的指向。

另外需要理解的是: 当插入修改值的时候,只需要在CF中插入新值即可。例如将Tom改成Jack,当别人去读取的时候,已经变成了Jack,就不用读Tom。

分布式事务如何解决原子性。

例如: 当前有个事务 里面的更新Tom为Jack是在node 1;更新Andy为Candy是在node 2 。 此时在第二阶段提交的时候 node 1成功,node 2失败。 因为节点1已经提交,相当于已经落盘持久化,但节点2此时由于故障 Lock并没有删除索引的信息,write中也没有提交信息。

在这里插入图片描述
此时,就可以通过主锁的机制来补齐相应的信息,流程如下: @1 可以找到对应的node 1,然后通过node 1 上的lock cf可以看到事务已经提交。此时在node 2 上,将write cf中补上<2_110,100> 在lock cf中添加清理索引的信息。这样就保障了分布式事务的原子性

在这里插入图片描述

MVCC

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

在这里插入图片描述
这个版本号,可以使用TSO来控制生成(可以简单理解为时间戳)

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 是有序的排列),这样当⽤户通过⼀个 Key + Version 来获取 Value
的时候,可以通过 Key 和 Version 构造出 MVCC 的 Key,也就是 Key_Version。然后
可以直接通过 RocksDB 的 SeekPrefix(Key_Version) API,定位到第⼀个⼤于等于这个
Key_Version 的位置。

在这里插入图片描述

mvcc:就是快照读的意思,因为修改未提交的数据不能直接读取,此时需要通过快照。在TiDB当中不论增删改,它都是追加新值的方式(put)。所以TiKV很便捷的实现MVCC。

在这里插入图片描述

在这里插入图片描述

id = 1 如何读取,首先在write当中到对最近一次提交的TSO,110的时间戳,然后看到对应的是1 100 put < 1_100,Jack)> ,这样就把Jack读出来。读的就是以前值。

如果是写入, 则还需要看上面锁的信息,发现上面有个锁,并且没有释放索引的记录,则表示虽然id =1 在110的时候已经提交,但在115的时候又被写入了,则我当前不能够对这条记录进行写,它当前被这个 lock cf中的记录阻塞了。

在这里插入图片描述

id = 2的时候,读跟id = 1一样。
写可以看到lock当中没有,或者说已经释放。则我这个id =2 的记录可以写。
在这里插入图片描述

读跟以前原理一样
写: 这个时候可以看到 除了在Default中找到对应记录,还需要再Lock中查找,可以看到< 4,(W,@1,115 …)> 有记录,并且没有删除锁的记录,则继续找对应的主锁@1,再分析 < 1,(W,pk,115 …)> 发现它并没有提交,则表明当前这个分布式事务并没有提交,所以会被阻塞。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数哥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值