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

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"
    }
]

安全原则: 最小权限原则。应用使用 rwro 账号,仅运维使用 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 部署前检查

  • 服务器配置满足最低要求
  • 磁盘为 SSD
  • 网络延迟 < 5ms(节点间)
  • 防火墙已配置(4001、4002 端口)
  • TLS 证书已生成
  • auth.json 已创建
  • systemd 服务文件已配置
  • 备份脚本已部署
  • 监控已接入

14.8.2 日常运维检查

  • 每日检查节点状态
  • 每日检查备份执行情况
  • 每周检查磁盘使用率
  • 每月执行恢复演练
  • 每季度检查证书有效期
  • 每季度检查安全配置

14.8.3 版本升级检查

  • 阅读 Release Notes
  • 在测试环境验证
  • 备份当前数据
  • 滚动升级(先 Follower 后 Leader)
  • 升级后验证集群状态
  • 监控升级后 24 小时

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 章:故障排查