暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

了解TiDB 6.0特性之内存悲观锁

一.TiDB悲观锁的基本概念?

在文章论文《TiDB:A Raft-based HTAP Database》阅读感悟(五)中我们了解到TiDB中既实现了乐观锁也实现了悲观锁,乐观锁与悲观锁最大的区别在于何时获取锁。TiDB的锁实现来自于Percolator模型,采用基本的两阶段提交(2PC)协议实现。

关于事务流程,简单一点儿说,假如有一个事务需要修改数据,事务在begin之后首先需要向PD获取一个开始时间戳start_timestamp,然后会从底层TiKV存储将相关的数据读取到内存中并在内存中进行修改操作。当客户端发起commit命令时, 便开启了两阶段中的第一阶段-prewrite(预写)Prewrite会写两部分内容:修改数据+锁信息,其中修改数据被写到Default这个CF(Column Family)中,而锁信息被写到Lock这个CF中。

在上述流程中,由于锁信息是在commit的时候才持久化到TiKV中,prewrite之前只在TiDB Server的内存中,因此其它并发事务感知不到锁的存在,这样的锁模型属于乐观锁模型

悲观锁模型中,事务的流程有所不同。Begin之后会先获取start_timestamp,然后把数据读取到内存并在内存中修改数据,但锁信息会持久化到TiKV,这样可以保证其它并发事务可以感知到锁的存在。悲观锁由于是在commit之前就开始写锁信息,因此可以减少事务因为冲突而回滚的情况。

二.悲观锁存在的问题?

显然,悲观锁因为要在commit之前需要将锁信息持久化到TiKV节点,这个过程会带来额外的磁盘IO;同时,锁信息在持久化到TiKV层需要通过Raft进行三副本复制,这样也会带来额外的网络IO

三.TiDB内存悲观锁的实现及解决的问题?

悲观锁在commit之前因持久化锁信息导致的磁盘IO和网络IO是必要的么?首先说一下这个网络IO,它是来自于Raft三副本复制,它存在的价值就是说如果TiKV Leader节点在正好有锁信息的情况下故障,那么可以切换到其他节点继续保持着这个锁信息,从而不影响事务的正常执行。再说一下这个磁盘IO,它是来自于commit前的锁信息写磁盘,那么如果不是写到磁盘而是写到TiKV节点的缓存中,那么就可以避免这个磁盘IO消耗。

内存悲观锁功能由此而来,通过在commit之前把锁信息写到TiKV节点的内存中,避免了之前的磁盘IO和网络IO操作,从而提升一定的性能。

当然,内存悲观锁也存在一定的问题。一个问题就是锁丢失,即当锁信息所在的TiKV节点宕机时,锁信息因为只存在于内存中会导致锁丢失(此时也没有三副本)。在出现锁丢失的情况下,数据库的机制是可以让事务自动回滚。

如果业务允许上述可能存在的锁丢失导致的事务回滚失败,则可以开启内存悲观锁的功能,从而提升事务执行的效率;用户也可以通过参数关闭/打开内存悲观锁的功能,通过以下命令实现。

set  config tikv pessimistic-txn.pipelined='true';

set  config tikv pessimistic-txn.in-memory='true';

四.内存悲观锁的总结?

综上所述,TiDB 6.0版本的内存悲观锁功能具有以下特征:

(1)减少事务的延时

(2)降低磁盘和网络带宽

(3)降低TiKVCPU消耗

(4)会导致锁丢失问题


文章转载自数据源的技术后花园,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论