【发布时间】:2015-04-05 14:07:45
【问题描述】:
原子批处理如何保证单个批处理中的所有语句都将被执行或不执行?
【问题讨论】:
原子批处理如何保证单个批处理中的所有语句都将被执行或不执行?
【问题讨论】:
为了了解批处理如何在后台工作,查看批处理执行的各个阶段会很有帮助。
客户
使用 CQL3 或现代 Cassandra 客户端 API 支持批处理。在每种情况下,您都可以指定要作为批处理的一部分执行的语句列表、用于所有语句的一致性级别和可选的时间戳。您将能够批量执行 INSERT、DELETE 和 UPDATE 语句。如果您选择不提供时间戳,则会自动使用当前时间并与批次相关联。
客户端必须处理两个异常以防批处理无法成功执行。
writeType 值(BATCH_LOG 或BATCH)来检查。 批处理日志阶段失败的写入将由 Java 驱动程序中的 DefaultRetryPolicy 自动显示为 retried once。批处理日志的创建对于确保在协调器在操作中途失败的情况下始终完成批处理至关重要。继续阅读以找出原因。
协调员
客户端发送的所有批次都将由协调器执行,就像任何写操作一样。与普通写入操作不同的是,Cassandra 还将使用一个专用日志,该日志将包含当前执行的所有待处理批处理(称为批处理日志)。此日志将存储在本地系统密钥空间中,并由每个节点单独管理。每个批处理执行首先在除了协调器之外的两个节点上创建一个包含完整批处理的日志条目。在协调器能够在其他节点上创建批处理日志后,它将开始执行批处理中的实际语句。
批处理中的每个语句都将使用整个批处理的 CL 和时间戳写入副本。除此之外,此时发生的写入并没有什么特别之处。写入也可能会被提示或抛出 WriteTimeoutException,这可以由客户端处理(见上文)。
批处理执行后,可以安全地删除所有创建的批处理日志。因此,coordinator 将在成功执行后向之前接收到 batchlog 的节点发送 batchlog 删除消息。这发生在后台,如果失败,将不会被注意到。
让我们总结一下协调器在批处理执行期间所做的事情:
批处理日志副本节点
如上所述,批处理日志将在批处理执行之前跨两个其他节点(如果集群大小允许)复制。这个想法是,这些节点中的任何一个都将能够拿起待处理的批次,以防协调器在完成批次中的所有语句之前停机。
让想法有点复杂的是,这些节点不会注意到协调器不再活着。使用批处理执行的当前状态更新批处理日志节点的唯一点是协调器发出删除消息,指示批处理已成功执行。如果这样的消息没有到达,批处理日志节点将假定由于某些原因该批处理尚未执行,并从日志中重播该批处理。
批处理日志重播可能每分钟都会发生,即。这是一个节点将检查本地批处理日志中是否有尚未被-可能被杀死-协调器删除的待处理批处理的时间间隔。为了在批处理日志创建和实际执行之间给协调器一些时间,使用了固定的宽限期(write_request_timeout_in_ms * 2,默认为 4 秒)。如果 4 秒后批处理日志仍然存在,它将被重播。
就像 Cassandra 中的任何写操作一样,可能会发生超时。在这种情况下,节点将回退为超时操作写入提示。当超时的副本将再次启动时,可以从提示中恢复写入。无论是否启用hinted_handoff_enabled,此行为似乎都不会受到影响。还有一个与提示关联的 TTL 值,这将导致提示在较长一段时间后被丢弃(对于任何涉及的 CF,最小的 GCGraceSeconds)。
现在您可能想知道在两个节点上同时重放批处理是否没有潜在危险,如果我们在两个节点上复制批处理日志可能会发生这种情况。这里要记住的重要一点是,由于受支持的操作(更新和删除)类型有限以及与批处理相关的固定时间戳,每个批处理执行都是幂等的。即使两个节点和协调器同时重试执行批处理也不会有任何冲突。
原子性保证
让我们回到“原子批次”的原子性方面,并回顾一下原子的确切含义 (source):
"(请注意,我们指的是数据库意义上的“原子”,如果任何部分 批次成功,一切都会。不暗示任何其他保证; 特别是没有隔离;其他客户将能够 从批次中读取第一个更新的行,而其他行在 进步。”
所以从某种意义上说,我们得到了“全有或全无”的保证。在大多数情况下,协调器只会将批处理中的所有语句写入集群。但是,在写入超时的情况下,我们必须通过读取writeType 值来检查超时发生的时间点。该批次必须已写入批处理日志,以确保这些保证仍然适用。同样在这一点上,其他客户端也可以从批处理中读取部分执行的结果。
回到这个问题,Cassandra 如何保证批处理中的所有语句或根本不执行语句? 原子批处理基本上依赖于成功的复制和幂等语句。这不是 100% 保证的解决方案,因为理论上可能存在 scenarios 仍然会导致不一致。但是对于 Cassandra 中的许多用例,如果您知道它是如何工作的,那么它是一个非常有用的工具。
【讨论】:
批处理文档(doc):
在 Cassandra 1.2 及更高版本中,批处理默认是原子的。在 Cassandra 批处理操作的上下文中,原子意味着如果任何批处理成功,那么所有批处理都会成功。为了实现原子性,Cassandra 首先将序列化批处理写入批处理日志系统表,该系统表将序列化批处理作为 blob 数据使用。当批处理中的行已成功写入并持久化(或提示)后,将删除批处理日志数据。原子性会降低性能。如果您不想招致此惩罚,请使用 UNLOGGED 选项阻止 Cassandra 写入批处理日志系统:BEGIN UNLOGGED BATCH
【讨论】:
Cassandra 批次:-
http://docs.datastax.com/en/cql/3.1/cql/cql_reference/batch_r.html
要添加到上述答案:- 使用 Cassandra 2.0,您可以编写批处理语句 + LWT。但限制是所有 DML 必须在同一个分区上
【讨论】: