在 Linux 内存管理(MM)与文件系统领域,Page Cache 预读(Readahead)一直以来都是决定 I/O 吞吐和应用响应延迟的核心机制之一。现有的内核预读算法主要依赖固定窗口策略(Fixed-window Approach),对于纯顺序读(Sequential Access)效果极佳,但面临复杂的交错模式、步长读取(Stride Access)或数据库访问模式时,传统的硬编码逻辑往往会显得力不从心。近期,开发者 Ayhan Aydin 向 linux-mm 邮件列表提交了一套 RFC Patch 补丁集([RFC PATCH 0/3] Neural Storage Driver - learning page cache prefetcher),试图引入一个名为 NSD (Neural Storage Driver) 的“自学习式”页缓存预读引擎。
NSD 的核心思想在于:不再仅靠线性窗口判断是否预读,而是让预读器具备“记忆”与“模式识别”能力。
根据补丁说明,NSD 在 4KB 区域粒度上记录文件访问模式。其内部构建了一个基于 “突触马尔可夫链(Synaptic Markov Chain)”的预测模型:
转移状态记录: 实时追踪文件内部不同页面区域之间的跳转与转移概率(Transitions between file regions)。
任意步长检测: 能够自动捕获并识别任意长度的跨步访问模式(Sequential strides of arbitrary length)。
主动预读触发: 当模型以高置信度预测出下一个将被访问的页面时,直接调用内核标准的page_cache_sync_readahead() 接口异步拉入页面。
高命中率表现: 在 SATA SSD 环境的测试中,NSD 对预测出的预读页面达到了 98% 的真实命中率(Real hit rate),大幅降低了无用预读带来的 I/O 放大与缓存污染。
实测性能:SQLite 查询提升 18.8%
作者在 x86_64 架构、SATA SSD 设备及 Linux 7.0.0 内核基础上,针对多种经典工作负载进行了 Benchmark
测试:
代码架构与 Patch 结构分析
本次 RFC 提交的代码体量非常精干,整个框架约 480 行代码,主要分为 3 个 Patch:
Patch 1/3: mm/filemap: Add NSD prefetch hook point (+5 lines)
Patch 2/3: nsd: Core prediction engine (fs/nsd/, ~480 lines)
Patch 3/3: Documentation: Add NSD documentation and MAINTAINERS entry
在机制实现上,NSD 目前采用了相对独立的模块化设计:在 mm/filemap.c 的核心入口 filemap_read()中嵌入了一个非常轻量级的钩子函数(Hook Point)。当应用程序发起读操作时,Hook 会抓取当前偏移量并送入 fs/nsd/ 中的预测引擎。
预测机制
结合 Ayhan Aydin 提交的 Patch 说明及代码实现框架,NSD的预测算法并非基于庞大昂贵的深度神经网络(如 Transformer 或 CNN),而是基于一种为内核热路径(Hot-path)优化的轻量级动态自适应模型——“突触马尔可夫链”(Synaptic Markov Chain)。
下面从数据结构、学习过程、步长与模式检测、预读决策触发机制等维度对该预测算法进行深入分析:
核心模型:突触马尔可夫链 (Synaptic Markov Chain)
马尔可夫链的核心假设是“未来的状态概率仅依赖于当前(或过去若干个)状态”。在文件 I/O 的场景中,状态S对应文件中的页面或区域(Region)。
(1) 4KB 区域粒度建模
(2) 突触权重与转移概率(Synaptic Weights & Transition Probabilities)
模型在内存中维持一个状态转移矩阵或邻接图(Transition Graph)。
节点代表文件区域,边(Edge)代表从区域 A 跳转到区域 B 的访问转移。
“突触”特性(Synaptic Adaptation): 边上的权重(Weight)模仿生物神经元突触的“赫布学习规则(Hebbing Learning)”——强化频发路径,惩罚/衰减衰退路径:
正向强化(LTP - Long-term Potentiation): 当观察到再次出现 A -> B$的跳转时,节点A 到 B 的边权重增加。
权重衰减(Weight Decay): 未被触发的转移路径,其权重会随时间和总访问次数按衰减因子衰减,从而使算法具备“遗忘”旧模式、适应新模式的能力。
转移概率计算: 区域 A 跳转到区域 B的概率
P(B|A) 即为 A->B的突触权重占 A所有出边权重总和的比例。
任意步长与复杂模式检测 (Arbitrary-Length Stride Detection)
对于纯连续读(如 0->1->2->3),传统内核预读器依靠检测连续性指针即可完成。但当出现复杂的非连续/步长访问(Stride Access)时(例如数据库跳跃读取索引表 0->16->32->48,或者交错读取),传统算法就会失效。
NSD 的算法在此展现出优势:
多阶历史追踪(Multi-step History Window):
NSD 维护了一个短序列缓冲区(滑动历史),不只观察
,还会结合
联合预测。
跨步模式的自动涌现:
如果应用程序以固定 Delta(如+N 页面)访问文件,经过数次访问后,
路径的突触权重会迅速占优。马尔可夫链的概率图会自动收敛出一条高权重的“跨步轨迹”,无需硬编码设定固定 Stride 规则,算法即可自发学习出任意长度的 Delta 步长。
预读决策与触发条件 (Inference & Triggering)
在 filemap_read() 中发起每次 Read 提示时,预测引擎会按如下流程做出决策:
高置信度阈值判定:
只有当计算得出的
超过设定阈值(例如 80% 或最高权重边优势明显)时,NSD 才会认为预测生效。这就是为什么在 Random 4K 纯随机读取测试中,NSD 能做到仅 +1.1% 的噪音级变动——因为随机读无法建立高置信度的突触路径,预测引擎会自动休眠,避免了无用的 I/O 放大。
高命中率保证 (98% Real Hit Rate):
通过在真正发起预读请求前进行严苛的概率阈值筛选,保证了被预读进来的页面极大概率会在短期内被用户态进程读取。
内核环境下的空间与时间复杂度优化
在内核空间中运行算法,最大的挑战是 不能造成 CPU 延迟飙升 和 不能无节制消耗内存。NSD 采用了以下设计策略:
时间复杂度:O(1) 的推理与更新
空间复杂度:有界内存与老化淘汰(LRU / Decay Eviction)
总结和展望
NSD 预测算法的核心精髓在于:用生物学中的“突触可塑性”来改造经典的马尔可夫链。
这种无须深度神经网络硬件(NPU/GPU)参与、完全依靠高效数据结构在 CPU 极短指令周期内完成的“轻量级在线自学习”,代表了 Linux 内核智能化的一个重要演进方向。
随着端侧 AI 和复杂数据库应用在 Linux 系统上的普及,传统的静态 I/O 算法正在迎来智能化的改造浪潮。
NSD 补丁集展示了利用轻量级机器学习模型(非深度学习,而是高效的马尔可夫链)优化内核子系统的巨大潜力。
无论 NSD 最终是以独立模块形式呈现,还是重构为现有 ra_state 的机器学习扩展,它都为 Linux Page Cache 的演进开辟了一条充满想象力的道路。