<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on Hellokitty&#39;s Blog</title>
    <link>https://yangyang233333.github.io/posts/</link>
    <description>Recent content in Posts on Hellokitty&#39;s Blog</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Mon, 31 Aug 2026 10:30:00 +0800</lastBuildDate>
    <atom:link href="https://yangyang233333.github.io/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>CUDA Event：GPU 时间线上的事件、同步原理与实战</title>
      <link>https://yangyang233333.github.io/posts/cuda-event-principles-demo/</link>
      <pubDate>Mon, 31 Aug 2026 10:30:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/cuda-event-principles-demo/</guid>
      <description>&lt;p&gt;CUDA kernel launch 通常是异步的：CPU 把 kernel、内存拷贝等操作提交到 stream 后便继续执行。由此产生两个常见问题：如何准确测量 GPU 工作耗时，以及如何让不同 stream 在不阻塞 CPU 的情况下建立依赖？&lt;/p&gt;
&lt;p&gt;CUDA Event 就是解决这类问题的基础设施。它可以理解为插入 GPU stream 时间线中的一个标记：当 event 之前的工作全部完成，event 才进入完成状态。借助这个状态，我们可以做 GPU 计时、CPU 等待、跨 stream 同步和异步资源回收。&lt;/p&gt;
&lt;h2 id=&#34;1-event-不是-cpu-事件而是-gpu-时间线标记&#34;&gt;1. Event 不是 CPU 事件，而是 GPU 时间线标记&lt;/h2&gt;
&lt;p&gt;一个 CUDA stream 是按序执行的 GPU 工作队列：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU 提交： Kernel A → memcpy → Event E → Kernel B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         异步提交
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GPU 执行： Kernel A ── memcpy ── E 完成 ── Kernel B
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;调用 &lt;code&gt;cudaEventRecord(event, stream)&lt;/code&gt; 时，CPU 通常只是向 &lt;code&gt;stream&lt;/code&gt; 提交一个 event 记录操作，并不会等待 GPU 执行到该位置。只有当这个 stream 中排在 event 前面的操作完成后，event 才会被标记为完成。&lt;/p&gt;</description>
    </item>
    <item>
      <title>SGLang 双 Stream 重叠调度：如何把 CPU 后处理藏到 GPU 计算背后</title>
      <link>https://yangyang233333.github.io/posts/sglang-overlap-scheduling/</link>
      <pubDate>Sun, 30 Aug 2026 23:09:10 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/sglang-overlap-scheduling/</guid>
      <description>&lt;p&gt;大模型自回归推理看起来是纯 GPU 工作：每一步做一次模型前向，采样一个 token，再把 token 喂给下一步。然而在高性能推理系统里，GPU 计算只是流水线的一部分。采样结果回传、EOS 判断、请求回收、KV Cache 管理、下一批组装和元数据准备，都可能在两次前向之间制造空洞。&lt;/p&gt;
&lt;p&gt;SGLang 的 Overlap Scheduling 解决的正是这个问题。它不是简单地“多开一条 CUDA stream”，而是同时完成两件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;让当前步产生的 token 留在 GPU，直接作为下一步输入，解除下一次 forward 对 CPU 读值的依赖；&lt;/li&gt;
&lt;li&gt;用 scheduler stream 和 engine stream 构造软件流水线，让 GPU 计算当前批次时，调度器处理上一批次的结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本文以 Mini-SGLang 的 &lt;code&gt;python/minisgl/scheduler/scheduler.py&lt;/code&gt; 为线索，解释 &lt;code&gt;overlap_loop&lt;/code&gt;、&lt;code&gt;_forward&lt;/code&gt; 和 &lt;code&gt;_process_last_data&lt;/code&gt; 背后的依赖重排。&lt;/p&gt;
&lt;h2 id=&#34;先看结论优化的不是提交速度而是依赖关系&#34;&gt;先看结论：优化的不是“提交速度”，而是依赖关系&lt;/h2&gt;
&lt;p&gt;CUDA kernel 的提交本来就是异步的。CPU 把工作放进 stream 后，不必等待 GPU 完成。因此一个自然的问题是：只用一条 stream，只要 CPU 提交得足够快，不也能让 GPU 连续工作吗？&lt;/p&gt;
&lt;p&gt;如果系统只有计算任务，这个判断基本成立。但自回归推理存在一个控制依赖：调度器通常要知道采样出的 token，才能判断请求是否命中 EOS、是否应该释放资源，以及下一轮有哪些请求仍应留在 batch 中。&lt;/p&gt;
&lt;p&gt;串行执行会形成如下链条：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GPU:  forward(B1) ── idle ── forward(B2) ── idle ── forward(B3)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU:               处理 B1                 处理 B2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   读 token                读 token
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   判 EOS                  判 EOS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   组 B2                   组 B3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GPU 完成 &lt;code&gt;B1&lt;/code&gt; 后，CPU 才读取结果并决定 &lt;code&gt;B2&lt;/code&gt;。此时 GPU 没有可执行的新工作，只能等待。这不是 CPU 调用 CUDA API 太慢，而是 &lt;code&gt;B2&lt;/code&gt; 在逻辑上依赖 &lt;code&gt;B1&lt;/code&gt; 的结果。&lt;/p&gt;</description>
    </item>
    <item>
      <title>SAC：面向稀疏注意力大模型的 CXL 解耦 KV Cache 系统</title>
      <link>https://yangyang233333.github.io/posts/sac-cxl-sparse-attention/</link>
      <pubDate>Fri, 28 Aug 2026 17:30:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/sac-cxl-sparse-attention/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本文翻译并整理自论文 &lt;strong&gt;SAC: Disaggregated KV Cache System for Sparse Attention LLMs with CXL&lt;/strong&gt;（arXiv:2606.19746v1，2026 年 6 月 18 日）。原论文采用 CC BY 4.0 许可。为适应博客阅读，本文省略参考文献列表中的完整出版信息，但保留正文结构、关键论证、实验结果与附录要点。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;随着大模型进入长上下文与稀疏注意力时代，推理系统的主要瓶颈正从算力转向内存容量。传统 RDMA 解耦 KV Cache 系统会在解码前把完整前缀 KV Cache 搬回本地；但稀疏注意力每一步只访问少量 top-k 条目，这种“全量搬运、少量使用”的方式会同时浪费网络带宽和本地内存。&lt;/p&gt;
&lt;p&gt;SAC 的核心思路是：使用 CXL 的低延迟、缓存行粒度 load/store 语义，把 KV Cache 留在解耦内存池中，只在计算时按需读取被选中的 top-k 条目。论文在 DeepSeek-V3.2 与 SGLang 上的实验显示，相比 RDMA 基线，SAC 可实现最高约 &lt;strong&gt;2.1 倍吞吐量、9.7 倍更低的 TTFT，以及 1.8 倍更低的 TBT&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;摘要&#34;&gt;摘要&lt;/h2&gt;
&lt;p&gt;大模型向长上下文推理扩展，使服务系统的主要瓶颈从计算能力转向内存容量。面向稠密注意力模型的传统方案通常采用基于 RDMA 的解耦内存池，在解码开始前，以粗粒度方式将整个前缀 KV Cache 从远端存储取回本地内存。&lt;/p&gt;
&lt;p&gt;然而，这种方法并不适合新兴的稀疏注意力模型。解码过程中虽然只有很少一部分 KV 条目真正活跃，系统仍然要把完整 KV Cache 拉回本地，从而造成严重的传输瓶颈和本地内存浪费。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mooncake 中的协程：从 coro_rpc 到同步接口桥接</title>
      <link>https://yangyang233333.github.io/posts/mooncake-coroutines/</link>
      <pubDate>Fri, 28 Aug 2026 14:55:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-coroutines/</guid>
      <description>&lt;p&gt;Mooncake 确实使用了协程，但它并不是把整个系统改造成“全异步架构”。截至本文分析的主分支提交 &lt;code&gt;3d1665a&lt;/code&gt;，协程主要出现在控制面 RPC、连接管理和阻塞任务卸载等 I/O 密集路径；对外接口仍大量保留同步调用形式。&lt;/p&gt;
&lt;p&gt;这形成了一个很实用的分层：内部用 C++20 协程组织异步流程，边界处再按需要转换成同步返回值或回调。&lt;/p&gt;
&lt;h2 id=&#34;技术栈&#34;&gt;技术栈&lt;/h2&gt;
&lt;p&gt;Mooncake 的协程代码主要建立在两层库之上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;async_simple::coro::Lazy&amp;lt;T&amp;gt;&lt;/code&gt; 表示一个惰性异步任务；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yalantinglibs&lt;/code&gt; 的 &lt;code&gt;coro_rpc&lt;/code&gt; 和 &lt;code&gt;coro_io&lt;/code&gt; 提供异步 RPC、网络连接与线程池调度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;典型代码形态如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;async_simple&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;coro&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;Lazy&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Result&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; request() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; response &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;co_await&lt;/span&gt; client.send_request(...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;co_return&lt;/span&gt; response;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Lazy&amp;lt;T&amp;gt;&lt;/code&gt; 创建后通常不会立刻执行。它需要被另一个协程 &lt;code&gt;co_await&lt;/code&gt;，通过 &lt;code&gt;.start(...)&lt;/code&gt; 启动，或者由 &lt;code&gt;syncAwait(...)&lt;/code&gt; 驱动至完成。&lt;/p&gt;
&lt;h2 id=&#34;路径一mooncake-store-的-master-rpc&#34;&gt;路径一：Mooncake Store 的 Master RPC&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mooncake-store/src/master_client.cpp&lt;/code&gt; 中的 &lt;code&gt;MasterClient::invoke_rpc&lt;/code&gt; 是最清晰的例子。它的外部签名是同步的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tl&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;expected&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;ReturnType, ErrorCode&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MasterClient&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;invoke_rpc(Args&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;... args);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;函数内部却先构造 &lt;code&gt;Lazy&lt;/code&gt;，再连续等待两个异步阶段：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; async_simple&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;coro&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;syncAwait(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;]() &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; async_simple&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;coro&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;Lazy&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                tl&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;expected&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;ReturnType, ErrorCode&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; pending &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;co_await&lt;/span&gt; pool&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;send_request(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;](coro_io&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;client_reuse_hint,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                coro_rpc&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;coro_rpc_client&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; client) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; client.send_request&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;ServiceMethod&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;pending.has_value()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;co_return&lt;/span&gt; tl&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;make_unexpected(ErrorCode&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;RPC_FAIL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;auto&lt;/span&gt; result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;co_await&lt;/span&gt; std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;move(pending.value());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;co_return&lt;/span&gt; result&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;result();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有两次 &lt;code&gt;co_await&lt;/code&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>tiny-llm：在 Apple Silicon 上从 Transformer 算子走到推理系统与 Agent</title>
      <link>https://yangyang233333.github.io/posts/tiny-llm-source-reading/</link>
      <pubDate>Thu, 27 Aug 2026 15:10:20 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/tiny-llm-source-reading/</guid>
      <description>&lt;p&gt;如果你已经知道 Transformer 的基本结构，却仍然不清楚 vLLM 一类推理系统为什么需要 KV Cache、Continuous Batching、Paged Attention，以及这些技术最终如何支撑 Agent，&lt;code&gt;skyzh/tiny-llm&lt;/code&gt; 是一条很好的动手路径。&lt;/p&gt;
&lt;p&gt;它不是一个追求生产可用的迷你框架，而是一门以 Qwen3 和 MLX 为载体的系统课程：先用可读的数组运算实现模型，再围绕真实性能瓶颈写 Metal 内核，随后搭出动态批处理和分页缓存，最后把同一个本地模型接入带工具、检查点、压缩、评测和分支选择的 Agent 循环。&lt;/p&gt;
&lt;p&gt;截至 2026 年 8 月 27 日，项目约有 4.5k stars，使用 Apache-2.0 许可证。课程主体分为四周，已覆盖从注意力到受控 Agent 的完整主线。&lt;/p&gt;
&lt;h2 id=&#34;项目定位不是再写一个-transformer&#34;&gt;项目定位：不是“再写一个 Transformer”&lt;/h2&gt;
&lt;p&gt;很多教学项目止步于“加载权重并生成一句话”。tiny-llm 的不同之处，是把模型实现当作起点，而不是终点。&lt;/p&gt;
&lt;p&gt;它试图回答三个递进的问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一个现代开源模型如何由矩阵运算变成文本？&lt;/li&gt;
&lt;li&gt;一个正确但缓慢的实现，如何通过测量和内核优化接近成熟框架？&lt;/li&gt;
&lt;li&gt;一个推理引擎如何进一步成为可暂停、可审计、可恢复的 Agent 执行器？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;项目选择 Apple Silicon、MLX 和 Qwen3。统一内存让 CPU、GPU 和模型权重处在相对简单的硬件环境里；MLX 提供熟悉的 Python 数组接口，同时允许下沉到 Metal；Qwen3 则带有 GQA、QK Norm、BF16 激活和 4-bit 权重，足以暴露真实推理系统中的带宽、注意力与缓存问题。&lt;/p&gt;
&lt;p&gt;代码结构刻意分成两套：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/tiny_llm/&lt;/code&gt; 是学习者逐步补全的实现；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/tiny_llm_ref/&lt;/code&gt; 是参考实现，用于测试和基准对照；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/extensions/&lt;/code&gt; 与 &lt;code&gt;src/extensions_ref/&lt;/code&gt; 分别放置 Metal/C++ 扩展；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tests_refsol/&lt;/code&gt; 按周和天组织验收测试；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;book/&lt;/code&gt; 是完整课程正文。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种布局把“阅读—实现—测试—测量”闭成了环。&lt;/p&gt;</description>
    </item>
    <item>
      <title>从朴素循环到硬件极限：GEMM / GEMV 高性能算子优化指南</title>
      <link>https://yangyang233333.github.io/posts/gemm-gemv-optimization/</link>
      <pubDate>Wed, 26 Aug 2026 14:20:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/gemm-gemv-optimization/</guid>
      <description>从 Roofline、数据布局和分层分块出发，逐步分析如何在 CPU 与 GPU 上优化 GEMM/GEMV，并建立可复现的性能验证方法。</description>
    </item>
    <item>
      <title>NVIDIA Dynamo 源码阅读（二）：分布式运行时如何组织服务与请求</title>
      <link>https://yangyang233333.github.io/posts/nvidia-dynamo-runtime-source-reading/</link>
      <pubDate>Wed, 26 Aug 2026 13:50:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-dynamo-runtime-source-reading/</guid>
      <description>深入 lib/runtime，分析 Namespace、Component、Endpoint、服务发现和网络流水线如何组成 Dynamo 的请求平面。</description>
    </item>
    <item>
      <title>NVIDIA Dynamo 源码阅读（三）：KV-aware Router 如何选择 Worker</title>
      <link>https://yangyang233333.github.io/posts/nvidia-dynamo-kv-aware-router-source-reading/</link>
      <pubDate>Wed, 26 Aug 2026 13:50:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-dynamo-kv-aware-router-source-reading/</guid>
      <description>从 token 分块哈希、KV 事件、Radix Tree、负载估计和选择策略出发，拆解 Dynamo KV-aware Router。</description>
    </item>
    <item>
      <title>NVIDIA Dynamo 源码阅读（四）：Prefill/Decode 分离与 KV 传输</title>
      <link>https://yangyang233333.github.io/posts/nvidia-dynamo-disaggregated-serving-source-reading/</link>
      <pubDate>Wed, 26 Aug 2026 13:50:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-dynamo-disaggregated-serving-source-reading/</guid>
      <description>分析 Dynamo 如何进行两阶段路由、交换传输元数据，并让 KV Cache 在 Prefill 与 Decode Worker 之间直接移动。</description>
    </item>
    <item>
      <title>NVIDIA Dynamo 源码阅读（一）：数据中心级推理栈的整体架构</title>
      <link>https://yangyang233333.github.io/posts/nvidia-dynamo-architecture-overview/</link>
      <pubDate>Wed, 26 Aug 2026 13:50:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-dynamo-architecture-overview/</guid>
      <description>从请求路径、控制面、数据面和后端边界出发，理解 NVIDIA Dynamo 为什么是推理引擎之上的分布式编排层。</description>
    </item>
    <item>
      <title>Mini-SGLang 源码阅读（五）：模型层、Tensor Parallel 与自定义 Kernel</title>
      <link>https://yangyang233333.github.io/posts/mini-sglang-source-reading-tensor-parallel/</link>
      <pubDate>Tue, 25 Aug 2026 21:10:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mini-sglang-source-reading-tensor-parallel/</guid>
      <description>从张量并行的矩阵切分原理出发，分析 Mini-SGLang 的并行 Linear、Embedding、模型注册、权重加载和底层 Kernel。</description>
    </item>
    <item>
      <title>Mini-SGLang 源码阅读（四）：Engine、Attention Backend 与 CUDA Graph</title>
      <link>https://yangyang233333.github.io/posts/mini-sglang-source-reading-engine/</link>
      <pubDate>Tue, 25 Aug 2026 21:00:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mini-sglang-source-reading-engine/</guid>
      <description>从 GPU 推理的 kernel 启动开销和 Prefill/Decode 差异出发，分析 Mini-SGLang Engine 的完整执行路径。</description>
    </item>
    <item>
      <title>Mini-SGLang 源码阅读（三）：Paged KV Cache 与 Radix Prefix Cache</title>
      <link>https://yangyang233333.github.io/posts/mini-sglang-source-reading-kv-cache/</link>
      <pubDate>Tue, 25 Aug 2026 20:50:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mini-sglang-source-reading-kv-cache/</guid>
      <description>从自回归推理的 KV Cache 成本出发，分析 Mini-SGLang 的物理页池、请求页表、前缀匹配与缓存驱逐。</description>
    </item>
    <item>
      <title>Mini-SGLang 源码阅读（二）：Scheduler、Continuous Batching 与 Chunked Prefill</title>
      <link>https://yangyang233333.github.io/posts/mini-sglang-source-reading-scheduler/</link>
      <pubDate>Tue, 25 Aug 2026 20:40:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mini-sglang-source-reading-scheduler/</guid>
      <description>先解释在线推理调度的资源约束，再分析 Mini-SGLang 如何组织 Prefill、Decode 和 CPU/GPU 重叠执行。</description>
    </item>
    <item>
      <title>Mini-SGLang 源码阅读（一）：一次 LLM 请求如何穿过推理引擎</title>
      <link>https://yangyang233333.github.io/posts/mini-sglang-source-reading-request-lifecycle/</link>
      <pubDate>Tue, 25 Aug 2026 20:30:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mini-sglang-source-reading-request-lifecycle/</guid>
      <description>从 Prefill、Decode、Continuous Batching 和多进程流水线出发，梳理 Mini-SGLang 一次请求的完整执行流程。</description>
    </item>
    <item>
      <title>Rust 异步编程原理：Future、状态机、Waker 与 Executor</title>
      <link>https://yangyang233333.github.io/posts/rust-async-state-machine/</link>
      <pubDate>Tue, 25 Aug 2026 15:35:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/rust-async-state-machine/</guid>
      <description>面向初学者，从 Future::poll 出发推导 Rust async/await 状态机，并解释 Waker、Executor、Reactor、Pin、并发与阻塞。</description>
    </item>
    <item>
      <title>vLLM 与 Mooncake 对接源码解读：Prefill/Decode 分离中的 KV Cache 如何跨节点传输</title>
      <link>https://yangyang233333.github.io/posts/vllm-mooncake-integration/</link>
      <pubDate>Mon, 24 Aug 2026 16:58:43 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/vllm-mooncake-integration/</guid>
      <description>深入分析 vLLM 内置 MooncakeConnector：从代理拆分请求、Scheduler 元数据、GPU KV Cache 注册，到 Mooncake Transfer Engine 通过 RDMA 将 Prefill KV 直接搬到 Decode 节点。</description>
    </item>
    <item>
      <title>FMS 2026 深度解读：AI 正在重构内存与存储层级</title>
      <link>https://yangyang233333.github.io/posts/fms-2026-core-trends/</link>
      <pubDate>Mon, 24 Aug 2026 15:14:44 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/fms-2026-core-trends/</guid>
      <description>深入解读 FMS 2026 的五条核心技术主线：High Bandwidth Flash、3D 内存封装、CXL 内存池、PCIe 6.0 液冷 SSD，以及面向 AI 的 NVMe 可运维基础设施。</description>
    </item>
    <item>
      <title>Phoenix 论文阅读：一种不使用伪缓冲区的 GPU Direct Storage 重构方案</title>
      <link>https://yangyang233333.github.io/posts/phoenix-paper-chinese-translation/</link>
      <pubDate>Mon, 24 Aug 2026 14:49:50 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/phoenix-paper-chinese-translation/</guid>
      <description>按原论文结构详译 SC&#39;25 论文 Phoenix：解释 NVIDIA GDS 的伪缓冲区问题、基于 ZONE_DEVICE 的 GPU 显存映射、POSIX/io_uring 编程模型，以及本地 NVMe、远程存储、KV Cache 和模型加载实验。</description>
    </item>
    <item>
      <title>Phoenix 源码解读：把 GPU 显存变成 Linux I/O 可直达的内存</title>
      <link>https://yangyang233333.github.io/posts/phoenix-source-code-reading/</link>
      <pubDate>Mon, 24 Aug 2026 14:40:15 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/phoenix-source-code-reading/</guid>
      <description>深入解析 xPU-IO/Phoenix：它如何通过内核模块、用户态库和应用适配器，将 SSD 数据直接送入 GPU 显存；并比较 full BAR、staging、batch、stream 等数据路径的实现与取舍。</description>
    </item>
    <item>
      <title>Mooncake Store 源码阅读（四）：Master 持久化、快照与热备恢复</title>
      <link>https://yangyang233333.github.io/posts/mooncake-store-source-reading-master-ha/</link>
      <pubDate>Mon, 24 Aug 2026 10:40:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-store-source-reading-master-ha/</guid>
      <description>解读 Mooncake Store Master 的 oplog、snapshot、standby 和租约机制，以及它们如何保护控制面状态。</description>
    </item>
    <item>
      <title>Mooncake Store 源码阅读（三）：Get、副本选择与淘汰回收</title>
      <link>https://yangyang233333.github.io/posts/mooncake-store-source-reading-get-eviction/</link>
      <pubDate>Mon, 24 Aug 2026 10:30:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-store-source-reading-get-eviction/</guid>
      <description>从 GetReplicaList、Replica 状态和批量 Eviction 分析 Mooncake Store 的读取与空间回收。</description>
    </item>
    <item>
      <title>Mooncake Store 源码阅读（二）：Put 写入链路与对象原子性</title>
      <link>https://yangyang233333.github.io/posts/mooncake-store-source-reading-put-path/</link>
      <pubDate>Mon, 24 Aug 2026 10:20:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-store-source-reading-put-path/</guid>
      <description>沿 RealClient、PutStart、Transfer Engine 和 PutEnd 阅读 Mooncake Store 的完整写入链路。</description>
    </item>
    <item>
      <title>Mooncake Store 源码阅读（一）：从对象存储接口到控制面与数据面</title>
      <link>https://yangyang233333.github.io/posts/mooncake-store-source-reading-architecture/</link>
      <pubDate>Mon, 24 Aug 2026 10:10:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-store-source-reading-architecture/</guid>
      <description>从源码目录、进程角色和一次请求的路径入手，解释 Mooncake Store 如何把元数据控制与大对象传输分离。</description>
    </item>
    <item>
      <title>PCIe BAR 深入解析：从设备地址窗口到 DMA 与 GPUDirect Storage</title>
      <link>https://yangyang233333.github.io/posts/pcie-bar-dma-gds/</link>
      <pubDate>Fri, 21 Aug 2026 16:25:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/pcie-bar-dma-gds/</guid>
      <description>&lt;p&gt;在操作系统驱动、高性能网卡、NVMe SSD 和 GPU 系统中，经常会同时看到 BAR、MMIO、DMA、IOMMU、peer-to-peer DMA、GPUDirect RDMA 和 GPUDirect Storage 等概念。这些名词都与“设备怎样通过 PCIe 交换控制信息和数据”有关，但它们处在不同层次。&lt;/p&gt;
&lt;p&gt;最简洁的理解是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BAR：让 CPU 能够定位并访问 PCIe 设备中的寄存器或显存窗口
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DMA：让 PCIe 设备能够主动读取或写入系统内存
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P2P DMA：让一个 PCIe 设备直接访问另一个 PCIe 设备暴露的地址空间
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GDS：利用 DMA、GPU 内存映射和驱动协作，让存储数据尽量直接进入 GPU 显存
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文从 PCIe 地址空间和事务模型出发，解释 BAR 是如何分配和映射的，驱动为什么通过 BAR 下发命令，DMA 地址为什么不能简单等同于物理地址，以及 GPUDirect Storage 如何把这些机制组合成一条高性能数据路径。&lt;/p&gt;
&lt;h2 id=&#34;一先建立-pcie-系统视图&#34;&gt;一、先建立 PCIe 系统视图&lt;/h2&gt;
&lt;p&gt;一个典型服务器的 PCIe 拓扑如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         CPU
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Memory Controller
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       Host RAM
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                          │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    Root Complex
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   ┌──────┴──────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                   │             │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              PCIe Switch    PCIe Endpoint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              ┌────┴────┐         GPU
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              │         │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           NVMe SSD     NIC
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CPU 和内存构成主机侧。Root Complex 把 CPU/内存系统连接到 PCIe fabric。NVMe、网卡和 GPU 通常是 Endpoint。PCIe Switch 用于扩展端口和转发事务。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Rust Tokio 深入解析：运行时原理、并发模型与最佳实践</title>
      <link>https://yangyang233333.github.io/posts/rust-tokio-runtime-and-best-practices/</link>
      <pubDate>Fri, 21 Aug 2026 11:35:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/rust-tokio-runtime-and-best-practices/</guid>
      <description>&lt;p&gt;Rust 语言只定义了 &lt;code&gt;Future&lt;/code&gt;、&lt;code&gt;async/await&lt;/code&gt; 和 &lt;code&gt;Waker&lt;/code&gt; 等异步基础设施，并没有在标准库中提供完整的异步运行时。Tokio 补齐了这一层：它提供任务调度器、网络 I/O 驱动、定时器、异步同步原语、异步文件接口以及阻塞任务隔离机制。&lt;/p&gt;
&lt;p&gt;如果把 Rust 异步程序比作一座城市：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Future            = 等待执行的工作
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Executor/Scheduler = 安排工作在哪个线程运行
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;I/O Driver         = 监听 socket 是否就绪
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Timer Driver       = 管理定时器何时到期
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Waker              = 通知某个任务可以继续
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Tokio              = 将上述组件组合成运行时
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文不再重复 &lt;code&gt;Future::poll&lt;/code&gt; 和状态机的基础推导，而是聚焦 Tokio 本身：runtime 如何启动，任务如何调度，网络 I/O 为什么不会阻塞线程，以及生产代码中应该怎样处理并发、超时、共享状态、CPU 密集任务和优雅退出。&lt;/p&gt;
&lt;h2 id=&#34;一tokio-提供了什么&#34;&gt;一、Tokio 提供了什么&lt;/h2&gt;
&lt;p&gt;一个典型 Tokio 应用依赖：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tokio&lt;/span&gt; = { &lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;features&lt;/span&gt; = [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;full&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;full&lt;/code&gt; 适合学习和应用开发，但库作者通常应该只启用实际需要的 feature，缩短编译时间并减少依赖面。&lt;/p&gt;
&lt;p&gt;Tokio 的主要组成包括：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;组件&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Runtime&lt;/td&gt;
					&lt;td&gt;组合调度器、I/O driver 和 timer driver&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Task&lt;/td&gt;
					&lt;td&gt;由 runtime 调度的异步任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;tokio::net&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;TCP、UDP、Unix Socket 等异步网络接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;tokio::time&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;sleep、interval、timeout&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;tokio::sync&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;channel、Mutex、RwLock、Semaphore、Notify&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;tokio::fs&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;文件系统异步接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;spawn_blocking&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;将阻塞或 CPU 密集工作移出异步 worker&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;select!&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;同时等待多个异步分支&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;需要先建立一个重要认识：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mooncake Transfer Engine 源码阅读（四）：TENT 下一代架构如何重构传输引擎</title>
      <link>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-tent/</link>
      <pubDate>Fri, 21 Aug 2026 11:18:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-tent/</guid>
      <description>&lt;p&gt;Mooncake 仓库同时存在经典 Transfer Engine 和 &lt;strong&gt;TENT（Transfer Engine Next）&lt;/strong&gt;。TENT 不是简单增加一种 Transport，而是重构了 Segment 生命周期、运行时调度、拓扑选择、QoS、故障转移和插件体系。&lt;/p&gt;
&lt;p&gt;阅读版本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Mooncake commit: 777cc7782417b6e554cf7c2d53210d0d8f89f5cc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;一为什么需要下一代引擎&#34;&gt;一、为什么需要下一代引擎&lt;/h2&gt;
&lt;p&gt;经典 TE 已经支持 RDMA、TCP、NVLink 和多种硬件，但随着后端增加，&lt;code&gt;TransferEngineImpl + MultiTransport + 各 Transport&lt;/code&gt; 容易出现几个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Segment 生命周期分散在元数据和后端注册逻辑中；&lt;/li&gt;
&lt;li&gt;传输选择主要依赖静态协议与局部规则；&lt;/li&gt;
&lt;li&gt;多 rail、拥塞、故障和 QoS 难以统一调度；&lt;/li&gt;
&lt;li&gt;不同后端各自维护进度线程和资源模型；&lt;/li&gt;
&lt;li&gt;新硬件接入需要理解大量经典内部约定；&lt;/li&gt;
&lt;li&gt;请求取消、deadline 和 failover 缺少统一运行时。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TENT 将这些能力上移到 Runtime 层。&lt;/p&gt;
&lt;h2 id=&#34;二目录结构&#34;&gt;二、目录结构&lt;/h2&gt;
&lt;p&gt;TENT 核心位于：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tent/src/runtime/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── transfer_engine_impl.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── segment.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── segment_manager.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── segment_registry.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── segment_tracker.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── transport_loader.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── transport_selector.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── progress_worker.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── admission_queue.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── qos_contract.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── receiver_credit.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── topology.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── control_plane.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── proxy_manager.cpp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;外围包括：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mooncake Transfer Engine 源码阅读（三）：RDMA、TCP 与请求完成状态机</title>
      <link>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-rdma-tcp/</link>
      <pubDate>Fri, 21 Aug 2026 11:17:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-rdma-tcp/</guid>
      <description>&lt;p&gt;Transfer Engine 的公共 API 很统一，但 RDMA 和 TCP 的实现差异很大。RDMA 需要 MR、QP、WR 和 CQ；TCP 需要连接、lane、消息 framing 和接收端主动拷贝。本文沿源码比较两条路径，并分析 Batch 状态如何完成。&lt;/p&gt;
&lt;p&gt;阅读版本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Mooncake commit: 777cc7782417b6e554cf7c2d53210d0d8f89f5cc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;一transport-抽象&#34;&gt;一、Transport 抽象&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Transport&lt;/code&gt; 基类统一定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;install / uninstall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;registerLocalMemory / unregisterLocalMemory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;submitTransfer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;getTransferStatus
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;allocateBatchID / freeBatchID
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它还定义 &lt;code&gt;TransferRequest&lt;/code&gt;、&lt;code&gt;TransferStatus&lt;/code&gt; 和内部 &lt;code&gt;BufferEntry&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;公共抽象要求每个后端回答三个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;本地内存如何准备为可传输状态；&lt;/li&gt;
&lt;li&gt;请求怎样排队和执行；&lt;/li&gt;
&lt;li&gt;如何查询每个 task 的最终状态和字节数。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;具体连接模型不属于公共 API。&lt;/p&gt;
&lt;h2 id=&#34;二rdma-初始化&#34;&gt;二、RDMA 初始化&lt;/h2&gt;
&lt;p&gt;RDMA 后端主要位于：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rdma_transport.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rdma_context.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rdma_endpoint.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;endpoint_store.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;worker_pool.cpp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装阶段通常完成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;枚举 RDMA devices / ports / GID
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 创建每张 HCA 的 context
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 建立 PD、CQ 等资源
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 启动 worker / poller
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 发布 NIC endpoint metadata
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 准备 endpoint store
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mooncake 支持多 HCA、多端口和 GPU 内存，因此一个逻辑请求可能被切到多个 rail 上并行发送。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mooncake Transfer Engine 源码阅读（二）：Segment、内存注册与元数据服务</title>
      <link>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-segment-metadata/</link>
      <pubDate>Fri, 21 Aug 2026 11:16:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-segment-metadata/</guid>
      <description>&lt;p&gt;Mooncake Transfer Engine 的核心抽象不是“远端指针”，而是 &lt;strong&gt;Segment + BufferDesc + Metadata&lt;/strong&gt;。应用注册本地内存后，TE 将地址范围、设备位置和传输协议发布为 Segment 描述，其他节点才能定位并建立连接。&lt;/p&gt;
&lt;p&gt;阅读版本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Mooncake commit: 777cc7782417b6e554cf7c2d53210d0d8f89f5cc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;一为什么不能直接发送指针&#34;&gt;一、为什么不能直接发送指针&lt;/h2&gt;
&lt;p&gt;一个进程中的地址：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x7f12...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在另一个进程中通常没有意义。即使两台机器都使用相同数值，它们也不指向同一块物理内存。&lt;/p&gt;
&lt;p&gt;高性能传输还需要额外信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这是 CPU DRAM 还是 GPU VRAM；&lt;/li&gt;
&lt;li&gt;对应哪张 GPU；&lt;/li&gt;
&lt;li&gt;是否注册成 RDMA MR；&lt;/li&gt;
&lt;li&gt;rkey 和网卡 endpoint 是什么；&lt;/li&gt;
&lt;li&gt;是否能用 NVLink、GPU IPC 或 CXL；&lt;/li&gt;
&lt;li&gt;节点当前是否存活；&lt;/li&gt;
&lt;li&gt;地址区间是否已经注销。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此 TE 把地址空间包装成 Segment，并通过元数据服务交换描述。&lt;/p&gt;
&lt;h2 id=&#34;二segmentdesc&#34;&gt;二、&lt;code&gt;SegmentDesc&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;TransferMetadata::SegmentDesc&lt;/code&gt; 是远端发现的中心结构，主要承载：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Segment ID
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Segment 名称
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;协议或协议集合
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;本机 RPC / endpoint 信息
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BufferDesc 列表
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;设备与拓扑信息
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;后端扩展元数据
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以把一个 Segment 理解成某个 TE 实例公开的可传输地址空间：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Segment: decode-node-7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── Buffer A: CPU metadata pool, protocol=rdma
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── Buffer B: GPU KV pool, protocol=rdma
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── Buffer C: GPU KV pool, protocol=hip
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同一块 GPU buffer 可以被多个后端注册，从而同时支持：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mooncake Transfer Engine 源码阅读（一）：统一传输 API 与整体架构</title>
      <link>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-architecture/</link>
      <pubDate>Fri, 21 Aug 2026 11:15:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/mooncake-transfer-engine-source-reading-architecture/</guid>
      <description>&lt;p&gt;Mooncake Transfer Engine（简称 TE）是 Mooncake 数据平面的基础组件。它不负责决定 KV Cache 应该放在哪里，而是提供统一接口，把一段本地内存搬到远端 Segment，或者从远端 Segment 读取到本地内存。&lt;/p&gt;
&lt;p&gt;本文基于 Mooncake 官方仓库：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit: 777cc7782417b6e554cf7c2d53210d0d8f89f5cc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit date: 2026-08-21
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当前仓库同时保留经典 Transfer Engine 和下一代 TENT。前三篇先阅读经典实现，第四篇再分析 TENT 如何重构控制面、调度和传输后端。&lt;/p&gt;
&lt;h2 id=&#34;一源码布局&#34;&gt;一、源码布局&lt;/h2&gt;
&lt;p&gt;核心目录为 &lt;code&gt;mooncake-transfer-engine/&lt;/code&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;路径&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;include/transfer_engine.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;对外 C++ API&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;include/transfer_engine_impl.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;经典实现内部接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;include/transport/transport.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Transport 抽象、请求和状态&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;include/transfer_metadata.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Segment、Buffer 与元数据接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;src/transfer_engine.cpp&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;公共 API 转发层，同时兼容经典 TE 与 TENT&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;src/transfer_engine_impl.cpp&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;初始化、内存注册、Segment 与批次管理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;src/multi_transport.cpp&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;安装和选择具体 Transport&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;src/transport/&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;RDMA、TCP、NVLink、NVMe-oF、EFA 等后端&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;tent/&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Transfer Engine Next 实现&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;TE 的经典架构可以概括为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;应用 / Mooncake Store
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TransferEngine
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TransferEngineImpl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ┌────┼──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ▼    ▼              ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Metadata  MultiTransport  Batch 生命周期
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ┌──────┼───────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ▼      ▼       ▼       ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  RDMA   TCP    NVLink   NVMe-oF ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;二公共-api-是一层门面&#34;&gt;二、公共 API 是一层门面&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;TransferEngine&lt;/code&gt; 类本身很薄，大多数函数转发给 &lt;code&gt;TransferEngineImpl&lt;/code&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>nvidia-fs 源码阅读（三）：文件 I/O、批处理、完成路径与诊断</title>
      <link>https://yangyang233333.github.io/posts/nvidia-fs-source-code-reading-io/</link>
      <pubDate>Fri, 21 Aug 2026 10:47:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-fs-source-code-reading-io/</guid>
      <description>&lt;p&gt;前两篇分别介绍了 &lt;code&gt;nvidia-fs&lt;/code&gt; 的模块结构，以及 GPU virtual address 到 peer DMA address 的映射。本文沿一次 &lt;code&gt;cuFileRead&lt;/code&gt; 对应的内核路径，分析文件 I/O 如何提交、完成和清理，并介绍 batch、稀疏文件、RDMA 与 &lt;code&gt;/proc&lt;/code&gt; 诊断接口。&lt;/p&gt;
&lt;p&gt;阅读版本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit: 328d1d8cce1175c013720985c30e123e9a35242c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GDS_VERSION: 2.29.4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;一io-入口&#34;&gt;一、I/O 入口&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nvfs_ioctl()&lt;/code&gt; 接收：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NVFS_IOCTL_READ
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NVFS_IOCTL_WRITE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NVFS_IOCTL_BATCH_IO
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;单次读写共用两阶段结构：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nvfs_io_init(op, ioargs)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 验证并构造 nvfs_io
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nvfs_io_start_op(nvfsio)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 向目标文件提交真正 I/O
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分成两步的意义在于：参数验证、对象引用和资源分配都应在进入异步 I/O 前完成。一旦请求提交，完成回调可能很快发生，初始化不完整会造成竞态。&lt;/p&gt;
&lt;h2 id=&#34;二nvfs_io_init-做了什么&#34;&gt;二、&lt;code&gt;nvfs_io_init&lt;/code&gt; 做了什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nvfs_io_init()&lt;/code&gt; 是用户参数到内核 I/O 对象的转换层，主要工作包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;根据文件描述符取得目标 &lt;code&gt;struct file&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;检查读写权限；&lt;/li&gt;
&lt;li&gt;查找已经注册的 GPU buffer/mgroup；&lt;/li&gt;
&lt;li&gt;验证 GPU buffer offset、文件 offset 和长度；&lt;/li&gt;
&lt;li&gt;建立影子 page 对应的 iov 或迭代器；&lt;/li&gt;
&lt;li&gt;初始化 &lt;code&gt;kiocb&lt;/code&gt;、完成函数和统计字段；&lt;/li&gt;
&lt;li&gt;为同步、异步和特殊文件系统路径设置标志。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;源码还会检查文件系统类型、direct I/O 条件和文件权限。写操作比读操作更复杂，因为它可能涉及文件扩展、页缓存一致性及磁盘空间预分配。&lt;/p&gt;</description>
    </item>
    <item>
      <title>nvidia-fs 源码阅读（二）：GPU 内存注册、影子页与 DMA 映射</title>
      <link>https://yangyang233333.github.io/posts/nvidia-fs-source-code-reading-memory-dma/</link>
      <pubDate>Fri, 21 Aug 2026 10:46:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-fs-source-code-reading-memory-dma/</guid>
      <description>&lt;p&gt;上一篇从 &lt;code&gt;nvfs_init()&lt;/code&gt;、字符设备和 ioctl 看到了 &lt;code&gt;nvidia-fs&lt;/code&gt; 的外部形态。本文进入 GDS direct path 的核心：怎样把用户分配的 GPU virtual address 变成存储设备能够 DMA 的地址，同时又让 Linux 文件 I/O 栈能够携带它。&lt;/p&gt;
&lt;p&gt;阅读版本仍为 NVIDIA &lt;code&gt;gds-nvidia-fs&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit: 328d1d8cce1175c013720985c30e123e9a35242c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GDS_VERSION: 2.29.4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;一问题本质&#34;&gt;一、问题本质&lt;/h2&gt;
&lt;p&gt;普通块 I/O 最终围绕 &lt;code&gt;bio_vec&lt;/code&gt;、&lt;code&gt;struct page&lt;/code&gt;、scatterlist 和 DMA mapping 展开。但 &lt;code&gt;cudaMalloc&lt;/code&gt; 得到的是 GPU 虚拟地址，对 Linux 页缓存和块层来说，它并不是普通 CPU 内存页。&lt;/p&gt;
&lt;p&gt;驱动需要解决三次“翻译”：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GPU virtual address
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; NVIDIA P2P page table 中的 GPU physical pages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; Linux I/O 栈可携带的影子 struct page
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -&amp;gt; 某个存储 PCIe 设备可使用的 DMA address
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;三个地址空间不能混为一谈：&lt;/p&gt;</description>
    </item>
    <item>
      <title>nvidia-fs 源码阅读（一）：模块初始化、设备接口与整体架构</title>
      <link>https://yangyang233333.github.io/posts/nvidia-fs-source-code-reading-architecture/</link>
      <pubDate>Fri, 21 Aug 2026 10:45:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-fs-source-code-reading-architecture/</guid>
      <description>&lt;p&gt;&lt;code&gt;nvidia-fs&lt;/code&gt; 是 NVIDIA GPUDirect Storage（GDS）的 Linux 内核模块。它不是一种文件系统，而是连接 &lt;code&gt;libcufile&lt;/code&gt;、NVIDIA GPU 驱动、Linux 文件 I/O 和支持 GPUDirect 的存储驱动的一层内核协调组件。&lt;/p&gt;
&lt;p&gt;这组文章阅读 NVIDIA 官方 &lt;code&gt;gds-nvidia-fs&lt;/code&gt; 仓库，采用的版本为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit: 328d1d8cce1175c013720985c30e123e9a35242c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GDS_VERSION: 2.29.4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit date: 2026-06-01
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;系列分为三篇：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;模块初始化、设备接口与整体架构；&lt;/li&gt;
&lt;li&gt;GPU 内存注册、页表与 DMA 映射；&lt;/li&gt;
&lt;li&gt;文件 I/O、批量请求、完成路径与可观测性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本文先回答一个问题：加载 &lt;code&gt;nvidia_fs.ko&lt;/code&gt; 后，内核里究竟多了什么？&lt;/p&gt;
&lt;h2 id=&#34;一源码目录&#34;&gt;一、源码目录&lt;/h2&gt;
&lt;p&gt;核心代码都位于 &lt;code&gt;src/&lt;/code&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;文件&lt;/th&gt;
					&lt;th&gt;职责&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-core.c/.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;字符设备、ioctl、GPU 内存注册和文件 I/O 主流程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-mod.c&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;与 NVMe、RDMA 等外部模块动态注册 DMA 回调&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-mmap.c/.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;GPU 页对应的影子 &lt;code&gt;struct page&lt;/code&gt; 和 mmap 管理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-dma.c/.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;block request 到 GPU DMA 地址的映射&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-batch.c/.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;批量 I/O 提交与完成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-rdma.c/.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;RDMA 注册信息管理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-pci.c/.h&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;GPU 与存储设备的 PCIe 拓扑、距离和亲和性&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-proc.c&lt;/code&gt;、&lt;code&gt;nvfs-stat.c&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/proc&lt;/code&gt; 配置、统计和诊断接口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;nvfs-kernel-interface.c&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;不同 Linux 内核版本的兼容封装&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;主线集中在 &lt;code&gt;nvfs-core.c&lt;/code&gt;，但真正的数据直达能力是多个文件共同完成的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>GDS、GIDS 与 uGDS 有什么区别：从数据直达、GPU 发起到用户态 NVMe</title>
      <link>https://yangyang233333.github.io/posts/gds-gids-ugds-comparison/</link>
      <pubDate>Thu, 20 Aug 2026 14:05:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/gds-gids-ugds-comparison/</guid>
      <description>&lt;p&gt;GDS、GIDS 和 uGDS 的名字非常接近，也都在讨论 GPU 与存储之间的数据通路，因此很容易被理解成同一项技术的三个版本。&lt;/p&gt;
&lt;p&gt;实际上，它们解决的是三个不同层面的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GDS&lt;/strong&gt; 关注数据路径：怎样让存储数据不经 CPU 内存中转，直接进入 GPU 显存；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GIDS&lt;/strong&gt; 关注控制路径：怎样让 GPU Kernel 自己决定并发起存储请求，减少 GPU 与 CPU 往返；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;uGDS&lt;/strong&gt; 关注软件栈：怎样让 CPU 在用户态直接管理 NVMe 队列，绕过内核 NVMe 驱动与文件系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以先用一句话概括：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;GDS 是“数据直达 GPU”，GIDS 是“GPU 主动要数据”，uGDS 是“用户态 CPU 直接驱动 NVMe 把数据送到 GPU”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文从请求由谁发起、数据经过哪里、NVMe 命令由谁构造、是否保留文件系统语义等维度，分析三者的区别与联系。更深入的原理可以继续阅读本系列的三篇文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://yangyang233333.github.io/posts/nvidia-gpudirect-storage-gds/&#34;&gt;NVIDIA GPUDirect Storage（GDS）详解：让存储数据绕过 CPU 直达 GPU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://yangyang233333.github.io/posts/nvidia-gpu-initiated-data-storage-gids/&#34;&gt;NVIDIA GPU-Initiated Data Storage（GIDS）详解：让 GPU Kernel 主动访问存储&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://yangyang233333.github.io/posts/ugds-userspace-gpu-direct-storage/&#34;&gt;uGDS 原理解析：在用户态打通 NVMe SSD 与 GPU 显存&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;一先区分数据路径与控制路径&#34;&gt;一、先区分数据路径与控制路径&lt;/h2&gt;
&lt;p&gt;理解这三项技术的关键，是不要把“数据经过哪里”和“谁发起 I/O”混为一谈。&lt;/p&gt;
&lt;h3 id=&#34;数据路径&#34;&gt;数据路径&lt;/h3&gt;
&lt;p&gt;数据路径描述有效载荷如何移动。例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;传统路径：SSD → CPU 内存 → GPU 显存
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;直接路径：SSD ──────────→ GPU 显存
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GDS、GIDS 和 uGDS 都希望建立 SSD 与 GPU 显存之间的 DMA 路径，减少 CPU bounce buffer。但“数据不经过 CPU 内存”并不代表“CPU 没有参与”。&lt;/p&gt;</description>
    </item>
    <item>
      <title>uGDS 原理解析：在用户态打通 NVMe SSD 与 GPU 显存</title>
      <link>https://yangyang233333.github.io/posts/ugds-userspace-gpu-direct-storage/</link>
      <pubDate>Thu, 20 Aug 2026 13:55:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/ugds-userspace-gpu-direct-storage/</guid>
      <description>&lt;p&gt;大模型推理正在把存储重新推到系统性能的核心位置。模型权重、KV Cache、Embedding 和训练检查点都可能在 SSD、主存与 GPU 显存之间频繁搬运。传统路径通常要经过文件系统、内核块层、页缓存或用户态中转缓冲区，不但增加 CPU 开销，也让小块 I/O 延迟变得难以控制。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/ScaleX-IO/uGDS&#34;&gt;uGDS&lt;/a&gt; 是 ScaleX-IO 开源的一套用户态 GPU Direct Storage 开发库。它的核心思路很直接：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;让 CPU 在用户态构造 NVMe 命令并管理提交队列与完成队列，由 SSD 通过 PCIe P2P DMA 直接读写 GPU 显存，从数据路径中绕开内核 NVMe 驱动和文件系统。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文结合 uGDS 当前源码，解释它为什么快、一次 I/O 如何执行、内核模块与用户态库如何分工，以及使用这类“绕过内核”的存储栈时必须承担哪些工程责任。&lt;/p&gt;
&lt;h2 id=&#34;一ugds-想解决什么问题&#34;&gt;一、uGDS 想解决什么问题&lt;/h2&gt;
&lt;p&gt;先看一条常见的数据读取路径：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NVMe SSD
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;内核 NVMe 驱动 → 块层 → 文件系统
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;主机内存缓冲区
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GPU 显存
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即使系统支持 Direct I/O，应用仍然通常要进入内核，由内核驱动准备 NVMe 命令、完成 DMA 映射并处理中断或轮询。若数据还要经过主机内存，再复制到 GPU，路径会更长。&lt;/p&gt;</description>
    </item>
    <item>
      <title>NVIDIA GPU-Initiated Data Storage（GIDS）详解：让 GPU Kernel 主动访问存储</title>
      <link>https://yangyang233333.github.io/posts/nvidia-gpu-initiated-data-storage-gids/</link>
      <pubDate>Wed, 19 Aug 2026 14:05:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-gpu-initiated-data-storage-gids/</guid>
      <description>&lt;p&gt;GPUDirect Storage（GDS）已经能够让存储数据绕过 CPU 内存，直接进入 GPU 显存。但经典 GDS 仍有一个重要特征：I/O 请求由 CPU 侧应用代码提交。&lt;/p&gt;
&lt;p&gt;当 GPU kernel 在执行过程中才知道下一份数据位于哪里时，控制权必须在 GPU 与 CPU 之间往返。对于图计算、向量检索、稀疏模型和超大规模数据分析，这种细粒度同步可能比数据传输本身更昂贵。&lt;/p&gt;
&lt;p&gt;NVIDIA GPU-Initiated Data Storage，简称 &lt;strong&gt;GIDS&lt;/strong&gt;，试图进一步消除这层控制瓶颈：让 GPU kernel 直接发起存储 I/O，使 GPU 不仅是数据的接收者，也是 I/O 请求的生产者。&lt;/p&gt;
&lt;p&gt;本文介绍 GIDS 的动机、架构、工作流程、适用场景，以及它和 GDS 的本质区别。&lt;/p&gt;
&lt;h2 id=&#34;一为什么有了-gds-还需要-gids&#34;&gt;一、为什么有了 GDS 还需要 GIDS&lt;/h2&gt;
&lt;p&gt;GDS 优化了数据路径：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU 发起请求
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;存储 ─────────────► GPU 显存
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       数据不经过 CPU 内存
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这已经消除了大量主机内存中转，但控制路径仍然经过 CPU。经典流程可能是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GPU 执行 kernel；&lt;/li&gt;
&lt;li&gt;GPU 产生下一批要访问的数据索引；&lt;/li&gt;
&lt;li&gt;kernel 结束或与 CPU 同步；&lt;/li&gt;
&lt;li&gt;CPU 读取结果并构造文件 I/O；&lt;/li&gt;
&lt;li&gt;CPU 调用 cuFile；&lt;/li&gt;
&lt;li&gt;数据进入 GPU；&lt;/li&gt;
&lt;li&gt;CPU 再次启动 kernel。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果每次请求都是大块、批量且可提前预测，这种方式通常没有问题。但如果 GPU 在计算过程中产生数以万计甚至更多的动态访问，频繁的 GPU—CPU 往返会带来：&lt;/p&gt;</description>
    </item>
    <item>
      <title>NVIDIA GPUDirect Storage（GDS）详解：让存储数据绕过 CPU 直达 GPU</title>
      <link>https://yangyang233333.github.io/posts/nvidia-gpudirect-storage-gds/</link>
      <pubDate>Wed, 19 Aug 2026 14:00:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/nvidia-gpudirect-storage-gds/</guid>
      <description>&lt;p&gt;在 AI 训练、科学计算和数据分析系统中，GPU 的算力越来越强，但数据从存储设备进入 GPU 的路径却可能成为瓶颈。传统 I/O 通常要先把数据读入 CPU 内存，再复制到 GPU 显存，不仅增加内存带宽消耗，还让 CPU 承担大量数据搬运工作。&lt;/p&gt;
&lt;p&gt;NVIDIA GPUDirect Storage，简称 &lt;strong&gt;GDS&lt;/strong&gt;，解决的正是这个问题：它在存储设备与 GPU 显存之间建立更直接的数据路径，使应用能够通过 &lt;code&gt;cuFile&lt;/code&gt; API 将文件数据读入 GPU 缓冲区，减少 CPU bounce buffer 和不必要的数据复制。&lt;/p&gt;
&lt;p&gt;本文介绍 GDS 的工作原理、软件栈、典型使用方式、适用场景以及它与 GPU-Initiated Data Storage（GIDS）的关系。&lt;/p&gt;
&lt;h2 id=&#34;一传统-gpu-io-为什么效率不高&#34;&gt;一、传统 GPU I/O 为什么效率不高&lt;/h2&gt;
&lt;p&gt;传统文件读取到 GPU 的路径大致如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NVMe / 文件系统
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU 内存缓冲区
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       │ cudaMemcpy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GPU 显存
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应用通常先调用 &lt;code&gt;read&lt;/code&gt;、&lt;code&gt;pread&lt;/code&gt; 或异步 I/O 接口，把文件内容读入主机内存，然后再调用 CUDA memcpy 将数据复制到 GPU。&lt;/p&gt;
&lt;p&gt;这条路径存在几个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一份数据先经过 CPU 内存，再进入 GPU 显存；&lt;/li&gt;
&lt;li&gt;存储流量和 GPU 传输流量竞争 CPU 内存带宽；&lt;/li&gt;
&lt;li&gt;CPU 需要提交、管理和完成数据搬运；&lt;/li&gt;
&lt;li&gt;大规模 GPU 系统中，CPU 和内存通道容易成为共享瓶颈；&lt;/li&gt;
&lt;li&gt;应用需要维护主机端 staging buffer，并处理双重缓冲。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当 GPU 计算越来越快、单机挂载更多 NVMe 或更高速的并行文件系统后，这些额外开销会更加明显。&lt;/p&gt;</description>
    </item>
    <item>
      <title>数据库 MVCC 原理与实现：版本链、事务快照和可见性判断</title>
      <link>https://yangyang233333.github.io/posts/database-mvcc-principles-and-implementation/</link>
      <pubDate>Fri, 14 Aug 2026 23:50:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/database-mvcc-principles-and-implementation/</guid>
      <description>&lt;p&gt;MVCC（Multi-Version Concurrency Control，多版本并发控制）是现代数据库实现高并发事务的重要机制。它的核心思想并不复杂：&lt;strong&gt;数据被修改时，不立即丢弃旧值，而是保留多个版本；事务读取数据时，根据自己的快照选择可见版本。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因此，读事务可以继续访问旧版本，写事务则创建新版本。普通读取通常不需要等待并发写入完成，写入也不必等待读事务释放共享锁。&lt;/p&gt;
&lt;p&gt;本文从 MVCC 要解决的问题出发，依次说明版本存储、事务快照、可见性判断、写冲突控制和旧版本回收，并比较 InnoDB 与 PostgreSQL 的典型实现。&lt;/p&gt;
&lt;h2 id=&#34;一为什么需要-mvcc&#34;&gt;一、为什么需要 MVCC&lt;/h2&gt;
&lt;p&gt;假设数据库中存在一条记录：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;账户 A 的余额 = 100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;事务 T1 正在读取这条记录，与此同时，事务 T2 希望把余额修改为 &lt;code&gt;80&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果所有读取都依赖共享锁，那么 T2 可能必须等待 T1 结束；如果 T2 已经持有排他锁，T1 又可能必须等待 T2。锁能够保证正确性，但大量读写互相等待会降低系统并发能力，并增加死锁概率。&lt;/p&gt;
&lt;p&gt;MVCC 使用另一种思路处理普通读取：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;新版本：balance = 80，由 T2 创建
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;旧版本：balance = 100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果 T1 的事务快照不允许它看到 T2 的修改，T1 就读取旧版本 &lt;code&gt;100&lt;/code&gt;；在 T2 提交后启动的新事务，则可以读取新版本 &lt;code&gt;80&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;于是，同一时刻可以出现：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;旧事务看到 100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;新事务看到 80
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这不是数据不一致，而是两个事务观察到了数据库在不同逻辑时刻的一致状态。&lt;/p&gt;
&lt;h2 id=&#34;二mvcc-的五个组成部分&#34;&gt;二、MVCC 的五个组成部分&lt;/h2&gt;
&lt;p&gt;一个完整的 MVCC 实现通常包含五个部分：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MVCC = 多版本存储
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     + 事务快照
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     + 可见性判断
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     + 写冲突控制
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     + 旧版本回收
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只保存历史版本还不够。数据库还必须知道版本由谁创建、事务能够看到哪些版本、两个写事务冲突时如何处理，以及历史版本何时可以安全删除。&lt;/p&gt;</description>
    </item>
    <item>
      <title>3FS 如何使用 FoundationDB：元数据模型、事务与并发控制</title>
      <link>https://yangyang233333.github.io/posts/3fs-foundationdb-metadata-design/</link>
      <pubDate>Fri, 14 Aug 2026 19:10:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/3fs-foundationdb-metadata-design/</guid>
      <description>&lt;p&gt;3FS 是面向 AI 训练和推理负载设计的分布式文件系统。它没有把 FoundationDB 当成普通的持久化 KV 使用，而是围绕 FoundationDB 的有序键空间、乐观事务、冲突检测和 Versionstamp，构建了一套强一致的文件系统元数据服务。&lt;/p&gt;
&lt;p&gt;本文从源码出发，梳理 3FS 如何接入 FoundationDB，如何编码 inode 和目录项，以及 create、rename、remove、list 等文件系统操作怎样映射为 FoundationDB 事务。&lt;/p&gt;
&lt;p&gt;本文分析的源码位于 3FS 仓库中的以下目录：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/fdb/             FoundationDB C API 封装
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/common/kv/       通用 KV 和事务接口
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/meta/store/      inode、目录项和元数据操作
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/meta/components/ ID 分配、服务分布和 GC 等组件
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;src/meta/service/    Meta Service RPC 入口
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;一3fs-中-foundationdb-的定位&#34;&gt;一、3FS 中 FoundationDB 的定位&lt;/h2&gt;
&lt;p&gt;3FS 将数据面和元数据面分开：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件的 chunk 数据由 Storage Service 保存。&lt;/li&gt;
&lt;li&gt;文件系统元数据由 Meta Service 管理，并持久化到 FoundationDB。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FoundationDB 中保存的主要内容包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;inode；&lt;/li&gt;
&lt;li&gt;directory entry，也就是目录项；&lt;/li&gt;
&lt;li&gt;文件打开会话；&lt;/li&gt;
&lt;li&gt;RPC 幂等记录；&lt;/li&gt;
&lt;li&gt;Meta Server 分布信息；&lt;/li&gt;
&lt;li&gt;用户、配置和其他全局状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整体调用链可以简化为：&lt;/p&gt;</description>
    </item>
    <item>
      <title>FoundationDB 事务如何实现？从源码看 GRV、Resolver、TLog 与 Storage Server</title>
      <link>https://yangyang233333.github.io/posts/foundationdb-transaction-implementation/</link>
      <pubDate>Fri, 14 Aug 2026 17:00:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/foundationdb-transaction-implementation/</guid>
      <description>&lt;p&gt;FoundationDB 支持跨任意 key range 的 ACID 事务，并向应用提供严格可串行化语义。但它既没有让每个 Storage Server 参与经典的两阶段提交，也不是传统单机数据库中“共享缓冲池 + Undo/Redo”的事务实现。&lt;/p&gt;
&lt;p&gt;它的核心方案可以概括为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;全局版本号 + MVCC 快照读 + 客户端暂存修改 + Resolver 乐观冲突检测 + 多副本 TLog 持久化。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文结合 FoundationDB 官方源码，沿着一笔事务的完整路径，解释它如何从读取、提交、冲突检测，一直走到日志持久化和 Storage Server 应用。&lt;/p&gt;
&lt;p&gt;本文分析的源码版本为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit: eab21ffe07c20575d5bac9ab0745375b8f7f8357
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;date:   2026-08-12
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;源码中的具体行号会随版本变化，阅读时应以函数和类型名为主要定位依据。&lt;/p&gt;
&lt;h2 id=&#34;一整体架构&#34;&gt;一、整体架构&lt;/h2&gt;
&lt;p&gt;FoundationDB 的事务涉及以下核心角色：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;角色&lt;/th&gt;
					&lt;th&gt;主要职责&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Client&lt;/td&gt;
					&lt;td&gt;保存事务 mutations、读冲突范围和写冲突范围&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;GRV Proxy&lt;/td&gt;
					&lt;td&gt;分配 Read Version&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Commit Proxy&lt;/td&gt;
					&lt;td&gt;批量接收事务、分配 Commit Version、组织提交流水线&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Resolver&lt;/td&gt;
					&lt;td&gt;检测乐观事务冲突&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;TLog&lt;/td&gt;
					&lt;td&gt;复制并持久化已提交 mutations&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Storage Server&lt;/td&gt;
					&lt;td&gt;提供版本化读取，异步应用 TLog mutations&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Sequencer&lt;/td&gt;
					&lt;td&gt;为事务系统提供版本推进基础&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;完整流程可以简化为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Client
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ├── 获取 Read Version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ├── 从 Storage Server 读取该版本
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ├── 在客户端积累 mutations 和 conflict ranges
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  └── 提交
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Commit Proxy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 组成 Commit Batch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 分配 Commit Version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── 按 key range 发给 Resolver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     Resolver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 检查 read conflict ranges
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 登记 write conflict ranges
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── 返回 committed / conflict / too old
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Commit Proxy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 丢弃冲突事务
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 为 mutation 添加 Storage Server tag
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── 将成功事务写入 TLog
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       TLog
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 按冗余策略复制和持久化
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── 返回 durable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Commit Proxy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── 向 Client 返回 Commit Version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ▼
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Storage Server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 异步读取自己的 tagged mutations
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ├── 应用到内存中的版本化数据
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └── 后台持久化到 Storage Engine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最关键的解耦是：&lt;/p&gt;</description>
    </item>
    <item>
      <title>FoundationDB 中有 Undo 和 Redo 吗？从 TLog、MVCC 到故障恢复</title>
      <link>https://yangyang233333.github.io/posts/foundationdb-undo-redo/</link>
      <pubDate>Fri, 14 Aug 2026 10:00:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/foundationdb-undo-redo/</guid>
      <description>&lt;p&gt;传统数据库通过 Undo Log 和 Redo Log 保证事务的原子性与持久性：Undo 撤销未提交的修改，Redo 恢复已经提交但尚未写入数据文件的修改。那么，在采用分布式事务架构的 FoundationDB 中，是否也存在这两类日志？&lt;/p&gt;
&lt;p&gt;简短回答是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;FoundationDB 有承担类似 Redo 职责的 TLog，但通常没有传统意义上的 Undo Log。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这并不意味着 FoundationDB 不支持事务回滚或 MVCC，而是因为它对未提交数据、提交日志和历史版本的组织方式与传统数据库不同。&lt;/p&gt;
&lt;h2 id=&#34;一先回顾传统数据库为什么需要-undo-和-redo&#34;&gt;一、先回顾传统数据库为什么需要 Undo 和 Redo&lt;/h2&gt;
&lt;p&gt;传统数据库通常允许事务直接修改缓冲池中的共享数据页。数据页何时写入磁盘，与事务何时提交并不完全同步。&lt;/p&gt;
&lt;p&gt;因此会出现两种状态。&lt;/p&gt;
&lt;h3 id=&#34;1-事务未提交数据页却已经落盘&#34;&gt;1. 事务未提交，数据页却已经落盘&lt;/h3&gt;
&lt;p&gt;例如事务把账户余额从 &lt;code&gt;100&lt;/code&gt; 改成 &lt;code&gt;80&lt;/code&gt;，但随后事务失败：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;BEGIN&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;UPDATE&lt;/span&gt; account
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SET&lt;/span&gt; balance &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ROLLBACK&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果包含 &lt;code&gt;80&lt;/code&gt; 的脏页已经写入磁盘，数据库就必须知道原值是 &lt;code&gt;100&lt;/code&gt;，才能撤销这次修改。这是 Undo Log 的主要职责。&lt;/p&gt;
&lt;h3 id=&#34;2-事务已经提交数据页却尚未落盘&#34;&gt;2. 事务已经提交，数据页却尚未落盘&lt;/h3&gt;
&lt;p&gt;另一个事务已经执行 &lt;code&gt;COMMIT&lt;/code&gt;，但修改可能仍然只存在于内存中的脏页里。如果服务器此时断电，已提交的数据就会丢失。&lt;/p&gt;
&lt;p&gt;因此数据库先持久化 Redo Log，再返回提交成功。重启后，即使数据页没有及时落盘，也可以通过 Redo 重新应用修改。&lt;/p&gt;
&lt;p&gt;可以把二者概括为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Undo：事务不应该生效，但修改可能已经进入数据文件。
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Redo：事务应该生效，但修改可能还没有进入数据文件。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;二foundationdb-的事务提交流程&#34;&gt;二、FoundationDB 的事务提交流程&lt;/h2&gt;
&lt;p&gt;FoundationDB 并不是把客户端事务中的每次 &lt;code&gt;set&lt;/code&gt; 或 &lt;code&gt;clear&lt;/code&gt; 立即写入 Storage Server。事务提交前，这些操作首先保存在客户端的事务对象中。&lt;/p&gt;</description>
    </item>
    <item>
      <title>哈希碰撞概率与生日界：从公式到 SHA-256 / XXH128 实测</title>
      <link>https://yangyang233333.github.io/posts/hash-collision-birthday-bound/</link>
      <pubDate>Tue, 11 Aug 2026 15:10:00 +0800</pubDate>
      <guid>https://yangyang233333.github.io/posts/hash-collision-birthday-bound/</guid>
      <description>&lt;p&gt;选哈希算法时常有两个问题绑在一起：&lt;strong&gt;碰撞概率有多小&lt;/strong&gt;、&lt;strong&gt;算得有多快&lt;/strong&gt;。这篇把碰撞概率背后的数学（生日界）讲清楚，再用它算一算 256-bit 的 SHA-256/BLAKE3 与 128-bit 的 XXH128 各自的碰撞概率，最后附上一组本机实测速度数据。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本文所有实测数据均来自随机生成的字节串，不含任何业务或私有数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;一背景碰撞概率的两种含义&#34;&gt;一、背景：碰撞概率的两种含义&lt;/h2&gt;
&lt;p&gt;对固定长度输出的哈希，&amp;ldquo;碰撞概率&amp;quot;必须分两种场景谈，否则会得出互相矛盾的结论：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;随机碰撞&lt;/strong&gt;：没有攻击者，数据是正常/随机的。这时只要输出在取值空间里均匀分布，碰撞概率就纯粹由&lt;strong&gt;输出位数&lt;/strong&gt;决定，与具体算法无关。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;抗恶意碰撞&lt;/strong&gt;：有攻击者知道算法、故意构造两个哈希相同的输入。这里才真正区分&lt;strong&gt;加密哈希&lt;/strong&gt;（SHA-256、BLAKE3、BLAKE2）和&lt;strong&gt;非加密哈希&lt;/strong&gt;（xxHash、CityHash、Murmur）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;第一种是数学问题，用生日界就能算。第二种是密码学性质，非加密哈希直接不提供保证。&lt;/p&gt;
&lt;h2 id=&#34;二生日问题直觉的陷阱&#34;&gt;二、生日问题：直觉的陷阱&lt;/h2&gt;
&lt;p&gt;一个房间里要多少人，才有超过 50% 的概率存在两人同一天生日？答案是 &lt;strong&gt;23 人&lt;/strong&gt;——远比直觉小。原因在于碰撞看的不是&amp;quot;某人和我同天&amp;rdquo;，而是&amp;quot;任意两人之间&amp;quot;的配对数：&lt;code&gt;n&lt;/code&gt; 个人有 &lt;code&gt;n(n-1)/2 ≈ n²/2&lt;/code&gt; 对，概率随 &lt;code&gt;n²&lt;/code&gt; 增长。&lt;/p&gt;
&lt;p&gt;哈希碰撞是同一个问题：把&amp;quot;人&amp;quot;换成&amp;quot;哈希输入&amp;quot;，把&amp;quot;365 天&amp;quot;换成&amp;quot;哈希空间大小 &lt;code&gt;N&lt;/code&gt;&amp;quot;。对 128-bit 哈希，&lt;code&gt;N = 2^128&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;三生日界公式的推导&#34;&gt;三、生日界公式的推导&lt;/h2&gt;
&lt;p&gt;设哈希空间大小为 &lt;code&gt;N&lt;/code&gt;，独立均匀地放入 &lt;code&gt;n&lt;/code&gt; 个值。直接算&amp;quot;至少一次碰撞&amp;quot;要用容斥，很麻烦，所以反过来算&amp;quot;全部不同&amp;quot;的概率：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;第 1 个：随便放         → N/N
第 2 个：不能撞前 1 个  → (N-1)/N
...
第 n 个：不能撞前 n-1 个 → (N-n+1)/N
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;全部不同的概率是连乘：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;P(无碰撞) = ∏_{k=0}^{n-1} (1 - k/N)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;于是至少一次碰撞：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;P(碰撞) = 1 - ∏_{k=0}^{n-1} (1 - k/N)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是精确解，但连乘不好用。用近似 &lt;code&gt;1 - x ≈ e^(-x)&lt;/code&gt;（&lt;code&gt;x&lt;/code&gt; 很小时成立）把每一项换掉：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
