软件运行速度为何仍然缓慢?这个看似简单的问题困扰着整个行业十年之久。即便硬件已从统一内存架构演进到能在笔记本上运行百亿参数模型的神经引擎,简单 Serverless 函数的冷启动仍需数秒,CSV 转数据库的 ETL 管道仍需数小时。2011 年,一位高频交易工程师 Martin Thompson 给出了答案:缺乏「机械亲和性」(Mechanical Sympathy)。这一理念源自 F1 世界冠军 Jackie Stewart 的名言 —— 不必成为工程师才能成为车手,但需要机械亲和性。将其应用到软件领域,意味着编写与硬件特性相契合的代码,能够构建出性能惊人的系统。LMAX 架构正是凭借这一理念,在单条 Java 线程上实现了每秒百万级事件处理。
内存层次结构与访问延迟
机械亲和性的根基在于理解 CPU 如何存储、访问和共享内存。现代 CPU 从 Intel 芯片到 Apple Silicon,均采用分层存储架构,各层在访问延迟上存在数量级差异。每个 CPU 核心拥有独立的高速寄存器和缓冲区,用于存储局部变量和执行中的指令。L1 缓存容量比寄存器大许多,但访问速度稍慢;L2 缓存更大,作为 L1 与 L3 之间的缓冲;L3 缓存在所有核心间共享,容量最大但速度最慢。最终,所有核心共享访问主存 RAM,其延迟比 L1 或 L2 缓存慢一个数量级。由于 CPU 缓冲区容量极小,程序频繁需要访问较慢的缓存层级或主存。为隐藏访问成本,CPU 实际上在进行一场概率游戏:近期访问的内存很可能再次被访问,邻近内存也可能很快被访问,访问模式往往具有规律性。线性访问的性能远优于同页内的随机访问,而跨页随机访问的性能最差。
缓存行对齐与伪共享
在 L1、L2、L3 缓存中,内存以「块」形式存储,称为缓存行。缓存行长度固定为 2 的幂,通常为 64 字节。CPU 始终以缓存行的整数倍进行读取或写入,这引出了一个微妙问题:当两个 CPU 写入同一缓存行中的两个独立变量时,会发生什么?这就是伪共享 —— 两个 CPU 争夺同一缓存行中两个不同变量的访问权,迫使它们通过共享的 L3 缓存轮流访问这些变量。许多低延迟应用通过填充空数据来隔离缓存行,使每行仅包含一个变量。有无填充的差异惊人:不使用填充时,缓存行伪共享导致延迟随线程数近似线性增长;使用填充后,延迟几乎恒定。值得注意的是,伪共享仅在变量被写入时才会出现。读取时,每个 CPU 可将缓存行复制到本地缓存或缓冲区,无需与其他 CPU 同步状态。原子变量是多线程应用中伪共享的常见受害者,因为它是少数可安全共享且可修改的数据类型之一。在追求多线程应用最终一点性能时,需检查是否存在多线程写入的数据结构,以及该结构是否可能成为伪共享的牺牲品。
单写者原则与异步 Actor 架构
伪共享并非多线程系统的唯一难题。还存在安全性和正确性问题(如竞态条件)、线程数超过 CPU 核心时的上下文切换成本,以及互斥锁的残酷开销。这些观察引出了最常用的机械亲和性原则:单写者原则。概念很简单:如果应用需要写入某些数据(如内存变量)或资源(如 TCP _socket),所有写入应由单个线程完成。以一个接收文本并生成向量嵌入的 HTTP 服务为例,大部分 AI 运行时同时只能执行一次模型推理调用。在朴素架构中使用互斥锁解决此问题会导致请求排队,引发队头阻塞。通过重构应用单写者原则,可将模型访问封装到专用 Actor 线程中,其他线程通过异步消息提交写入。由于 Actor 是单一写者,它可将独立请求合并为单次批量推理调用,然后异步将结果返回给各个请求线程。这种设计完全避免了互斥锁,实现了自然批处理优化。
自然批处理策略
使用单写者原则消除了简单 AI 服务中的互斥锁问题,并添加了批量推理调用支持。但 Actor 应如何创建这些批次?如果等待达到预定批量大小,请求可能无限期阻塞直到足够请求到达;如果按固定间隔创建批次,请求将在每次批次间受到有界延迟。有一种策略优于两者:自然批处理。 Actor 一旦队列中有请求便开始创建批次,并在达到最大批量大小或队列为空时完成批次。以超时为基础的批处理策略,假设超时时间为 100 微秒,当批次中所有请求同时到达时,最佳延迟为 200 微秒(请求本身 100 微秒加上等待更多请求的 100 微秒),最差延迟为 400 微秒。而自然批处理策略的最佳延迟为 100 微秒,最差延迟为 200 微秒。无论哪种情况,自然批处理的性能都是超时策略的两倍。
实践建议
这些原则不仅适用于单个应用,也能扩展到整个系统。顺序可预测的数据访问适用于大数据湖和内存数组。单写者原则可提升 IO 密集型应用的性能,或为 CQRS 架构提供坚实基础。编写具有机械亲和性的软件,性能会自然随之而来。但在行动之前,需优先考虑可观测性再优化。在应用这些原则前,定义 SLI、SLO 和 SLA,明确关注点和停止时机。
资料来源:Martin Fowler《Principles of Mechanical Sympathy》