Somtochi Onyekwere:将协议逻辑与 I/O 分离,实现确定性测试

原标题Somtochi Onyekwere: Separate Protocol Logic from I/O for Deterministic Tests

Sans I/O 设计让本地模拟器可以使用虚拟时间和受控故障运行数千个协议状态。

SOSomtochi Onyekwere讲者 · Fly.io
频道
GOTO Conferences
发布
2026年10月30日
视频
20:04
阅读
5 分钟
幻灯片
4
原文
英语
在 YouTube 打开
往下滚动阅读时,视频会缩到右下角继续播放。字幕跟随阅读语言。
阅读语言共 2 种语言可读
由 AI 从英语原文翻译。打开“对照原文”可以逐段核对。
摘要

30 秒看懂

Fly.io 工程师 Somtochi Onyekwere 介绍如何将 Corrosion 的 Plumtree 广播逻辑与套接字、定时器和随机性分离。调用方提供运行时,使确定性模拟成为可能;生产集成仍需另行测试。

  1. 1输入事件,输出动作协议处理事件,并将消息发送与定时器交给调用方。
  2. 2本地集群模拟按时间排序的事件堆在一个进程中驱动约 2000 个节点状态。
  3. 3故障也是事件测试可以让节点下线、丢弃消息,再在之后恢复节点。
  4. 4仍需测试集成即使协议正确,周边运行时处理副作用的方式不正确仍可能导致失败。

要点建议

  1. 分布式协议面临消息交付、时间和节点故障带来的非确定性。
  2. 协议状态机可以接收事件并请求副作用,而不必拥有套接字或时钟。
  3. 事件堆和虚拟时间可以在本地模拟大量节点。
  4. 注入随机性和故障可以让场景复现。
  5. 测试协议核心不能取代对生产集成的测试。
全文

按章节阅读整理后的全文

只看原始文稿
01

分布式协议为何难以测试

网络、定时器和节点故障引入非确定性,而大型集成环境成本高昂。

我在 Fly.io 从事分布式系统和网络软件开发。这次演讲讨论如何组织分布式协议,让我们能够进行确定性测试,并在部署前更有信心地确认协议正常工作。

分布式系统难以测试,因为许多节点需要通过网络协调。消息可能延迟、乱序或丢失,定时器会触发,节点也可能不可用。即使发生这些故障,协议仍必须维持自己的假设。

大型集成测试运行成本高,也难以复现。拥有数千节点的集群涉及大量进程,而下一次运行时事件顺序可能不同。规模和非确定性都会增加故障排查难度。

02

将协议与副作用分离

协议接收事件并请求动作,由调用方提供运行时。

我们在修改 Fly.io 使用的开源 SQLite 复制系统 Corrosion 的广播协议时发现,论文中的协议本身相对简单。我们希望保留这个小型核心,同时能轻松改变条件、复现故障并复用实现。

协议代码经常将逻辑与线程创建、消息发送和定时器混在一起。如果实现内部会休眠,测试可能也不得不等待,从而带来不稳定。我们希望把这些副作用移到协议之外,建立清晰的边界,让测试可以替换运行环境。

输入事件,输出动作
幻灯片 1 / 4输入事件,输出动作状态机接收事件,由环境执行发送和调度。

我们的模型将协议视为状态机。它接收消息、节点上线或定时器触发等事件,并指出接下来应执行的动作。协议本身不拥有套接字或时钟;调用方决定如何发送消息和安排定时器。

这里的例子是 Plumtree,一个在集群中广播的 gossip 协议。节点向 eager peers 发送完整消息,后者继续转发。lazy peers 接收消息标识,必要时可以请求缺失的内容,作为回退路径。

在 Corrosion 中,广播请求等输入会交给 Plumtree 状态。协议可以要求调用方发送消息,或将内容交付给应用。调用方还负责提供时间,因此副作用都在核心逻辑之外。

一种可行的接口是返回所需动作的列表。我们选择使用由调用方实现的 trait,即接口。它暴露向节点或对等节点发送消息、交付内容、通知应用和安排定时器等副作用。

调用方提供的运行时
幻灯片 2 / 4调用方提供的运行时接口将网络、应用和时钟副作用暴露给调用方。

协议请求定时器后,由调用方负责安排。定时器触发时,调用方再把触发事件传回协议。消息也采用相同的分离方式:应用提供运行时,并决定如何执行副作用。

例如,Corrosion 会短暂缓冲消息,以便批量发送、提高效率。其他库使用者可以选择不同实现。集成层很小:只需提供接口,协议就会使用该环境。

03

模拟集群

本地事件队列和虚拟时间让多个节点状态运行起来,无需真实套接字或休眠。

这种边界对测试尤其有用,因为测试运行时可以与生产环境不同。生产环境可以使用线程和套接字;本地模拟则记录事件并将其排队,不需要真实网络,也不需要为每个模拟节点创建线程。

我们的测试用二叉堆按事件时间排序。一个循环取出最早的事件,将它应用到对应的协议状态,再把产生的消息、定时器或交付操作加入队列。映射表保存每个模拟节点的状态,使一台机器可以运行约 2000 个节点。

记录动作的运行时
幻灯片 3 / 4记录动作的运行时模拟器记录发送、定时器和交付操作,交由事件循环处理。

测试开始时,会选择一些节点在不同时间广播,并将这些事件加入队列。处理一次广播又可能产生更多发送、定时器请求和应用交付。循环不断处理后续事件,直到队列清空。

时间是虚拟的。模拟器不会等待真实定时器,而是跳到下一个事件的时间,并告诉协议定时器已经触发。这让一长串定时行为能够快速执行和重复。

04

故障与取舍

模拟可以注入故障、测量不同选择,但集成本身仍需要测试。

将网络行为表示为事件
幻灯片 4 / 4将网络行为表示为事件交付、定时器、节点故障和成员事件可以结合种子进行重放。

故障也是事件。测试可以让节点下线、丢弃发往该节点的消息、通知其他节点,并在之后恢复它。这样,我们就能检查协议对选定故障条件的响应。

我们还修改了 Plumtree,使它适应 Corrosion,因此需要测试修改带来的影响。论文采用的成员信息机制与我们的做法不同:在 Corrosion 中,节点知道完整成员列表。我们可以改变对等节点选择方式,例如是否偏向附近节点,并测量对广播交付时间的影响。

这种确定性测试使我们能够在上线前运行和重放协议行为。它不是多宇宙调试器,但提供了有用的本地模拟,以及系统地模拟外部副作用的方法。

这里有一个重要限制:测试协议核心并不能证明集成正确。如果调用方在发送时阻塞,可能无法及时将收到的消息传给协议。因此,周边集成仍需要自己的测试。

这种方法通常称为 Sans I/O。它不会消除复杂性,而是明确边界和责任。根据协议的不同,将请求的动作与副作用分离,可以让库更容易理解和复用。

我们还由应用注入随机性。生产环境使用操作系统的随机数,测试则使用带种子的随机源,使运行可复现。调用方必须提供环境并理解如何传入事件,因此设计增加了一些集成工作,但在我们的案例中,测试收益值得付出这些成本。

同频道的其他文章

7 张幻灯片40:04EN → 简体中文
GOTO Conferences· 2026年11月2日Sophia Drossopoulou:如何在开放世界中验证可信代码Sophia Drossopoulou · Imperial College London当可信代码调用未知对象时,能力、有作用域不变量和明确的信任假设有助于推理其影响。Code review & verificationProgramming LanguagesSoftware engineering
4 张幻灯片51:06EN → 简体中文
GOTO Conferences· 2026年11月2日Kent Beck:为人的需求构建 AI 编程工具Kent Beck“精灵”会放大健康或不健康的开发实践。Beck 呼吁工具保留学习、连接与未来选择。编程智能体Software engineeringDeveloper productivity+1
3 张幻灯片39:12EN → 简体中文
GOTO Conferences· 2026年10月28日Cate Huston:严谨如何支撑 AI 辅助开发的交付速度Cate Huston · Twill两人团队分享发布关口、自动检查、优先级和加快交付的成本。AI 工程管理Software engineeringAI agents
4 张幻灯片22:33EN → 简体中文
GOTO Conferences· 2026年10月26日William Schor:Netflix 如何从单元测试走向合成金丝雀William Schor · Netflix用生成的工作负载和接近生产的基础设施,测试分布式键值服务。Software engineering
5 张幻灯片34:11EN → 简体中文
GOTO Conferences· 2026年10月23日Anatoliy Bilenko 和 Alberto Carretero:用形式化方法和 AI 让数据库协议可靠Anatoliy Bilenko, Alberto Carretero · CanonicalCanonical 的数据库工程师把可执行规格、基于模型的测试、故障探索和重建的执行历史串起来,并说明为什么这些方法单独用,都无法证明真实系统正确。开发流程与测试Code review & verification可观测性与可靠性+2
28:15EN → 简体中文
GOTO Conferences· 2026年10月22日Steve Poole:开源安全与 AI 带来的维护挑战Olimpiu Pop, Steve Poole为什么漏洞发现加速会给维护者、依赖使用者和升级流程增加压力。Software engineeringAI security