Posts for: #架构设计

分布式系统演进:从 CAP 到 PACELC 的架构思考

CAP 定理是分布式系统的「牛顿第一定律」——它定义了这个领域的基本约束。但在真实的工程实践中,CAP 定理过于粗粒度,以至于它无法指导我们在实际系统中做出正确的设计决策。我们需要一个更精细的模型。

CAP 定理的再理解

2000 年,Eric Brewer 提出 CAP 猜想;2002 年,Gilbert 和 Lynch 给出了形式化证明。CAP 定理告诉我们:

在一个分布式系统中,以下三个特性最多只能同时满足两个:

C (Consistency)  - 一致性:所有节点在同一时刻看到相同的数据
A (Availability) - 可用性:每个请求都能在合理时间内收到非错误响应
P (Partition Tolerance) - 分区容错:网络分区发生时系统仍能运行

大多数架构师对 CAP 的理解停留在「三选二」的层面。但这个理解有几个问题:

问题 1:P 不是一个可选项

在真实的分布式系统中,网络分区是必然会发生的事情——交换机故障、光缆被挖断、数据中心之间的网络抖动。所以 P 不是你可以「选择放弃」的特性,它是一个既定事实。

真正的选择是在 C 和 A 之间,而且这个选择只在分区发生时才有意义。

没有分区时:C 和 A 可以同时满足
发生分区时:必须在 C 和 A 之间选择

CP 系统:分区时拒绝服务,保证一致性
  例:ZooKeeper、etcd、HBase

AP 系统:分区时继续服务,可能返回过期数据
  例:Cassandra、DynamoDB、CouchDB

问题 2:CAP 是全局的,但需求是局部的

同一个系统中,不同的业务操作可能有不同的一致性需求:

电商系统的一致性需求:

操作 A:扣减库存
  → 需要强一致性(不能超卖)→ CP

操作 B:展示商品评价
  → 可以接受最终一致性(延迟几秒看到新评价无所谓)→ AP

操作 C:用户修改收货地址
  → 需要强一致性(改错了会寄错地方)→ CP

操作 D:商品浏览量计数
  → 可以接受最终一致性(少计几次没关系)→ AP

一个成熟的分布式系统不会在全局层面选择 CP 或 AP,而是在每个操作级别做精细的选择。

[阅读全文]

Redis 高并发缓存架构:击穿、穿透、雪崩全解

缓存是提升系统吞吐量最简单的手段,但它引入的问题也比你想象的更多。击穿、穿透、雪崩——这三个听起来像地质灾害的名词,是每一个高并发系统设计者必须跨越的三道坎。

缓存的基本模型

在深入三个核心问题之前,先建立一个标准的缓存读写模型:

标准缓存读取流程:

客户端 → 缓存层(Redis)→ [命中] → 直接返回
                         → [未命中] → 数据库层 → 写入缓存 → 返回

标准缓存写入流程:

方案 A(Cache Aside):先更新数据库,再删除缓存
方案 B(Read/Write Through):通过缓存层代理读写
方案 C(Write Behind):只写缓存,异步刷入数据库

在绝大多数互联网场景中,Cache Aside(旁路缓存)是最常用的模式——代码直接操作 Redis 和数据库,简单透明。但正是这种简单性,隐藏着三大问题。

问题一:缓存穿透(Cache Penetration)

定义:查询一个根本不存在的数据,缓存中没有,数据库中也没有。每次请求都会穿透缓存直接打到数据库。

正常请求:
  查询 user_id=123 → 缓存命中 → 返回(快)

穿透请求:
  查询 user_id=-1 → 缓存未命中 → 查数据库 → 数据库也没有 → 返回空
  查询 user_id=-1 → 缓存未命中 → 查数据库 → 数据库也没有 → 返回空
  查询 user_id=-1 → 缓存未命中 → 查数据库 → 数据库也没有 → 返回空
  
  如果每秒 10000 次这样的请求,数据库直接被压垮

穿透通常由恶意攻击或业务 Bug 引起——攻击者构造大量不存在的 ID,绕过缓存直接攻击数据库。

[阅读全文]