论文标题:Non-scalable locks are dangerous
论文作者:Boyd-Wickizer, Silas and Kaashoek, M Frans and Morris, Robert and Zeldovich, Nickolai
论文出处:Proceedings of the Linux Symposium
本文结论总结
本文主要观察到下面三个结论:
- 使用不可扩展的锁会严重影响整体体系统的性能
- 整个系统性能性能断崖式下坠可能会比较的突然,N个核还好好的,比其多几个核就突然collapse了
- 临界区越短,越容易导致系统性能断崖式下坠
本文提供了一个马尔可夫模型,通过模型解释上面的现象。
且本文总结在Linux内核中中,工作负载和竞争程度都是不好预测的。
从不可扩展的锁转到可扩展锁的提升是巨大的。而可扩展锁之间的提升就比较小了。
为什么不可扩展的锁会慢
如果使用spinlock
或者ticketlock
,其实都是对单一缓存行的竞争。如果有多个核竞争该锁,则都会将这个缓存行缓存在本地。一旦有一个核释放了锁,就会使这些缓存行都失效。所以其它核必须读这个新的值,而这些读都是线性的,所以消耗的时间与核数线性相关。因此,释放锁的动作是一个
O(N)
O
(
N
)
的操作。
测试不可扩展锁的性能
本文用了四个Linux内核中的测试集对non-scalable lock进行测试。
其中除了可以观察到使用不可扩展锁导致整体系统性能断崖式下坠之外,还可以通过下面这个表解释下坠时使用的核数。
下面表中 Operation time 代表着 benchmark 中一个 Operation 所消耗的时间,Acquires per operation 为每次操作对竞争最强的锁尝试获取次数。Avg Critical section 和所占比例为临界区所占比例。
如MEMPOP测试集中临界区占全部的7%的运行时间。故当有1/7% = 14个核心在运行Operation时,就会有一个核心在临界区中,当核数增多时,对于临界区的竞争就会逐渐激烈。但是实际上更早地出现了下坠现象。
解释不可扩展锁性能的模型
将整个系统带入马尔可夫模型 Markov model ,一共有 n n 种状态,代表着现在有个核心在等待。
当已经有 k k 个核获取了锁:
则有新的核获取锁的概率为:
其中 1a 1 a 代表着一个核获取锁的可能。
则有已经得到锁的释放锁的概率为:
其中 s s 代表着cs区域所需要的周期数,为home directory回复一个request所消耗周期数, k2 k 2 是 k k 个request顺利找到下一个ticket平均需要的次数。
假设为整个稳态系统处于各个状态的概率,则有以下等式:
可以推导 P0 P 0
后再利用 ∑ni=0Pi=1 ∑ i = 0 n P i = 1 ,可以推出
因此可以知道一个锁有少核心等待的概率,并算出期望值:
所以当整个系统有 n−w n − w 个核的时候达到最大加速比。
实际测试验证模型准确性
第一个测试是选用了固定的cs区域内周期数与非临界区周期数,并选用不同的比例进行测试:
论文中没有详细说模型的加速比是怎么来的,应该是上面马尔可夫模型中的一个状态(比如 k k 个核心在等待锁时),对应等待锁消耗周期为。然后算出整体系统所消耗时间,并算出其加速比。
第二个测试是固定临界区所占比例不变,改变临界区的周期数。观察不同的临界区长度对
模型中没有实际的陡是因为在collapse点周围时,lock的性能表现不稳定。
模型能说明什么
这个模型可以说明以下问题:
模型验证了,断崖式下坠并不是硬件的问题,而是本身设计的问题。任何符合模型假设的硬件都会面临这个问题。可以利用模型这样理解为何会出现这样的现象:当本身有很多锁竞争的时候,从 k k 状态释放锁变为状态的概率 Sk S k 本身随着 k k 增大而变小,所以竞争数量变小就变得十分困难。所以当到达某个时间点,更有可能变成,而非变成 k−1 k − 1 。也可以这样理解,如果核数增多,则需要更多时间将锁迁移到其它核上,这段时间可能有更多竞争者开始竞争该锁。
可以从第二个实验看出,断崖式下坠只出现在临界区较短的情况下。这个可以利用 Sk S k 的值进行解释。由于 Sk S k 的推导公式如下:
Sk=1s+ck2 S k = 1 s + c k 2
所以短的临界区对应的 s s 较小,较容易被 k k 影响,故当较大时, Sk S k 会迅速减少。而若临界区较大,则 Sk S k 较稳定。断崖式下坠导致了整体系统的性能不能接近Amdahl定律预估的理想的性能。也可以这样理解:锁消耗的时间明显增加,导致不可并行的部分变多,故加速比减少。
可扩展的锁
最简单的将ticket lock变成可扩展锁是加入线性后退机制,避免频繁竞争。
也可以替换成正真可扩展的锁。可扩展锁的标准是:每个获取锁请求导致的cache misses数量都是固定的,不随着核心数增多而增多。这些锁都有一个队列,每个核都在自己队列中的对应entry上循环等待。
本文中列举的有mcs CLH HCLH 锁。实际在Linux内核中实现mcs lock后性能提升可观,这里不继续翻译了。相关论文已经提到了很多。
读完文章思考模型能否衍生推导其他锁
如何解释可扩展锁的性能提升
可扩展锁与不可扩展锁(均为本地锁)的最大不同是从 k k 到的概率 Sk S k
理论上,可扩展锁的
Sk
S
k
为:
其中 s s 代表着cs区域所需要的周期数,为home directory回复一个request所消耗周期数。 Sk S k 并不随着 k k 增大而减小,所以从很大的到 k−1 k − 1 和很小的 k k 到的概率是相同的。不会出现断崖式下坠。
迁移锁能否使用这个模型
固定服务器的迁移锁
固定服务器的迁移锁也可以用类似的模型进行描述:
其中 sDdelegation s D d e l e g a t i o n 根据临界区不同,可能由于具有更好的本地性远远小于 s s
迁移服务器的迁移锁
而迁移服务器由于还有服务器的开销,忽略变成服务器开销,可以近似用以下模型描述:
其中 sMdelegation s M d e l e g a t i o n 根据临界区不同,会比 sDdelegation s D d e l e g a t i o n 更短。
且 clocal c l o c a l 会比 c c 更短,但是引入了迁移服务器平均下来的开销。
其实严格的来说,迁移服务器的迁移锁不能用Markov model来描述,其情况比较复杂,这里只是近似比较。