线性一致性和可串行化有什么区别?
简化版
线性一致性约束单个操作在真实时间上的可见顺序:操作 A 已经完成后,后来开始的操作 B 必须看到 A 的结果。 可串行化约束并发事务的整体效果等价于某种串行执行,但这个串行顺序不一定遵守真实时间。 两者维度不同;严格可串行化等于可串行化再加真实时间约束。
详细版
线性一致性通常讨论寄存器、KV 读写等操作历史,每个操作仿佛在调用与返回之间某一瞬间生效。 可串行化通常讨论多对象事务,要求最终执行等价于事务一个接一个运行,以防脏写、写偏等异常。
一个数据库可以可串行化却不线性一致:事务 T1 已返回提交成功,随后开始的 T2 仍被排序到 T1 之前。 反过来,分别线性一致的多个对象也不自动提供跨对象原子事务。 选型时要先问业务需要实时可见性、事务不变量,还是两者都需要。
完整版教学
一、两种保证回答不同问题
线性一致性回答“已完成的写,后来读是否必须看见”。 可串行化回答“多个并发事务的结果能否解释成某个串行顺序”。 前者强调外部真实时间,后者强调事务之间的逻辑等价。
记忆要点:线性一致性看时间,可串行化看事务顺序,严格可串行化同时满足二者。
二、线性一致性的操作历史
假设客户端 A 写入 x=1 并收到成功,随后客户端 B 才发起读取 x。 线性一致系统必须返回 1 或更新的值,不能返回旧值 0。
A: write(x=1) ----- success
B: read(x) -> must not be 0
并发重叠的两个操作可以按任一顺序线性化,只要每个操作的线性化点位于调用和返回之间。
三、可串行化的事务历史
假设 T1 和 T2 同时修改账户与订单。 系统允许物理执行交错,但结果必须等价于 T1 后 T2 或 T2 后 T1。 它并不要求选择的串行顺序与墙上时钟的先后完全一致。
| 保证 | 主要对象 | 是否约束真实时间 |
|---|---|---|
| 线性一致性 | 单次读写操作 | 是 |
| 可串行化 | 多操作事务 | 否 |
| 严格可串行化 | 事务 | 是 |
四、可串行化但不线性的例子
T1 在 10:00 已返回提交成功,T2 在 10:01 才开始。 若系统的串行化结果把 T2 排在 T1 前,只要事务结果仍等价于一个串行历史,就可能满足可串行化。 但它违反真实时间,因此不满足严格可串行化,也无法给外部用户“提交后立即可见”的保证。
五、线性一致对象不等于事务
x 和 y 两个键各自由线性一致的共识组维护。 客户端先写 x 再写 y,中间失败时,其他客户端可能看见 x 新、y 旧。 单键操作都有明确顺序,却没有跨键原子性。 跨对象业务不变量仍需要事务协议、同一共识组或应用补偿。
六、实现代价与可用性
线性一致读通常要确认当前 Leader 仍掌握多数派授权,或走 quorum/read-index。 网络分区时少数派不能继续确认线性一致写,否则会产生两个都对外成功的历史。 可串行化可通过严格两阶段锁、SSI、确定性调度等实现,各有阻塞、回滚或协调成本。 两种保证都会牺牲部分延迟与分区期间可用性。
七、业务如何选择
余额扣减、唯一约束和权限撤销常同时需要事务不变量与实时顺序。 报表、推荐和缓存可能只需要快照隔离或最终一致。 如果接口文档只写“强一致”,还不够,需要明确操作粒度、真实时间、事务边界和故障语义。 测试应使用历史检查器或并发异常用例,而非只跑单线程正确性。
八、常见误区与追问
- 误区:可串行化天然遵守提交的真实时间。 普通可串行化只要求存在某个串行顺序。
- 误区:所有单键都线性一致就有跨键事务。 原子性与隔离仍需额外协议。
- 误区:线性一致等于所有节点数据瞬时相同。 它约束对外操作历史,不要求副本物理同步到同一时刻。
- 误区:读主节点必然线性一致。 Leader 失去多数派后仍可能自认有效,需要任期或 quorum 确认。
- 追问:严格可串行化是什么? 可串行化事务再满足真实时间先后。
- 追问:快照隔离是可串行化吗? 通常不是,可能出现写偏等异常。
- 追问:如何验证线性一致性? 记录调用与返回时间及结果,对并发历史做线性化检查。
九、加强记忆
- 线性一致性约束真实时间下的单次操作。
- 可串行化约束并发事务等价于某种串行执行。
- 严格可串行化把二者合并。
- 单键线性一致不能替代跨键事务。
- 回答时必须说明对象粒度、事务边界和分区期间的可用性代价。