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

dqlite 分布式 SQLite 教程 / 第 1 章:dqlite 概述与适用场景

第 1 章:dqlite 概述与适用场景

本章介绍 dqlite 的核心理念、技术背景、适用场景,并与 rqlite 进行详细对比,帮助你判断 dqlite 是否适合你的项目。


1.1 什么是 dqlite?

dqlite(发音为 “dee-queue-lite”,即 distributed SQLite)是一个用 C 语言编写的开源库,它将 SQLite 扩展为一个分布式、容错的关系型数据库。

dqlite 的核心设计理念是:

设计原则说明
嵌入式优先作为 C 库链接到你的应用中,不依赖外部服务进程
零配置不需要独立的数据库服务器,不需要复杂配置
SQLite 兼容支持标准 SQL 和 SQLite 的大部分特性
高可用基于 Raft 共识协议实现多节点数据复制
轻量级最小化资源占用,适合边缘设备和容器
┌─────────────────────────────────────┐
│           Your Application          │
│  ┌───────────┐   ┌──────────────┐   │
│  │  App Logic │──▶│ libdqlite.so │   │
│  └───────────┘   │  ┌────────┐  │   │
│                  │  │SQLite  │  │   │
│                  │  │Engine  │  │   │
│                  │  ├────────┤  │   │
│                  │  │  Raft  │  │   │
│                  │  │Module  │  │   │
│                  │  └────────┘  │   │
│                  └──────────────┘   │
│                        │            │
│                  ┌─────┴─────┐      │
│                  │ Network   │      │
│                  │ Transport │      │
│                  └─────┬─────┘      │
└──────────────────────┬─┴────────────┘
                       │
            ┌──────────┼──────────┐
            ▼          ▼          ▼
        ┌──────┐  ┌──────┐  ┌──────┐
        │Node 2│  │Node 3│  │Node N│
        └──────┘  └──────┘  └──────┘

1.1.1 项目背景

dqlite 由 Canonical 工程师发起,最初是为了解决 LXD(Linux 容器管理器)的高可用需求。LXD 需要一个轻量的、可嵌入的分布式存储来保存集群状态,但不想引入 etcd 或 Consul 这类重量级组件。

“我们需要一个像 SQLite 一样简单,但又能跨多节点复制数据的数据库。” — Stéphane Graber,LXD 项目负责人

1.1.2 技术特点一览

特性描述
实现语言C(核心)+ Go 绑定
共识算法Raft(基于 C-raft 库)
存储引擎SQLite
通信协议自定义二进制协议(基于 MessagePack)
最大节点数无硬限制(推荐 3-7 个)
数据一致性强一致性(线性一致性读写)
支持平台Linux only(依赖 epoll
许可证LGPLv3

1.2 Raft 共识协议简介

dqlite 使用 Raft 共识协议来保证多节点间数据的一致性。理解 Raft 的基本概念对使用 dqlite 集群至关重要。

1.2.1 Raft 核心概念

Raft 是一种分布式共识算法,其设计目标是易于理解。它将共识问题分解为三个子问题:

子问题说明
Leader 选举(Leader Election)集群中选出一个 Leader 节点负责协调写入
日志复制(Log Replication)Leader 将写操作日志复制到所有 Follower
安全性(Safety)保证所有节点最终执行相同的日志序列
  ┌──────────┐     日志复制      ┌──────────┐
  │  Leader  │ ───────────────▶ │ Follower │
  │          │ ───────────────▶ │          │
  └────┬─────┘                  └──────────┘
       │
       │ 写请求                    ┌──────────┐
       │                          │ Follower │
       └─────────────────────── ▶ │          │
                                  └──────────┘

1.2.2 Raft 在 dqlite 中的工作方式

在 dqlite 集群中:

  1. 所有写操作 必须经过 Leader 节点
  2. Leader 将写操作以日志(Log Entry)形式广播给所有 Follower
  3. 多数节点(Quorum)确认收到日志后,该写操作被提交(Commit)
  4. 提交后的日志被应用到本地 SQLite 数据库
Client ──▶ Leader
              │
              ├──▶ Follower 1 (确认 ✓)
              ├──▶ Follower 2 (确认 ✓)
              │
          [多数确认]
              │
              ▼
         提交并应用

注意: 读操作默认也需要经过 Leader 以保证线性一致性。dqlite 支持通过配置允许 Follower 读取(可能返回稍旧的数据)。


1.3 dqlite 与 rqlite 详细对比

如果你同时在评估 dqlite 和 rqlite,以下对比表可以帮助你做出选择:

维度dqliterqlite
实现语言CGo
部署方式嵌入应用(库)独立服务进程
通信协议自定义二进制协议HTTP REST API
查询接口C API / Go 绑定HTTP 请求(curl 可调用)
开发复杂度较高(需管理生命周期)较低(HTTP 调用即可)
运行时开销低(进程内调用)中(HTTP + JSON 序列化)
写延迟~0.1ms~1-5ms
读延迟~0.01ms~0.5-2ms
客户端生态C / Go 语言绑定任意语言(HTTP)
运维复杂度中等
适用场景嵌入式、容器运行时、系统软件微服务、HTTP 后端、Web 应用
主要用户LXD、MicroK8s各类中小型项目
GitHub Stars~2.5k~13k
成熟度生产级(Canonical 维护)生产级(活跃社区)

1.3.1 架构差异

rqlite 架构(客户端-服务器):

┌──────────┐     HTTP       ┌────────────┐     ┌──────────┐
│  Client  │ ──────────────▶│  rqlite    │────▶│  SQLite  │
│ (curl等) │◀──────────────│  Server    │     └──────────┘
└──────────┘    JSON 响应    │  (Go进程)  │
                             │  + Raft    │
                             └─────┬──────┘
                                   │
                             ┌─────┴──────┐
                             │ Cluster    │
                             │ (Raft)     │
                             └────────────┘

dqlite 架构(嵌入式库):

┌────────────────────────────────┐
│  Your Application              │
│  ┌──────────────┐              │
│  │  App Logic   │              │
│  └──────┬───────┘              │
│         │ C API / Go 绑定      │
│  ┌──────▼───────┐              │
│  │  libdqlite   │              │
│  │  ┌────────┐  │              │
│  │  │SQLite  │  │              │
│  │  │+ Raft  │  │              │
│  │  └────────┘  │              │
│  └──────┬───────┘              │
└─────────┼──────────────────────┘
          │ 二进制协议
    ┌─────┼─────┐
    ▼     ▼     ▼
  Node2 Node3 NodeN

1.3.2 选择建议

场景推荐理由
已有 Go 微服务,需要分布式存储rqliteHTTP API 更易集成
C/C++ 系统软件,需要嵌入式数据库dqliteC 库直接嵌入
容器运行时 / Kubernetes 相关dqliteCanonical 生态支持好
快速原型开发rqlitecurl 即可操作
对延迟敏感的嵌入式场景dqlite进程内调用延迟极低
需要多语言客户端rqliteHTTP 协议语言无关
已在使用 LXD / MicroK8sdqlite一致的技术栈

1.4 dqlite 适用场景

1.4.1 适用场景

场景说明案例
容器/虚拟机管理器存储集群元数据和配置LXD
Kubernetes 数据存储替代 etcd 的轻量方案MicroK8s
边缘计算在资源受限设备上运行分布式数据库IoT 网关
嵌入式系统需要关系型数据库 + 高可用的嵌入式应用工业控制
配置管理小规模分布式配置存储微服务配置中心
本地优先应用离线可用、自动同步的桌面/移动应用协同编辑工具

1.4.2 不适用场景

场景说明替代方案
高吞吐写入SQLite 写入受限于单线程 WALPostgreSQL、TiKV
大规模数据集推荐数据量 < 10GBPostgreSQL、MySQL
复杂查询优化SQLite 查询优化器不如大型数据库PostgreSQL
跨平台需求仅支持 Linuxrqlite、CockroachDB
多数据中心不适合高延迟的跨地域复制CockroachDB、YugabyteDB
高并发读写共享缓存模式下并发有限PostgreSQL、MySQL

1.4.3 容量参考

指标推荐上限说明
节点数3-7Raft 多数派机制,奇数节点
数据库大小< 10GBSQLite WAL 模式性能限制
并发连接~100共享缓存模式限制
写 QPS~1000-5000取决于硬件和同步策略
读 QPS~10000-50000本地读取,可 Follower 分担

1.5 dqlite 生态系统

dqlite 不仅仅是一个库,它有一套完整的生态系统:

组件说明
libdqlite核心 C 库,实现 Raft 共识和 SQLite 集成
go-dqliteGo 语言绑定,LXD 和 MicroK8s 使用
C-raftC 语言实现的 Raft 协议库(内嵌在 dqlite 中)
dqlite-demo官方演示程序
canonical/dqliteGitHub 主仓库

1.5.1 版本历史里程碑

版本时间重要变更
v1.02019首个稳定版本,LXD 正式采用
v1.62021引入共享缓存模式
v1.92022改进快照机制
v1.122023性能优化,日志压缩改进
v1.152024TLS 支持增强
v1.162025成员变更协议改进

1.6 快速感受:30 秒体验 dqlite

在深入了解之前,先感受一下 dqlite 的使用方式:

使用 Go 绑定启动单节点

package main

import (
    "context"
    "database/sql"
    "fmt"
    "log"

    _ "github.com/canonical/go-dqlite/driver"
)

func main() {
    // 创建 dqlite 节点
    dir := "/tmp/dqlite-data"
    node, err := dqlite.New(1, "127.0.0.1:9001", dir, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer node.Close()

    // 打开数据库连接
    db, err := sql.Open("dqlite", "test.db")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    // 创建表
    _, err = db.Exec("CREATE TABLE IF NOT EXISTS demo (id INTEGER PRIMARY KEY, name TEXT)")
    if err != nil {
        log.Fatal(err)
    }

    // 插入数据
    _, err = db.Exec("INSERT INTO demo VALUES(1, 'hello dqlite')")
    if err != nil {
        log.Fatal(err)
    }

    // 查询
    var name string
    err = db.QueryRow("SELECT name FROM demo WHERE id = 1").Scan(&name)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Result:", name) // Output: Result: hello dqlite
}

使用 C API 启动单节点

#include <dqlite.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    dqlite_node *node;
    int rc;

    // 创建节点
    rc = dqlite_node_create(1, "/tmp/dqlite-data", "127.0.0.1:9001", &node);
    if (rc != 0) {
        fprintf(stderr, "Error: %s\n", dqlite_node_errmsg(node));
        return 1;
    }

    // 设置日志级别
    dqlite_node_set_bind_address(node, "127.0.0.1:9001");

    // 启动节点
    rc = dqlite_node_start(node);
    if (rc != 0) {
        fprintf(stderr, "Start error: %s\n", dqlite_node_errmsg(node));
        return 1;
    }

    printf("dqlite node running. Press Enter to stop.\n");
    getchar();

    // 停止并释放
    dqlite_node_stop(node);
    dqlite_node_destroy(node);
    return 0;
}

编译并运行:

gcc -o dqlite-demo dqlite-demo.c -ldqlite -lsqlite3 -lraft -lpthread
./dqlite-demo

1.7 核心术语表

在后续章节中会频繁出现以下术语:

术语英文说明
节点Node集群中的一个 dqlite 实例
LeaderLeaderRaft 集群中负责协调写入的节点
FollowerFollower跟随 Leader 复制日志的节点
候选人Candidate发起选举的节点(临时状态)
日志条目Log Entry一条写操作记录
提交Commit日志条目被多数节点确认后生效
快照Snapshot数据库在某一时刻的完整状态
任期TermLeader 的任期编号
心跳HeartbeatLeader 周期性发送的心跳信号
法定人数Quorum多数节点(N/2 + 1)
线性一致性Linearizability最强的一致性保证

本章小结

要点说明
dqlite 是什么C 语言实现的嵌入式分布式 SQLite
核心机制Raft 共识 + SQLite 存储
最大优势极低延迟、零外部依赖、可嵌入
最大限制仅支持 Linux、需要自行管理生命周期
与 rqlite 的区别嵌入式库 vs 独立服务、二进制协议 vs HTTP
适用场景嵌入式系统、容器管理、边缘计算

下一章

第 2 章:安装与编译 — 学习如何在 Linux 上编译和安装 dqlite,以及使用 Docker 快速上手。