Cassandra分布式架构 #
一、架构概述 #
1.1 无主架构 (Masterless) #
Cassandra采用对等式(P2P)无主架构,所有节点地位平等,没有主从之分。
text
┌─────────────────────────────────────────────────────────┐
│ Cassandra 集群 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ │
│ │ Node A │◄──────────────┐ │
│ │ (对等) │ │ │
│ └────┬────┘ │ │
│ │ │ │
│ ▼ │ │
│ ┌─────────┐ ┌─────────┐ │
│ ┌────│ Node B │─────────│ Node D │────┐ │
│ │ │ (对等) │ │ (对等) │ │ │
│ │ └─────────┘ └─────────┘ │ │
│ │ ▲ ▲ │ │
│ │ │ │ │ │
│ │ ┌────┴────┐ │ │ │
│ └───►│ Node C │───────────────┘ │ │
│ │ (对等) │◄───────────────────────┘ │
│ └─────────┘ │
│ │
│ 所有节点对等 │ 任意节点可接受请求 │ 无单点故障 │
└─────────────────────────────────────────────────────────┘
1.2 与主从架构对比 #
| 特性 | Cassandra (无主) | MySQL主从 |
|---|---|---|
| 节点角色 | 全部对等 | 主节点/从节点 |
| 写入点 | 任意节点 | 仅主节点 |
| 故障转移 | 自动 | 需要手动/半自动 |
| 单点故障 | 无 | 主节点故障影响大 |
| 扩展性 | 线性扩展 | 有限扩展 |
1.3 核心组件 #
text
┌─────────────────────────────────────────────────────────┐
│ Cassandra 节点 │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Client │ │ Storage │ │ Gossip │ │
│ │ Request │ │ Engine │ │ Service │ │
│ │ Handler │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ MemTable │ │ SSTable │ │ CommitLog │ │
│ │ (内存) │ │ (磁盘) │ │ (日志) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Compaction │ │ BloomFilter │ │ Hinted │ │
│ │ Manager │ │ │ │ Handoff │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
二、Gossip协议 #
2.1 Gossip工作原理 #
Gossip是一种去中心化的通信协议,用于节点间的状态同步。
text
Gossip通信流程:
时间T1: 时间T2: 时间T3:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Node A │───Gossip───►│ Node B │───Gossip───►│ Node C │
│ 状态:Up │ │ 状态:Up │ │ 状态:Up │
└─────────┘ └─────────┘ └─────────┘
│ │ │
└──────────────────────────┴──────────────────────────┘
所有节点最终状态一致
2.2 Gossip消息类型 #
| 消息类型 | 描述 |
|---|---|
| GOSSIP_DIGEST_SYN | 同步请求,发送节点状态摘要 |
| GOSSIP_DIGEST_ACK | 确认响应,返回差异状态 |
| GOSSIP_DIGEST_ACK2 | 最终确认,发送完整状态 |
2.3 Gossip配置 #
yaml
# cassandra.yaml Gossip配置
# Gossip间隔(毫秒)
phi_convict_threshold: 8
# 故障检测阈值
# 值越低,故障检测越敏感
# 生产环境推荐8,开发环境推荐12
# 种子节点
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "192.168.1.1,192.168.1.2,192.168.1.3"
2.4 故障检测 #
text
故障检测机制:
节点A监控节点B
│
├── 定期发送心跳
│ └── 记录响应时间
│
├── 计算Phi值
│ └── φ(t) = -log10(1 - F(t))
│ F(t) = 响应时间概率分布
│
└── 判断节点状态
├── φ < 阈值: 节点正常
└── φ >= 阈值: 节点故障
三、数据读写路径 #
3.1 写入路径 #
text
写入流程:
Client
│
▼
┌─────────────────────────────────────────────────────┐
│ Coordinator Node (协调节点) │
│ ┌─────────────────────────────────────────────┐ │
│ │ 1. 确定数据应存储的节点(根据分区键) │ │
│ │ 2. 将写入请求转发到所有副本节点 │ │
│ │ 3. 等待足够数量的确认(根据一致性级别) │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Replica Node (副本节点) │
│ ┌─────────────────────────────────────────────┐ │
│ │ 1. 写入CommitLog(顺序写,保证持久性) │ │
│ │ 2. 写入MemTable(内存结构) │ │
│ │ 3. 返回确认 │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ 后台操作: │
│ ┌─────────────────────────────────────────────┐ │
│ │ • MemTable满 → 刷入SSTable │ │
│ │ • SSTable合并(Compaction) │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
3.2 读取路径 #
text
读取流程:
Client
│
▼
┌─────────────────────────────────────────────────────┐
│ Coordinator Node (协调节点) │
│ ┌─────────────────────────────────────────────┐ │
│ │ 1. 确定数据所在的节点 │ │
│ │ 2. 根据一致性级别选择读取策略 │ │
│ │ 3. 合并结果并返回 │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Replica Node (副本节点) │
│ ┌─────────────────────────────────────────────┐ │
│ │ 1. 检查Row Cache(如果启用) │ │
│ │ 2. 检查Key Cache + BloomFilter │ │
│ │ 3. 检查MemTable │ │
│ │ 4. 检查SSTable │ │
│ │ 5. 合并数据并返回 │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
3.3 一致性保证 #
text
写入一致性(CL.W)和读取一致性(CL.R)的关系:
强一致性: CL.W + CL.R > RF (Replication Factor)
最终一致性: CL.W + CL.R <= RF
示例(RF=3):
┌──────────────┬──────────────┬─────────────────────┐
│ 写入一致性 │ 读取一致性 │ 结果 │
├──────────────┼──────────────┼─────────────────────┤
│ ALL (3) │ ONE (1) │ 强一致 (3+1>3) │
│ QUORUM (2) │ QUORUM (2) │ 强一致 (2+2>3) │
│ ONE (1) │ ONE (1) │ 最终一致 (1+1<=3) │
│ ANY (1) │ ONE (1) │ 最终一致 (1+1<=3) │
└──────────────┴──────────────┴─────────────────────┘
四、Hinted Handoff #
4.1 工作原理 #
Hinted Handoff确保在节点临时故障时不丢失写入。
text
Hinted Handoff流程:
正常写入:
Node A ───写入───► Node B (副本1)
│
└──写入───► Node C (副本2)
│
└──写入───► Node D (副本3)
节点D故障时:
Node A ───写入───► Node B (副本1) ✓
│
└──写入───► Node C (副本2) ✓
│
└──保存Hint───► 本地 (为Node D保存)
│
│ Node D恢复后
▼
传递给Node D
4.2 配置 #
yaml
# cassandra.yaml
# 启用Hinted Handoff
hinted_handoff_enabled: true
# Hint数据目录
hints_directory: /var/lib/cassandra/hints
# Hint保留时间(秒)
max_hint_window_in_ms: 10800000 # 3小时
# Hint刷新频率
hints_flush_period_in_ms: 10000
# 最大Hint文件大小
max_hints_file_size_in_mb: 128
五、反熵修复 #
5.1 Anti-Entropy Repair #
当节点长时间故障后,需要使用修复来同步数据。
bash
# 全量修复
nodetool repair
# 修复特定键空间
nodetool repair my_keyspace
# 修复特定表
nodetool repair my_keyspace my_table
# 增量修复(仅修复已知差异)
nodetool repair --incremental
# 并行修复
nodetool repair --parallel
5.2 Repair策略 #
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 全量修复 | 比较所有数据 | 长时间故障后 |
| 增量修复 | 仅修复差异 | 定期维护 |
| 并行修复 | 多表并行 | 大集群 |
| 主范围修复 | 按Token范围 | 减少网络开销 |
5.3 自动修复配置 #
yaml
# cassandra.yaml
# 启用自动修复
auto_bootstrap: true
# 修复线程数
repair_threads: 1
# 修复会话超时
repair_session_timeout: 3600
六、节点引导与退役 #
6.1 添加节点 #
bash
# 1. 配置新节点的cassandra.yaml
cluster_name: 'MyCluster'
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "现有种子节点IP"
listen_address: 新节点IP
rpc_address: 新节点IP
# 2. 启动新节点(自动引导)
bin/cassandra
# 3. 检查状态
nodetool status
# 4. 数据自动平衡
# 新节点会自动从现有节点获取数据
6.2 移除节点 #
bash
# 方式1: 正常退役(节点在线)
nodetool decommission
# 方式2: 强制移除(节点离线)
# 在其他节点执行
nodetool removenode <host_id>
# 查看节点host_id
nodetool status
6.3 节点替换 #
bash
# 替换故障节点
# 1. 获取故障节点的Token
nodetool status
# 2. 配置新节点
# cassandra.yaml
auto_bootstrap: false
# 3. 启动时指定要替换的Token
bin/cassandra -Dcassandra.replace_address=<故障节点IP>
# 4. 完成后检查状态
nodetool status
七、Snitch配置 #
7.1 Snitch类型 #
Snitch决定了节点之间的拓扑关系,影响数据分布和副本放置。
| Snitch | 描述 | 适用场景 |
|---|---|---|
| SimpleSnitch | 单数据中心 | 开发测试 |
| GossipingPropertyFileSnitch | 多数据中心 | 生产环境 |
| Ec2Snitch | AWS EC2 | AWS部署 |
| GoogleCloudSnitch | GCP | GCP部署 |
| AzureSnitch | Azure | Azure部署 |
7.2 配置示例 #
yaml
# cassandra.yaml
# 使用GossipingPropertyFileSnitch
endpoint_snitch: GossipingPropertyFileSnitch
# 配置节点属性
# cassandra-rackdc.properties
dc=DC1
rack=RAC1
7.3 拓扑配置 #
text
多数据中心拓扑示例:
┌─────────────────────────────────────────────────────────┐
│ 集群拓扑 │
├───────────────────────┬─────────────────────────────────┤
│ DC1 (北京) │ DC2 (上海) │
├───────────────────────┼─────────────────────────────────┤
│ RAC1 │ RAC1 │
│ ├── Node1 │ ├── Node4 │
│ └── Node2 │ └── Node5 │
├───────────────────────┼─────────────────────────────────┤
│ RAC2 │ RAC2 │
│ └── Node3 │ └── Node6 │
└───────────────────────┴─────────────────────────────────┘
八、总结 #
Cassandra架构要点:
- 无主架构:所有节点对等,无单点故障
- Gossip协议:节点间状态同步,故障检测
- 数据分布:基于Token环的自动分片
- 高可用:Hinted Handoff处理临时故障
- 数据修复:Anti-Entropy保证最终一致性
- 弹性扩展:无缝添加/移除节点
下一步,让我们学习数据分布与分区!
最后更新:2026-03-27