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 每核心独立处理

最佳实践:

  1. 配置多个种子节点
  2. 合理设置vNode数量
  3. 使用Shard感知驱动
  4. 监控节点健康状态
  5. 规划好数据中心和机架

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

最后更新:2026-03-27