ScyllaDB分布式架构 #
一、架构概述 #
1.1 Masterless架构 #
ScyllaDB采用无主(Masterless)架构,所有节点地位平等,没有单点故障。
text
┌─────────────────────────────────────────────────────────┐
│ Masterless架构 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node1 │────▶│ Node2 │────▶│ Node3 │ │
│ │ (平等) │◀────│ (平等) │◀────│ (平等) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ └───────────────┴───────────────┘ │
│ 所有节点平等 │
└─────────────────────────────────────────────────────────┘
1.2 架构优势 #
| 特性 | 说明 |
|---|---|
| 无单点故障 | 任何节点故障不影响整体服务 |
| 线性扩展 | 添加节点即可线性增加容量 |
| 高可用 | 自动故障检测和转移 |
| 低延迟 | 数据就近访问 |
| 弹性伸缩 | 动态添加/移除节点 |
二、节点角色 #
2.1 节点类型 #
text
节点类型:
├── 种子节点(Seed Node)
│ ├── 新节点加入集群的入口
│ ├── 不存储特殊数据
│ └── 建议配置多个
├── 数据节点
│ ├── 存储数据分片
│ ├── 处理读写请求
│ └── 参与集群通信
└── 协调节点(Coordinator)
├── 接收客户端请求
├── 路由请求到正确节点
└── 聚合返回结果
2.2 协调节点工作流程 #
text
┌─────────────────────────────────────────────────────────┐
│ 读写请求流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ Client ──▶ Coordinator ──▶ Replica Nodes │
│ │ │
│ ├── 1. 接收请求 │
│ ├── 2. 计算分区键 │
│ ├── 3. 确定副本位置 │
│ ├── 4. 转发请求 │
│ └── 5. 聚合响应 │
│ │
└─────────────────────────────────────────────────────────┘
2.3 节点状态 #
| 状态 | 说明 |
|---|---|
| Normal | 正常运行,存储数据 |
| Joining | 正在加入集群 |
| Leaving | 正在离开集群 |
| Moving | 正在移动数据 |
| Bootstrapping | 正在启动引导 |
三、Gossip协议 #
3.1 Gossip工作原理 #
Gossip协议用于节点间的状态信息交换,类似于流行病传播。
text
Gossip通信模式:
┌─────────────────────────────────────────────────────────┐
│ │
│ T=0s T=1s T=2s T=3s │
│ │
│ [A]──▶[B] [A]──▶[C] [A]──▶[D] [A]──▶[E] │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ [B]──▶[C] [B]──▶[D] [B]──▶[E] [B]──▶[F] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [C]──▶[D] [C]──▶[E] [C]──▶[F] │
│ │
│ 信息呈指数级传播 │
└─────────────────────────────────────────────────────────┘
3.2 Gossip消息类型 #
java
// Gossip消息结构
GossipMessage {
cluster_name: "Test Cluster",
partitioner: "Murmur3Partitioner",
generation: 1234567890,
heartbeat: {
generation: 1234567890,
version: 100
},
application_state: {
STATUS: "NORMAL",
LOAD: "1024.0",
DC: "datacenter1",
RACK: "rack1"
}
}
3.3 故障检测 #
text
故障检测机制:
├── Phi Accrual Failure Detector
│ ├── 计算节点健康分数
│ ├── 基于历史心跳间隔
│ └── 动态阈值判断
├── 心跳检测
│ ├── 每秒发送心跳
│ ├── 记录响应时间
│ └── 更新健康状态
└── 故障判定
├── 超过阈值标记为DOWN
├── 恢复后标记为UP
└── 触发故障转移
四、Raft共识协议 #
4.1 Raft概述 #
ScyllaDB 5.0+引入Raft共识协议,用于集群元数据管理。
text
Raft架构:
┌─────────────────────────────────────────────────────────┐
│ Raft共识组 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Leader │────▶│Follower │────▶│Follower │ │
│ │ │◀────│ │◀────│ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ └── 处理所有写请求 │
│ │
└─────────────────────────────────────────────────────────┘
4.2 Raft应用场景 #
| 场景 | 说明 |
|---|---|
| Schema变更 | 表结构变更的共识 |
| 集群拓扑 | 节点加入/离开共识 |
| Token分配 | 数据分片分配共识 |
| 用户权限 | 权限变更共识 |
4.3 Raft vs 传统方式 #
text
传统方式(Schema版本):
├── Gossip传播Schema变更
├── 最终一致性
├── 可能出现短暂不一致
└── 并发变更可能冲突
Raft方式:
├── 强一致性共识
├── 线性一致性
├── 无并发冲突
└── 变更顺序可预测
五、数据分区 #
5.1 分区器 #
ScyllaDB使用分区器将数据分布到不同节点。
text
分区器类型:
├── Murmur3Partitioner(默认)
│ ├── 使用MurmurHash算法
│ ├── 性能优秀
│ └── 分布均匀
├── RandomPartitioner
│ ├── 使用MD5哈希
│ └── 兼容旧版本
└── ByteOrderedPartitioner
├── 按字节顺序
└── 不推荐使用
5.2 Token计算 #
python
# Murmur3分区器Token计算示例
def calculate_token(partition_key):
# 将分区键转换为字节
key_bytes = partition_key.encode('utf-8')
# 计算MurmurHash
token = murmur3_hash(key_bytes)
# Token范围: -2^63 到 2^63-1
return token
# 示例
token = calculate_token("user_123")
# token: 8765432109876543210
5.3 Token环 #
text
Token环示例(3节点,RF=3):
┌─────────────────────────────────────────────────────────┐
│ │
│ Token Ring │
│ │
│ Node A │
│ (0 ~ 1/3) │
│ / \ │
│ / \ │
│ / \ │
│ Node C Node B │
│ (2/3 ~ 0) (1/3 ~ 2/3) │
│ │
│ 数据根据Token值分布到对应节点 │
└─────────────────────────────────────────────────────────┘
六、虚拟节点(vNode) #
6.1 vNode概念 #
每个物理节点包含多个虚拟节点,简化数据分布和负载均衡。
text
vNode分布:
┌─────────────────────────────────────────────────────────┐
│ │
│ Physical Node 1 Physical Node 2 │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ vNode 1 vNode 2│ │ vNode 5 vNode 6│ │
│ │ vNode 3 vNode 4│ │ vNode 7 vNode 8│ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ 每个vNode管理一段Token范围 │
└─────────────────────────────────────────────────────────┘
6.2 vNode优势 #
| 优势 | 说明 |
|---|---|
| 负载均衡 | 自动均匀分布数据 |
| 简化运维 | 添加/移除节点自动再平衡 |
| 快速恢复 | 故障节点数据分散到多节点 |
| 灵活配置 | 不同节点可配置不同vNode数 |
6.3 vNode配置 #
yaml
# scylla.yaml配置
num_tokens: 256 # 默认每个节点256个vNode
# 生产环境建议
# - 小集群:256
# - 中等集群:128
# - 大集群:64
七、数据读写路径 #
7.1 写入路径 #
text
写入流程:
┌─────────────────────────────────────────────────────────┐
│ │
│ Client ──▶ Coordinator ──▶ Replica Nodes │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ 1. 接收 │ │
│ │ 写请求 │ │
│ └────┬─────┘ │
│ ▼ │
│ ┌──────────┐ │
│ │ 2. 计算 │ │
│ │ Token │ │
│ └────┬─────┘ │
│ ▼ │
│ ┌──────────┐ │
│ │ 3. 确定 │ │
│ │ 副本 │ │
│ └────┬─────┘ │
│ ▼ │
│ ┌──────────┐ │
│ │ 4. 写入 │ │
│ │ 副本 │ │
│ └────┬─────┘ │
│ ▼ │
│ ┌──────────┐ │
│ │ 5. 确认 │ │
│ │ 响应 │ │
│ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
7.2 写入存储结构 #
text
写入存储层次:
┌─────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ MemTable (内存) │ │
│ │ - 有序内存结构 │ │
│ │ - 快速写入 │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ ▼ (刷写到磁盘) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ SSTable (磁盘) │ │
│ │ - 不可变文件 │ │
│ │ - 有序存储 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Commit Log │ │
│ │ - 写前日志 │ │
│ │ - 故障恢复 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
7.3 读取路径 #
text
读取流程:
┌─────────────────────────────────────────────────────────┐
│ │
│ 1. 检查 Row Cache (如果启用) │
│ │ │
│ ▼ 未命中 │
│ 2. 检查 Key Cache │
│ │ │
│ ▼ 未命中 │
│ 3. 检查 Bloom Filter │
│ │ │
│ ▼ 可能存在 │
│ 4. 查询 MemTable │
│ │ │
│ ▼ 未找到 │
│ 5. 查询 SSTable (从新到旧) │
│ │ │
│ ▼ │
│ 6. 合并结果返回 │
│ │
└─────────────────────────────────────────────────────────┘
八、Shard架构 #
8.1 Shard-per-Core #
ScyllaDB的独有特性:每个CPU核心独立处理一个Shard。
text
Shard架构:
┌─────────────────────────────────────────────────────────┐
│ ScyllaDB进程 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Shard 0 │ │ Shard 1 │ │ Shard 2 │ │ Shard 3 │ │
│ │ (Core 0)│ │ (Core 1)│ │ (Core 2)│ │ (Core 3)│ │
│ │ │ │ │ │ │ │ │ │
│ │ 独立 │ │ 独立 │ │ 独立 │ │ 独立 │ │
│ │ 内存 │ │ 内存 │ │ 内存 │ │ 内存 │ │
│ │ 处理 │ │ 处理 │ │ 处理 │ │ 处理 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 无锁设计,每个Shard独立处理 │
└─────────────────────────────────────────────────────────┘
8.2 Shard优势 #
| 特性 | 说明 |
|---|---|
| 无锁设计 | 每个Shard独立,无需锁竞争 |
| 缓存友好 | 数据局部性好 |
| 线性扩展 | 核心数增加,性能线性提升 |
| 低延迟 | 无上下文切换开销 |
8.3 Shard感知驱动 #
python
# Python Shard感知连接
from cassandra.cluster import Cluster
from cassandra.policies import TokenAwarePolicy, DCAwareRoundRobinPolicy
cluster = Cluster(
['192.168.1.1', '192.168.1.2'],
load_balancing_policy=TokenAwarePolicy(
DCAwareRoundRobinPolicy(local_dc='datacenter1')
)
)
# 自动路由到正确的Shard
session = cluster.connect()
九、总结 #
架构要点:
| 组件 | 说明 |
|---|---|
| Masterless | 所有节点平等,无单点故障 |
| Gossip | 节点状态信息交换 |
| Raft | 元数据共识协议 |
| vNode | 虚拟节点,简化数据分布 |
| Shard | 每核心独立处理 |
最佳实践:
- 配置多个种子节点
- 合理设置vNode数量
- 使用Shard感知驱动
- 监控节点健康状态
- 规划好数据中心和机架
下一步,让我们学习数据分布与分区!
最后更新:2026-03-27