zoukankan      html  css  js  c++  java
  • tikv事务优化 async commit阅读笔记

    tikv事务优化 async commit阅读笔记

    阅读了tikv的sig-transaction中关于async commit的优化的方案,做一下简单的笔记。

    思路

    percolator是一种2PC协议,一次正常的事务提交至少需要两次从tidb到tikv的round trip, async-commit则尽量希望能尽量减少一次round trip。其基本的想法为:在primary key的记录中记录下所有的secondary key的值,prewrite完成后就认为事务已经提交。

    能这么做的主要原因在于primary key中记录了所有secondary key,因此可以通过primary key找到所有secondary key,即使发生了crash也可以通过这些信息判断事务是否完成提交,只要primary key和所有secondary key都已经完成写入,则这个事务就已经提交,事务的commit point为最后一个key完成写入的那一瞬间。

    commit TS选择

    按这种思路最关键的一个问题在于如何选择commitTS,percolator事务需要startTS和commitTS来判断是否相可见,一个事务只能读到commit TS小于它的start TS的记录,如果选择的commitTS不恰当,则会影响系统外部线性一致。需要杜绝以下两个情况:

    • 这个事务提交后,随后开启的事务读取不到它写入的数据。(因此该事务的commit TS需要比后续事务的start TS小,以便后面的事务能够读取到它的数据)
    • 必须比没有读到锁的事务的startTS大。(如果这个事务的commitTS小于没有读取到锁的事务的startTS,那么按理读取事务应该能读取到数据,但是由于还没读取到锁,因此读取事务直接去读最近的可见的版本了)

    对于第一种情况,可以否定一种方案,那就是prewrite完成后,再异步的去PD获取一个TS进行commit,因为prewrite后就返回了client,如果这时候client新开了一个事务去读取刚提交的数据,那么它的TS可能是小于异步获取的commitTS的,可能会读取不到已经提交的数据。对于第二种情况,如果一个事务在锁写入前读取了某行数据,那么这个事务的startTS必须小于要提交的commitTS,否则会读取不到该读取到的数据。

    由于async commit是prewrite的最后一个key写入完成就需要能确定commitTS,一个思路是:可以由tikv维护一个maxTS,表示当前tikv所见到的最大的TS,在每个key里prewrite写入的时候带上这个maxTS。prewrite完成后,选择返回的所有写入成功的key所带的TS的最大值+1作为commitTS。

    对于第一个问题,由于新的事务需要去PD获取一个startTS,而最终选定的commitTS是从各个tikv节点见到的TS中选取的,由于PD分配的TS是单调递增的,所以新事务的startTS一定大于之前async commit的事务。这个问题能解决。

    对于第二个问题,看上去好像可以,因为是使用的当前见到的最大的TS+1作为commitTS,按理应该不会存在一个再写入前已经去读取过数据而startTS又大于commitTS的事务,但是关键在于prewrite写入是需要时间的,例如,在某一时刻选择了TS1作为commitTS,但是写入还没有完成,此时有一个更大的startTS为TS2的事务来进行读取,此时prewrite还没写入成功,依然读取不到锁,无法解决上面的问题二。

    解决这类问题的本质是:推迟可能发生错误的操作直到确保没有错误。解决办法有:

    1. region 记录 min commit ts,即当前正在进行的 parallel commit 事务的最小的 commit ts。若读请求的 start ts 大于 min commit ts 就阻塞住直到 min commit ts 大于 start ts。也就是有可能发生错误的读请求被阻塞到确保没错误时再执行。
    2. 方法 1 粒度太大,为 region 级别,可以 region 内再划分 range,最细的粒度为 key 级别,也就是下面的方法:a. lock 先写到内存中,然后获取 max start ts 再写到 raftstore。读的时候先读内存中的 lock。写入到 raftstore 成功后清理掉 mem 中的锁,leader 切换时清理掉 region 对应的锁。b. 用 rocksdb 当内存锁的存储介质,先写到 rocksdb,再写到 raftstore。实现也简单,效果和 a一样,要注意清理。
  • 相关阅读:
    java多线程(待完善)
    eclipse console 查看全部的输出
    maven仓库地址
    拷贝Maven工程依赖的jar包出来
    ElasticSearch
    python2学习------基础语法5(常用容器以及相关操作)
    文本框焦点事件改变默认文字
    随机更换图片
    妙味——JS数组的方法
    妙味——封装getStyle()获取样式
  • 原文地址:https://www.cnblogs.com/FateTHarlaown/p/14211262.html
Copyright © 2011-2022 走看看