会话保证:弱一致系统的实用契约

03-一致性与复制 核心 约 15 分钟 #会话保证#读己之写#单调读#路由 更新 2026-10-02
当前状态:未学
本文基于模型知识整理(生成时未联网核对),关键结论建议对照经典文献复核。

一句话定义

会话保证把一致性承诺从"全体用户全体请求"收缩到"单个用户的会话之内"——读己之写、单调读、单调写、一致前缀读——用远低于线性一致的成本,消除用户可直接感知的异常。

为什么重要

AP 系统(缓存、读从库、无主存储)默认最终一致,直接暴露给用户会产生"我刚改的头像又变回去了"这类体验事故。会话保证是以会话为界的分级承诺:用路由与元数据小成本堵住最刺眼的坑,是弱一致系统落地的关键一层。

前置知识

kp-011(复制滞后异常)、kp-013(一致性谱系位置)。

核心概念

  • 读己之写(read-your-writes):会话内写后必能读到。
  • 单调读(monotonic reads):会话内不会读到"比之前更旧"的值(不许时光倒流)。
  • 单调写(monotonic writes):会话内写按发起顺序生效(不许乱序覆盖)。
  • 一致前缀读(consistent prefix read):因果链条(先问后答)不拆散、不颠倒。
  • 实现工具:会话粘性路由(sticky session)、复制位点/版本令牌(token)随会话携带、分区因果元数据(分区顺序戳)。

原理与机制

为什么按会话承诺可行:用户直接感知的异常几乎都发生在自己的操作链路内;其他用户的数据"晚几秒可见"通常无害。因此把强保证收敛到会话内,会话外维持最终一致——性价比极高。

实现机制对照:

  • 读己之写:会话记录上次写的版本/时间戳,读时路由到"副本位点 ≥ 该版本"的节点(等待或换节点)。
  • 单调读:会话固定路由到同一副本,或记录已读最大版本、只接受更新的版本。
  • 单调写:会话内写都送同一 leader/同一分区(按用户 key 路由)。
  • 一致前缀读:记录各分区的写入序号,读时等待所有相关分区的序号都覆盖已见最大值(如 Kafka 分区 offset 的会话追踪)。

代价:粘性路由损害负载均衡;等待位点增加尾延迟;会话服务器重启需恢复令牌。这是"一致性预算"在用户体验上的精确投放。

图示

会话内:  写 v3 → 主库        读请求携带 token=v3
         副本A 位点 v2 ✕ → 副本B 位点 v3 ✓ → 读到 v3(读己之写)
会话外:  其他用户的旧值可见(最终一致),用户无感

实例或案例

  • Cassandra 的 consistency level + Lightweight Transactions:写后读配 LOCAL_QUORUM 模拟会话保证。
  • MongoDB 的 Causal Consistency Sessions:显式 session token 传递因果。
  • 前端实践:修改资料后跳详情页强制走写库/主缓存并加版本参数,规避"改完看旧值"工单。

常见误区

  • 误区一:"最终一致系统加个会话保证就不弱了"。会话保证只覆盖单用户链路,跨用户因果(如 B 回复 A 后 C 看到回复却看不到原帖)需要一致前缀读,往往被遗漏。
  • 误区二:"粘住主库就完事"。粘性路由会在主库故障切换时失效,切换瞬间会话 token 逻辑必须能跟着新主重建。
  • 误区三:"会话令牌可以不传"。保证只在令牌持续传递时成立;移动端多设备、多进程并发会话会打破"单会话"假设,需明确会话边界。

与其他知识点的关系

  • kp-011:三类复制滞后异常正是这些保证的治理对象。
  • kp-013:会话保证位于因果一致与最终一致之间的实用层。
  • kp-014:位点/token 的比较依赖版本元数据。

自测题

  1. 单调读失效的典型用户观感?

答:"时光倒流":第一次看到评论已有,刷新后评论消失——两次读落到滞后程度不同的副本。

  1. 一致前缀读解决什么跨分区问题?

答:问题与回答写入不同分区且延迟不同,导致"答案先于问题可见";追踪分区序号,读时等齐因果前缀。

  1. 会话保证与线性一致的本质差别?

答:前者只对单个会话的操作序列承诺可见性规则,其他会话可见性无约束;后者对全体操作给出统一实时全序。

延伸阅读

  • Martin Kleppmann《DDIA》第 5 章"Problems with Replication Lag"。
  • MongoDB Causal Consistency 文档(会话 token 设计实例)。
  • Mahajan 等, COPS(causal+ 语义,会话保证的系统化版本)。