知识库

限制 Bolt 请求

当大量数据在 Neo4j 数据库和客户端之间传输时(通常是大型查询结果,从服务器到客户端),可能会涉及到一些隐藏的节流机制。

TCP 节流

客户端与 Neo4j 服务器之间的 Bolt 连接通过 TCP 传输。

客户端接收窗口

TCP 尝试调整发送的数据量,以免客户端过载。客户端确实需要处理接收到的数据,这可能需要时间,并可能导致读取缓冲区填充速度快于其清空速度。

它是如何工作的?每次客户端确认接收数据时,它都会发送一个 TCP ACK,其中包含其读取缓冲区的当前可用容量。这被称为“接收窗口”。

当捕获流量(例如使用 tcpdump)并在 Wireshark 等工具中打开捕获文件时,接收窗口会显示为 ACK 中的属性“WIN”。该值最高可达 65536。要将其转换为字节数,请将该值乘以“窗口缩放因子”,您可以在初始 TCP 连接三向握手(SYN/SYN-ACK/ACK)中找到该因子,其属性为“WS”。

服务器将使用该接收窗口来调节其发送的数据量。它会跟踪“在途”数据(已发送但尚未确认)的数量,并通过降低数据发送速率来确保数据量永远不会超过接收窗口。如果客户端的接收窗口变为零(Wireshark 将这些 ACK 标记为 TCP ZeroWindow),服务器将停止发送并等待其再次增加(客户端随后发送 TCP 窗口更新以表示增加)。

拥塞窗口

TCP 还会根据拥塞情况调整传输速率。服务器维护一个拥塞窗口。该窗口从较小的值(网络 MTU 的小数倍)开始,并稳步增加,直到发生丢包。发生丢包时,拥塞窗口会减半(通常如此,但减少量因不同的拥塞避免算法而异),然后恢复稳步增加。TCP 的实际发送速率取决于客户端接收窗口和拥塞窗口中的最小值。

Bolt 服务器节流

除了 TCP 自身的节流外,Neo4j Bolt 服务器还会对其写入缓冲区的数据写入速率进行节流。

这由以下配置参数控制

unsupported.dbms.bolt.outbound_buffer_throttle=true
unsupported.dbms.bolt.outbound_buffer_throttle.high_watermark=512k
unsupported.dbms.bolt.outbound_buffer_throttle.low_watermark=128k
unsupported.dbms.bolt.outbound_buffer_throttle.max_duration=15min

当写入缓冲区填充到高水位时,写入将暂停。当 Bolt 服务器等待时,它会收到来自客户端的 ACK,这些 ACK 允许它从写入缓冲区中删除相应的数据。服务器每秒轮询缓冲区,检查是否已达到低水位。达到低水位时,它会恢复写入。

关于超时的说明

配置参数 `unsupported.dbms.bolt.outbound_buffer_throttle.max_duration` 控制连接可以被节流的最大时间量。当达到该时间时,客户端将返回一个异常:“Bolt 连接 [%s] 将被关闭,因为客户端在 %s 时间内没有消耗出站缓冲区,这并非预期行为。”

该超时可能会干扰事务超时(`dbms.transaction.timeout`)。当事务超时低于节流超时时,节流暂停可能会延迟超时事务终止的时间,这可能使其看起来像是事务超时被超出。

如何判断 Bolt 节流正在发生?

线程转储是您最佳的查看方式,因为在节流触发时日志中没有条目。通常认为对于结果集相对于高水位线(1MB 以上)较大的查询,这种情况确实会发生,因为结果的消费很可能比生成慢,并且出站缓冲区会迅速填满。

© . All rights reserved.