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

LevelDB 完全指南 / 第 2 章 · 编译安装与语言绑定

第 2 章 · 编译安装与语言绑定

2.1 环境准备

在编译 LevelDB 之前,需要安装以下依赖:

Ubuntu / Debian

sudo apt-get update
sudo apt-get install -y \
    build-essential \
    cmake \
    git \
    libgflags-dev \
    libsnappy-dev \
    zlib1g-dev \
    libbz2-dev \
    liblz4-dev \
    libzstd-dev

CentOS / RHEL

sudo yum groupinstall -y "Development Tools"
sudo yum install -y cmake3 git gflags-devel snappy-devel \
    zlib-devel bzip2-devel lz4-devel libzstd-devel

macOS

brew install cmake gflags snappy lz4 zstd

依赖说明

依赖用途必需?
CMake构建系统✅ 是
gflags命令行参数解析(db_bench)可选
Snappy默认压缩算法推荐
zlib替代压缩算法可选
bzip2替代压缩算法可选
lz4替代压缩算法可选
zstd替代压缩算法可选

2.2 源码编译安装

获取源码

git clone --depth 1 --branch 1.23 \
    https://github.com/google/leveldb.git
cd leveldb
git submodule update --init --recursive

💡 提示:使用 --depth 1 只克隆最新提交,加快下载速度。

编译

mkdir -p build && cd build

# Release 模式(推荐生产使用)
cmake -DCMAKE_BUILD_TYPE=Release \
      -DLEVELDB_BUILD_BENCHMARKS=ON \
      -DLEVELDB_BUILD_TESTS=ON \
      ..

# 并行编译(使用所有 CPU 核心)
cmake --build . -j$(nproc)

CMake 常用选项

选项默认值说明
CMAKE_BUILD_TYPEDebugRelease / Debug / RelWithDebInfo
CMAKE_INSTALL_PREFIX/usr/local安装路径
LEVELDB_BUILD_BENCHMARKSON是否编译 db_bench
LEVELDB_BUILD_TESTSON是否编译测试
HAVE_SNAPPY自动检测启用 Snappy 压缩
HAVE_ZLIB自动检测启用 zlib 压缩
HAVE_BZIP2自动检测启用 bzip2 压缩
HAVE_LZ4自动检测启用 lz4 压缩
HAVE_ZSTD自动检测启用 zstd 压缩

运行测试

# 运行所有测试
ctest --output-on-failure

# 运行特定测试
./leveldb_tests --gtest_filter="DBTest.PutGet"

安装

sudo cmake --install .

安装后文件位置:

/usr/local/
├── include/
│   └── leveldb/
│       ├── db.h              # 核心 API
│       ├── options.h         # 配置选项
│       ├── write_batch.h     # 批量写入
│       ├── comparator.h      # 自定义比较器
│       ├── filter_policy.h   # Bloom Filter
│       ├── cache.h           # 缓存接口
│       ├── snapshot.h        # 快照
│       ├── iterator.h        # 迭代器
│       ├── status.h          # 状态码
│       └── ...
├── lib/
│   ├── libleveldb.a          # 静态库
│   └── libleveldb.so         # 动态库
└── bin/
    └── db_bench              # 性能测试工具

验证安装

# 检查头文件
ls /usr/local/include/leveldb/db.h

# 检查库文件
ls /usr/local/lib/libleveldb.*

# 检查 db_bench
which db_bench

2.3 第一个 LevelDB 程序(C++)

hello_leveldb.cpp

#include <cassert>
#include <iostream>
#include <string>

#include "leveldb/db.h"

int main() {
    leveldb::DB* db;
    leveldb::Options options;
    options.create_if_missing = true;  // 数据库不存在时自动创建

    // 打开数据库
    leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
    if (!status.ok()) {
        std::cerr << "打开数据库失败: " << status.ToString() << std::endl;
        return 1;
    }

    // 写入数据
    leveldb::WriteOptions write_opts;
    status = db->Put(write_opts, "name", "LevelDB");
    assert(status.ok());

    status = db->Put(write_opts, "version", "1.23");
    assert(status.ok());

    // 读取数据
    leveldb::ReadOptions read_opts;
    std::string value;
    status = db->Get(read_opts, "name", &value);
    assert(status.ok());
    std::cout << "name = " << value << std::endl;

    // 删除数据
    status = db->Delete(write_opts, "version");
    assert(status.ok());

    // 遍历所有键值对
    leveldb::Iterator* it = db->NewIterator(read_opts);
    for (it->SeekToFirst(); it->Valid(); it->Next()) {
        std::cout << it->key().ToString() << " -> "
                  << it->value().ToString() << std::endl;
    }
    assert(it->status().ok());
    delete it;

    delete db;  // 关闭数据库
    return 0;
}

编译运行

# 编译
g++ -std=c++17 -O2 -o hello_leveldb hello_leveldb.cpp \
    -lleveldb -lpthread -lsnappy

# 运行
./hello_leveldb

# 输出:
# name = LevelDB
# name -> LevelDB

CMakeLists.txt 方式

cmake_minimum_required(VERSION 3.10)
project(hello_leveldb)

set(CMAKE_CXX_STANDARD 17)

find_package(leveldb REQUIRED)

add_executable(hello_leveldb hello_leveldb.cpp)
target_link_libraries(hello_leveldb leveldb::leveldb)

2.4 Docker 部署

Dockerfile

FROM ubuntu:22.04 AS builder

RUN apt-get update && apt-get install -y \
    build-essential cmake git \
    libgflags-dev libsnappy-dev zlib1g-dev \
    libbz2-dev liblz4-dev libzstd-dev \
    && rm -rf /var/lib/apt/lists/*

# 克隆并编译 LevelDB
RUN git clone --depth 1 --branch 1.23 \
    https://github.com/google/leveldb.git /opt/leveldb

WORKDIR /opt/leveldb
RUN mkdir build && cd build && \
    cmake -DCMAKE_BUILD_TYPE=Release .. && \
    cmake --build . -j$(nproc)

# 运行阶段 - 最小镜像
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y \
    libsnappy1v5 libgflags2.2 \
    && rm -rf /var/lib/apt/lists/*

COPY --from=builder /opt/leveldb/build/libleveldb.so* /usr/local/lib/
COPY --from=builder /opt/leveldb/include/leveldb/ /usr/local/include/leveldb/

RUN ldconfig

VOLUME ["/data"]
EXPOSE 8080

CMD ["echo", "LevelDB library installed. Link it in your application."]

构建与运行

# 构建镜像
docker build -t leveldb:1.23 .

# 运行容器
docker run -v /host/data:/data leveldb:1.23

⚠️ 注意:LevelDB 是嵌入式库,不是独立服务。Docker 中通常需要配合自己的应用服务器一起使用。详见 第 13 章 · Docker 部署


2.5 Go 语言绑定(goleveldb)

安装

go get github.com/syndtr/goleveldb/leveldb

完整示例

package main

import (
    "fmt"
    "log"

    "github.com/syndtr/goleveldb/leveldb"
    "github.com/syndtr/goleveldb/leveldb/opt"
    "github.com/syndtr/goleveldb/leveldb/util"
)

func main() {
    // 打开数据库
    db, err := leveldb.OpenFile("/tmp/goleveldb", nil)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    // ========== 基本操作 ==========

    // Put - 写入
    err = db.Put([]byte("user:1001:name"), []byte("张三"), nil)
    if err != nil {
        log.Fatal(err)
    }
    db.Put([]byte("user:1001:email"), []byte("[email protected]"), nil)
    db.Put([]byte("user:1002:name"), []byte("李四"), nil)
    db.Put([]byte("user:1002:email"), []byte("[email protected]"), nil)

    // Get - 读取
    data, err := db.Get([]byte("user:1001:name"), nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("user:1001:name = %s\n", data)

    // Delete - 删除
    err = db.Delete([]byte("user:1002:email"), nil)
    if err != nil {
        log.Fatal(err)
    }

    // ========== 批量写入 ==========

    batch := new(leveldb.Batch)
    batch.Put([]byte("user:1003:name"), []byte("王五"))
    batch.Put([]byte("user:1003:email"), []byte("[email protected]"))
    batch.Delete([]byte("user:1002:name"))
    err = db.Write(batch, nil)
    if err != nil {
        log.Fatal(err)
    }

    // ========== 迭代器 ==========

    // 前缀扫描:查询所有 user:1001 的字段
    fmt.Println("\n--- user:1001 的所有字段 ---")
    iter := db.NewIterator(util.BytesPrefix([]byte("user:1001:")), nil)
    for iter.Next() {
        key := string(iter.Key())
        value := string(iter.Value())
        fmt.Printf("  %s = %s\n", key, value)
    }
    iter.Release()

    // 范围扫描
    fmt.Println("\n--- 所有 user ---")
    iter = db.NewIterator(nil, nil)
    for iter.Next() {
        fmt.Printf("  %s = %s\n", iter.Key(), iter.Value())
    }
    iter.Release()

    if err := iter.Error(); err != nil {
        log.Fatal(err)
    }

    // ========== Snapshot(快照)==========

    snap, err := db.GetSnapshot()
    if err != nil {
        log.Fatal(err)
    }
    defer snap.Release()

    // 在快照上读取(不受后续写入影响)
    snapData, _ := snap.Get([]byte("user:1001:name"), nil)
    fmt.Printf("\n快照读取: user:1001:name = %s\n", snapData)
}

Go 高级配置

opts := &opt.Options{
    // 块缓存大小(默认 8MB)
    BlockCacheCapacity: 64 * opt.MiB,

    // 块大小(默认 4KB)
    BlockSize: 4 * opt.KiB,

    // 写缓冲区大小(默认 4MB)
    WriteBuffer: 8 * opt.MiB,

    // 最大打开文件数
    OpenFilesCacheCapacity: 500,

    // Bloom Filter 位数(每个 key 10 bits)
    Filter: filter.NewBloomFilter(10),

    // 压缩类型
    Compression: opt.SnappyCompression,

    // Level 0 文件数触发 Compaction
    CompactionL0Trigger: 4,

    // Level 0 慢写触发阈值
    WriteL0SlowdownTrigger: 8,
    WriteL0PauseTrigger: 12,
}

db, err := leveldb.OpenFile("/tmp/goleveldb-advanced", opts)

2.6 Python 绑定(Plyvel)

安装

pip install plyvel

完整示例

import plyvel
import json

# 打开数据库
db = plyvel.DB('/tmp/pyldb', create_if_missing=True)

# ========== 基本操作 ==========

# 写入(注意:key 和 value 必须是 bytes)
db.put(b'user:1001:name', '张三'.encode('utf-8'))
db.put(b'user:1001:age', b'30')
db.put(b'user:1002:name', '李四'.encode('utf-8'))
db.put(b'user:1002:age', b'25')

# 读取
name = db.get(b'user:1001:name')
print(f"user:1001:name = {name.decode('utf-8')}")

# 删除
db.delete(b'user:1002:age')

# ========== 批量写入 ==========

with db.write_batch() as wb:
    wb.put(b'user:1003:name', '王五'.encode('utf-8'))
    wb.put(b'user:1003:age', b'35')
    wb.put(b'user:1003:email', b'[email protected]')

# ========== 迭代器 ==========

# 前缀扫描
print("\n--- 前缀扫描 user:1001 ---")
for key, value in db.iterator(prefix=b'user:1001:'):
    print(f"  {key.decode()} = {value.decode()}")

# 范围扫描
print("\n--- 范围扫描 [user:1001, user:1003) ---")
for key, value in db.iterator(start=b'user:1001', stop=b'user:1003'):
    print(f"  {key.decode()} = {value.decode()}")

# 反向遍历
print("\n--- 反向遍历 ---")
for key, value in db.iterator(reverse=True):
    print(f"  {key.decode()} = {value.decode()}")

# ========== Snapshot ==========

snap = db.snapshot()
db.put(b'user:1001:name', '张三改名'.encode('utf-8'))

# 快照读取的是旧值
old_name = snap.get(b'user:1001:name')
new_name = db.get(b'user:1001:name')
print(f"\n快照值: {old_name.decode()}")
print(f"当前值: {new_name.decode()}")

# 关闭数据库
db.close()

高级配置

import plyvel

db = plyvel.DB(
    '/tmp/pyldb_advanced',
    create_if_missing=True,
    max_open_files=500,
    write_buffer_size=8 * 1024 * 1024,    # 8MB
    max_file_size=2 * 1024 * 1024,         # 2MB
    block_size=8 * 1024,                    # 8KB
    bloom_filter_bits=10,                   # Bloom Filter
    compression='snappy',                   # 压缩方式
)

2.7 其他语言绑定

语言安装命令备注
Rustrusty_leveldbcargo add rusty-leveldb纯 Rust 实现
Rustleveldbcargo add leveldbC++ 绑定
JavaleveldbjniMaven: leveldbjni-allJNI 绑定
Node.jslevelnpm install level基于 C++ 绑定
Rubyleveldb-rubygem install leveldb-rubyFFI 绑定
ErlangeleveldbGitHub 克隆Riak 使用

2.8 常见编译问题

问题一:找不到 libleveldb

error: libleveldb.so: cannot open shared object file

解决

# 方法 1:设置 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

# 方法 2:更新动态链接器缓存
sudo ldconfig

# 方法 3:静态链接
g++ -o app app.cpp /usr/local/lib/libleveldb.a -lpthread -lsnappy

问题二:CMake 找不到 LevelDB

# 方法 1:指定路径
set(leveldb_DIR "/usr/local/lib/cmake/leveldb")
find_package(leveldb REQUIRED)

# 方法 2:手动链接
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
target_link_libraries(app leveldb)

问题三:Snappy 相关链接错误

undefined reference to 'snappy::...'

解决:确保安装了 Snappy 开发包并链接:

# Ubuntu
sudo apt-get install libsnappy-dev

# 编译时加 -lsnappy
g++ -o app app.cpp -lleveldb -lsnappy -lpthread

2.9 本章小结

内容要点
编译工具CMake 3.10+、GCC 7+ 或 Clang 6+
必需依赖无(Snappy 推荐安装)
C++ 使用#include "leveldb/db.h",链接 -lleveldb
Go 绑定github.com/syndtr/goleveldb,纯 Go 实现
Python 绑定plyvel,Cython 实现
Docker多阶段构建,运行时保留最小依赖

扩展阅读

  1. LevelDB CMake 源码leveldb/CMakeLists.txt,理解构建配置
  2. goleveldb 文档GoDoc
  3. Plyvel 文档ReadTheDocs
  4. Snappy 压缩库GitHub

第 1 章 · 简介与历史 | 第 3 章 · 架构总览