rqlite 完全指南 / 第 14 章:最佳实践
第 14 章:最佳实践
何时选择 rqlite、生产环境规范、架构建议和实际经验总结。
14.1 何时选择 rqlite
14.1.1 决策矩阵
你需要分布式数据库吗?
│
├── 否 → 使用 SQLite
│
├── 是 → 你需要完整的 SQL 支持吗?
│ │
│ ├── 否 → 考虑 etcd / Consul / Redis
│ │
│ └── 是 → 数据规模多大?
│ │
│ ├── < 10GB → 考虑 rqlite ✅
│ │
│ ├── 10GB - 1TB → 考虑 PostgreSQL / MySQL
│ │
│ └── > 1TB → 考虑 TiDB / CockroachDB
│
└── 边缘场景 → IoT/嵌入式/资源受限?
│
├── 是 → rqlite 是最佳选择 ✅
│
└── 否 → 评估团队经验和运维能力
14.1.2 推荐使用 rqlite 的场景
| 场景 | 数据量 | 读写比 | 节点数 | 推荐度 |
|---|
| IoT 数据存储 | < 1GB | 8:2 | 3 | ⭐⭐⭐⭐⭐ |
| 配置管理 | < 100MB | 9:1 | 3 | ⭐⭐⭐⭐⭐ |
| 小型 SaaS 后端 | < 5GB | 7:3 | 3-5 | ⭐⭐⭐⭐ |
| CI/CD 状态存储 | < 1GB | 6:4 | 3 | ⭐⭐⭐⭐ |
| 开发/测试环境 | 任意 | 任意 | 1-3 | ⭐⭐⭐⭐⭐ |
| 微服务元数据 | < 100MB | 8:2 | 3 | ⭐⭐⭐⭐ |
| 边缘计算 | < 1GB | 7:3 | 3 | ⭐⭐⭐⭐⭐ |
14.1.3 不推荐使用 rqlite 的场景
| 场景 | 不推荐原因 | 替代方案 |
|---|
| TB 级数据存储 | SQLite 单文件限制 | PostgreSQL、TiDB |
| 万级 TPS 写入 | Raft 复制瓶颈 | Redis Cluster、TiKV |
| 复杂 OLAP 查询 | 不支持分布式查询 | ClickHouse、DuckDB |
| 多数据中心部署 | Raft 延迟敏感 | CockroachDB |
| 需要存储过程 | SQLite 不支持 | PostgreSQL、MySQL |
| 超低延迟读取(< 0.1ms) | HTTP API 开销 | 内嵌 SQLite + 同步复制 |
14.2 生产环境规范
14.2.1 部署规范
| 规范 | 要求 | 说明 |
|---|
| 节点数 | 3 或 5 | 必须为奇数 |
| 服务器 | 最少 2 核 4GB | 根据数据量调整 |
| 磁盘 | SSD,≥ 50GB | Raft 日志和 SQLite 文件 |
| 网络 | 同机房,延迟 < 5ms | Raft 对延迟敏感 |
| 操作系统 | Linux(推荐 Ubuntu 22.04+) | — |
14.2.2 启动参数规范
# 生产环境推荐启动参数
rqlited \
-node-id=<唯一节点ID> \
-http-addr=0.0.0.0:4001 \
-raft-addr=0.0.0.0:4002 \
-http-cert=/etc/rqlite/certs/server.crt \
-http-key=/etc/rqlite/certs/server.key \
-http-ca-cert=/etc/rqlite/certs/ca.crt \
-node-cert=/etc/rqlite/certs/server.crt \
-node-key=/etc/rqlite/certs/server.key \
-node-ca-cert=/etc/rqlite/certs/ca.crt \
-auth=/etc/rqlite/auth.json \
-disco-mode=off \
-fk \
/var/lib/rqlite/data
14.2.3 认证配置规范
// /etc/rqlite/auth.json
[
{
"username": "admin",
"password": "使用强密码(至少 16 字符,含大小写+数字+特殊字符)",
"perm": "all"
},
{
"username": "app_write",
"password": "应用写入专用密码",
"perm": "rw"
},
{
"username": "app_read",
"password": "应用只读密码",
"perm": "ro"
},
{
"username": "monitor",
"password": "监控专用密码",
"perm": "ro"
}
]
安全原则: 最小权限原则。应用使用 rw 或 ro 账号,仅运维使用 all 账号。
14.2.4 systemd 服务规范
# /etc/systemd/system/rqlited.service
[Unit]
Description=rqlite distributed SQLite
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=rqlite
Group=rqlite
ExecStart=/opt/rqlite/start.sh
Restart=always
RestartSec=5
LimitNOFILE=65536
# 安全加固
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/rqlite /var/log/rqlite
# 资源限制
MemoryMax=2G
CPUQuota=200%
[Install]
WantedBy=multi-user.target
14.3 数据库设计规范
14.3.1 表设计规范
-- ✅ 推荐:使用明确的主键和类型
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
status TEXT CHECK(status IN ('active', 'inactive', 'banned')) DEFAULT 'active',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ✅ 推荐:外键约束
CREATE TABLE orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
total REAL NOT NULL CHECK(total >= 0),
status TEXT CHECK(status IN ('pending', 'paid', 'shipped', 'completed')) DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- ✅ 推荐:为高频查询字段创建索引
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
CREATE INDEX idx_orders_created ON orders(created_at DESC);
CREATE INDEX idx_users_status ON users(status);
14.3.2 索引规范
| 规则 | 说明 | 示例 |
|---|
| 为 WHERE 条件建索引 | 高频查询字段必须有索引 | CREATE INDEX idx ON t(col) |
| 复合索引顺序 | 选择性高的列在前 | CREATE INDEX idx ON t(status, user_id) |
| 避免过多索引 | 每个索引增加写入开销 | 只创建必要的索引 |
| 覆盖索引 | 包含查询所需的所有列 | CREATE INDEX idx ON t(a, b, c) |
| 定期 REINDEX | 碎片整理 | REINDEX idx_name |
14.3.3 查询规范
-- ✅ 使用参数绑定
-- ❌ 字符串拼接(SQL 注入风险)
-- ✅ 仅选择需要的列
SELECT id, username, email FROM users WHERE id = ?;
-- ✅ 使用 LIMIT 限制结果集
SELECT * FROM orders WHERE status = 'pending' ORDER BY created_at DESC LIMIT 50;
-- ✅ 使用 EXPLAIN QUERY PLAN 分析查询
EXPLAIN QUERY PLAN SELECT * FROM orders WHERE user_id = 1 AND status = 'paid';
14.4 写入规范
14.4.1 批量写入
# ✅ 推荐:批量写入(50-100 条/批)
def batch_insert(records: list[dict], batch_size: int = 100):
"""分批插入数据"""
for i in range(0, len(records), batch_size):
batch = records[i:i + batch_size]
statements = [
["INSERT INTO logs (level, message, ts) VALUES (?, ?, ?)",
r["level"], r["message"], r["ts"]]
for r in batch
]
client.execute(statements)
14.4.2 读写分离
# ✅ 推荐:读写分离
def get_user(user_id: int) -> dict:
"""查询用户 — 弱一致性"""
result = client.query(
"SELECT * FROM users WHERE id = ?",
params=[user_id],
level="weak" # 一般查询用 weak
)
return result
def create_order(order: dict) -> int:
"""创建订单 — 写入后读取用 strong"""
client.execute(
"INSERT INTO orders (user_id, product, total) VALUES (?, ?, ?)",
params=[order["user_id"], order["product"], order["total"]]
)
# 写后读取用 strong 一致性
result = client.query(
"SELECT * FROM orders WHERE user_id = ? ORDER BY id DESC LIMIT 1",
params=[order["user_id"]],
level="strong"
)
return result["results"][0]["values"][0][0]
14.4.3 一致性级别选择指南
| 业务场景 | 推荐级别 | 理由 |
|---|
| 创建后立即查询 | strong | 保证读到刚写入的数据 |
| 列表查询 | weak | 可接受短暂延迟 |
| 统计报表 | none | 不需要实时准确 |
| 搜索建议 | none | 可接受缓存数据 |
| 下单操作 | strong | 关键业务,必须一致 |
| 日志写入 | 任意 | 日志可容忍少量丢失 |
14.5 备份与恢复规范
14.5.1 备份策略
| 环境 | 频率 | 格式 | 保留天数 | 存储位置 |
|---|
| 开发 | 每天 | SQL dump | 7 | 本地磁盘 |
| 测试 | 每天 | SQL dump | 14 | 本地磁盘 |
| 生产 | 每 6 小时 | 二进制 + SQL dump | 30 | S3 + 本地 |
| 金融 | 每小时 | 二进制 + SQL dump | 90 | 多区域 S3 |
14.5.2 恢复演练
# 每月至少执行一次恢复演练
#!/bin/bash
# restore-drill.sh
BACKUP_FILE=$(ls -t /var/backup/rqlite/rqlite_*.sql.gz | head -1)
DRILL_DIR="/tmp/drill-$(date +%Y%m%d)"
mkdir -p "$DRILL_DIR/node1"
# 启动临时节点
rqlited -node-id=drill -disco-mode=off "$DRILL_DIR/node1" &
sleep 3
# 恢复数据
gunzip -c "$BACKUP_FILE" | curl -s -XPOST 'localhost:4001/db/load' \
-H 'Content-Type: text/plain' --data-binary @-
# 验证数据
tables=$(curl -s -G 'localhost:4001/db/query' \
--data-urlencode 'q=SELECT COUNT(*) FROM sqlite_master WHERE type="table"' \
| python3 -c "import json,sys; print(json.load(sys.stdin)['results'][0]['values'][0][0])")
echo "恢复表数: $tables"
# 清理
kill %1
rm -rf "$DRILL_DIR"
14.6 监控规范
14.6.1 必须监控的指标
| 指标 | 告警阈值 | 说明 |
|---|
| 节点在线状态 | 连续 30s 离线 | P0 告警 |
| Leader 存在 | 无 Leader 超过 30s | P0 告警 |
| 复制延迟 | > 1000 条日志 | P2 告警 |
| 磁盘使用率 | > 85% | P2 告警 |
| 数据库大小 | 增长率异常 | P2 告警 |
| HTTP 响应时间 | > 5s | P2 告警 |
| 错误率 | > 1% | P1 告警 |
14.6.2 健康检查脚本
#!/bin/bash
# health-check.sh — 生产环境健康检查
NODES=("node1:4001" "node2:4001" "node3:4001")
ERRORS=0
for node in "${NODES[@]}"; do
host="${node%%:*}"
port="${node##*:}"
# 就绪检查
code=$(curl -s -o /dev/null -w "%{http_code}" \
"http://$node/status/ready" --connect-timeout 5)
if [ "$code" != "200" ]; then
echo "CRITICAL: $node not ready (HTTP $code)"
((ERRORS++))
fi
done
if [ $ERRORS -gt 0 ]; then
echo "CRITICAL: $ERRORS nodes unhealthy"
exit 2
fi
echo "OK: All ${#NODES[@]} nodes healthy"
exit 0
14.7 容量规划
14.7.1 资源估算公式
内存需求 ≈ 数据大小 × 2(in-memory 模式)
≈ 数据大小 × 0.5 + 256MB(on-disk 模式)
磁盘需求 ≈ 数据大小 × 3(SQLite + Raft 日志 + 快照)
CPU 需求 ≈ 2 核起步,4 核推荐(取决于并发量)
14.7.2 容量规划表
| 数据量 | 内存(in-memory) | 内存(on-disk) | 磁盘 | CPU |
|---|
| 100 MB | 512 MB | 256 MB | 500 MB | 2 核 |
| 500 MB | 2 GB | 512 MB | 2 GB | 2 核 |
| 1 GB | 4 GB | 1 GB | 4 GB | 4 核 |
| 5 GB | 不推荐 | 3 GB | 20 GB | 4 核 |
| 10 GB | 不推荐 | 5 GB | 40 GB | 8 核 |
建议: 数据量超过 1GB 时使用 -on-disk 模式。
14.8 运维 Checklist
14.8.1 部署前检查
14.8.2 日常运维检查
14.8.3 版本升级检查
14.9 架构建议
14.9.1 单集群 vs 多集群
单集群架构(推荐):
┌───────────────────────────────┐
│ rqlite 集群 (3节点) │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Node1│ │Node2│ │Node3│ │
│ └─────┘ └─────┘ └─────┘ │
└───────────────────────────────┘
适用:数据量 < 5GB,单机房
多集群架构:
┌─────────────────┐ ┌─────────────────┐
│ 集群 A (北京) │ │ 集群 B (上海) │
│ 3 节点 │ │ 3 节点 │
└────────┬────────┘ └────────┬────────┘
│ │
└────────┬───────────┘
应用层同步(非 Raft)
适用:跨地域部署,数据本地化
14.9.2 与其他存储组合
推荐架构:rqlite + Redis + 对象存储
┌──────────────────────────────────────────┐
│ 应用层 │
├──────────┬──────────────┬────────────────┤
│ │ │ │
│ ┌──────▼──────┐ ┌────▼─────┐ ┌───────▼───────┐
│ │ rqlite │ │ Redis │ │ 对象存储 (S3) │
│ │ 核心业务数据 │ │ 热数据缓存│ │ 文件/图片 │
│ │ 结构化数据 │ │ Session │ │ 大文件 │
│ └─────────────┘ └──────────┘ └───────────────┘
│ │
│ rqlite: 配置、订单、用户等结构化数据 │
│ Redis: 缓存热点查询、Session、排行榜 │
│ S3: 图片、文件、备份 │
└──────────────────────────────────────────┘
14.10 本指南总结
| 章节 | 核心要点 |
|---|
| 第 1 章 | rqlite = SQLite + Raft,适合小到中规模 |
| 第 2 章 | 推荐 3 节点,使用 -join 参数搭建集群 |
| 第 3 章 | 三层架构:HTTP API → Raft → SQLite |
| 第 4 章 | 使用参数绑定,批量操作利用事务 |
| 第 5 章 | 一致性级别 none/weak/strong 灵活选择 |
| 第 6 章 | Raft 自动选举,支持动态增删节点 |
| 第 7 章 | 定期备份,保留 SQL dump + 二进制格式 |
| 第 8 章 | 生产必须启用 TLS + 认证 + 防火墙 |
| 第 9 章 | 批量写入是最重要的性能优化手段 |
| 第 10 章 | 任何能发 HTTP 请求的语言都能作为客户端 |
| 第 11 章 | K8s 使用 StatefulSet + Headless Service |
| 第 12 章 | Prometheus + Grafana 全面监控 |
| 第 13 章 | 节点状态 → 集群状态 → 错误信息 → 日志 |
| 第 14 章 | 适合场景明确,生产规范严格 |
扩展资源
上一章:第 13 章:故障排查