内容简介:2018-10-11简单介绍一下 VLDB 的一篇 paper:多个事务访问到相同资源的时候,会涉及到加锁,怎么样进行调度,会使得各个事务的延迟尽量短,系统整体的吞吐更高,以及保证调度的公平性?
2018-10-11
简单介绍一下 VLDB 的一篇 paper: Contention-Aware Lock Scheduling for Transactional Databases
问题
多个事务访问到相同资源的时候,会涉及到加锁,怎么样进行调度,会使得各个事务的延迟尽量短,系统整体的吞吐更高,以及保证调度的公平性?
这个问题是比较难搞的。
- 首先这是一个 在线问题 。在事务结束之前,一个锁将会被持有多久,无法事先预知。
- 其次 依赖关系特别复杂 。一个事务可能持有许多的锁,以及多个事务间可能都依赖同一个锁。
- 接着是 访问模式的不确定 。不同的事务有不同的访问模式,有些对象可能是比较 popular 的,被许多事务依赖,不同对象之间并不等价。
- 锁的模式也有多种类别。比如写锁是排它的,而读锁是可共享的。
常规的系统大多采用的是 FIFO 的调度方式,也即是哪个事务请求先到达就先执行,并对相应的资源加锁。paper 里面指出,FIFO 的策略效果其实是很差的,而它提出的 contention aware 调度策略则相当牛逼。另外,MySQL innodb 引擎在 8.0.3 版本以后,默认采用的也是这篇 paper 里面的方法。
想法
contention-aware 调度的意思是,根据事务整体的锁竞争会对系统造成的影响,将事务分配优先级。调度是根据优先级进行的,而不是按 FIFO 方式。
那么第一个点就是如何确定锁竞争的激烈程度,下面是一些直观的想法。
最多锁持有优先(MLF)
一个事务,它持有的锁越多,则越有可能 block 住其它的事务。所以最多锁持有可以作为一种评判标准。
持有锁越多的事务,越优先调度。我们将这种方式称为“最多锁持有优先”。
这里的问题在于,对象之间并不是等价的。有些对象很 popular,持有它的锁会 block 住其它事务,而另一些对象其实并不 block 其它事务。依赖的节点多,并不意味着导致锁竞争。大部分上的节点都不会发生冲突。只有冲突节点上,才造成锁竞争。
最多 block 锁持有优先(MBLF)
事务依赖的锁,只有当这个锁还同时被其它事务依赖时,才导致锁竞争。所以上面的算法可以优化一下,不使用依赖的节点数量,而使用依赖的锁数量。
这里的问题在于,没有考虑进去锁的因素,将所有锁都看作相同的。假设有两个锁,其中一个 block 住了一个事务,而另一个锁 block 住了 10 个事务,在这个评判标准里面,两个锁还是被等同处理的。
依赖子图深度优先(DDF)
锁 block 住的事务多了,这个锁重要性也就提升了。为了抓住锁之间的重要性不同这个因素,我们可以考虑 “事务依赖的锁,锁 block 住的事务” 这一层关系,可以画一个依赖图出来。用子图的深度来衡量整个 block 的程度,也即反映了锁竞争的程度。
从事务到依赖图的叶子节点的路径深度,作为一个事务的优先级。
最大依赖集优先(LDSF)
因为我们不能考虑事务什么时候到达,什么时候结束,所以我们只能考虑当前执行中的事务。考虑事务之前的依赖图关系。
如果把依赖图画出来后,就会发现,“依赖子图深度优先” 跟 “最多 block 锁持有优先”,一种是反映图的垂直方向,一种是图的水平方向。把它两结合到一起考虑,就会变成“最大依赖集优先”。
将锁授予依赖集最大的事务,它能继续执行往前推进,则意味着依赖集里面的所有事务,都有潜在推进的可能。这样最有利于系统整体的向前推进。
修正的最大依赖集优先(bLDSF)
上面的最大依赖集优先是一个简化了的场景,假定只存在排它锁。实际上,如果存在共享锁,则问题会变得复杂一些。
共享锁会有一个"饥饿"问题,它被一直持有,导致排它锁加不上去,从而申请排它锁的事务时间会被拖长,造成系统整体的吞吐下降。所以论文里面还有一个结论是说,共享锁并不是分配给越多的事务就越好。
paper 里面有关于共享锁的处理细节,这里先略过。
算法实现
输入是依赖图,依赖对象;输出是应该将什么样的锁,分配给什么样的事务集合。
- 如果还有其它事务仍然对象 o 上面持有锁,则返回空
- 获取在对象 o 上面等待共享锁的集合 {t1,t2...tm}
- 获取在对象 o 上面等待排它锁的集合 {ta,tb...tn**
- 计算一个 共享锁的子集 ,使依赖集 {g(t1) |+ g(t2) |+ ...g(tk)} / f(k) 达到最大值
- 取排它锁的依赖集的最大值
- 如果是从共享锁依赖集算出来的最大值,大于排它锁算出来的值,则唤醒共享锁的一个子集的事务
- 否则,唤醒依赖集最大的那个排它锁事务
这算法并不是来一个事务,就给它授予锁,或者遇到锁了将它排队(FIFO)。而是从头到尾的扫描整个 waiting 的事务,找出一个满足条件的并授予锁。
如何计算依赖集大小?
计算依赖集要遍历子图,而且每次依赖图变化了,每个节点要重新实时的计算,这种方式代价太高了。所以paper 里面是取一个近似值。如果一个事务 t,没有锁 block 这个事务,那么 g(t) = 1
。否则,它依赖某些锁,这些锁被事务集合 t1...tn
占着,则 g(t) = g(t1)+g(t2)...+g(tn) + 1
。这是一个近似算法,原因是依赖图不是一个树,而是一个 DAG,是有节点重叠的。
另外的麻烦的点是算共享锁的子图的依赖集情况,先略过了。
大致就这些,至于结果对比...各种吊打 FIFO 策略,就不提了。最后我想质疑一下的是,它的数据场景构造的有一些极端,发论文嘛,动不动就说 100x 提升...真实 case 里面达不到冲突严重到那种程度,所以数据肯定不会有那么好看。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 理解golang调度之一 :操作系统调度
- 理解golang调度之二 :Go调度器
- Golang 源码学习调度逻辑(三):工作线程的执行流程与调度循环
- Node.js CPU调度优化(多服务器多核心分配调度)
- Hadoop 容器调度器与公平调度器原理和实践深入剖析-Hadoop商业环境实战
- golang调度器
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入浅出Ext JS
何启伟、徐会生、康爱媛 / 人民邮电出版社 / 2010-5 / 69.00元
以用户为中心的时代,应用的界面外观变得越来越重要。然而,很多程序员都缺乏美术功底,要开发出界面美观的应用实属不易。Ext JS的出现,为广大程序员解决了这一难题。它有丰富多彩的界面和强大的功能,是开发具有炫丽外观的RIA应用的最佳选择。 本书是《深入浅出Ext JS》的升级版,涵盖了最新发布的Ext JS 3.2新特性,并对上一版的内容进行增补,充实了示例代码,同时补充了两个功能强大的实例。......一起来看看 《深入浅出Ext JS》 这本书的介绍吧!
Base64 编码/解码
Base64 编码/解码
MD5 加密
MD5 加密工具