假设一个客服知识库场景:客服刚把一条错误答案标记为”已撤回”(一次
delete),三十毫秒后同一个客服在同一个会话里追问,触发一次
search。如果这次 search
命中的执行节点还没来得及处理那条
delete,撤回的错误答案会重新出现在检索结果里,客服可能当场把它读给用户听。反过来,如果每一次
search
都要等到”集群里所有节点都追上最新写入”才放行,撤回生效很快,但代价是每次查询都可能因为别的租户的写入峰值而排队。“实时可搜”常被简化理解成”insert
返回成功后下一次 search
一定看到”,但这句话在存算分离架构下并不成立——Milvus
用可调一致性级别把它拆成一句更诚实的话:你愿意为多新的数据视图等待多久。第
4、9 篇 已引入
GuaranteeTs;本文按官方文档把四级语义、等待条件与代价交代清楚。
本文是「向量检索引擎」系列第 12 篇(共 19 篇)。→ 系列目录
版本锚定:Milvus 2.6.x Consistency Level、Timestamp;数据面路径对齐 Data Processing(Growing / Sealed)。
一、问题从哪来:PACELC,不是”要不要一致”
存算分离下,执行节点可能尚未看见全部最新流式更新;若不加约束,直接在不完整视图上 search 会丢未提交/未追上的点。这不是 Milvus 独有的困境,而是所有复制数据的分布式系统共享的结构性权衡。Abadi 在 Consistency Tradeoffs in Modern Distributed Database System Design(IEEE Computer, 2012)里把 CAP 定理之外的这层权衡显式化为 PACELC:如果发生网络分区(P),系统要在可用性(A)与一致性(C)之间取舍;否则(E,正常运行时),系统要在延迟(L)与一致性(C)之间取舍。Abadi 的论文用这套框架给 Dynamo/Cassandra(PA/EL)、PNUTS(PC/EL)、VoltDB/Megastore(PC/EC)、MongoDB(PA/EC)各自定位——绝大多数系统在”正常运行时”这一栏(ELC)上是固定的架构选择,不是每次请求可变的参数。
Milvus 官方 Consistency Level 文档直接引用
PACELC
定理来解释四级设计的动机:高一致性意味着更高准确性也意味着更高搜索延迟,低一致性带来更快的搜索速度但有一定的数据可见性损失。它与
Abadi 分类的系统不同之处在于:Milvus 把 ELC
权衡从”系统级固定架构选择”下放成了”单次 search / query
可覆盖的参数”——同一个 Collection 里,一次功能测试的
search 可以用
Strong,一次高峰期的推荐召回可以用
Eventually,二者共享同一份底层数据和执行节点。这个”per-request
可调”的设计本身没有对应的独立学术定位——PACELC
论证的是系统架构层面的一次取舍,Milvus
的做法更接近把这次取舍参数化并交给调用方,是工程上对
PACELC 权衡的一种再包装,而不是对该权衡的绕开。
二、四级一致性与 GuaranteeTs
支持级别:Strong、Bounded、Session、Eventually;默认 Bounded。
| 级别 | GuaranteeTs 如何定(官方直觉) | 体验 |
|---|---|---|
| Strong | 等于最新系统时间戳 | 等到 ServiceTime 追上再搜;延迟↑,新鲜度↑ |
| Bounded(默认) | 早于最新的时间点,容忍有界陈旧 | 延迟与新鲜度折中 |
| Session | 该客户端最近一次写操作的时间戳 | “我刚写的”优先可见,不代表其它客户端的写也立即可见 |
| Eventually | 取一个很小的值,跳过一致性检查 | 立即在已有视图上返回 |
用一条时间轴把四级的 GuaranteeTs 摆在同一个刻度上,比记住四条定义更容易在排障时对号入座:
flowchart LR
t0["t = t0(历史数据,已稳定)"] --> t1["t = t1(write A 提交到 WAL)"]
t1 --> t2["t = t2(write B 刚提交,此刻发起 search)"]
subgraph G["四级一致性对应的 GuaranteeTs 取值"]
strong["Strong: GuaranteeTs = t2"]
bounded["Bounded(默认): GuaranteeTs 落在 [t0, t2) 的某个容忍窗口内"]
session["Session: GuaranteeTs = 发起方自己最近一次写的时间戳(可能是 t1 或更早)"]
eventually["Eventually: GuaranteeTs ≈ 0,跳过比较"]
end
t2 -.->|"必须等 ServiceTime 追上 t2"| strong
t1 -.->|"容忍窗口内即可"| bounded
t1 -.->|"只保证看到自己写的那部分"| session
t0 -.->|"立即在旧视图上执行"| eventually
可在创建 Collection 时设默认级别,也可在单次 search / query 覆盖(官方 API 示例)。用户通常不手写原始 TSO;选级别即可,由系统映射 GuaranteeTs。
三、等待条件与 Strong 一致性的完整时序
Timestamp
文档给出的比较对象:Service_timestamp(执行侧已完成的
DML
水位)、Guarantee_timestamp(本次查询要求的水位)、Graceful_time(集群配置的容忍窗口,是一段时长,不是时间点)。
| 条件 | 行为 |
|---|---|
| \(S \ge G\) | 可立即执行 |
| \(S + g \ge G\)(\(g\) 为 Graceful_time) | 可在容忍窗口内执行 |
| 仍不满足 | 推迟 search/query,直到水位追上 |
用一组具体数字把四级映射到这张判定表,能看出它们其实共享同一套比较逻辑,只是
\(G\)
的取值方式不同。假设某次查询发起时刻,全局最新时间戳是 \(t=1000\)(单位为逻辑时间刻度),执行节点当前
Service_timestamp 是 \(S=940\),容忍窗口 \(g=80\):
| 一致性级别 | \(G\) 的取值 | 判定 | 结果 |
|---|---|---|---|
| Strong | \(G=1000\) | \(S=940 < G=1000\),且 \(S+g=1020\ge G\) | 若严格按 \(S\ge G\) 判定则需等待 \(S\) 追到 1000;Strong 语义上不使用 Graceful_time 容忍,必须等 \(S\ge G\) |
| Bounded(默认) | \(G\) 略小于 1000,例如 \(920\)(示意值,非官方精确算法) | \(S=940 \ge G=920\) | 立即执行 |
| Session | \(G=\) 该客户端上次写入时间戳,例如 \(900\) | \(S=940 \ge G=900\) | 立即执行 |
| Eventually | \(G\approx 0\) | 恒成立 | 立即执行 |
这组数字想说明的是:四级一致性不是四套不同的比较算法,而是同一个 \(S \ge G\)(或 \(S+g\ge G\))判定式下,\(G\) 的四种不同生成方式——Strong 把 \(G\) 钉在”此刻的绝对最新”,其它三级都在用不同规则让 \(G\) 更容易被 \(S\) 满足,从而减少等待。表中 Bounded 的具体数值是示意,用来说明”\(G\) 比最新时间戳小一些”这句官方定性描述在判定式里如何生效,不代表官方给出的精确折算公式。
把开篇客服撤回的故事画成时序图:客户端发起
delete,随后同一会话发起 Strong 一致性
search,Streaming Node 必须等到自己的
Service_timestamp
追上这次删除的时间戳才放行。
sequenceDiagram
participant C as Client(客服会话)
participant Px as Proxy
participant SN as Streaming Node(Delegator)
C->>Px: delete(pk, filter)
Px->>Px: TSO 分配时间戳 t_del,写入 WAL
Note over C,Px: 30ms 后,同一会话追问
C->>Px: search(consistency_level=Strong)
Px->>Px: 解出 Guarantee_timestamp = 当前最新时间戳(>= t_del)
Px->>SN: search(plan, Guarantee_timestamp)
loop 直到水位满足
SN->>SN: 比较 Service_timestamp (+ Graceful_time) 与 Guarantee_timestamp
alt Service_timestamp >= Guarantee_timestamp
SN->>SN: 放行,进入段级 search(已应用删除 bitset)
else 尚未追上
SN->>SN: 推迟,等待 WAL 消费追赶
end
end
SN-->>Px: 不含撤回答案的结果
Px-->>C: 最终结果
因此 Strong 相对 Eventually
的主要代价往往是尾延迟(等待),不是另一套
ANN 算法——图中卡住的环节是”比较水位、决定放行还是等待”,不是
Knowhere 的向量距离计算。若这次删除还在 WAL 提交与 Growing
追加的路径上排队(写入峰值期),这次 search
就会跟着卡住。
四、Session 与 Bounded 的精确边界
Session 保证的是”该客户端能看到自己写入的效果”,对应经典的 read-your-writes 语义(Terry, Demers, Petersen, Spreitzer, Theimer, Welch, Session Guarantees for Weakly Consistent Replicated Data, PDIS 1994,定义了会话一致性的四种保证,read-your-writes 是其中一种)。官方文档明确 Session 是”该客户端插入到达的时间点为 GuaranteeTs”——这不是”全集群所有客户端任意写入立即彼此可见”,那更接近 Strong。开篇故事里,如果客服 A 撤回答案、客服 B 在另一个会话里立刻查询,Session 级别不保证 B 能看到 A 的撤回——只有 A 自己的下一次查询才有这层保证。
4.1 Terry et al. 的四种会话保证,Milvus 只实现了其中一种
Terry et al. 1994 年的论文不是只定义了”read-your-writes”,而是给出了一组四种独立的会话保证,工程上经常被笼统地简化成”session consistency”一个词,但四种保证各自约束的读写关系不同:
| 保证 | 论文定义(简述) | Milvus Session 是否实现 |
|---|---|---|
| Read Your Writes(RYW) | 一次读操作能看到该会话此前所有写操作的效果 | 是——官方 Session 定义直接对应这一条 |
| Monotonic Reads | 该会话内连续的读操作,看到的数据只会越新不会倒退 | 官方文档未显式声明;若同一 collection
存在多个执行节点各自追赶 GuaranteeTs 的速度不同,两次连续的
Session 级 search
理论上也可能落在不同节点,是否单调未见官方保证 |
| Writes Follow Reads | 该会话一次写操作发生在它读到的所有更新之后(写不会”追不上”已读的更新) | 官方文档未提及;Milvus 的写路径通过 TSO 分配时间戳,时间戳本身单调,但这条保证关心的是”因果顺序”而非”时间戳大小”,官方未给出因果层面的说明 |
| Monotonic Writes | 该会话内的写操作按发起顺序生效,不会乱序提交 | 同一 shard 内的 DML 由持有 WAL 的单一 Streaming Node 顺序处理(第 5 篇),符合直觉,但官方 Consistency Level 文档没有把这条作为 Session 级别的显式承诺 |
把这张表摆出来的意义是:“Session 一致性”这个名字容易让人以为四种保证都齐了,但 Milvus 官方只显式承诺了 Read Your Writes 这一条。剩下三条即便工程实现上大概率成立(例如同 shard 内 DML 顺序处理天然满足 Monotonic Writes),也没有被写进产品语义承诺——如果业务逻辑依赖”两次连续读一定不会倒退”这类更强的假设,需要自己验证,不能只看 Session 这个名字就当作免费获得。
4.2 Bounded:从定性描述到一个具体窗口的例子
Bounded 允许有界陈旧,但官方给出的只是定性描述:“GuaranteeTs 设得比最新时间戳小一些,容忍一个窗口内的陈旧”,没有给出这个窗口有多大、多少比例的请求会落在窗口内的概率化保证。Bailis, Venkataraman, Franklin, Hellerstein, Stoica 在 Probabilistically Bounded Staleness for Practical Partial Quorums(VLDB 2012)里给的是相反方向的工作:对 quorum 复制系统,给出”\(t\) 毫秒后读到最新写入的概率是多少”的可计算模型。Milvus 的 Bounded 是一个运维可调的定性旋钮,Bailis et al. 的 PBS 是一个理论上可计算的概率模型——两者解决同一个问题(有界陈旧),但一个给旋钮,一个给公式,不能拿 PBS 的公式去预测 Milvus Bounded 窗口下的具体命中率。
把这个”旋钮”具体化成一个可推演的时间线,比记住”容忍一个窗口”这句话更容易在运维时对号入座。假设某个
Collection 配置的容忍窗口对应的 Graceful_time
是一个固定时长(记为 \(g\)),一次写入在 \(t_1\) 时刻提交,一次 Bounded
级别的 search 在 \(t_1 + 3g\) 时刻发起:
\[ \text{Guarantee\_timestamp} = t_{\text{now}} - g \quad(\text{官方描述的定性关系,具体折算方式未公开}) \]
如果发起查询时 \(t_{\text{now}}
= t_1 + 3g\),则 \(\text{Guarantee\_timestamp} = t_1 +
2g\),早于当前最新时间戳;只要执行节点的
Service_timestamp 已经追到 \(t_1 +
2g\)(这几乎总是成立,除非该节点严重落后),查询立即放行,读到的数据可能比”绝对最新”落后最多
\(g\)。反过来,如果查询紧贴写入发起(\(t_{\text{now}} = t_1\)),\(\text{Guarantee\_timestamp} = t_1 -
g\),早于写入本身的时刻,查询同样立即放行——但这次很可能读不到
\(t_1\)
这次写入的效果,因为查询要求的水位本来就在写入之前。这个推演想说明的是:Bounded
的”陈旧窗口”不是”写入后固定等 \(g\)
才可见”,而是”查询愿意接受比当前时刻旧 \(g\)
的视图”——旧到什么程度取决于查询发起的时刻与写入时刻的相对位置,不是一个对每次写入都固定的等待时长。官方文档没有公开
Graceful_time 具体如何折算进 Guarantee_timestamp
的计算公式,上面的推演是按官方定性描述做的示意,不代表官方承诺的精确算法。
五、多 shard 场景下,一次查询的 GuaranteeTs 要满足几个节点
前几节都在单个 Streaming Node
的视角下讨论”水位追上”,但一次真实的 search
通常会按 Channel/shard 拆成多路并发请求(第 9
篇的多级归并树)。这里有一个容易被忽略的细节:Guarantee_timestamp
是这次查询整体的要求,但”是否放行”要在每一路 shard 各自的
Streaming/Query Node
上分别判断,不是由某个中心节点统一裁决一次。
flowchart TB
Px["Proxy:解出 Guarantee_timestamp = G"]
Px --> SN1["Shard 0 Streaming Node<br/>比较本地 Service_timestamp"]
Px --> SN2["Shard 1 Streaming Node<br/>比较本地 Service_timestamp"]
Px --> SN3["Shard 2 Streaming Node<br/>比较本地 Service_timestamp"]
SN1 -->|"已追上 G"| R1["立即返回 shard 0 局部结果"]
SN2 -->|"仍落后 G"| W2["推迟,等待追赶"]
SN3 -->|"已追上 G"| R3["立即返回 shard 2 局部结果"]
W2 -.->|"追上后"| R2["返回 shard 1 局部结果"]
R1 --> Merge["Proxy 归并三路结果"]
R3 --> Merge
R2 --> Merge
这张图想说明的是:只要有一路 shard
落后,整次查询的可观测延迟就是”最慢那一路追赶的时间”,不是各
shard 延迟的平均值。这解释了为什么”某个 shard
因为写入倾斜、消费 WAL 慢半步”这类局部问题,会拖累使用
Strong 或严格 Bounded
一致性的整次查询,即便其它 shard 早就绪——第
9
篇讨论的”多级归并树”在一致性维度上还叠加了一层”多路水位对齐”,两层放大机制会同时出现在同一次慢查询里。排障时如果只看
Proxy 侧的平均延迟指标,容易漏掉”某一个 shard
长期落后”这类局部问题,需要下钻到分 shard 的
Service_timestamp 差值。
六、对照 2.6 数据面:精确理解”刚写入就能搜”
2.6 Data Processing:WAL 提交后进入 Growing,由 Streaming Node 路径参与实时查询;Sealed 在 Query Node。Consistency 文档的示意图仍用较笼统的 QueryNode 收流叙述——阅读时映射为:
- 写入成功 = 相关 Message 已按 TSO 提交到 WAL(第 5 篇);
- 对某次 search 可见 = 该次请求的 GuaranteeTs 所要求的更新,已进入执行路径的可见水位(Growing 与/或已 handoff 的 Sealed);
- 索引最优路径就绪 = Data Node 建索 + Query Node 加载完成(第 10 篇)——这是性能问题,不是一致性级别字面承诺的内容。
三者互相独立:一致性级别只回答第 2 步,不回答第 3 步。一次 Strong 一致性的查询完全可能”看到”了刚写入的数据(第 2 步满足),但因为这批数据还在 Growing 段里跑暴力或未优化的临时索引路径(第 7 篇),延迟仍然偏高——这不是一致性级别的问题,是索引生命周期的问题,混在一起排障容易找错方向。
七、常见误解
误解一:一致性级别只影响能不能读到最新数据,不影响延迟。
第三节的时序图已经说明:Strong 意味着执行侧要等到
Service_timestamp
追上请求发起时刻的最新写入水位,这段等待是真实可观测的排队时间。反过来,Eventually
的低延迟不是”性能优化”换来的,是”放弃等待”换来的——PACELC
框架下这是同一枚硬币的两面,不是一个更”先进”、一个更”过时”。
误解二:Bounded 是”不完全一致”,Strong 才是唯一正确选择,能用就应该用。 第四节已经区分:Bounded 的陈旧窗口是定性可调的,不是”错误”或”降级”,而是产品默认值——多数业务能接受秒级陈旧,换来的是查询延迟不被写入峰值拖累。把 Strong 当成默认正确项,会让高并发写入场景下的查询排队现象被误判成”系统故障”。
误解三:选了 Session 级别,就能保证团队里任何两个成员的操作立刻互相可见。 第四节已经引用官方定义澄清:Session 只保证发起写入的那个客户端自己的后续查询能看到自己的写入,不覆盖 Terry et al. 论文里定义的跨会话因果一致性。多客户端协作场景(如开篇的多客服会话)如果需要”任意客户端都能看到彼此的最新操作”,语义上更接近 Strong,而不是 Session。
误解四:Session 级别既然叫”会话一致性”,就自动获得 Terry et al. 论文定义的全部四种会话保证。 4.1 节已经把四种保证摆成表格对照:Milvus 官方只显式承诺了 Read Your Writes 这一条,Monotonic Reads、Writes Follow Reads、Monotonic Writes 三条即便工程实现上大概率成立,也没有写进产品语义。业务如果依赖”连续读一定不倒退”这类更强的假设,不能只凭 Session 这个名字就假定已经获得保证。
误解五:多 shard 场景下,Strong 一致性查询的延迟等于各 shard 等待时间的平均值,个别 shard 慢一点问题不大。 第五节的图已经说明:Proxy 侧要等所有 shard 都放行才能归并结果,可观测延迟由最慢的一路决定,不是平均值。一个长期落后的 shard 会持续拖慢整个 collection 的 Strong 查询,即便其它 shard 表现正常,这类问题不下钻到分 shard 指标很难发现。
八、与 RAG 工程的选型直觉
| RAG 场景 | 更常见选择 | 依据 |
|---|---|---|
| 文档入库后立刻问答同一会话 | Session 或 Strong | 4.1 节确认 Session 至少满足 RYW,覆盖”自己刚写的能看到”这一诉求 |
| 批量索引、可接受秒级陈旧 | Bounded(默认) | 4.2 节的窗口推演:陈旧程度取决于查询与写入的时间差,批量场景天然有时间差 |
| 离线评测、只读近似视图 | Eventually 可能够用 | 不涉及”刚写的能不能看到”,评测关心的是稳定的近似分布 |
| 多租户 SaaS,各租户 SLA 不同 | per-request 覆盖默认级别 | 第二节已强调 Milvus 把 ELC 权衡下放成 per-request 参数,租户可各自选 |
权限过滤很严时,陈旧视图可能导致偶发读到已撤销文档的向量——这正是开篇故事的通用版本。产品上常与第 11
篇的过滤、应用层 ACL 一并设计,而不是只调
ef_search。往前看一步:第 13
篇会说明 upsert 的 merge
模式内部会先发起一次强一致性查询取回旧值再合并——一致性级别不只是查询侧的旋钮,也是写路径内部实现细节的隐藏依赖。
九、学术谱系、工程间隙、开放问题
9.1 谱系
| 主题 | 对照 |
|---|---|
| 一致性/延迟权衡的统一框架 | Abadi, Consistency Tradeoffs in Modern Distributed Database System Design, IEEE Computer 2012(PACELC;Milvus 官方文档直接引用) |
| 有界陈旧的概率化模型 | Bailis et al., PBS, VLDB 2012(Bounded 的旋钮与 PBS 的公式是两种解法层次) |
| 会话一致性的经典定义 | Terry et al., Session Guarantees for Weakly Consistent Replicated Data, PDIS 1994(Session 级别的命名对照,非完整实现声明) |
9.2 工程间隙
- Milvus 把 PACELC 的 ELC 权衡做成 per-request 参数,这本身是工程创新点,但也意味着同一个 Collection 在同一时刻可能同时存在跑 Strong 排队和跑 Eventually 立即返回的两类请求——容量规划与告警阈值不能假设整个集群只有一档延迟画像。
- 官方 Bounded 级别只给定性描述,没有像 PBS 论文那样给出概率化的陈旧-延迟权衡曲线;容量规划者如果直接套用 PBS 的公式去预测 Milvus 的陈旧窗口,缺乏依据。
- Graceful_time 是集群级配置,与 per-request 级别不在同一层,调参要写进运行手册,不能指望在 SDK 里按请求覆盖。
- Strong 下的超时应配置为”等水位”可观测(如暴露
ServiceTime与GuaranteeTs的差值指标),避免客户端把这段合理等待误判为 Knowhere 挂死。
9.3 开放问题
- 多副本下 ServiceTime 取多个副本节点的 min、max 还是法定人数——第 14 篇会展开副本拓扑,但一致性水位和副本选取的交互点官方文档未给出公式。
- Session 在连接池复用、跨进程客户端共享同一逻辑”会话”时的精确语义边界是什么?是否退化为只保证单个物理连接内的顺序?
- 能否给 Bounded 级别补一个类似 PBS 的概率化陈旧模型,让运维者用 SLO 反推该设多大的容忍窗口,而不是凭经验试参数——这是 Bailis et al. 论文留下的、尚未被 Milvus 官方文档回应的方向。
- per-request 可调的 ELC 权衡在多租户共享集群上,是否会出现”一个租户大量发起 Strong 请求,拖慢共享执行节点上其它租户的 Bounded 请求”的资源隔离问题?
- 第五节指出多 shard
查询的可观测延迟由最慢的一路决定;能否给出一个跨 shard
的水位倾斜度指标(例如各 shard
Service_timestamp相对 Proxy 时钟的差值分布),让运维者提前发现”个别 shard 持续落后”,而不是等到 Strong 查询整体变慢才排查——这类指标官方文档未公开,本篇不代入未证实的监控方案。
十、小结
三句话小结:
- 一致性级别本质是把 PACELC 定理里”延迟换一致性”的权衡从系统级固定架构,下放成了 Milvus 里 per-request 可调的 GuaranteeTs 参数;默认 Bounded。
- Strong 的代价是可观测的等待——执行侧要等
Service_timestamp追上Guarantee_timestamp,这段等待发生在归并树的某一层,不是 Knowhere 变慢。 - “能搜到”(一致性水位满足)≠“索引已最优”(Data Node 建索 + handoff 完成);两者独立,混在一起排障容易找错方向。
下一篇顺着”能搜到什么”往下走一步:Delete · Upsert · TTL,说明数据从”逻辑可见”到”物理清理”之间还有一段时间差,其中 upsert 的 merge 模式还会内部反过来依赖本篇的 Strong 一致性查询。
参考资料
核心论文
- Abadi, D. J., Consistency Tradeoffs in Modern Distributed Database System Design: CAP is Only Part of the Story, IEEE Computer 45(2), 2012(PACELC 定理;Milvus 官方 Consistency Level 文档直接引用)。
- Bailis, P., Venkataraman, S., Franklin, M. J., Hellerstein, J. M., Stoica, I., Probabilistically Bounded Staleness for Practical Partial Quorums, VLDB 2012。
- Terry, D. B., Demers, A. J., Petersen, K., Spreitzer, M., Theimer, M., Welch, B. B., Session Guarantees for Weakly Consistent Replicated Data, PDIS 1994。
文档
- Milvus Documentation v2.6.x, Consistency Level(四级定义、PACELC 引用)。
- Milvus Documentation v2.6.x, Timestamp(Guarantee_timestamp / Service_timestamp / Graceful_time 完整比较逻辑)。
- Milvus Documentation v2.6.x, Data Processing、Streaming Service。
- 第 4、5、9 篇、系列 index。
返回 系列目录 | 上一篇:混合过滤 | 下一篇:Delete · Upsert · TTL
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【向量检索引擎】分布式 search 归并:Delegator、多级 reduce 与 GuaranteeTs
按 Milvus 2.6.x Data Processing 与 Architecture 拆解 search 的多级归并树:Proxy → Streaming Node Delegator → Query Node 段级结果;用最小故事、GuaranteeTs 等待时序图与常见误解说明一致性级别如何变成排队等待。
【向量检索引擎】Proxy 与 Coordinator:接入面、TSO 与集群大脑
以一次 collection 生命周期里的 DDL/DML/DQL 请求为线索,拆解 Milvus 2.6.x 无状态 Proxy 的路由与 MPP 归并,单活跃 Coordinator 的 TSO/timetick 全序机制与任务调度,并对照 Spanner/TiDB 的时间戳设计说明工程取舍。
【向量检索引擎】Streaming Node 与 Woodpecker WAL:实时可搜的日志层
以一条 insert 从 SDK 到「立刻能被搜到」的最小故事为线索,拆解 Milvus 2.6.x Streaming Service 三件套、Message/TSO 写顺序、Woodpecker 零本地盘 WAL 的 MemoryBuffer/QuorumBuffer 模式,并标明官方吞吐数字的引用边界。
【向量检索引擎】向量引擎全景:算法、RAG 与专用引擎之间的一层
定位专用向量检索引擎相对 ANN 算法、RAG 应用与湖仓格式的分工;以 Milvus 2.6.x 四层架构与 insert/search 最小故事建立坐标系,并交代从 SIGMOD 2021 到 Streaming 演进的谱系与常见误解。