跳转到内容

配置丢包注入

丢包注入是在生产环境替你完成之前,主动给恢复路径施压的手段。Java media driver 允许你在 JVM 启动时通过系统属性把丢包率固化进 driver——确定且可复现,这正是自动化测试和 CI 所需要的。

本页讲的是如何接好这种静态丢包注入并读出其效果。至于 Aeron 究竟如何检测间隙并完成重传,请参阅 The Aeron Files。关于同一套 io.aeron.driver.ext 机制以及 CUBIC 拥塞控制,参见 丢包注入与 CUBIC 拥塞控制

在 JVM 启动时设置丢包参数。这些属性由 DebugChannelEndpointConfiguration 消费。

只设这些 rate 属性是不够的——默认的 channel endpoint 从不查询丢包生成器。你必须先换上 debug endpoint,这是每一侧各自独立的属性:

Terminal window
-Daeron.ReceiveChannelEndpoint.supplier=io.aeron.driver.ext.DebugReceiveChannelEndpointSupplier
-Daeron.SendChannelEndpoint.supplier=io.aeron.driver.ext.DebugSendChannelEndpointSupplier
属性说明
aeron.debug.receive.data.loss.rate接收侧数据丢包率(0.0 - 1.0)
aeron.debug.receive.data.loss.seed接收侧数据丢包 RNG 的种子
aeron.debug.receive.control.loss.rate接收侧控制丢包率
aeron.debug.receive.control.loss.seed接收侧控制丢包 RNG 的种子
aeron.debug.send.data.loss.rate发送侧数据丢包率
aeron.debug.send.data.loss.seed发送侧数据丢包 RNG 的种子
aeron.debug.send.control.loss.rate发送侧控制丢包率
aeron.debug.send.control.loss.seed发送侧控制丢包 RNG 的种子

你由此获得四个相互独立的丢包旋钮:发送/接收与数据/控制的交叉组合。最有意思的测试往往来自非对称配置。

让丢包注入更贴近真实的四个设计要点

Section titled “让丢包注入更贴近真实的四个设计要点”

整个框架建立在四项有意为之的设计决策之上。

1. 数据丢包与控制丢包相互独立

Section titled “1. 数据丢包与控制丢包相互独立”

数据包与控制包(状态消息、NAK、RTT)拥有各自独立的丢包生成器。这让你能够测试”数据能通过,但 NAK 丢失”的场景。该场景考验的是:当系统的恢复机制本身受损时,它还能否恢复。

2. 两种丢包模型——随机 rate vs. 编排间隙

Section titled “2. 两种丢包模型——随机 rate vs. 编排间隙”

上面的 *.loss.rate 属性接的是 RandomLossGenerator,它逐帧的判定就是 random.nextDouble() <= lossRate。它具备重传感知:在给定 rate 下,它会以同样的 rate 丢掉重传帧——这对有损链路是真实的,但意味着高 rate 会让重传不断累积。

这个包还提供了 FixedLossGeneratorMultiGapLossGenerator,它们确实具备重传感知:按 stream 和 session 跟踪哪些帧已经被丢弃,并放行其重传。若没有这一点,“丢弃第 42 号帧”的规则也会把第 42 号帧的重传一并丢掉——从而制造出无法恢复的间隙和无限的重传循环。但系统属性这套机制从不实例化这两者——它们用于编程式搭建(例如 JavaTestMediaDriver)。需要均匀随机丢包时用这些属性;需要编排好的、具备重传感知的间隙模式时,走编程式路径。

每个随机丢包生成器都接受一个种子。固定的种子意味着相同的丢包模式,也就意味着相同的测试结果。正是这一点让那些看似不稳定的测试变得可复现——这对 CI/CD 至关重要,因为你需要一致的通过/失败行为。

调用 dontCoalesceNaksOnReceiverByDefault() 即可将 NAK 延迟设为零。NAK 会被立即发送,而不必等待合并窗口。这能在不改变丢包行为的前提下,加快测试中的重传速度。

下面这四个计数器能告诉你:系统如何检测丢包、如何恢复,以及为此付出了多大代价。

计数器它告诉你什么
NAK messages sent/received丢包发生时会出现尖峰——反映检测速度
Retransmits sent反映恢复活动——有多少带宽用于恢复
Publisher pos vs Subscriber pos丢包下间隙增大——反映 subscriber 落后了多远
Bytes sent/received吞吐影响——量化丢包的代价

丢包如何映射到 p50、p99 与吞吐量

Section titled “丢包如何映射到 p50、p99 与吞吐量”

丢包注入会撼动这三个数字,但程度并不均衡。

  • 吞吐量受到的冲击最为直接。重传发送与新鲜数据争抢同一份带宽,而 bytes sent/received 计数器会实时量化这一代价。
  • p99 与长尾最先被拉长。一个被丢弃的帧会让 subscriber 停滞,直到检测与重传完成。NAK 检测速度和合并窗口决定了这一停滞持续多久——这也正是 dontCoalesceNaksOnReceiverByDefault() 能缩短它的原因。
  • p50 在低丢包率下相对稳定,因为大多数消息一次就能送达。只有当丢包率攀升到足以影响中位投递时,它才会劣化。