Cassandra 文档

版本

您正在查看预发布版本的文档。

查看最新版本

改进的节点间消息传递

Apache Cassandra 4.0 在节点间消息传递方面添加了一些新的改进。

优化的节点间消息传递协议

节点间消息传递协议已优化 (CASSANDRA-14485)。以前,即使在建立初始连接/会话时已发送过一次 IPAddressAndPort,发送的每条消息中都会包含发送者的 IPAddressAndPort。在 Cassandra 4.0 中,IPAddressAndPort 已从发送的每条单独消息中删除,仅在启动连接/会话时发送。

另一个改进是,在几个实例(列出)中,固定 4 字节整数值已被 vint 替换,因为 vint 几乎总是小于 1 字节

  • paramSize(标头中的参数数量)

  • 每个单独的参数值

  • payloadSize

NIO 消息传递

在 Cassandra 4.0 中,点对点(节点间)消息传递已通过 Netty (CASSANDRA-8457) 切换到非阻塞 I/O (NIO)。

作为序列化格式,每条消息都包含一个标头,其中包含几个固定字段,一个可选的键值参数部分,以及消息有效负载本身。注意:标头中的 IP 地址可以是 IPv4(4 字节)或 IPv6(16 字节)。

下图显示了 IPv4 地址,以简明起见。

1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 6 6
0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       PROTOCOL MAGIC                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Message ID                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Timestamp                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Addr len |           IP Address (IPv4)                       /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/           |                 Verb                              /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/           |            Parameters size                        /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/           |             Parameter data                        /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Payload size                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               /
/                           Payload                             /
/                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

单个参数具有一个字符串键和一个字节数组值。键与其长度一起序列化,编码为两个字节,后跟字符串的 UTF-8 字节编码。主体与其长度一起序列化,编码为四个字节,后跟值的字节。

排队消息的资源限制

通过对排队出站消息的数量(以消息的 serializedSize 衡量)实施严格的资源限制 (CASSANDRA-15066),提高了系统稳定性。同时实施了三个独立的限制,以确保在任何合理的故障组合情况下都能始终取得进展,而不会影响节点的稳定性。

  1. 对排队以供传递到其他节点的消息以及等待从集群中的其他节点到达并进行处理的消息,实施全局、每个端点和每个连接限制。这些限制适用于发送或接收的消息的在线大小。

  2. 基本每个链接限制在实施任何端点或全局限制之前单独使用。每个节点对都有三个链接:紧急、小和大型。任何给定节点最多可以有 N*3 * (internode_application_send_queue_capacity in bytes + internode_application_receive_queue_capacity in bytes) 的消息数据排队,而它们之间没有任何协调,尽管在实践中,使用令牌感知路由,只有 RF*tokens 节点需要与重要的带宽进行通信。

  3. 每个端点限制对超过每个链接限制的所有消息实施,同时与全局限制一起,对集群中单个节点的所有链接实施。全局限制对超过每个链接限制的所有消息实施,同时与每个端点限制一起,对集群中任何节点的所有链接实施。以下配置设置已添加到 cassandra.yaml 中,用于排队消息的资源限制。

internode_application_send_queue_capacity: 4MiB
internode_application_send_queue_reserve_endpoint_capacity: 128MiB
internode_application_send_queue_reserve_global_capacity: 512MiB
internode_application_receive_queue_capacity: 4MiB
internode_application_receive_queue_reserve_endpoint_capacity: 128MiB
internode_application_receive_queue_reserve_global_capacity: 512MiB

用于消息传递指标的虚拟表

通过使用虚拟表保存节点间入站和出站消息传递的指标 (CASSANDRA-15066),改进了指标。对于入站消息传递,已添加了一个虚拟表 (internode_inbound) 来保存以下指标:

  • 由于错误而无法序列化或刷新消息的字节数和数量

  • 已安排的消息的字节数和数量

  • 成功处理的消息的字节数和数量

  • 成功接收的消息的字节数和数量

  • 被节流的消息的纳秒数和数量

  • 已过期消息的字节数和数量

  • 已恢复和未恢复的损坏帧

已为出站节点间消息传递添加了一个单独的虚拟表 (internode_outbound)。出站虚拟表保存以下指标:

  • 待处理消息的字节数和数量

  • 已发送消息的字节数和数量

  • 已过期消息的字节数和数量

  • 由于错误而无法发送的消息的字节数和数量

  • 过载消息的字节数和数量

  • 活动连接数

  • 连接尝试次数

  • 成功连接尝试次数

提示消息传递

已添加一个专门版本的提示消息,该消息采用已编码为 ByteBuffer 的提示并逐字发送。当将当前消息传递版本的提示文件分派到具有相同消息传递版本的节点时,这是一个优化,这是最常见的情况。它节省了额外的 ByteBuffer 分配,一个冗余的提示反序列化-序列化循环。

节点间应用程序超时

已在 cassandra.yaml 中添加了一个配置设置,用于连接在应用程序空间中不可写入的最大持续时间。

# internode_application_timeout_in_ms = 30000

其他一些新功能包括记录消息大小以跟踪消息以跟踪查询。

针对本地请求优化的 Paxos 准备和提议阶段

在 4.0 之前的版本中,即使请求要本地服务,Paxos 准备和提议消息始终在 Cassandra 中通过整个 MessagingService 堆栈,我们可以增强并使本地请求在不涉及 MessagingService 的情况下进行服务。Cassandra 中的其他地方也做了类似的事情,这些地方跳过了本地请求的 MessagingService 阶段。

如果我们在 4.0 之前启用了跟踪并运行了一个轻量级事务,则它看起来像这样

Sending PAXOS_PREPARE message to /A.B.C.D [MessagingService-Outgoing-/A.B.C.D] | 2017-09-11
21:55:18.971000 | A.B.C.D | 15045
… REQUEST_RESPONSE message received from /A.B.C.D [MessagingService-Incoming-/A.B.C.D] |
2017-09-11 21:55:18.976000 | A.B.C.D | 20270
… Processing response from /A.B.C.D [SharedPool-Worker-4] | 2017-09-11 21:55:18.976000 |
A.B.C.D | 20372

提议阶段也是如此。

在 4.0 版本中,针对本地请求优化的 Paxos 准备和提议阶段 (CASSANDRA-13862)。

质量保证

在 4.0 版本中 (CASSANDRA-15066),进行了一些其他质量保证改进。

4.0 版本将帧引入所有节点间消息,即,将消息分组到具有标头和尾部的单个逻辑有效负载中;这些帧保证最多包含一条消息,该消息被拆分为其自己的唯一帧序列(对于大型消息),或者帧仅包含完整消息。

防止损坏

以前,默认情况下,数据中心内部的节点间消息不受损坏保护,因为只有 LZ4 提供了任何完整性检查。所有发送到 4.0 后节点的消息都写入显式帧,这些帧可以是

  • LZ4 编码

  • CRC 保护

未保护选项仍然可用。

弹性

为了提高弹性,所有帧都使用单独的 CRC 保护标头写入,分别为 8 字节和 6 字节。如果此标头发生损坏,则必须像以前一样重置连接。如果在标头之外的任何地方发生损坏,则会跳过损坏的帧,保持连接完整,并避免不必要地丢失任何消息。

以前,流中的任何问题都会导致连接重置,并导致任何正在传输的消息丢失。

效率

入站和出站消息的总体内存使用量和字节混洗次数都减少了。

出站 Netty LZ4 编码器维护一个块大小缓冲区 (64KiB),在生成任何压缩帧之前,该缓冲区会被填充。我们的帧编码器避免了这种冗余复制,并释放了每个端点 192KiB。

入站,帧解码器保证仅复制解析帧所需的字节数,并且绝不存储超过必要的字节数。此改进对 LZ4 连接应用了两次,改进了消息解码和 LZ4 帧解码。

入站路径

4.0 版本对入站路径进行了一些改进。

根据在标志中设置的特定连接上是否预期大小消息,使用适当的消息处理程序。NonblockingBufferHandler 在事件循环中运行,用于处理小消息,而 BlockingBufferHandler 在事件循环之外运行,用于处理大消息。InboundMessageHandler 的单个实现通过从字节流中推导出传入消息的大小,有效地处理任何大小的消息。除了从流中推导出消息的大小之外,在尝试反序列化整个消息之前,会主动读取传入消息的过期时间。如果在遇到消息时它已过期,则该消息将完全跳过字节流。如果消息在接收方仍然无法反序列化 - 例如,由于表 ID 或列未知 - 字节将被跳过,而不会丢弃整个连接并丢失所有缓冲的消息。立即将失败原因的回复发送回协调器节点,而不是等待协调器回调过期。此逻辑扩展到损坏的帧;损坏的帧将被安全地跳过,而不会丢弃连接。

入站路径对内存利用率施加严格的限制。具体来说,所有已解析但未处理的消息所占用的内存是有限制的 - 在每个连接、每个端点和全局基础上。一旦连接超过其本地未处理容量并且无法从每个端点和全局预留中借用任何许可证,它就会简单地停止处理更多消息,提供自然的背压 - 直到重新获得足够的容量。

出站连接

打开连接

对所有类型的连接失败采用一致的方法,包括:被端点拒绝、版本不兼容或意外异常;

  • 无限期重试,直到成功或没有消息等待传递。

  • 在重新连接之前等待越来越长的时间,最长 1 秒。

  • 在连接失败时,不会获取任何预留队列限制。

关闭连接

  • 正确地清空等待传递的出站消息(除非断开连接并且无法重新连接)。

  • 写入关闭连接的消息要么被传递,要么被拒绝,如果旧连接被不可逆转地关闭,则会打开新的连接。

  • 未使用的连接最终会被修剪。

重新连接

我们有时需要重新连接一个完全有效的连接,例如,如果首选 IP 地址更改。我们确保底层连接在关闭和重新连接之前没有进行中的操作。

消息失败

立即传播到回调,通过回收已提交的内存更好地防止过载。

过期
  • 不再遇到行首阻塞(例如,不可丢弃的消息阻止所有可丢弃的消息过期)。

  • 在过载时,会在入队线程上积极尝试过期。

  • 在断开连接时,我们会安排定期修剪,以处理不再发送消息但我们有大量积压要过期的这种情况。

过载
  • 通过排队的字节数进行跟踪,而不是消息数。

序列化错误
  • 不会导致连接失效;消息只是完成失败,然后从帧中删除。

  • 包括检测到计算出的序列化大小与实际大小不匹配。

无法刷新到网络,可能是因为连接已重置,目前不会通知回调处理程序,因为必要的信息已被丢弃,尽管如果我们决定这样做值得我们付出,将来可以这样做。

QoS

"Gossip" 连接已被通用 "Urgent" 连接取代,用于影响系统稳定性的任何小消息。

指标

我们跟踪并通过虚拟表和 JMX 公开以下消息和字节数:由于错误而无法序列化或刷新,由于过载或超时而丢弃,正在挂起以及已成功发送。

添加了消息大小限制

Cassandra 4.0 之前的版本无法保护服务器免受为节点间消息对象分配巨大缓冲区的攻击。添加消息大小限制将有助于处理诸如集群参与者故障等问题。4.0 版本引入了类似于最大变异大小的最大消息大小配置参数 - 默认情况下设置为端点预留容量。

在反序列化节点间消息时从未知表中恢复

如 (CASSANDRA-9289) 中所述,从另一个节点的消息中看到未知表时能够优雅地恢复会很好。4.0 之前的版本,我们会关闭连接并重新连接,这会导致其他并发查询失败。4.0 版本通过使用 TrackedDataInputPlus 包装消息流,捕获 UnknownCFException 并跳过此消息中的剩余字节来解决此问题。TCP 不会关闭,它将保持连接以处理其他消息。