写点什么

深度剖析 | 关于数据锁定和读取一致性问题

用户头像
VoltDB
关注
发布于: 2021 年 05 月 13 日

1 背景介绍

传统的 RDBMS 系统在三件事上值得注意:锁定:即锁定记录的功能,以便其他人无法更改它们。

阅读一致性:您(仅您自己)可以看到您所做的更改,直到您提交为止,这时其他人才可以看到它们。

遗憾的是,其较差的可伸缩性:在线事务处理(OLTP)工作负载无法很好地扩展。在现实情况下,将 CPU 内核数量加倍不会使您的容量翻倍。

这种失败导致许多人尝试使用 NoSQL 解决方案,但是随着时间的流逝,越来越明显的是,如果没有这些解决方案,锁定和读取一致性将很难实现。VOLTDB 是唯一的数据平台,可让企业按比例进行锁定和读取一致性。

本文解释了为什么很难做到这一点,以及 VOLTDB 是如何做到这一点的。

2 为什么缩放 OLTP 很难?

为了让大家更直观地了解为什么扩展 OLTP 很难,先来让我们看一下简单的白板交易的典型生命周期:

  • 在表格“ a”中插入一行

  • 更新表“ b”中的行

  • 更新表“ c”中的行

  • 做外部活动

  • 更新表“ a”中的行

  • 犯罪

乍一看,可能很难看出这是如何扩展的。但是,让我们看一下使用旧版 RDBMS 的实际实现:


在此图中,有这样几件事变得显而易见:

1.此操作不会立即完成

您需要 12 次网络运行,每次运行都需要花费不少时间。在任意一段时间内,“现实世界的设备”都会关闭,并会做任何需要做的事情。简而言之:即使一切工作正常,此事务的耗时也将是几毫秒。

2. 长时间运行的数据交换将是数据库服务器的挑战

每次更改数据库服务器中的内容时,您都需要做更多工作,因为所有其他正在进行的数据交换都需要查看表的“旧”版本,直到提交为止。出于实际目的的考量,每个不完整的交易都需要自己的数据库版本,该数据库由现有数据及其未提交的更改组成。这意味着,如果您每秒运行一千笔交易,并且每笔交易的端到端需要 10 毫秒(即每次网络行程少于 1 毫秒),则随时将至少有 100 种不同版本的数据库存在,并且必须仔细检查任何新交易,以确保它不会与其他人的更改冲突。无论您使用 SELECT FOR UPDATE,MVCC 还是任何其他机制,此开销仍然存在。

3.当您增加 CPU 芯数时,递减收益法则就会生效随着工作量的增加,常规解决方法是添加更多的 CPU 内核并将工作分散在它们之间。虽然这在短期内会有所帮助,但它会带来另一个问题:当您只有一个 CPU 内核时,可以肯定的是,当尝试处理会话请求时,数据库的其他 100 个实时版本不会改变。这正是我们正在做的。但是,添加第二个 CPU 内核后,数据库需要协调它们的活动。这引入了一个全新的层的开销,每当您在“帮助”中添加另一个 CPU 内核时,问题就会以几何级的速度变得更糟。最终的结果是形成了一个恶性循环,在其中添加 CPU 内核以提高 TPS,但是每个新内核都需要关联消耗所有其他核心,最终将消耗您通过添加额外核心获得的 CPU 容量。如果额外的 CPU 容量来自群集中的另一个节点,那么事情将会出错。因为 CPU 内核之间相互争论的问题现在变成了到另一个数据库节点的网络访问。

4.随着容量的增加,性能变得越来越不稳定实际经验告诉我们,即使您在各方面都做到最佳,您仍然会在实际环境中遇到锁定问题,因为实际数据使用模式可能与测试场景大不相同。一个典型的例子是网站访问者在添加购物车或购物篮并按下“重新加载”时会不耐烦,这可能会导致以下情况:旧请求已锁定记录,而新请求则通知用户“其他人”已锁定它。物联网(IoT)和电信应用程序尤其容易出现这种情况,因为许多 API 的默认行为是在未收到即时响应时自动重试。这可能会导致完全违背直觉的情况,即减少请求数量将大大增加成功完成的交易数量,因为交易妨碍对方的机会较少。现实生活中发生的是,任何阻止其他更多交易完成的单个交易都可能导致活动量激增,尤其是当应用程序开始盲目重试时。

5.应用服务器或微服务器成为系统中的薄弱环节市场上几乎每台数据库服务器都具有某种形式的高可用性,但是应用程序服务器和微服务器通常被视为“无状态”,因为数据库服务器负责管理状态。但是,如果您所有的客户都被路由到单个组件,并且该组件有大约 100 笔未完成的交易,那么如果死机了该怎么办?数据库服务器从已连接的会话的角度看待世界,其中一些会话已锁定。在已结束组件的会话持有数百个行级锁的世界中,您可以期望数据库服务器在几分钟内遵守该锁定,直到最终弄清该组件已结束并关闭所涉及的会话,释放他们的锁定状态。这意味着,即使您已经准备好另一个应用服务器或容器立即承担其已结束前置的工作量,否则它将无法对锁定了几分钟的任何记录进行任何更改,这意味着“有效”多组数据将冻结几分钟,在此期间它将无法进行修改。

6.没有任何明显的方法可以解决此问题尝试扩展 OLTP 的最简单方法是切换到 NoSQL 存储,该存储要求客户端在进行更改之前发送证明已读取特定版本的记录的证据。这将为您带来更快的性能,直到人们开始争用数据为止。最常见的实现是将值的哈希值与值本身一起发送回客户端。然后,将该哈希作为一种密码通过网络发送,以证明该更改是对先前状态的合法修改。如果哈希错误,则意味着其他人同时更改了该值,您需要重新开始。这是一个不能令人满意的解决方案,因为当多个人开始同时更改同一条记录时,它会导致与传统系统相同的负载下不稳定的性能。这也意味着,在上述情况下,您可能需要操纵两个或甚至三个键值对。实际上,您要做的就是将事务复杂性降低到客户端层。显然,您需要另一种解决方案。

3 VOLTDB 是如何做到这一点的?

VoltDB 的创建者,包括图灵奖获得者 Michael Stonebraker,都考虑到了这一特定问题,开发了 VoltDB 数据平台,并有效地解决了该问题。VoltDB 数据平台在做三件事上有不同之处:

1.IT 分区将工作负载分配给每个分区,而这是控制 CPU 核心的单一物理线程的专有责任是的,许多现代数据平台都在划分工作负载。但是,我们仅需将分区与在单个 CPU 内核上运行的单线程对齐即可,这意味着该内核无需担心另一个内核在做什么,因此,VoltDB 立即消除了上述几何可伸缩性问题。

2.它允许任意数量的 SQL 语句和每个 TRIP 的逻辑关联到 VOLTDB 尽管您可以愉快地将 JDBC 与 VoltDB 一起使用,但是当您尝试将事例名称和您使用的参数传递到 VoltDB 上的服务器侧逻辑时,您可以减少网络访问次数和 VoltDB 必须跟踪的中间状态数量。

3.它表明每次访问都以提交结束这似乎有些剧烈,但对性能有重大影响。在任何时候,VoltDB 分区都仅仅处理一个事务,因为它只有单个线程“拥有”其中的所有数据。通过坚持所有事务都是“提交”或“返回”状态,VoltDB 不必从客户的角度跟踪存储状态数据库的任何额外“副本”。因此,在上面的实例中,VoltDB 实现无需跟踪数据库的 100 个版本, 每个分区仅使用一个活动副本。

综上,这些更改既为您提供了传统 RDBMS 的功能,并且具有出色的可伸缩性,其性能是同一个硬件的大约 9 倍。现在,让我们看一下同一笔交易在 VoltDB 中是如何进展的。


这可以通过两次调用 VoltDB 来完成。第一次调用执行前三个更改,并将会话 ID /到期日期添加到另外两个软锁列中。这允许其他交互查看正在进行的交易,并自行决定要做什么。当外部任务完成时,第二个调用触发,并清除软锁列。


让我们比较两种方法的统计信息:如您所见,VoltDB 的真实事务是通过更少的网络行程,更少的客户端 API 调用以及通过避免应用服务器节点丢失的明确方法来完成的。但这并不意味着没有其他可考虑的情况。让我们看看有关 VoltDB 如何进行锁定和读取一致性的常见问题。

4 Q & A

1.如果数据库服务器出故障了怎么办?我们在序列图中未显示的是,分区每次收到请求时,都会立即同步将该请求转发到位于另一台物理服务器上的一个或多个“备份”分区。然后,所有分区将同时开始处理同一任务。这意味着,如果一个节点死亡,则在群集中的其他节点上会存在该分区的可行且最新副本,数据库将以最小的时间损失和机上交易损失,重新启动。2.如果应用程序服务器出现故障,该怎么办?只要客户可以使用正确的锁标识符找我们,我们的处理将照常进行。在传统的 RDBMS 中,当涉及到锁定时,状态将有效地保留在客户端和服务器上,因为服务器已使用客户端会话唯一的标识符标记行。但是,如果客户端销户,则该会话将无效。这意味着您需要等待服务器将数据库连接标识为过去状态并结束它,然后其他人才能修改该记录。在 VoltDB 的系统里,我们通过允许多个 SQL 语句和关联的逻辑在服务器上运行,来“设计”大多数应用场景。如果逻辑交易在关联的交易事件完成之前依然无法完成,您可以使用简单的 SQL 自行锁定逻辑,从而重新控制情况并满足您的 SLAs 。3.VoltDB 是否会自动执行此操作?不会,但是它在数据库表中多了两列,并增加了大约十二行代码。与处理传统 RDBMS 或 NoSQL 交易和锁定行为所需的开发人员时间相比,这是完全合理的。

4.我们仍然可以使用 JDBC 吗?

是的,我们的许多应用程序代码是基于 JDBC 的。在大多数应用程序中,20% 的开发人员时间用于编写 80% 的 SQL,这些 SQL 是友好的或直接的。其他 20% 涉及复杂的交易,正是这种方法使其变得非常有价值。5.“每个内核一个分区一个线程”为何比共享工作负载的多线程和多内核更快?乍一看,似乎任何核心能够处理任何问题看起来是最佳选择。但是,正如我们上面讨论的那样,随着您线性地添加多个内核,协调多个内核活动所需的努力会以几何方式升级。而将事务强制进入虚拟队列并让每个队列进行单个线程。这个过程要高效得多。

5 结论

锁定和读取一致性是当今世纪的两个重要领域,RDBMS 和较新的 NoSQL 系统都无法满足其需求,提供合理答案。在 VoltDB,我们的使命是专注于可预测的、符合严苛标准的大规模交易。虽然我们理解我们的一些设计决策可能看起来非常规,但这些决策却是由多年的实际经验决定的。如果您还有其他疑问,或者想了解更多有关 VoltDB 如何在保持低延迟的情况下支持现代应用程序的信息,请联系我们吧!

关于 VoltDBVoltDB 支持强 ACID 和实时智能决策的应用程序,以实现互联世界。没有其它数据库产品可以像 VoltDB 这样,可以同时需要低延时、大规模、高并发数和准确性相结合的应用程序加油。VoltDB 由 2014 年图灵奖获得者 Mike Stonebraker 博士创建,他对关系数据库进行了重新设计,以应对当今不断增长的实时操作和机器学习挑战。Stonebraker 博士对数据库技术研究已有 40 多年,在快速数据,流数据和内存数据库方面带来了众多创新理念。在 VoltDB 的研发过程中,他意识到了利用内存事务数据库技术挖掘流数据的全部潜力,不但可以满足处理数据的延迟和并发需求,还能提供实时分析和决策。VoltDB 是业界可信赖的名称,在诺基亚、金融时报、三菱电机、HPE、巴克莱、华为等领先组织合作有实际场景落地案例。

VoltDB 中国:https://www.voltdb-china.cn/

用户头像

VoltDB

关注

VoltDB以及数据库应用场景知识库 2020.11.02 加入

VOLTDB诞生作为支持云端部署的内存数据库,并在持续增强流计算能力,原生分布式架构提供了可伸缩性,同时完全满足ACID要求,数据安全可靠,是由2014图灵奖得主Mike Stonebraker博士领导全新设计的架构。

评论

发布
暂无评论
深度剖析 | 关于数据锁定和读取一致性问题