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架构要点:

  1. 无主架构:所有节点对等,无单点故障
  2. Gossip协议:节点间状态同步,故障检测
  3. 数据分布:基于Token环的自动分片
  4. 高可用:Hinted Handoff处理临时故障
  5. 数据修复:Anti-Entropy保证最终一致性
  6. 弹性扩展:无缝添加/移除节点

下一步,让我们学习数据分布与分区!

最后更新:2026-03-27