强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

rqlite 完全指南 / 第 3 章:架构深度解析

第 3 章:架构深度解析

深入了解 rqlite 的内部架构,包括 Raft 共识层、SQLite 存储引擎和 HTTP API 层的设计细节。


3.1 整体架构

rqlite 的架构可以分为三层:

┌─────────────────────────────────────────────────────────┐
│                    客户端层                               │
│        (curl / rqlite CLI / SDK / 浏览器)                 │
└──────────────────────┬──────────────────────────────────┘
                       │ HTTP/JSON
┌──────────────────────▼──────────────────────────────────┐
│                   HTTP API 层                            │
│  ┌───────────┐  ┌───────────┐  ┌──────────┐  ┌───────┐ │
│  │  /status  │  │  /nodes   │  │  /db/*   │  │ /join │ │
│  └───────────┘  └───────────┘  └──────────┘  └───────┘ │
└──────────────────────┬──────────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────────┐
│                  rqlite 核心层                            │
│  ┌─────────────────────────────────────────────┐        │
│  │            查询/执行路由                      │        │
│  │  - 查询路由: Follower/Leader 读分流           │        │
│  │  - 执行路由: 写请求强制到 Leader              │        │
│  └─────────────────┬───────────────────────────┘        │
│                    │                                     │
│  ┌─────────────────▼───────────────────────────┐        │
│  │              Raft 共识层                     │        │
│  │  - Leader 选举                               │        │
│  │  - 日志复制                                   │        │
│  │  - 成员变更                                   │        │
│  │  - 快照 (Snapshot)                           │        │
│  └─────────────────┬───────────────────────────┘        │
│                    │                                     │
│  ┌─────────────────▼───────────────────────────┐        │
│  │             SQLite 存储引擎                   │        │
│  │  - WAL 模式 (Write-Ahead Logging)            │        │
│  │  - in-memory 或 on-disk                      │        │
│  │  - go-sqlite3 (CGO)                          │        │
│  └─────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────┘

3.2 Raft 共识层详解

3.2.1 Leader 选举机制

rqlite 使用 hashicorp/raft 库实现 Raft 协议。Leader 选举是集群正常工作的基础。

选举流程:

时间线 ──────────────────────────────────────────►

Node1 (Leader)  │███│███│███│███│ 崩溃!     │         │███│███│
Node2 (Follower)│   │   │   │   │ 超时!→候选 │ 选为Leader│███│███│
Node3 (Follower)│   │   │   │   │         │ 投票给Node2│   │███│
                  心跳正常          选举超时    新 Leader
配置项默认值说明
HeartbeatTimeout1s心跳超时时间
ElectionTimeout1s选举超时时间
LeaderLeaseTimeout500msLeader 租约超时
SnapshotInterval120s快照触发间隔
SnapshotThreshold8192触发快照的日志条目数

3.2.2 日志复制

当 Leader 收到写请求时,流程如下:

客户端                    Leader                    Follower 1              Follower 2
  │                        │                          │                       │
  │──── 写请求 ────────────►│                          │                       │
  │                        │                          │                       │
  │                        │── AppendEntries ─────────►│                       │
  │                        │── AppendEntries ──────────────────────────────────►│
  │                        │                          │                       │
  │                        │◄── 确认 ──────────────────│                       │
  │                        │◄── 确认 ─────────────────────────────────────────│
  │                        │                          │                       │
  │                        │ (多数确认,提交日志)       │                       │
  │                        │                          │                       │
  │◄── 返回结果 ───────────│                          │                       │
  │                        │── AppendEntries (commit)──►│                       │
  │                        │── AppendEntries (commit)──────────────────────────►│

3.2.3 快照(Snapshot)

随着日志增长,rqlite 会定期创建快照以压缩日志:

快照机制说明
触发条件日志条目数超过 SnapshotThreshold 或超过 SnapshotInterval
快照内容当前 SQLite 数据库文件的完整副本
增量传输新节点加入时,通过快照快速同步状态
自动清理旧的快照和日志在新快照创建后自动清理

查看当前快照状态:

curl -s 'localhost:4001/status?pretty' | python3 -c "
import json, sys
data = json.load(sys.stdin)
store = data.get('store', {})
print(f'Raft State: {store.get(\"raft_state\")}')
print(f'Last Log Index: {store.get(\"last_log_index\")}')
print(f'Last Snapshot Index: {store.get(\"last_snapshot_index\")}')
"

3.3 SQLite 存储引擎

3.3.1 存储模式

rqlite 支持两种 SQLite 存储模式:

模式说明适用场景
in-memory(默认)SQLite 数据库完全在内存中数据量小、追求性能
on-diskSQLite 数据库写入磁盘数据量大、需要持久化
# 使用 on-disk 模式启动
rqlited -on-disk /var/lib/rqlite/data

# 使用 in-memory 模式启动(默认)
rqlited /var/lib/rqlite/data

重要: 即使使用 in-memory 模式,数据也是持久化的——Raft 日志和快照会写入磁盘,启动时会从快照恢复。

3.3.2 WAL 模式

rqlite 默认启用 SQLite 的 WAL(Write-Ahead Logging)模式。WAL 模式有以下优势:

特性WAL 模式默认日志模式
并发读写✅ 读写不阻塞❌ 读阻塞写
写入性能更好一般
崩溃恢复更快一般
文件数量3 个(db, wal, shm)2 个(db, journal)

3.3.3 SQLite 版本和特性

rqlite 通过 CGO 绑定 SQLite,查看当前版本:

curl -s -G 'localhost:4001/db/query' \
    --data-urlencode 'q=SELECT sqlite_version()' | python3 -m json.tool
{
    "results": [{
        "columns": ["sqlite_version()"],
        "types": ["text"],
        "values": [["3.45.0"]]
    }]
}

支持的 SQLite 高级特性:

特性支持情况
FTS5 全文搜索
JSON 函数
窗口函数
递归 CTE
生成列
ATTACH DATABASE❌ 不支持

3.4 HTTP API 层

3.4.1 API 端点总览

端点方法说明
/statusGET查看节点状态
/nodesGET查看集群节点列表
/db/queryGET/POST执行查询(SELECT)
/db/executePOST执行写入(INSERT/UPDATE/DELETE)
/db/requestPOST混合请求(查询+执行)
/db/backupGET备份数据库
/db/loadPOST加载数据(恢复)
/joinPOST加入集群
/removePOST移除节点
/status/readyGET就绪检查
/status/leaderGETLeader 检查

3.4.2 请求和响应格式

所有数据库操作使用 JSON 格式:

查询请求(Query):

curl -G 'localhost:4001/db/query' \
    -H 'Content-Type: application/json' \
    --data-urlencode 'q=SELECT * FROM users WHERE id > 10' \
    --data-urlencode 'level=strong' \
    --data-urlencode 'pretty'

执行请求(Execute):

curl -XPOST 'localhost:4001/db/execute' \
    -H 'Content-Type: application/json' \
    -d '[
        ["INSERT INTO users (name, email) VALUES (?, ?)", "张三", "zhangsan@example.com"],
        ["INSERT INTO users (name, email) VALUES (?, ?)", "李四", "lisi@example.com"]
    ]'

响应格式:

{
    "results": [
        {
            "last_insert_id": 1,
            "rows_affected": 1,
            "time": 0.000234
        },
        {
            "last_insert_id": 2,
            "rows_affected": 1,
            "time": 0.000156
        }
    ],
    "time": 0.000500
}

3.4.3 读写分离

rqlite 的 HTTP API 层智能地将读写请求路由到不同节点:

                    ┌──────────────┐
                    │  HTTP API    │
                    └──────┬───────┘
                           │
                    ┌──────▼───────┐
                    │   请求分类    │
                    └──────┬───────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
        ┌─────▼─────┐ ┌───▼───┐ ┌─────▼─────┐
        │  Query    │ │Execute│ │  Request   │
        │  (读)     │ │ (写)   │ │  (混合)    │
        └─────┬─────┘ └───┬───┘ └─────┬─────┘
              │            │            │
    ┌─────────┼──┐         │     ┌──────┼──────┐
    │ level?   │  │         │     │ 逐条分类    │
    ├──────────┤  │         │     └──────┬──────┘
    │ strong   │  │         │            │
    │ → Leader │  │    ┌────▼────┐  ┌────▼────┐
    │ weak     │  │    │ Leader  │  │ Leader  │
    │ → Leader │  │    └─────────┘  └─────────┘
    │ none     │  │
    │ → 任意   │  │
    └──────────┘  │

3.5 数据流完整示例

下面展示一个写操作从客户端到磁盘的完整数据流:

# 1. 客户端发起写请求
curl -XPOST 'localhost:4001/db/execute' \
    -H 'Content-Type: application/json' \
    -d '[["INSERT INTO orders (product, quantity) VALUES (?, ?)", "笔记本", 5]]'
请求流转过程:
1. HTTP API 层接收请求
2. 请求被分类为 Execute(写操作)
3. 路由到 Leader 节点(如果不是 Leader,返回重定向)
4. 将 SQL 转为 Raft 日志条目
5. Raft 复制日志到 Follower
6. 多数节点确认后,提交日志
7. 应用到 SQLite 存储引擎
8. 返回操作结果给客户端

3.6 内存与磁盘使用

3.6.1 文件结构

数据目录下的文件结构:

/var/lib/rqlite/data/
├── db.sqlite           # SQLite 数据库文件
├── db.sqlite-wal       # WAL 文件(Write-Ahead Log)
├── db.sqlite-shm       # 共享内存文件
├── raft/               # Raft 日志目录
│   ├── logs.db         # Raft 日志数据库
│   ├── stable.db       # Raft 稳定存储
│   └── snapshots/      # 快照目录
│       └── 1-5-1234567890/
│           └── db.sqlite  # 快照中的数据库文件
└── raft-peers.json     # 节点配置

3.6.2 内存消耗估算

数据量in-memory 模式on-disk 模式
100 MB~300-500 MB~100-150 MB
1 GB~2-3 GB~200-400 MB
10 GB不推荐~500 MB - 1 GB

建议: 数据量超过 1 GB 时使用 -on-disk 模式。


3.7 本章小结

要点内容
三层架构HTTP API → Raft 共识 → SQLite 存储
Raft 实现基于 hashicorp/raft,支持 Leader 选举和日志复制
快照机制定期压缩日志,支持增量传输
存储模式in-memory(默认)和 on-disk
API 设计RESTful 风格,JSON 格式,支持读写分离
文件结构SQLite 文件 + Raft 日志 + 快照目录

上一章:第 2 章:安装与集群搭建 下一章:第 4 章:基础操作