跳到主要内容
分离式事务的动态锁所有权

第6章:迁移协议 —— freeze-drain-handoff-publish

AURA 4 阶段迁移协议的完整时序、epoch 单调性、不变式 I1–I4 的证明草图、关键 corner case(owner 故障 / 跨 cohort 事务 / 链式迁移)

AURA 迁移协议 epoch 不变式 drain fallback corner case

第 4 章给了 AURA 的骨架,第 5 章解释了”决策怎么做”,本章解决最后一个核心问题:决策做完之后怎么把锁所有权安全搬过去。AURA 用一个 4 阶段协议——freeze-drain-handoff-publish——加 epoch 单调与 4 个不变式,把”迁移期间一致性不丢”钉死。读完你应该能徒手画完整时序图,并能描述至少 3 个 corner case 下协议的行为——这是 paper §3b/§5 的核心。

📑 目录


1. 4 阶段时序图

1.1 完整时序

   时刻      Old Owner (CN_A)     Planner       New Owner (CN_B)    Clients
   ─────     ────────────────     ────────      ────────────────    ───────
   t0        OWNED                 decide         (idle)             use OwnerMap_e
                                   migrate
                                   A → B

   t0+10µs   ◄── Phase 1 Freeze ── │
             refuse new acquire
             cohort.state =
               TRANSFERRING
   t0+20µs   notify Planner ──────►

   t0+50µs                         │
             drain in-flight       │
             ──┐                   │
               │ wait commit/abort │
             ◄─┘                   │
   t0+200µs  drain done ──────────►

   t0+250µs  ── Phase 3 Handoff ──────────►
             ship lock state         (apply)
             ────────────────────────►
   t0+300µs  ◄── ack ────────────  ──────────

   t0+310µs                        Phase 4 ────────────────► broadcast
                                   Publish    OwnerMap_(e+1)
                                   epoch++
   t0+360µs  cohort.state =          (ready)                          OwnerMap_(e+1)
             RELEASED               new owner serve
                                                                      route to B

1.2 总耗时分解

Phase实测时长关键操作
1 Freeze~10–20µsatomic flag 翻转 + cohort.state = TRANSFERRING
2 Drain~50–200µs等 in-flight tx commit/abort
3 Handoff~50–80µsRPC 传 lock state(数 KB 数据)
4 Publish~50–80µsOwnerMap delta 广播
合计~150–400µs

🌟 关键事实:单次迁移 ~150–400µs,与 5ms 决策窗口比是 1/15。这给了 AURA 在一个 5ms 内完成 1–2 次迁移的物理预算

1.3 协议设计原则

原则解释
先关后开必须先 freeze 旧 owner,再 publish 新 owner。否则有”双 owner 窗口”
单调推进每次迁移 epoch 严格 +1,不可回退
可中断任意 phase 失败可以回退到上一稳定状态
可观测每 phase 记日志 + 计数,便于 debug

🍎 直觉比喻:4 阶段协议像”换柜员”——先告诉旧柜员”别再接新客”(Freeze),等他把手头客户处理完(Drain),把账本递给新柜员(Handoff),最后挂”新柜员上岗”的牌子(Publish)。


2. Phase 1: Freeze

2.1 旧 owner 收到 Freeze cmd 后做什么

// TransferController 调用旧 owner
void OldOwner::on_freeze(cohort_id_t c) {
    auto& cohort = cohorts_[c];
    cohort.state.store(CohortState::TRANSFERRING, std::memory_order_release);
    cohort.freeze_ts = now_us();
    
    // 通知 OwnerLockTable:拒绝新 acquire
    lock_table_.set_frozen(c, true);
    
    // 通知 OwnerRpc:拒绝新 cross-cohort 请求
    owner_rpc_.set_frozen(c, true);
    
    // 立即回 ack 给 Planner
    rpc_reply(FREEZE_ACK);
}

2.2 新 acquire 请求收到 frozen 怎么办

AcquireResult OwnerLockTable::acquire(key_group_id_t kg, ...) {
    auto cohort_id = kg2cohort_[kg];
    if (cohorts_[cohort_id].state == CohortState::TRANSFERRING) {
        return TRANSFERRING_RETRY;  // ← 客户端会 short retry
    }
    // 正常 CAS 路径
    ...
}

🌟 客户端处理:收到 TRANSFERRING_RETRY 后短 retry(~100µs),等 Phase 4 publish 完。这是 AURA 用户事务的”短暂 stall 时间”

2.3 在途 acquire 怎么处理

情况处理
acquire 已经被 OldOwner.granted让它继续完成(不会被 freeze 影响)
acquire 还在 OwnerLockTable.queue立刻返回 TRANSFERRING_RETRY
acquire 还没到 OldOwner路由到 OwnerLockTable 时返回 TRANSFERRING_RETRY

关键事实:Freeze 不影响已经持锁的事务——它们继续 commit + release。Drain 阶段在等的就是这些事务。

2.4 Freeze 失败怎么办

失败场景处理
OldOwner 心跳超时TransferController 把 cohort 直接进入 FALLBACK
OldOwner crash同上
网络分区同上

互补Freeze 失败 = OldOwner 不可用 ≈ 它已经”自然 freeze 了”。后续直接走 fallback 路径。

2.5 Freeze 防止”双 owner 窗口”

考虑反例:如果不 Freeze 直接 Publish 新 OwnerMap:

   Old OwnerMap: cohort_C → CN_A
   New OwnerMap: cohort_C → CN_B
   
   t=0     Publish New OwnerMap
   t+1µs   Client X 用旧 OwnerMap,发到 CN_A → 取得锁
   t+2µs   Client Y 用新 OwnerMap,发到 CN_B → 也取得锁
   t+3µs   X 和 Y 同时 commit → 数据 race

🌟 结论Phase 1 Freeze 是 I1(Authority Uniqueness)的关键保证。少了它,I1 立刻被破坏。


3. Phase 2: Drain

3.1 drain 的语义

drain = 等待该 cohort 上所有已经在执行的事务完成(commit 或 abort)。

void OldOwner::drain(cohort_id_t c, uint64_t timeout_us) {
    auto deadline = now_us() + timeout_us;
    while (now_us() < deadline) {
        auto in_flight = count_in_flight_txns(c);
        if (in_flight == 0) {
            return DRAIN_OK;
        }
        std::this_thread::sleep_for(std::chrono::microseconds(10));
    }
    return DRAIN_TIMEOUT;
}

3.2 在途事务的”in-flight”定义

事务状态是否需要 drain
Read phase(取 read set)否(不持锁)
Validate(已开始但还没 commit)
Commit acquire(取锁中)
Commit data(写数据中)
Commit release(释放锁中)
Already committed
Already aborted

3.3 drain 超时怎么办

auto res = drain(cohort_id, timeout_us=200);
if (res == DRAIN_TIMEOUT) {
    // 强制 abort 所有 in-flight 事务
    abort_all_in_flight(cohort_id);
    // 进入 FALLBACK
    cohort.state = CohortState::FALLBACK;
    return MIGRATION_ABORTED;
}

⚠️ 关键风险:强制 abort 会让客户端看到大量 abort,影响 SLO。所以 drain timeout 不能太短——AURA 默认 200µs(覆盖 99% 的 in-flight tx)。

3.4 drain 期间的并发情况

   时刻      OldOwner             in-flight tx (5 个)
   ─────     ────────              ──────────────────
   t0        FREEZE done             A: validate
                                     B: commit acquire (4/5 取了)
                                     C: commit data (写到一半)
                                     D: commit release (1/3 释放了)
                                     E: read phase (没影响)
   
   t0+50µs   wait                    A: validate fail → abort(不影响 drain)
                                     B: 取完 lock 5/5 → commit data
                                     C: data 写完 → release
                                     D: release 完 → done
                                     E: validate ... commit
   
   t0+200µs  done?                   全部 done!
             return DRAIN_OK

🌟 关键事实drain 不阻塞已持锁的事务的 release——它们能正常完成。drain 真正等的是”还在 commit phase 里”的事务。

3.5 drain 时长的实测分布

c6525, TPC-C 1M tps:

百分位drain 耗时
P50~30µs
P95~120µs
P99~180µs
P99.9~250µs(超时风险)

互补:超时阈值设 200µs 时 P99.9 仍可能 timeout——这部分会被 fallback 兜住。生产中可调到 500µs,trade-off 是迁移更慢


4. Phase 3: Handoff

4.1 转移什么

OldOwner 必须把 cohort 内所有锁状态转给 NewOwner:

struct CohortHandoffPayload {
    cohort_id_t                                     id;
    epoch_t                                         from_epoch;
    
    // ❶ 该 cohort 的所有锁状态
    std::unordered_map<key_group_id_t, LockEntry>  lock_entries;
    
    // ❷ 当前持锁的事务(应该是空,因为 drain 完了)
    std::vector<TxnId>                              still_held;
    
    // ❸ cohort metadata
    Cohort                                          cohort_meta;
    
    // ❹ 跨 cohort 协调状态(如果有)
    std::vector<CrossOwnerRpcState>                 pending_rpcs;
};

4.2 用 RPC 而不是 RDMA WRITE

理论上可以用 RDMA WRITE 直接把状态写到 NewOwner 的内存。但 AURA 用 RPC:

维度RDMA WRITERPC
字节带宽
解析开销接收方必须解析 + 复制发送方序列化、接收方反序列化
错误处理复杂(需要应用层 ack)标准 RPC 框架
兼容性要求 NewOwner 已注册 MR不需要

选 RPC 的关键理由:handoff 数据是结构化的(hashmap + metadata),RPC 框架(如 grpc / brpc)能自动处理。RDMA WRITE 适合 bulk binary 传输。

4.3 RPC 的幂等性

NewOwner 必须对同一个 from_epoch 的 handoff 幂等——重发不会重新应用:

void NewOwner::on_handoff(const CohortHandoffPayload& p) {
    auto& cohort = cohorts_[p.id];
    if (cohort.last_handoff_epoch >= p.from_epoch) {
        return rpc_reply(HANDOFF_ALREADY_APPLIED);  // 幂等
    }
    
    // 应用状态
    for (const auto& [kg, entry] : p.lock_entries) {
        lock_table_.install(kg, entry);
    }
    cohort.last_handoff_epoch = p.from_epoch;
    cohort.state = CohortState::OWNED;  // 但还没 publish
    cohort.epoch = p.from_epoch + 1;
    rpc_reply(HANDOFF_OK);
}

关键设计:NewOwner 在 Phase 3 完成后已经持有锁状态,但不接受新 acquire,因为 OwnerMap 还没 publish。这是有意的——Phase 4 是真正的”上线”开关。

4.4 Handoff 失败怎么办

失败处理
RPC timeout(NewOwner 无响应)标记 NewOwner 不可用 → 选其他 CN 重试
NewOwner 拒绝(容量不足)选其他 CN
网络分区进 FALLBACK

如果所有候选 NewOwner 都失败 → cohort 进入 FALLBACK。

4.5 Handoff 与 OwnerLockTable 的协调

   t=0      drain done in OldOwner
   t=10µs   OldOwner serialize lock state → ~30KB
   t=20µs   RPC send → NewOwner
   t=30µs   NewOwner receive → deserialize
   t=50µs   NewOwner.lock_table.install(entries)
   t=70µs   NewOwner reply HANDOFF_OK
   t=80µs   OldOwner ack received → enter Phase 4

🍎 直觉比喻:handoff 像”快递包裹”——OldOwner 打包、寄出,NewOwner 收到后拆包安装。Phase 4 才是”开门营业”


5. Phase 4: Publish

5.1 Publish 的语义

Publisher 通过原子操作推进 epoch,并广播 OwnerMap delta:

class OwnerMapPublisher {
    std::atomic<epoch_t> current_epoch_{0};
public:
    epoch_t publish_delta(const std::vector<OwnerMapEntry>& deltas) {
        epoch_t old = current_epoch_.load();
        epoch_t next = old + 1;
        if (!current_epoch_.compare_exchange_strong(old, next)) {
            return 0;  // 别人推进了,本次放弃
        }
        // 广播
        for (auto cn : all_cns_) {
            broadcast_owner_map_delta(cn, next, deltas);
        }
        return next;
    }
};

5.2 广播 vs 拉取

维度广播(push)拉取(pull)
一致性强(Publisher 确保送到)弱(CN 自己来拿)
失败处理Publisher 重发CN 检测过期重拉
带宽Publisher 单点CN 分散
实现简单需要 epoch heartbeat

AURA 选广播 + lazy refresh:广播是主要路径,CN 收到 STALE_EPOCH 时 lazy 重拉作兜底。

5.3 客户端 lazy epoch 同步

// 客户端事务路径
void TxnExecutor::run(TxnRequest& tx) {
    auto reply = OwnerRpc::send(target_cn, tx, my_epoch);
    if (reply.status == STALE_EPOCH) {
        owner_map_ = OwnerMapPublisher::pull_latest();
        my_epoch = owner_map_.epoch;
        goto retry;
    }
}

🌟 关键性质:客户端 epoch 落后不会引发不一致——只会被 reject + retry。这是 AURA 不要求 epoch 全局严格同步的关键

5.4 何时旧 OwnerMap 可以 GC

条件解释
所有 CN 都已经升级到 new_epoch通过 epoch heartbeat 确认
没有 in-flight 事务还在使用 old_epoch 的 OwnerMap等 in-flight grace period 过去
一般保守 100ms(5 ms × 20)safety margin

5.5 Publish 失败怎么办

失败处理
atomic CAS 失败(并发推进)当前 publish 放弃,等下一轮 tick
广播部分 CN 失败重发(不影响 epoch 推进)
所有 CN 失败极端罕见,cohort 自动 fallback

5.6 Publish 完成后老 owner 的责任

老 owner 在 Publish 之后还要做一件事:帮助 release 已经持锁但还没 release 的事务

void OldOwner::on_publish_complete(cohort_id_t c) {
    // I4 保证:这些事务的 release 仍然来到 OldOwner
    for (auto& tx : my_pending_releases_for_cohort_[c]) {
        // 正常处理 release(forward 到 NewOwner 也可,但简单起见就地处理)
        process_release(tx);
    }
    // 全部 release 完之后,cohort 状态变 RELEASED
    cohort.state = CohortState::RELEASED;
}

🧠 关键设计OldOwner 在 publish 之后还”留尾”一段时间——等 in-flight 事务完成 release。这是 I4 的具体实现。


6. 不变式 I1–I4 的证明草图

6.1 I1:Authority Uniqueness

证明

设迁移 C:ABC: A \to B 时刻区间 [t1,t4][t_1, t_4],其中:

  • t1t_1:Phase 1 Freeze 开始
  • t2t_2:Phase 2 Drain 完成
  • t3t_3:Phase 3 Handoff 完成
  • t4t_4:Phase 4 Publish 完成

A 是唯一 owner 的时段t<t1t < t_1(A 完全 OWNED)

TRANSFERRING 时段[t1,t4][t_1, t_4]):

  • A 已 freeze(拒绝新 acquire)
  • B 还没接收 publish(拒绝新 acquire)
  • 没有任何节点接受新 acquire

B 是唯一 owner 的时段t>t4t > t_4(B 完全 OWNED)

🌟 结论任意时刻最多一个节点接受新 acquire——I1 成立。

6.2 I2:Epoch Monotonicity

证明

epoch 推进通过 compare_exchange_strong(old, old+1) 实现,这是单调递增的原子操作。任何并发推进只有一个成功,其他全部 retry → epoch 永不回退。

OwnerMap 携带 epoch,客户端只接受 new_epoch > local_epoch → 老广播被拒绝。

epoch 在所有节点视图下单调递增

6.3 I3:Migration Drain

证明

Phase 2 Drain 显式等待 in_flight_count(C) == 0 或 timeout:

  • DRAIN_OK:所有 in-flight 都已 commit/abort → C 上无未完事务进入 Phase 3
  • DRAIN_TIMEOUT:强制 abort 所有 in-flight → 同样无未完事务进入 Phase 3

进入 Phase 3 时 cohort C 上没有未完成的事务

6.4 I4:Data Commit Invariance

证明

每个事务在 acquire 阶段记录”持锁的 owner CN”在事务对象里:

struct Txn {
    std::unordered_map<key_group_id_t, cn_id_t> lock_owners_;  // 取锁时的 owner
};

Release 时根据 lock_owners_ 路由,不再查 OwnerMap:

void release_locks(Txn& tx) {
    for (auto& [kg, owner] : tx.lock_owners_) {
        send_release(owner, kg, tx.id);
    }
}

commit 路径只依赖事务局部状态,与 OwnerMap 无关 → I4 成立。

6.5 不变式之间的依赖

   I2 (epoch monotonicity)
       │ 帮助

   I1 (authority uniqueness): epoch 比较防止老 owner 误以为仍是 owner
       │ 帮助

   I3 (migration drain): drain 配合 freeze 把双 owner 窗口压到 0

   I4 (commit invariance) 独立兜底:即使 I1 短暂违反,commit 也不丢一致

🧠 设计师视角I4 是兜底——即使 I1 在边界 case 短暂被破坏(比如时钟偏移导致 freeze 晚到),I4 保证数据本身不会损坏。这是工程上”多重防御”。


7. corner cases

7.1 owner CN 在 Drain 期间挂

   t=0    Phase 1 Freeze done
   t=50µs OldOwner crash
   t=??   Drain wait...

处理

  • TransferController 检测心跳超时(500ms)
  • 标记 cohort 为 FALLBACK
  • 所有 in-flight 事务的 release 自动 fallback 到 MN(依赖 I4——它们记录了 owner 是 OldOwner,但现在路由到 fallback 的 RDMA CAS)

互补OldOwner crash 不会卡住整个 cohort——FALLBACK 是兜底。

7.2 Planner 决定 A→B 同时 A→C

并发迁移同一 cohort 必须串行化

class TransferController {
    std::unordered_map<cohort_id_t, std::mutex> cohort_locks_;
public:
    void apply(MigrationDelta d) {
        std::lock_guard lk(cohort_locks_[d.cohort_id]);  // ← 串行化
        do_4_phase_migration(d);
    }
};

🌟 结论:同一 cohort 的迁移严格串行,不同 cohort 可并发。

7.3 客户端 epoch 落后多个版本

   Client epoch = 100
   Latest epoch = 105
   Client routes to A (according to e=100)

A 已经不是 cohort 的 owner(在 e=103 迁走)→ A 返回 STALE_EPOCH。

Client 处理

case STALE_EPOCH:
    pull_latest_owner_map();
    target_cn = router.lookup(tx, latest_map);
    retry_with_new_target();

最坏情况:连续 retry 几次(每次 epoch 又往前推),直到稳定。

7.4 Drain 超时 → 强制 abort 所有 in-flight

实测中 P99.9 drain 超时是 250µs,AURA 默认 timeout 200µs。~0.1% 概率会 timeout

后果处理
强制 abort ~10 个事务它们看到 ABORT_DRAIN,client 重试
客户端尾延迟 +100µs罕见,对 SLO 影响小
cohort 进入 FALLBACK短暂降级,下一窗口可能重新升级

7.5 Handoff 包丢失

Handoff 用幂等 RPC(带 from_epoch):

   t=0    OldOwner send handoff (epoch=100)
   t=??   Network drop
   t=50µs OldOwner timeout, resend
   t=70µs NewOwner receive (epoch=100, 第一次)
          install
          reply HANDOFF_OK
   t=120µs OldOwner receive ack

如果第二次到达:

   t=200µs NewOwner receive (epoch=100, 第二次)
           check last_handoff_epoch == 100 → already applied
           reply HANDOFF_ALREADY_APPLIED

重复无副作用

7.6 跨 cohort 事务在迁移中

最复杂的 case:事务 T 同时访问 cohort_C1 和 cohort_C2,C2 正在迁移。

   T 路由到 C1 owner = CN_A
   T 在 CN_A 取 cohort_C1 锁 ✓
   T 通过 OwnerRpc 让 CN_A 跟 cohort_C2 owner 取 C2 锁
       但 C2 处于 TRANSFERRING → 返回 TRANSFERRING_RETRY
   CN_A 收到 → 选择:
       (a) abort T,client 重试
       (b) 短 retry(等 C2 publish 完)
   AURA 默认(a)—— 简单且符合 OCC 语义

🌟 结论:跨 cohort 事务在迁移中会被 abort + retry——这是 OCC 风格(不阻塞)的合理选择。

7.7 链式迁移:A→B→C

   t=0    Planner 决定 cohort_X: A → B
   t=300µs migration done, X owner = B
   t=400µs Planner 决定 cohort_X: B → C

这是合法的——只要每次迁移完整(4 phase 都完成)+ 冷却窗口没违反,链式迁移没问题。

但如果在 t=200µs(B 还没完整接管)就决定 B→C:

// TransferController
if (cohort.state == CohortState::TRANSFERRING) {
    // 拒绝新迁移决策
    return MIGRATION_REJECTED;
}

不允许”迁移中再迁移”


8. fallback 路径详细

8.1 进入 fallback 的 4 种触发

触发例子
主动降级冷数据 cohort,OwnershipPlanner 决定不再有 owner
owner 故障心跳超时、crash、network partition
迁移 timeoutdrain timeout / handoff fail
控制面异常epoch 推进失败超过 N 次

8.2 fallback 期间的事务路径(与原 CREST 一致)

TxnExecutor::run() {
    if (route_result == FALLBACK) {
        // 走原 CREST 路径
        for (auto& key : write_set) {
            if (!fallback_lock.cas_mn(key, expected=0, swap=tx_id)) {
                abort();
                return;
            }
        }
        rdma_write_data();
        rdma_release_locks();
        return COMMITTED;
    }
}

🌟 关键性质fallback 路径就是 CREST——AURA 与 CREST 二进制兼容,已 deployed 的 CREST 集群升级 AURA 无感。

8.3 fallback 期间的成本

维度OWNEDFALLBACK
取锁延迟~100ns(本地)~5µs(RDMA CAS)
atomic 消耗0每事务 ~3 次
owner CN CPU0(不参与)
MN atomic 上限不影响影响(与 baseline 同)

8.4 fallback 退出条件

# OwnershipPlanner 每个窗口检查
def check_fallback_recovery(cohort):
    if cohort.access_count > THRESHOLD_HEAT and \
       cohort.recent_window_growth > 1.5:
        # 选新 owner
        new_owner = pick_owner(cohort)
        # 进入 TRANSFERRING (FALLBACK → TRANSFERRING)
        transfer_controller.elect(cohort, new_owner)
条件阈值
单窗口访问次数 > THRESHOLD_HEAT1000 ops
连续 N 个窗口热度上升N=3
距离上次 fallback 超过 cooldown1s

8.5 fallback 与渐进部署

   集群组成
   ──────────────────
   3 × AURA-aware CN  (升级版)
   2 × legacy CN       (未升级)
   
   AURA-aware CN 处理 OwnerMap,能跑 OWNED 路径
   legacy CN 不认 OwnerMap,所有事务自动走 fallback
   
   AURA 设计上把 legacy CN 的所有 cohort 都 mark 为 FALLBACK

   两类 CN 混合运行,无冲突,逐步升级

互补FALLBACK 是 AURA 渐进发布的关键支撑——如果 fallback 不存在,就必须全集群同时升级。


✅ 自我检验清单

  • 4 阶段时序:能徒手画完整时序图(含 4 个角色 / 时间标尺)
  • 总耗时:能列出 4 个 phase 的 µs 估算并解释为什么总和小于 5ms 决策窗口
  • Freeze:能描述 Freeze 阶段如何处理新到达的事务
  • 双 owner 反例:能解释为什么不 freeze 直接 publish 会破坏 I1
  • Drain in-flight 定义:能列出哪些事务状态需要 drain
  • Drain 超时:能描述 timeout 后的处理路径
  • Handoff RPC 选择:能解释为什么用 RPC 而不是 RDMA WRITE
  • Handoff 幂等性:能写一段代码示意如何保证幂等
  • Publish epoch 推进:能写 atomic CAS 推进 epoch 的代码
  • 客户端 STALE_EPOCH:能描述 lazy refresh 的工作流
  • 不变式证明:能用 1 段话说清 I3 是怎么被 Phase 2 保证的
  • I4 兜底:能解释为什么 I4 让 I1 短暂违反也不致命
  • corner cases:能描述至少 4 个 corner case 及对应处理
  • 链式迁移限制:能解释为什么不允许 transferring 状态再触发迁移
  • 跨 cohort 事务 abort:能解释为什么 OCC 选 abort 而不是等待
  • fallback 与 CREST 兼容:能解释为什么 fallback 路径就是 CREST 原路径

📚 参考资料

概念入门

  • AURA 论文 §3b 组件 workflows:本仓库 paper_lock_ownership_cn/sections/3b_component_workflows.tex
  • AURA 论文 §5 不变式与协议:本仓库 paper_lock_ownership_cn/sections/

关键论文

  • 2PC / 3PC / Paxos —— 分布式协议的经典对照(AURA 不是 2PC,但 epoch + drain 受其启发)
  • Spanner (Corbett et al., OSDI’12) —— TrueTime 与 epoch 模型的工业先例
  • Calvin (Thomson et al., SIGMOD’12) —— deterministic transaction
  • FaRM (Dragojević et al., NSDI’14) —— 早期 RDMA OCC commit 协议

行业讨论

  • Chandy-Lamport snapshot algorithm (1985) —— 分布式快照经典
  • Distributed Snapshots: Determining Global States —— epoch-based snapshot 教材

框架文档

  • gRPC / brpc 文档 —— 用于 OwnerRpc 实现参考
  • CREST 仓库 —— commit 路径在 fallback 路径下完全保留