乐观的并发控制(OCC)是一种在不丢失写入的情况下安全修改单个对象的多个作家的迭代方式。 OCC有三个很好的属性:只要底层商店可用,它将始终进行进度,很容易理解,它很容易实现。 DynamoDB的条件写入为DynamoDB用户提供了自然适合DynamoDBMAPPER客户端。
虽然OWN保证进行进度,但它仍然可以在高争用下表现不佳。最简单的这些争用例是当大量客户端同时启动,并尝试更新相同的数据库行。有一个客户保证每轮成功,完成所有更新的时间随着争用而直线增长。
对于此帖子中的图表,我使用了一个小模拟器来模拟网络上的行为,以延迟(和延迟方差),对抗远程数据库。在此模拟中,网络引入了10ms的平均值和4ms方差的延迟。第一个仿真显示了完成时间如何与争用线性增长。这种线性增长是因为一个客户端每一轮成功,所以所有N个客户都需要n轮才能成功。
不幸的是,这不是整个画面。通过N客户竞争,系统完成的总工作量随N2而增加。
这里的问题是N个客户在第二轮中的第一轮,N-1中竞争。每一轮都竞争每一轮都是浪费的。减速客户可以帮助,并且慢速客户的经典方式被缩小指数退避。盖住指数退避意味着客户端在每次尝试后通过常量将其退避,最大值乘以一些最大值。在我们的案例中,在每次不成功的尝试后,客户睡眠:
再次运行模拟显示退避帮助少量,但不能解决问题。客户工作仅略有减少。
看到问题的最佳方式是看看这些指数抵消抵消的次数发生。
显然,指数退避正在工作,因为呼叫越来越频繁。问题也脱颖而出:仍有呼叫群集。而不是减少每一轮竞争的客户数量,而不是在没有客户正在竞争的时候推出的。争用虽然网络延迟的自然差异引入了一些蔓延,但争用尚未减少太多。
解决方案不是要删除退避。这是为了添加抖动。最初,抖动可能似乎是一个反向直观的想法:尝试通过添加随机性来提高系统的性能。上面的时间序列为抖动做出了一个大案例 - 我们希望将尖峰展开到大致持续的速率。添加抖动是睡眠功能的小变化:
那个时间序列看起来更好。差距消失了,超出了初始飙升,有大约不断持续的呼叫率。它对总呼叫数量也有很大的影响。
在100个竞争客户端的情况下,我们将呼叫数减少超过一半。与Un-抖动的指数退避相比,我们还显着提高了完成时间。
有几种方法可以实现这些定时退避循环。让我们称之为“完整抖动”的算法,并考虑两个替代方案。第一个替代方案是“相等的抖动”,在那里我们始终将一些退避和抖动通过较小的量保存:
这一个背后的直觉是它可以防止很短的睡眠,始终将一些缓慢的下降速度从退避中保持速度。第二种替代方案是“去相关的抖动”,类似于“全抖动”,但我们还基于最后一个随机值增加最大抖动。
查看客户的工作量,对于“完整”和“平等”抖动大致相同,并且“去相关”较高。两者都相对于禁止抖动方法基本上减少工作。
无抖动指数退避方法是清晰的输家。它不仅需要更多的工作,而且比抖动的方法需要更多时间。事实上,我们需要更多的时间我们必须离开图表以获得其他方法的良好比较。
抖动的方法,“等于抖动”是失败者。它的工作略高于“全抖动”,需要更长时间。 “去相关抖动”和“全抖动”之间的决定不太清晰。 “全抖动”方法使用较少的工作,但稍微更多的时间。但是,这两种方法都在客户工作和服务器负载中提出了大量减少。
值得注意的是,这些方法都没有从根本上改变要完成的工作的N2性质,但实际上在合理的争用程度上进行了大幅减少工作。使用抖动退避的实现复杂性的回报是巨大的,它应该被视为远程客户端的标准方法。
使用此帖子的所有图形和数字使用简单的OCC行为模拟生成。您可以在Github上获取我们的模拟器代码,在AWS-Arce-Backoff-Simulator项目中。