Generated comprehensive interview preparation materials covering: - Distributed systems (transactions, locks, ID generation, consistency) - Database (indexing, sharding, replication, transactions) - Caching (Redis, cache problems, distributed lock) - Message queues (RocketMQ, Kafka) - Concurrency (ThreadLocal, ConcurrentHashMap, thread pools) - JVM (GC, memory, tuning) - System design (seckill, short URL, IM, feed, LBS) - Algorithms (B+ tree, LRU, Red-Black tree, Skip list, Timing wheel) - Network (TCP/IP, HTTP/HTTPS) - Security (encryption, SQL injection, XSS) - Performance tuning - Design patterns - Microservices (Spring Boot, Gateway, Service Mesh) - Container orchestration (Kubernetes, Docker) - CI/CD, observability Each file includes: - Detailed questions - Comprehensive answers - Code examples - Real project experience - Alibaba P7 level requirements Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
440 lines
10 KiB
Markdown
440 lines
10 KiB
Markdown
# CAP 理论和 BASE 理论
|
||
|
||
## 问题
|
||
|
||
1. 什么是 CAP 理论?CAP 三者为什么不可兼得?
|
||
2. 什么是 BASE 理论?
|
||
3. CP、AP、AP 架构分别适用于什么场景?
|
||
4. Zookeeper、Eureka、Nacos、Consul 分别是 CP 还是 AP?
|
||
5. 在实际项目中如何权衡一致性、可用性、分区容错性?
|
||
|
||
---
|
||
|
||
## 标准答案
|
||
|
||
### 1. CAP 理论
|
||
|
||
#### **定义**
|
||
|
||
CAP 是指分布式系统中的三个核心指标:
|
||
|
||
| 指标 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| **Consistency(一致性)** | 所有节点在同一时间看到相同的数据 | 写入后,所有节点立即读取到新数据 |
|
||
| **Availability(可用性)** | 系统持续提供服务,每个请求都能得到响应 | 即使部分节点故障,系统仍能响应 |
|
||
| **Partition Tolerance(分区容错性)** | 系统在网络分区时仍能继续运行 | 节点间网络断开,系统仍能工作 |
|
||
|
||
---
|
||
|
||
#### **CAP 定理**
|
||
|
||
**一个分布式系统最多只能同时满足两项**:
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ CAP 三选二 │
|
||
│ │
|
||
│ CA ────┐ │
|
||
│ │ │
|
||
│ ╱ │ ╲ │
|
||
│ ╱ │ ╲ │
|
||
│ ╱ │ ╲ │
|
||
│ ●────────●──────● │
|
||
│ C P A │
|
||
│ │
|
||
│ CP AP CA │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
**为什么?**(证明)
|
||
```
|
||
场景:两个节点 N1、N2,网络分区(P)
|
||
|
||
情况 1:保证 C(一致性)
|
||
├─ N1 写入数据
|
||
└─ 为了保证一致性,N2 必须拒绝读取(牺牲 A)
|
||
|
||
情况 2:保证 A(可用性)
|
||
├─ N1 写入数据
|
||
└─ 为了保证可用性,N2 返回旧数据(牺牲 C)
|
||
|
||
结论:在有分区(P)的情况下,C 和 A 无法同时满足
|
||
```
|
||
|
||
---
|
||
|
||
#### **CP、AP、CA 架构**
|
||
|
||
**1. CP(一致性 + 分区容错)**
|
||
|
||
**特点**:
|
||
- 保证数据一致性
|
||
- 分区时部分节点不可用
|
||
|
||
**适用场景**:
|
||
- 金融系统(转账、支付)
|
||
- 库存系统(超卖不可接受)
|
||
|
||
**代表系统**:
|
||
- Zookeeper(CP)
|
||
- HBase(CP)
|
||
- Redis Cluster(CP,主从切换时短暂不可用)
|
||
|
||
**示例**:
|
||
```java
|
||
// Zookeeper 写入流程
|
||
client.setData("/node", data);
|
||
// 等待大多数节点确认
|
||
// 如果网络分区,部分节点无法写入
|
||
```
|
||
|
||
---
|
||
|
||
**2. AP(可用性 + 分区容错)**
|
||
|
||
**特点**:
|
||
- 保证系统可用
|
||
- 分区时可能读到脏数据
|
||
|
||
**适用场景**:
|
||
- 社交媒体(点赞、评论)
|
||
- 内容分发(CDN)
|
||
- 用户行为统计
|
||
|
||
**代表系统**:
|
||
- Cassandra(AP)
|
||
- DynamoDB(AP)
|
||
- Eureka(AP)
|
||
- DNS(AP)
|
||
|
||
**示例**:
|
||
```java
|
||
// Cassandra 写入
|
||
session.execute("INSERT INTO users (id, name) VALUES (1, 'Alice')");
|
||
// 写入成功立即返回
|
||
// 数据可能尚未复制到其他节点(最终一致性)
|
||
```
|
||
|
||
---
|
||
|
||
**3. CA(一致性 + 可用性)**
|
||
|
||
**注意**:**在分布式系统中,CA 不存在**(因为网络分区不可避免)。
|
||
|
||
**CA 存在于**:
|
||
- 单机系统(RDBMS)
|
||
- 传统关系型数据库(MySQL、PostgreSQL)
|
||
|
||
---
|
||
|
||
### 2. BASE 理论
|
||
|
||
#### **定义**
|
||
|
||
BASE 是对 CAP 中 AP 方案的补充,通过**牺牲强一致性**来获得**高可用性**。
|
||
|
||
| 指标 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| **Basically Available(基本可用)** | 系统出现故障时,允许损失部分可用性 | 秒杀时拒绝部分请求 |
|
||
| **Soft state(软状态)** | 允许数据存在中间状态 | 订单状态:待支付 → 已支付 |
|
||
| **Eventually consistent(最终一致性)** | 数据最终会达到一致状态 | 支付后 1 秒内到账 |
|
||
|
||
---
|
||
|
||
#### **BASE vs ACID**
|
||
|
||
| 特性 | ACID(传统数据库) | BASE(NoSQL) |
|
||
|------|-------------------|---------------|
|
||
| **一致性** | 强一致性(立即) | 最终一致性(延迟) |
|
||
| **可用性** | 可能(锁、事务) | 高(无锁、异步) |
|
||
| **隔离性** | 严格(锁) | 松散 |
|
||
| **持久性** | 强 | 弱(可能丢失) |
|
||
|
||
---
|
||
|
||
#### **最终一致性的实现**
|
||
|
||
**1. 读时修复(Read Repair)**:
|
||
```java
|
||
// 读取时检查一致性
|
||
public User getUser(Long userId) {
|
||
// 从多个节点读取
|
||
User user1 = node1.get(userId);
|
||
User user2 = node2.get(userId);
|
||
|
||
// 发现不一致,修复
|
||
if (!user1.equals(user2)) {
|
||
// 使用版本号或时间戳决定哪个更新
|
||
User latest = user1.getVersion() > user2.getVersion() ? user1 : user2;
|
||
|
||
// 异步修复旧数据
|
||
asyncRepair(latest);
|
||
|
||
return latest;
|
||
}
|
||
|
||
return user1;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
**2. 写时修复(Write Repair)**:
|
||
```java
|
||
// 写入时同步到所有节点
|
||
public void saveUser(User user) {
|
||
// 写入主节点
|
||
masterNode.save(user);
|
||
|
||
// 异步同步到从节点
|
||
for (Node slave : slaves) {
|
||
CompletableFuture.runAsync(() -> {
|
||
slave.save(user);
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
**3. 异步复制**:
|
||
```
|
||
主节点收到写入
|
||
↓
|
||
立即返回成功
|
||
↓
|
||
异步复制到从节点
|
||
↓
|
||
最终一致
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 主流注册中心对比
|
||
|
||
#### **Zookeeper(CP)**
|
||
|
||
**特点**:
|
||
- 保证一致性(ZAB 协议)
|
||
- Leader 挂了会重新选举(期间不可用)
|
||
|
||
**适用场景**:
|
||
- 需要强一致性
|
||
- 对可用性要求不高(如配置中心)
|
||
|
||
**示例**:
|
||
```java
|
||
// Zookeeper 注册
|
||
zk.create("/services/order/192.168.1.10:8080", data, ZooDefs.Ids.OPEN, NodeMode.EPHEMERAL);
|
||
```
|
||
|
||
---
|
||
|
||
#### **Eureka(AP)**
|
||
|
||
**特点**:
|
||
- 保证可用性
|
||
- 客户端缓存注册信息
|
||
- 网络分区时仍能提供服务
|
||
|
||
**适用场景**:
|
||
- 对可用性要求高
|
||
- 可容忍短暂的服务发现不准确
|
||
|
||
**示例**:
|
||
```java
|
||
// Eureka 注册
|
||
@Bean
|
||
public EurekaInstanceBeanBean eurekaInstanceBean(InetAddress inetAddress) {
|
||
EurekaInstanceBeanBean bean = new EurekaInstanceBeanBean();
|
||
bean.setHostname(inetAddress.getHostAddress());
|
||
bean.setAppName("order-service");
|
||
bean.setNonSecurePort(8080);
|
||
return bean;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### **Nacos(AP + CP)**
|
||
|
||
**特点**:
|
||
- 支持 AP 和 CP 切换
|
||
- 默认 AP(临时实例)
|
||
- 可配置 CP(持久化实例)
|
||
|
||
**配置**:
|
||
```yaml
|
||
# Nacos 配置
|
||
spring:
|
||
cloud:
|
||
nacos:
|
||
discovery:
|
||
server-addr: localhost:8848
|
||
ephemeral: true # true=AP, false=CP
|
||
```
|
||
|
||
---
|
||
|
||
#### **Consul(CP)**
|
||
|
||
**特点**:
|
||
- 保证一致性(Raft 协议)
|
||
- 支持 KV 存储
|
||
- 支持健康检查
|
||
|
||
**适用场景**:
|
||
- 服务发现
|
||
- 配置中心
|
||
- 分布式锁
|
||
|
||
---
|
||
|
||
### 4. 实际项目应用
|
||
|
||
#### **场景 1:订单系统(CP)**
|
||
|
||
**需求**:
|
||
- 不能超卖
|
||
- 库存数据必须准确
|
||
|
||
**方案**:
|
||
```
|
||
1. 使用分布式锁(Redis、Zookeeper)
|
||
2. 数据库使用强一致性事务
|
||
3. 库存扣减使用串行化
|
||
```
|
||
|
||
**代码**:
|
||
```java
|
||
@Transactional
|
||
public void createOrder(Order order) {
|
||
// 1. 获取分布式锁
|
||
RLock lock = redissonClient.getLock("product:" + order.getProductId());
|
||
lock.lock();
|
||
|
||
try {
|
||
// 2. 查询库存
|
||
Product product = productMapper.selectById(order.getProductId());
|
||
if (product.getStock() < order.getQuantity()) {
|
||
throw new BusinessException("库存不足");
|
||
}
|
||
|
||
// 3. 扣减库存
|
||
product.setStock(product.getStock() - order.getQuantity());
|
||
productMapper.updateById(product);
|
||
|
||
// 4. 创建订单
|
||
orderMapper.insert(order);
|
||
|
||
} finally {
|
||
lock.unlock();
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### **场景 2:社交点赞(AP)**
|
||
|
||
**需求**:
|
||
- 高并发点赞
|
||
- 允许点赞数短暂不准确
|
||
|
||
**方案**:
|
||
```
|
||
1. 先更新缓存(Redis)
|
||
2. 异步同步到数据库
|
||
3. 最终一致(1 秒内)
|
||
```
|
||
|
||
**代码**:
|
||
```java
|
||
public void like(Long userId, Long postId) {
|
||
// 1. 更新缓存(立即返回)
|
||
redisTemplate.opsForSet().add("post:" + postId + ":likes", userId);
|
||
|
||
// 2. 异步更新数据库
|
||
CompletableFuture.runAsync(() -> {
|
||
likeMapper.insert(new Like(userId, postId));
|
||
});
|
||
}
|
||
|
||
public Long getLikeCount(Long postId) {
|
||
// 1. 先查缓存
|
||
Long count = redisTemplate.opsForSet().size("post:" + postId + ":likes");
|
||
|
||
// 2. 如果缓存不存在,查数据库
|
||
if (count == null || count == 0) {
|
||
count = likeMapper.countByPostId(postId);
|
||
redisTemplate.opsForValue().set("post:" + postId + ":count", count, 1, TimeUnit.HOURS);
|
||
}
|
||
|
||
return count;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### **场景 3:库存同步(最终一致性)**
|
||
|
||
**需求**:
|
||
- 多个仓库库存同步
|
||
- 允许短暂不一致
|
||
|
||
**方案**:
|
||
```
|
||
1. 使用消息队列(RocketMQ)
|
||
2. 事务消息保证不丢失
|
||
3. 消费者重试保证最终一致
|
||
```
|
||
|
||
**代码**:
|
||
```java
|
||
// 1. 发送事务消息
|
||
@Transactional
|
||
public void updateStock(Long productId, int quantity) {
|
||
// 更新数据库
|
||
productMapper.updateStock(productId, quantity);
|
||
|
||
// 发送事务消息
|
||
Message msg = new Message("StockTopic", "StockUpdate",
|
||
JSON.toJSONString(new StockUpdateEvent(productId, quantity)).getBytes());
|
||
rocketMQTemplate.sendMessageInTransaction(msg, null);
|
||
}
|
||
|
||
// 2. 消费消息
|
||
@RocketMQMessageListener(topic = "StockTopic", consumerGroup = "stock-consumer")
|
||
public class StockConsumer implements RocketMQListener<StockUpdateEvent> {
|
||
@Override
|
||
public void onMessage(StockUpdateEvent event) {
|
||
// 同步到其他仓库
|
||
warehouseService.syncStock(event.getProductId(), event.getQuantity());
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 5. 阿里 P7 加分项
|
||
|
||
**深度理解**:
|
||
- 理解 CAP 理论的局限性(如网络延迟、时钟问题)
|
||
- 理解各种一致性协议(Paxos、Raft、ZAB)
|
||
- 理解分布式事务的权衡
|
||
|
||
**实战经验**:
|
||
- 有设计 CP 或 AP 系统的经验
|
||
- 有处理数据不一致问题的经验
|
||
- 有最终一致性调优的经验
|
||
|
||
**架构能力**:
|
||
- 能根据业务特点选择合适的架构
|
||
- 能设计混合架构(部分 CP、部分 AP)
|
||
- 能设计数据修复和补偿机制
|
||
|
||
**技术选型**:
|
||
- 了解各种注册中心和存储系统的 CAP 特性
|
||
- 能根据业务特点选择合适的技术
|
||
- 有分布式系统设计经验
|