分布式层 #

一、分布式层概述 #

1.1 分布式架构 #

text
分布式层架构
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   事务层                                                    │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Range 分片管理                         │   │
│   │   数据分片 / Range 分裂合并                        │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Raft 共识协议                          │   │
│   │   副本一致性 / Leader选举                          │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              副本管理                               │   │
│   │   副本分布 / 故障恢复                              │   │
│   └─────────────────────────────────────────────────────┘   │
│       │                                                     │
│       ▼                                                     │
│   ┌─────────────────────────────────────────────────────┐   │
│   │              Gossip 协议                            │   │
│   │   节点发现 / 信息传播                              │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 核心概念 #

概念 说明
Range 数据分片单元
Replica Range的副本
Raft 共识协议
Gossip 节点通信协议

二、Range分片 #

2.1 Range概念 #

text
Range 数据分片
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   数据按 Key 范围分片:                                      │
│                                                             │
│   整个数据空间                                              │
│   ┌─────────────────────────────────────────────────────┐   │
│   │ Range 1 │ Range 2 │ Range 3 │ Range 4 │ Range 5    │   │
│   │ [a-f)   │ [f-m)   │ [m-r)   │ [r-w)   │ [w-z]      │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
│   Range 特点:                                               │
│   ├── 默认大小: 512MB                                      │
│   ├── 自动分裂: 超过阈值自动分裂                          │
│   ├── 自动合并: 数据减少自动合并                          │
│   └── 自动均衡: 自动迁移到不同节点                        │
│                                                             │
│   每个 Range 是一个 Raft Group:                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                  Range 1                             │   │
│   │                                                      │   │
│   │   ┌──────────┐                                      │   │
│   │   │ Leader   │  Replica 1                           │   │
│   │   └──────────┘                                      │   │
│   │        │                                             │   │
│   │        ├─────────────────┐                          │   │
│   │        ▼                 ▼                          │   │
│   │   ┌──────────┐    ┌──────────┐                      │   │
│   │   │Follower  │    │Follower  │                      │   │
│   │   │ Replica 2│    │ Replica 3│                      │   │
│   │   └──────────┘    └──────────┘                      │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.2 Range分裂 #

text
Range 分裂
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   触发条件:                                                 │
│   ├── Range 大小超过阈值 (默认 512MB)                      │
│   └── 手动触发                                             │
│                                                             │
│   分裂过程:                                                 │
│                                                             │
│   分裂前:                                                   │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                    Range 1                           │   │
│   │                  [a-z]                               │   │
│   └─────────────────────────────────────────────────────┘   │
│                         │                                   │
│                         ▼                                   │
│   分裂后:                                                   │
│   ┌─────────────────────┐   ┌─────────────────────┐        │
│   │      Range 1        │   │      Range 2        │        │
│   │       [a-m)         │   │       [m-z]         │        │
│   └─────────────────────┘   └─────────────────────┘        │
│                                                             │
│   分裂步骤:                                                 │
│   1. 选择分裂点                                            │
│   2. 创建新 Range                                          │
│   3. 分配副本                                              │
│   4. 更新元数据                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.3 Range合并 #

text
Range 合并
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   触发条件:                                                 │
│   ├── Range 大小过小                                       │
│   └── 相邻 Range 都很小                                    │
│                                                             │
│   合并过程:                                                 │
│                                                             │
│   合并前:                                                   │
│   ┌─────────────────────┐   ┌─────────────────────┐        │
│   │      Range 1        │   │      Range 2        │        │
│   │       [a-m)         │   │       [m-z]         │        │
│   │     (很小)          │   │     (很小)          │        │
│   └─────────────────────┘   └─────────────────────┘        │
│                         │                                   │
│                         ▼                                   │
│   合并后:                                                   │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                    Range 1                           │   │
│   │                  [a-z]                               │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.4 查看Range #

sql
-- 查看 Range 分布
SELECT 
    range_id,
    start_key,
    end_key,
    replicas,
    lease_holder
FROM crdb_internal.ranges;

-- 查看特定表的 Range
SHOW RANGES FROM TABLE users;

-- 查看 Range 统计
SELECT 
    range_id,
    round(statistics->>'key_bytes'::numeric / 1024 / 1024, 2) AS size_mb
FROM crdb_internal.ranges
ORDER BY range_id;

三、Raft共识协议 #

3.1 Raft原理 #

text
Raft 共识协议
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   角色:                                                     │
│   ├── Leader: 处理所有请求                                 │
│   ├── Follower: 接收 Leader 日志                           │
│   └── Candidate: 选举时的候选者                            │
│                                                             │
│   每个 Range 是一个 Raft Group:                             │
│                                                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                  Raft Group                         │   │
│   │                                                      │   │
│   │   ┌──────────────────────────────────────────────┐  │   │
│   │   │              Leader (Node 1)                 │  │   │
│   │   │                                              │  │   │
│   │   │  - 处理所有客户端请求                       │  │   │
│   │   │  - 复制日志到 Followers                     │  │   │
│   │   │  - 提交日志                                 │  │   │
│   │   └──────────────────────────────────────────────┘  │   │
│   │                         │                            │   │
│   │              ┌──────────┴──────────┐                │   │
│   │              ▼                     ▼                │   │
│   │   ┌──────────────────┐  ┌──────────────────┐        │   │
│   │   │ Follower (Node 2)│  │ Follower (Node 3)│        │   │
│   │   │                  │  │                  │        │   │
│   │   │ - 接收日志       │  │ - 接收日志       │        │   │
│   │   │ - 应用日志       │  │ - 应用日志       │        │   │
│   │   └──────────────────┘  └──────────────────┘        │   │
│   │                                                      │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.2 写入流程 #

text
Raft 写入流程
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   客户端写入请求                                            │
│       │                                                     │
│       ▼                                                     │
│   1. 客户端发送写入到任意节点                               │
│       │                                                     │
│       ▼                                                     │
│   2. 转发到 Range Leader                                    │
│       │                                                     │
│       ▼                                                     │
│   3. Leader 追加日志到本地                                  │
│       │                                                     │
│       ▼                                                     │
│   4. Leader 复制日志到 Followers                            │
│       │                                                     │
│       │    ┌──────────┐                                     │
│       │    │ Leader   │                                     │
│       │    └────┬─────┘                                     │
│       │         │                                           │
│       │    ┌────┴────┐                                      │
│       │    ▼         ▼                                      │
│       │ ┌──────┐ ┌──────┐                                   │
│       │ │Foll 1│ │Foll 2│                                   │
│       │ └──────┘ └──────┘                                   │
│       │                                                     │
│       ▼                                                     │
│   5. 多数节点确认 (Quorum)                                  │
│       │                                                     │
│       ▼                                                     │
│   6. Leader 提交日志                                        │
│       │                                                     │
│       ▼                                                     │
│   7. 返回客户端成功                                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.3 Leader选举 #

text
Leader 选举
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   触发条件:                                                 │
│   ├── Leader 故障                                          │
│   └── Follower 超时未收到心跳                              │
│                                                             │
│   选举过程:                                                 │
│                                                             │
│   1. Follower 超时,转为 Candidate                         │
│      │                                                      │
│      ▼                                                      │
│   2. Candidate 增加任期号                                   │
│      │                                                      │
│      ▼                                                      │
│   3. 向其他节点发送投票请求                                 │
│      │                                                      │
│      ▼                                                      │
│   4. 收集投票                                               │
│      │                                                      │
│      ├── 多数投票 → 成为 Leader                            │
│      │                                                      │
│      ├── 收到更高任期 → 降为 Follower                      │
│      │                                                      │
│      └── 未获多数 → 重新选举                                │
│                                                             │
│   选举安全:                                                 │
│   ├── 一个任期最多一个 Leader                              │
│   └── 只有最新日志的节点才能当选                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

四、副本管理 #

4.1 副本分布 #

text
副本分布策略
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   默认副本数: 3                                             │
│                                                             │
│   分布原则:                                                 │
│   ├── 不同节点                                             │
│   ├── 不同机架 (如配置)                                    │
│   └── 不同区域 (如配置)                                    │
│                                                             │
│   示例: 5节点集群                                           │
│                                                             │
│   Node 1      Node 2      Node 3      Node 4      Node 5   │
│   ┌─────┐    ┌─────┐    ┌─────┐    ┌─────┐    ┌─────┐     │
│   │R1 L │    │R1 F │    │R1 F │    │     │    │     │     │
│   │R2 F │    │R2 L │    │R2 F │    │     │    │     │     │
│   │R3 F │    │R3 F │    │R3 L │    │     │    │     │     │
│   │R4 F │    │R4 F │    │     │    │R4 L │    │     │     │
│   │R5 F │    │R5 F │    │     │    │R5 F │    │R5 L │     │
│   └─────┘    └─────┘    └─────┘    └─────┘    └─────┘     │
│                                                             │
│   L = Leader, F = Follower                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2 副本配置 #

sql
-- 配置默认副本数
ALTER DATABASE defaultdb CONFIGURE ZONE USING 
    num_replicas = 5;

-- 配置特定表的副本数
ALTER TABLE users CONFIGURE ZONE USING 
    num_replicas = 5;

-- 配置副本放置约束
ALTER DATABASE mydb CONFIGURE ZONE USING 
    constraints = '[+region=us-east]';

-- 查看Zone配置
SHOW ZONE CONFIGURATION FOR DATABASE defaultdb;

4.3 副本迁移 #

text
副本迁移
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   触发条件:                                                 │
│   ├── 节点添加                                             │
│   ├── 节点移除                                             │
│   ├── 负载不均衡                                           │
│   └── 存储空间不足                                         │
│                                                             │
│   迁移过程:                                                 │
│                                                             │
│   1. 选择目标节点                                           │
│      │                                                      │
│      ▼                                                      │
│   2. 添加新副本 (Learner)                                   │
│      │                                                      │
│      ▼                                                      │
│   3. 同步数据                                               │
│      │                                                      │
│      ▼                                                      │
│   4. 新副本追上进度                                         │
│      │                                                      │
│      ▼                                                      │
│   5. 新副本成为 Follower                                    │
│      │                                                      │
│      ▼                                                      │
│   6. 移除旧副本                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

五、Gossip协议 #

5.1 Gossip原理 #

text
Gossip 协议
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   用途:                                                     │
│   ├── 节点发现                                             │
│   ├── 信息传播                                             │
│   └── 集群状态维护                                         │
│                                                             │
│   工作原理:                                                 │
│                                                             │
│   每个节点定期随机选择其他节点交换信息:                     │
│                                                             │
│   Node 1          Node 2          Node 3                   │
│   ┌─────┐        ┌─────┐        ┌─────┐                   │
│   │     │◄──────►│     │◄──────►│     │                   │
│   │     │        │     │        │     │                   │
│   └─────┘        └─────┘        └─────┘                   │
│       ▲              │              │                      │
│       │              │              │                      │
│       └──────────────┴──────────────┘                      │
│                                                             │
│   传播的信息:                                               │
│   ├── 节点状态                                             │
│   ├── Range 元数据                                         │
│   ├── 存储容量                                             │
│   └── 网络延迟                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5.2 节点发现 #

bash
# 启动时指定 join 节点
cockroach start --join=node1:26257,node2:26257,node3:26257

# 新节点自动通过 Gossip 发现其他节点

六、负载均衡 #

6.1 自动均衡 #

text
自动负载均衡
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   均衡目标:                                                 │
│   ├── Range 数量均衡                                       │
│   ├── Leader 数量均衡                                      │
│   ├── 存储空间均衡                                         │
│   └── 负载均衡                                             │
│                                                             │
│   均衡过程:                                                 │
│                                                             │
│   1. 监控集群状态                                           │
│      │                                                      │
│      ▼                                                      │
│   2. 计算均衡得分                                           │
│      │                                                      │
│      ▼                                                      │
│   3. 选择需要迁移的 Range                                   │
│      │                                                      │
│      ▼                                                      │
│   4. 执行副本迁移                                           │
│      │                                                      │
│      ▼                                                      │
│   5. 更新元数据                                             │
│                                                             │
│   示例:                                                     │
│   Node 1 (100 Ranges) → Node 2 (50 Ranges)                 │
│   迁移 25 Ranges 到 Node 2                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.2 查看均衡状态 #

sql
-- 查看节点状态
SELECT 
    node_id,
    is_live,
    ranges,
    replicas,
    lease_holder
FROM crdb_internal.kv_node_status;

-- 查看 Range 分布
SELECT 
    node_id,
    COUNT(*) AS range_count
FROM crdb_internal.ranges
CROSS JOIN UNNEST(replicas) AS node_id
GROUP BY node_id
ORDER BY node_id;

七、故障恢复 #

7.1 节点故障 #

text
节点故障处理
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   故障检测:                                                 │
│   ├── 心跳超时                                             │
│   └── Gossip 信息更新                                      │
│                                                             │
│   恢复过程:                                                 │
│                                                             │
│   1. 检测到节点故障                                         │
│      │                                                      │
│      ▼                                                      │
│   2. 受影响的 Range 触发 Leader 选举                        │
│      │                                                      │
│      ▼                                                      │
│   3. 新 Leader 选出                                         │
│      │                                                      │
│      ▼                                                      │
│   4. 添加新副本到其他节点                                   │
│      │                                                      │
│      ▼                                                      │
│   5. 集群恢复正常                                           │
│                                                             │
│   示例: Node 1 故障                                         │
│                                                             │
│   故障前:                                                   │
│   Node 1 (Leader)  Node 2 (Follower)  Node 3 (Follower)    │
│                                                             │
│   故障后:                                                   │
│   Node 1 (Down)   Node 2 (Leader)    Node 3 (Follower)     │
│                                                             │
│   恢复后:                                                   │
│   Node 4 (Follower) Node 2 (Leader)  Node 3 (Follower)     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

7.2 数据恢复 #

sql
-- 查看集群健康状态
SELECT * FROM crdb_internal.kv_node_status;

-- 查看副本不足的 Range
SELECT 
    range_id,
    replicas,
    voting_replicas
FROM crdb_internal.ranges
WHERE array_length(replicas, 1) < 3;

-- 手动触发副本补充
-- CockroachDB 自动处理

八、总结 #

分布式层要点:

组件 功能
Range 数据分片
Raft 共识协议
Replica 副本管理
Gossip 节点通信

下一步,让我们学习事务层!

最后更新:2026-03-27