相关笔记

概览

本节研究在线缓存问题(Online Caching / Paging),即在不知道未来请求序列的条件下,如何做出缓存替换决策。核心分析工具是竞争分析(competitive analysis)——将在线算法的代价与最优离线算法(Belady 的 furthest-in-future 策略)的代价进行最坏情况比较。

  • 缓存未命中代价:命中代价为 0,未命中代价为 1(需从慢速存储加载)
  • 竞争比(competitive ratio):在线算法代价与最优离线代价之比的上界
  • LRU(Least Recently Used):淘汰最近最少使用的页面,竞争比为
  • FIFO(First In First Out):淘汰最早进入的页面,竞争比同样为
  • Marking 算法:随机化策略,竞争比为 ,远优于确定性策略
  • k-Server 问题:在线缓存的一般化, 个服务器在度量空间中响应请求

知识结构总览

flowchart TD
    A["在线缓存问题<br/>缓存大小 k,请求序列逐个到达"] --> B["确定性在线策略"]
    A --> C["随机化在线策略"]
    A --> D["最优离线策略<br/>Belady / furthest-in-future"]

    D --> D1["竞争比 = 1<br/>(已知完整序列)"]

    B --> B1["LRU<br/>淘汰最近最少使用"]
    B --> B2["FIFO<br/>淘汰最早进入"]
    B --> B3["确定性下界<br/>竞争比 ≥ k"]

    B1 --> B4["竞争比 = k<br/>势能法证明"]
    B2 --> B5["竞争比 = k<br/>(令人惊讶!)"]

    C --> C1["Marking 算法<br/>分阶段 + 随机淘汰"]
    C1 --> C2["竞争比 = O(log k)<br/>远优于确定性策略"]

    A --> E["一般化:k-Server 问题<br/>k 个服务器在度量空间中"]
    E --> E1["k-Server 猜想<br/>竞争比 = k"]
    E --> E2["Work Function 算法"]

核心思想

2.1 在线缓存问题定义

在线缓存问题(Online Caching / Paging)

  • 缓存容量,缓存中最多存放 个不同的页面
  • 请求序列,逐个到达,算法在处理 时不知道 的内容
  • 代价模型:缓存命中代价为 0,缓存未命中代价为 1(需从慢速存储加载到缓存)
  • 目标:最小化总代价(即最小化缓存未命中次数)

与第15章离线缓存的关键区别

  • 离线缓存(第15章):算法预先知道完整的请求序列 ,可以使用 Belady 的 furthest-in-future 策略达到最优
  • 在线缓存(第27章):算法不知道未来请求,必须在信息不完全的条件下做出不可撤回的替换决策
  • 评价标准:离线缓存用绝对最优性评价;在线缓存用竞争比评价——算法代价与最优离线代价之比的最坏情况上界

2.2 最优离线算法:Belady 算法(MIN)

Belady 算法(又称 MIN 或 furthest-in-future)

当缓存已满且发生未命中时,淘汰缓存中未来最晚被使用(或不再被使用)的页面。该策略在已知完整请求序列的条件下是最优的(见 Theorem 15.5)。

Belady 算法是在线缓存分析的基准线——所有在线算法的竞争比都是相对于 Belady 算法的代价来定义的。

2.3 确定性在线算法的下界

确定性在线缓存的下界

定理:任何确定性在线缓存算法的竞争比至少为

证明思路(对抗性构造):对手维护一个大小为 的页面集合 。对手总是请求当前不在在线算法缓存中的那个页面。由于缓存大小为 ,在线算法每次都会发生未命中。而最优离线算法可以保留一个页面不淘汰,只需每 次请求淘汰一次。因此竞争比至少为

2.4 LRU 策略

LRU(Least Recently Used)

淘汰最近最少使用的页面。维护一个使用时间戳,每次访问更新时间戳,淘汰时选择时间戳最旧的页面。

LRU 算法执行流程

flowchart TD
    A["收到请求 σ_i"] --> B{"σ_i 在缓存中?"}
    B -- 是 --> C["缓存命中<br/>更新 σ_i 的时间戳<br/>代价 = 0"]
    B -- 否 --> D["缓存未命中<br/>代价 = 1"]
    D --> E{"缓存已满?"}
    E -- 否 --> F["将 σ_i 加入缓存<br/>设置时间戳"]
    E -- 是 --> G["找到时间戳最旧的页面 e<br/>(最近最少使用的)"]
    G --> H["淘汰 e,将 σ_i 加入缓存<br/>设置时间戳"]

LRU-ACCESS 伪代码

LRU-ACCESS(S, σ_i):
    // S: 当前缓存集合(每个元素附带时间戳)
    // σ_i: 当前请求的页面
    if σ_i ∈ S:
        更新 σ_i 的时间戳为当前时间    // 命中
        return 0                       // 代价 = 0
    else:
        if |S| < k:
            将 σ_i 加入 S,设置时间戳   // 缓存未满
        else:
            e = S 中时间戳最旧的页面    // 最近最少使用
            S = S \ {e} ∪ {σ_i}        // 淘汰 e,加载 σ_i
        return 1                       // 代价 = 1

定理 27.3:LRU 的竞争比为

证明(势能分析法):

定义势能函数 ,即当前缓存 与最优离线缓存 不同页面的数量(对称差的一半)。

【势能法(势能=当前缓存与最优缓存的对称差)】 势能函数 衡量在线缓存与最优缓存之间的”距离”。势能始终满足

分析每次请求 后势能的变化

情况 1:LRU 命中(

  • LRU 代价 = 0
  • 若 OPT 也命中():势能不变,
  • 若 OPT 未命中:OPT 加载 ,可能淘汰某个页面 ,此时 至多减少 1,
  • 总代价:

情况 2:LRU 未命中(

  • LRU 代价 = 1,LRU 加载 并淘汰 (最近最少使用的页面)
  • 子情况 2a:OPT 也未命中
    • OPT 代价 = 1,OPT 也加载
    • 原来不在 也不在 中,现在两者都包含 ,势能至多不变
    • LRU 淘汰的 :若 ,则 减少 1;若 ,则 不变
    • 总代价:
  • 子情况 2b:OPT 命中(
    • OPT 代价 = 0
    • 原来在 但不在 中,现在两者都包含 至少减少 1
    • LRU 淘汰的 :若 再减少 1;若 不变
    • 总代价:(最坏情况)

【竞争比推导(LRU代价 ≤ k · OPT代价)】 综合所有情况,每次请求 满足:

对整个请求序列求和:

由于 (初始缓存为空)且

因此 LRU 的竞争比为 。结合确定性下界,LRU 是最优的确定性在线缓存算法

2.5 FIFO 策略

FIFO(First In First Out)

淘汰最早进入缓存的页面。维护一个先进先出队列,新页面从队尾加入,淘汰时从队首移除。

FIFO 算法执行流程

flowchart TD
    A["收到请求 σ_i"] --> B{"σ_i 在缓存中?"}
    B -- 是 --> C["缓存命中<br/>代价 = 0"]
    B -- 否 --> D["缓存未命中<br/>代价 = 1"]
    D --> E{"缓存已满?"}
    E -- 否 --> F["将 σ_i 加入队列尾部"]
    E -- 是 --> G["移除队列头部页面 e<br/>(最早进入的)"]
    G --> H["将 σ_i 加入队列尾部"]

FIFO-ACCESS 伪代码

FIFO-ACCESS(S, σ_i):
    // S: FIFO 队列,维护缓存中页面的进入顺序
    if σ_i ∈ S:
        return 0                       // 命中,不做操作
    else:
        if |S| < k:
            将 σ_i 加入 S 的尾部        // 缓存未满
        else:
            e = S 的头部元素            // 最早进入的页面
            从 S 中移除 e
            将 σ_i 加入 S 的尾部        // 淘汰 e,加载 σ_i
        return 1                       // 代价 = 1

定理:FIFO 的竞争比为

证明(势能分析法,类似 LRU):

使用类似的势能函数 。关键观察是:虽然 FIFO 的淘汰策略与 LRU 不同,但势能变化的界与 LRU 相同——每次请求的摊还代价不超过

FIFO 竞争比为 k 的直觉

令人惊讶的是,FIFO 这样一个”不聪明”的策略也达到了与 LRU 相同的竞争比 。原因是竞争比分析的是最坏情况,而 FIFO 在最坏情况下的表现与 LRU 一样好。然而在实际工作负载中,LRU 通常优于 FIFO(见第五节习题 2 的对比示例)。

2.6 随机化 Marking 算法

Marking 算法

一种随机化在线缓存策略,通过分阶段(phase)和随机淘汰来打破确定性算法的 竞争比下界。

核心思想

  1. 将请求序列划分为若干阶段(phase),每个阶段包含恰好 不同页面的首次请求
  2. 阶段开始时,标记缓存中的所有页面
  3. 处理请求时:
    • 若请求页面在缓存中:标记该页面(命中)
    • 若请求页面不在缓存中且缓存有未标记页面:随机淘汰一个未标记页面,加载请求页面并标记
    • 若缓存中所有页面都已标记:当前阶段结束,开始新阶段,清除所有标记

Marking 算法执行流程

flowchart TD
    A["收到请求 σ_i"] --> B{"σ_i 在缓存中?"}
    B -- 是 --> C["标记 σ_i<br/>命中,代价 = 0"]
    B -- 否 --> D["缓存未命中<br/>代价 = 1"]
    D --> E{"缓存中有未标记页面?"}
    E -- 是 --> F["随机选一个未标记页面淘汰<br/>加载 σ_i 并标记"]
    E -- 否 --> G["新阶段开始<br/>清除所有标记<br/>标记所有缓存页面<br/>淘汰任意页面,加载 σ_i 并标记"]

MARKING-ACCESS 伪代码

MARKING-ACCESS(S, σ_i):
    // S: 当前缓存,每个页面有 marked/unmarked 状态
    // phase_count: 当前阶段中已见不同页面数

    if σ_i ∈ S:
        标记 σ_i                      // 命中
        return 0
    else:
        // 缓存未命中
        if S 中存在未标记页面:
            从未标记页面中均匀随机选一个 e
            S = S \ {e} ∪ {σ_i}
            标记 σ_i
        else:
            // 所有页面已标记,新阶段开始
            清除 S 中所有页面的标记
            标记 S 中所有页面
            从 S 中均匀随机选一个 e 淘汰
            S = S \ {e} ∪ {σ_i}
            标记 σ_i
            phase_count = 1            // 重置阶段计数
        return 1

定理:Marking 算法的期望竞争比为 ,其中 是第 调和数

证明概要

【分阶段分析(每阶段最多 k 次未命中)】 定义阶段(phase):从序列开头(或上一阶段结束)开始,到出现第 个不同页面为止。每个阶段恰好包含 个不同页面的首次请求。

关键性质:在每个阶段中,Marking 算法最多发生 次未命中——因为阶段中只有 个不同页面需要首次加载,而后续对同一页面的请求都是命中。

【随机化竞争比(期望未命中次数 ≤ H(k) · OPT)】 分析每个阶段中 Marking 算法的期望未命中次数与 OPT 在同一阶段的未命中次数之比:

  1. 在每个阶段中,OPT 至少发生一次未命中(因为阶段中有 个不同页面,而 OPT 的缓存大小也是 ,阶段结束时的第 个页面必然导致 OPT 未命中)
  2. 设 OPT 在某阶段中发生了 次未命中,则该阶段中 OPT 淘汰了 个页面
  3. Marking 算法在该阶段的期望未命中次数不超过
  4. 对所有阶段求和:

因此 Marking 算法的期望竞争比为 ,远优于确定性策略的

随机化算法的优势

确定性在线缓存算法的竞争比下界为 ,而随机化算法可以打破这个壁垒。Marking 算法达到了 的竞争比,且可以证明随机化在线缓存算法的竞争比下界为 (对某些访问模型),因此 Marking 算法在数量级上是最优的。

2.7 k-Server 问题(扩展)

k-Server 问题

在线缓存的一般化。给定一个度量空间(metric space)和 个服务器(每个服务器位于度量空间中的某个点上),请求序列是度量空间中点的序列。对于每个请求,必须移动一个服务器到请求点,代价为移动距离。目标是最小化总移动距离。

与在线缓存的关系:当度量空间为一致度量(uniform metric,即任意两点距离为 1,同一点距离为 0)时,k-Server 问题退化为在线缓存问题——服务器位于缓存中的页面上,移动代价对应缓存未命中。

k-Server 猜想

猜想(Manasse, McGeoch, Sleator, 1988):对于任何有超过 个点的度量空间,k-Server 问题的竞争比为

已知结果

  • :猜想成立(Manasse et al., 1988)
  • 度量空间恰好有 个点:猜想成立
  • 树度量、HST 度量:猜想成立
  • 一般度量空间:竞争比上界为 (Koutsoupias, Papadimitriou, 1995)
  • 随机化版本:James R. Lee (2018) 证明了 竞争比的随机化算法

补充理解与拓展

LRU 的竞争比分析与实际表现

Sleator 和 Tarjan (1985) 在开创性论文中证明了 LRU、FIFO 和 Flush-when-full 三种策略的竞争比均为 (其中 是最优离线算法的未命中次数),并证明这是确定性在线缓存算法的最优竞争比。虽然竞争比为 看似很大,但在实际工作负载中 LRU 的表现通常远好于最坏情况——许多实际访问序列表现出局部性(locality of reference),使得 LRU 的未命中率接近最优。

来源:Sleator, D.D. and Tarjan, R.E. (1985). “Amortized Efficiency of List Update and Paging Rules.” Communications of the ACM, 28(2), 202-208. https://dl.acm.org/doi/10.1145/2786.2793

Marking 算法的经典论文

Fiat, Karlin, Raghavan 和 Schieber (1991) 提出了 Marking 算法并证明了其 的竞争比。该论文还证明了随机化在线缓存算法的下界为 ,说明 Marking 算法在数量级上是最优的。这一结果揭示了随机化在在线算法中的强大优势——将竞争比从 降到了

来源:Fiat, A., Karlin, A.R., Raghavan, P., and Schieber, B. (1991). “Competitive Randomized Algorithms for the Weighted Paging Problem.” Journal of Algorithms, 12(4), 652-667. https://www.sciencedirect.com/science/article/pii/019667749190004E

k-Server 猜想的研究进展

k-Server 猜想由 Manasse, McGeoch 和 Sleator (1988) 提出,是竞争分析领域最著名的开放问题之一。Koutsoupias 和 Papadimitriou (1995) 提出的 Work Function 算法在一般度量空间上达到了 的竞争比,这是目前已知最好的确定性结果。2018 年,James R. Lee 证明了在一般度量空间上存在 竞争比的随机化算法,大幅推进了随机化版本的上界。

来源:Koutsoupias, E. and Papadimitriou, C. (1995). “On the k-Server Conjecture.” Journal of the ACM, 42(5), 971-983. https://dl.acm.org/doi/10.1145/210118.210128

来源:Lee, J.R. (2018). “Fusible HSTs and the Randomized k-Server Conjecture.” FOCS 2018. https://ieee-focs.org/FOCS-2018-Papers/pdfs/59f438.pdf

实际系统中的缓存替换策略

虽然本章从理论角度分析了 LRU、FIFO 和 Marking 算法,但实际操作系统和数据库系统中的缓存替换策略更加复杂。Linux 内核曾使用 LRU 的变体(如 Clock 算法),后来转向更复杂的策略如 ARC(Adaptive Replacement Cache)和 LIRS(Low Inter-reference Recency Set)。现代 CPU 的 L1/L2 缓存通常使用 LRU 的近似版本(如伪 LRU / PLRU),因为硬件实现需要考虑面积和延迟约束。

来源:Young, N.E. (2016). “Online Paging and Caching.” Handbook of Approximation Algorithms and Metaheuristics, 2nd ed., Chapman and Hall/CRC. https://cs.ucr.edu/~neal/publication/Young16Paging.pdf


易混淆点与辨析

LRU 与 FIFO 的竞争比相同,但实际表现不同

LRU 和 FIFO 的竞争比都是 ,但这并不意味着它们的实际表现相同。竞争比是最坏情况下的界,而实际工作负载通常具有局部性(locality of reference),LRU 利用访问时间的局部性,表现通常优于 FIFO。此外,FIFO 存在 Belady 异常——增加缓存容量可能导致未命中次数反而增加,而 LRU 不会出现这种现象。竞争比分析无法捕捉这种差异。

竞争比 ≠ 平均性能

竞争比衡量的是最坏情况下在线算法与最优离线算法的比值,并不反映算法在平均情况特定工作负载下的表现。一个竞争比为 的算法在实际应用中可能表现优异(如 LRU 在具有局部性的访问序列上),而一个竞争比更小的算法在某些实际场景中可能反而更差。竞争比分析是一种对抗性分析,对手可以精心构造最坏的请求序列。


习题精选

编号题目难度涉及知识点
1LRU 在特定请求序列上的模拟与代价分析★★☆LRU 策略、缓存模拟
2构造 FIFO 表现劣于 LRU 的请求序列★★★FIFO vs LRU、Belady 异常
3Marking 算法在 时的分析★★★Marking 算法、竞争比
4证明确定性在线缓存算法竞争比下界为 ★★★★对抗性论证、下界证明

视频学习指南

资源讲者/来源主题时长难度语言
MIT 6.046 Lecture 14Erik DemaineOnline Algorithms & Paging~80 min★★★EN
Advanced Data Structures (MIT 6.851)Erik DemaineCompetitive Analysis~90 min★★★★EN
CMU 15-451 LectureAvrim BlumOnline Learning & Paging~75 min★★★EN
算法导论第27章解读殷建平团队在线算法(中文)~60 min★★★ZH
Young, “Online Paging and Caching”Neal E. Young综合综述论文阅读时间 ~2h★★★★EN

教材原文

算法导论(第4版)第27.3节

在线缓存问题是竞争分析最经典的应用之一。在一个缓存系统中,有 个槽位可以存放数据项。当请求数据项 时,如果 已经在缓存中,则产生一次命中(代价为 0);否则产生一次未命中(代价为 1),需要将 从慢速存储加载到缓存中。如果缓存已满,则必须选择一个缓存项进行淘汰。在线缓存问题的挑战在于:算法在做出淘汰决策时,不知道未来的请求序列。

对于确定性在线算法,Sleator 和 Tarjan 证明了 LRU 和 FIFO 都达到了 -competitive 的最优竞争比。对于随机化在线算法,Fiat 等人的 Marking 算法达到了 的竞争比,大幅优于确定性策略。


参见Wiki


第27章-在线算法 在线缓存