1. 诞生
RocksDB 是一个高性能的键值存储引擎,由 Facebook 开发并开源,起源于 Google 的 LevelDB。
发展历程
- 2012 年:Facebook 开始在 LevelDB 的基础上开发 RocksDB。
- 2013 年:RocksDB 首次开源,成为 GitHub 上的一个项目。
- 持续改进:自开源以来,RocksDB 得到了社区的广泛关注和贡献,Facebook 也持续改进和优化 RocksDB,以满足不断变化的需求。
LevelDB
LevelDB 是由 Google 开发的,它是一个基于磁盘的键值存储库,使用 LSM-Tree(Log-Structured Merge Tree)数据结构。LevelDB 设计简洁、性能优秀,适用于嵌入式系统,但在某些高负载情况下,性能和功能不符合 Facebook 的需求。
Facebook 的需求
在 2012 年,Facebook 需要一个能够处理大量数据、高并发读写请求的存储引擎。LevelDB 虽然性能优异,但在面对 Facebook 的海量数据和高并发请求时,暴露出了一些瓶颈和问题,如:
- 写入放大(Write Amplification):LevelDB 在高写入负载下的性能瓶颈。
- 读放大(Read Amplification):在某些查询模式下,读取性能不佳。
- 缺乏多线程支持:LevelDB 的单线程设计难以充分利用多核处理器的性能。
RocksDB 的诞生
为了满足自身的需求,Facebook 在 LevelDB 的基础上进行了大量优化和扩展,最终开发出了 RocksDB。以下是一些关键的改进:
- 多线程支持:RocksDB 通过引入多线程机制来提升并发性能,充分利用多核处理器的优势。例如,多线程 Compaction 和多线程写入操作。
- 更好的写入性能:提升写入性能是 RocksDB 的核心目标之一,通过优化 LSM-Tree 和引入多种写入缓冲机制来减少写入放大。
- 更高效的压缩:提供多种压缩算法和多级别压缩策略,用户可以根据具体需求选择合适的压缩方式,进一步优化存储效率。
- 丰富的配置选项:RocksDB 提供了大量的配置选项,允许用户根据具体场景进行微调和优化,例如内存管理、缓存大小、写入缓冲区大小等。
- 列族支持:引入了列族(Column Families)的概念,允许用户将数据按逻辑分组,提供更灵活的数据组织方式。
- 更强的持久化机制:通过改进 Write-Ahead Log (WAL) 和快照机制,RocksDB 提供了更强的数据持久化和恢复能力。
2. 应用场景
2.1. 特性
- 高性能:RocksDB 是为快速读写操作优化的,特别适用于需要低延迟和高吞吐量的应用场景,如实时分析、在线事务处理等。
- 可嵌入:它是一个嵌入式数据库,这意味着它可以直接嵌入到应用程序中,而不需要运行一个独立的服务器进程。这使得它非常适合于需要紧密集成数据库存储的应用程序。
- 灵活的配置:RocksDB 提供了多种配置选项,允许开发者根据具体需求调整读写性能、内存使用、磁盘使用等。
- 支持多种存储引擎:除了默认的磁盘存储引擎外,RocksDB 还支持基于内存的存储引擎,以满足不同的性能需求。
- 丰富的功能:包括快照、事务、列族、压缩、合并操作等,这些功能使得 RocksDB 能够应对各种复杂的应用场景。
- 横向扩展:虽然 RocksDB 本身是一个嵌入式数据库,但它可以通过集成到分布式系统(如 Apache Cassandra、TiDB 等)中实现横向扩展。
2.2. 应用场景
RocksDB 常用在以下场景中:
- 缓存存储:由于其快速的读写性能,RocksDB 经常被用作缓存存储解决方案。
- 实时数据分析:适用于需要低延迟数据写入和查询的实时分析系统。
- 嵌入式设备:因其嵌入式特性,RocksDB 常用于需要本地数据存储的嵌入式设备中。
- 分布式系统:作为存储引擎集成到分布式数据库和文件系统中。
1. 日志存储和处理
在日志存储和处理系统中,RocksDB 可以处理高频率的写入操作,并提供高效的数据持久化和查询能力。
特点和优势:
- 高效写入:RocksDB 的 LSM-Tree 结构和写缓冲机制可以处理高频率的写入操作,减少写入放大。
- 持久化:通过 WAL 日志和快照机制,确保数据在系统崩溃时也能恢复。
- 压缩:支持多种压缩算法,减少存储空间消耗。
示例:
- Kafka 使用 RocksDB 作为内部的状态存储引擎,用于存储日志和偏移量信息。
2. 缓存系统
RocksDB 可以作为持久化缓存层,结合内存缓存和磁盘存储的优势。
特点和优势:
- 持久化缓存:数据可以永久存储在磁盘上,减少数据丢失的风险。
- 内存管理:灵活的内存管理策略,可以根据内存大小调整缓存策略。
- 高性能读取:通过内存中的 memtable 和 block cache 提供高效的读取性能。
示例:
- Facebook 的 McDipper:一个分布式缓存系统,使用 RocksDB 作为持久化存储。
3. 大数据和分布式系统
在大数据处理和分布式系统中,RocksDB 可以作为高效的存储引擎,支持高并发读写操作。
特点和优势:
- 多线程支持:充分利用多核处理器的优势,提升并发性能。
- 灵活配置:提供大量的配置选项,可以根据具体场景进行优化。
- 事务支持:基本的事务支持,确保数据一致性。
示例:
- Apache Flink:一个流处理框架,使用 RocksDB 作为状态存储引擎。
- CockroachDB:一个分布式 SQL 数据库,使用 RocksDB 作为底层存储引擎。
4. 物联网和边缘计算
在资源受限的物联网设备和边缘计算环境中,RocksDB 提供高效的数据存储和处理能力。
特点和优势:
- 小内存占用:适合内存有限的设备。
- 高效写入和读取:适合频繁的传感器数据收集和查询。
- 嵌入式:无需独立服务,可以直接嵌入到应用程序中。
示例:
物联网网关设备:收集传感器数据并进行本地存储和处理。
5. NoSQL 数据库
许多 NoSQL 数据库使用 RocksDB 作为存储引擎,提供高效的键值存储和查询能力。
特点和优势:
- 高并发支持:多线程写入和读取,提升并发性能。
- 灵活的键值存储:支持多种数据类型和复杂查询。
- 持久化和压缩:确保数据安全并优化存储空间。
示例:
- TiDB:一个分布式 SQL 数据库,使用 RocksDB 作为底层存储。
- ScyllaDB:一个高性能的 NoSQL 数据库,也使用 RocksDB 作为存储引擎。
3.配置调优
3.1. 配置调优
RocksDB 提供了许多可配置的选项,用于优化数据库的性能、内存使用和磁盘 I/O。以下是一些关键的调优配置选项,涵盖了内存管理、Compaction 策略、WAL(Write-Ahead Log)日志、Block 缓存、数据压缩和并发控制等方面:
3.1.1. 内存管理
MemTable 配置:
- setWriteBufferSize: 控制 MemTable 的大小,以平衡写入性能和 Compaction 频率。
- setMaxWriteBufferNumber: 设置同时存在的 MemTable 数量,以处理并发写入。
- setMinWriteBufferNumberToMerge: 设置合并到磁盘前需要的最小 MemTable 数量。
Table Format 配置: - BlockBasedTableConfig: 配置 SSTable 文件的 Block 大小,以优化读取性能。
3.1.2. Compaction 策略
Level Compaction
- setLevelCompactionDynamicLevelBytes: 动态调整每层的大小,以平衡 Compaction 频率和读写放大。
- setMaxBytesForLevelBase 和 setMaxBytesForLevelMultiplier: 设置各级别的目标大小和倍数,控制 Compaction 触发条件。
- setCompactionPri: 设置 Compaction 优先级,如 BySize、ByCompensatedSize 等。
Universal Compaction
- setCompactionStyle: 设置为 CompactionStyle.UNIVERSAL,适用于写密集型应用。
- setUniversalCompactionOptions: 配置 Universal Compaction 的相关参数,如合并策略、阈值等。
3.1.3. WAL 配置
- setWalDir: 设置 WAL 日志的存储路径。
- setWalTtlSeconds 和 setWalSizeLimitMB: 控制 WAL 日志的保留时间和大小,以平衡数据安全和磁盘使用。
3.1.4. Block Cache
- LRUCache: 创建和配置 Block Cache,用于缓存 SSTable 中的数据块,提高读性能。
- setBlockSize: 设置 Block 大小,影响 Block Cache 的利用率。
- setPinL0FilterAndIndexBlocksInCache: 是否将 Level 0 的过滤器和索引块保留在 Block Cache 中。
3.1.5. 数据压缩
- setCompression: 设置数据压缩算法,如 NoCompression、Snappy、Zlib、LZ4 或 Zstd,以节省磁盘空间。
- setCompressionPerLevel: 针对不同级别设置不同的压缩算法。
3.1.6. 并发控制
- setMaxBackgroundJobs: 设置后台任务的最大并发数,包括 Compaction 和刷写操作。
- setMaxBackgroundCompactions: 设置最大 Compaction 线程数。
- setMaxBackgroundFlushes: 设置最大刷写线程数。
3.1.7. 其他优化
- useFsync: 是否在写入时使用 fsync,以确保数据的持久性。
- setTableFormatConfig: 配置 SSTable 的其他属性,如过滤器类型、索引间隔等。
3.1.8. 示例代码
import org.rocksdb.*;
public class RocksDBConfig {
static {
RocksDB.loadLibrary();
}
public RocksDB createRocksDB() throws RocksDBException {
Options options = new Options()
// 内存管理
.setWriteBufferSize(128 * 1024 * 1024) // MemTable 大小,可以根据写入速率调整
.setMaxWriteBufferNumber(4) // 最大 MemTable 数量,用于并发写入
.setMinWriteBufferNumberToMerge(2) // 合并 MemTable 的最小数量
.setTargetFileSizeBase(256 * 1024 * 1024) // 每个 SSTable 文件的目标大小,根据磁盘 I/O 能力调整
.setMaxBytesForLevelBase(1024 * 1024 * 1024) // Level 1 的目标大小,根据磁盘空间调整
.setMaxBytesForLevelMultiplier(10) // 每层的目标大小是前一层的倍数,控制 Compaction 触发条件
.setLevelCompactionDynamicLevelBytes(true) // 动态调整每层大小
.setCompactionPri(CompactionPriority.ByCompensatedSize) // 根据补偿大小优先级排序
// Compaction 策略
.setMaxBackgroundCompactions(4) // 最大后台 Compaction 线程数,根据 CPU 核心数调整
.setMaxBackgroundFlushes(2) // 最大后台刷写线程数,根据 CPU 核心数调整
// WAL 配置
.setWalDir("/path/to/wal") // WAL 日志路径
.setWalTtlSeconds(60 * 60 * 24) // WAL 日志保留时间,根据数据安全性需求调整
.setWalSizeLimitMB(2048) // WAL 日志大小限制,根据磁盘空间调整
.setUseFsync(false) // 是否在写入时使用 fsync,平衡性能和数据安全
// Block Cache
.setBlockBasedTableConfig(new BlockBasedTableConfig()
.setBlockSize(16 * 1024) // Block 大小,根据数据特性调整
.setPinL0FilterAndIndexBlocksInCache(true) // Pin Level 0 的过滤器和索引块
.setCacheIndexAndFilterBlocks(true) // 缓存索引和过滤器块,提高读性能
.setBlockCache(new LRUCache(512 * 1024 * 1024))) // Block Cache 大小,根据内存资源调整
// 数据压缩
.setCompression(CompressionType.LZ4Compression) // 使用 LZ4 压缩算法,也可以选择其他算法
.setCompressionPerLevel(Arrays.asList(
CompressionType.LZ4Compression, // Level 0
CompressionType.LZ4Compression, // Level 1
CompressionType.ZSTD, // Higher levels
CompressionType.ZSTD,
CompressionType.ZSTD)) // 自定义不同级别的压缩算法
// 并发控制
.setMaxTotalWalSize(2 * 1024 * 1024 * 1024) // WAL 文件总大小限制
.setMaxOpenFiles(-1) // 允许打开的最大文件数,-1 表示无限制
.setMaxSequentialSkipIn_iterations(8) // 优化迭代器性能
// 其他优化
.setTableFormatConfig(new BlockBasedTableConfig().setFilterPolicy(new BloomFilter(10, false))); // 使用布隆过滤器减少读操作
String dbPath = "/path/to/rocksdb";
return RocksDB.open(options, dbPath);
}
}
3.2. MemTable、Block Cache
功能
- MemTable:数据首先被写入 MemTable,然后再根据一定的策略刷写到磁盘生成 SSTable 文件。主要用于存储新写入的数据,临时存储在内存中并定期刷写到磁盘。优化写性能。
- Block Cache:主要用于缓存从磁盘读取的数据块,减少后续读取相同数据块的磁盘 I/O。优化读性能。
操作路径
- MemTable:写操作首先写入 MemTable,读操作首先检查 MemTable。
- Block Cache:读操作在MemTable之后查不到之后会读 Block Cache,如果命中则返回缓存数据;否则从磁盘读取并缓存。
持久性
- MemTable:数据最终会被持久化到磁盘生成 SSTable 文件。
- Block Cache:缓存的数据块不具备持久性,缓存失效或系统重启后需要重新加载。
配置
- MemTable:通过 setWriteBufferSize 和 setMaxWriteBufferNumber 配置大小和数量。
- Block Cache:通过 LRUCache 配置大小。
配置建议
MemTable:
- 在写密集型场景中,适当增加 MemTable 大小和数量,可以提高写入性能和减少刷写频率。
- 在内存有限的情况下,配置适当的 MemTable 大小,确保内存使用的合理性,避免内存不足。
Block Cache:
- 在读密集型场景中,适当增加 Block Cache 大小,可以提高读缓存命中率和读性能。
- 在内存有限的情况下,配置适当的 Block Cache 大小,确保内存使用的合理性,避免内存不足。
3.3. 读顺序
在 RocksDB 中,读操作的流程涉及多个步骤,主要目的是尽可能快速地找到所需的数据。具体步骤如下:
1.查询 MemTable
首先,RocksDB 会在 MemTable 中查找数据。MemTable 存储的是最近的写操作数据,由于在内存中查询速度非常快,所以这是第一步。
如果在 MemTable 中找不到数据,RocksDB 接着会在 Immutable MemTable 中查找。Immutable MemTable 是已经写满并准备刷到磁盘但尚未完成的 MemTable。
2.查询 Block Cache
如果在 MemTable 和 Immutable MemTable 中都没有找到数据,RocksDB 会查找 Block Cache。Block Cache 存储的是从 SSTable 文件中读取的数据块(block),用于加速读操作。
Block Cache 是基于 LRU(Least Recently Used)策略管理的,旨在保留最近使用的数据块,以提高缓存命中率。
3.查询 SSTable 文件
如果数据不在 Block Cache 中,RocksDB 会从磁盘上的 SSTable 文件中查找。首先会查找每层的索引和过滤器(如布隆过滤器)来确定数据可能存在的文件和位置。
从 SSTable 文件中读取数据块时,RocksDB 会将这些数据块加载到 Block Cache 中,以便后续访问更快。
4.合并数据
如果在多个位置找到数据版本(例如在 MemTable 和 SSTable 中同时存在),RocksDB 会根据数据的序列号(sequence number)和操作类型(如 PUT 或 DELETE)来确定最终返回的数据。
4. spring使用
4.1. 配置类
RocksDB 是一个嵌入式数据库,这意味着它不需要单独的服务器进程。一般情况下,你只需要指定数据存储目录和一些配置选项。
pom
<dependency>
<groupId>org.rocksdb</groupId>
<artifactId>rocksdbjni</artifactId>
<version>6.20.3</version> <!-- 请根据最新版本进行更新 -->
</dependency>
调优选项解释
MemTable 配置
- setWriteBufferSize: 设置每个 MemTable 的大小。例如,这里设置为 64MB。
- setMaxWriteBufferNumber: 设置同时存在的最大 MemTable 数量,这里设置为 3。
- setMinWriteBufferNumberToMerge: 设置合并 MemTable 的最小数量。
Block Cache 配置
- 使用 LRUCache 进行 Block Cache 的配置,这里设置为 128MB。
Compaction 策略
- setLevelCompactionDynamicLevelBytes: 启用动态调整每层大小的 Compaction 策略。
- setMaxBackgroundCompactions: 设置最大后台 Compaction 线程数。
- setMaxBackgroundFlushes: 设置最大后台刷写线程数。
WAL 配置
- setWalDir: 设置 WAL 文件的存储路径,以确保数据的持久性。
通过这些配置,您可以根据业务需求和系统资源情况,合理调整 RocksDB 的参数,提升其在 Spring 项目中的性能。
import org.rocksdb.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RocksDBConfig {
static {
RocksDB.loadLibrary();
}
@Bean
public RocksDB rocksDB() throws RocksDBException {
// 配置 RocksDB 选项
Options options = new Options();
options.setCreateIfMissing(true);
// 配置 MemTable
options.setWriteBufferSize(64 * 1024 * 1024); // 64MB
options.setMaxWriteBufferNumber(3); // 3个 MemTable
options.setMinWriteBufferNumberToMerge(1); // 最少1个 MemTable 合并
// 配置 Block Cache
Cache blockCache = new LRUCache(128 * 1024 * 1024); // 128MB Block Cache
BlockBasedTableConfig tableConfig = new BlockBasedTableConfig();
tableConfig.setBlockCache(blockCache);
options.setTableFormatConfig(tableConfig);
// 配置 Compaction 策略
options.setLevelCompactionDynamicLevelBytes(true); // 动态调整每层大小
options.setMaxBackgroundCompactions(4); // 最大后台 Compaction 线程数
options.setMaxBackgroundFlushes(2); // 最大后台刷写线程数
// 配置 WAL
options.setWalDir("/path/to/wal"); // 指定 WAL 目录
// 指定数据存储目录
String dbPath = "/path/to/rocksdb";
// 打开 RocksDB 数据库
return RocksDB.open(options, dbPath);
}
}
4.1. 操作类
你可以通过注入 RocksDB bean 来在 Spring 中使用 RocksDB 进行数据操作。以下是一个简单的示例,展示了如何进行基本的增删改查操作:
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RocksDBService {
private final RocksDB rocksDB;
@Autowired
public RocksDBService(RocksDB rocksDB) {
this.rocksDB = rocksDB;
}
// 存储数据
public void put(String key, String value) {
try {
rocksDB.put(key.getBytes(), value.getBytes());
} catch (RocksDBException e) {
e.printStackTrace();
}
}
// 获取数据
public String get(String key) {
try {
byte[] value = rocksDB.get(key.getBytes());
return value != null ? new String(value) : null;
} catch (RocksDBException e) {
e.printStackTrace();
}
return null;
}
// 删除数据
public void delete(String key) {
try {
rocksDB.delete(key.getBytes());
} catch (RocksDBException e) {
e.printStackTrace();
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。