LevelDB 入门 —— 全面了解 LevelDB 的功能特性

为什么ActiveMQ官方不再推荐使用LevelDB 为什么ActiveMQ官方不再推荐使用LevelDB 最近在学习mq,虽然已经在使用,但是却未深入的了解,于是阅读官方文档的时候发现ActiveMQ官方不再推荐使用LevelDB。ActiveMQ在5.8.0 版本后引入了LevelDB的,并且LevelDB存储是基于文件的持久性数据库,可提供比KahaDB更快的持久性。为什么ActiveMQ官方不再支持或建议使用levelDB?在网上搜了一大堆终... 阅读详情
AI摘要

本文深入解析LevelDB数据库的特性,包括其C++开发背景、Java接口应用、原子批处理、安全写、并发控制、快照隔离、自定义比较器、数据块管理、压缩策略、块缓存、布隆过滤器及数据校验机制。LevelDB采用类似HashMap的API设计,支持原子批处理以确保数据一致性,提供安全写操作避免数据丢失,通过快照隔离保证多线程安全,允许自定义键值比较,优化数据块大小,利用压缩提高存储效率,引入块缓存减少磁盘访问,运用布隆过滤器减少无效磁盘读,以及严格的校验机制确保数据完整性。

640?wx_fmt=png

本节我们将全面了解一下 LevelDB 的各种特性。LevelDB 的开发语言是 C++,考虑到会使用 C++ 语言的同学不是很多,在本节我们将使用 Java 语言来描述 LevelDB 的特性。其它语言栈的同学也不必担心,因为不同语言操纵 LevelDB 的接口 API 都是一样的,使用起来大同小异。

打开和关闭

LevelDB 的数据存储在一个特定的目录中,里面有很多数据文件、日志文件等。使用 LevelDB API 来打开这个目录,就得到了 db 的引用。后续我们就使用这个 db 引用来执行读写操作。下面的代码是 Java 语言描述的伪代码。

class LevelDB {
  public static LevelDB open(String dbDir, Options options);
  void close(); // 关闭数据库
}

基础 API

LevelDB 用起来就像 HashMap,但是比 HashMap 要稍微弱一些,因为 put 方法不能返回旧值,delete 操作也不知道对应的 key 是否真的存在。

class LevelDB {
  byte[] get(byte[] key)
  void put(byte[] key, byte[] value)
  void delete(byte[] key)
  ...
}

原子批处理

对于多个连续的写操作如果因为宕机有可能导致这多个连续的写操作只完成了一部分。为此 LevelDB 提供了批处理功能,批处理操作就好比事务,LevelDB 确保这一些列写操作的原子性执行,要么全部生效要么完全不生效。

class WriteBatch {
  void put(byte[] key, byte[] value);
  void delete(byte[] key);
}

class LevelDB {
  ...
  void write(WriteBatch wb);
}

日志文件

当我们调用 LevelDB 的 put 方法往库里写数据时,它会先将数据记录到内存中,延后再通过某种特殊的策略持久化到磁盘。这就存在一个问题,如果突发宕机,这些来不及写到磁盘的数据就丢失了。所以 LevelDB 也采用了和 Redis AOF 日志类似的策略,先讲修改操作的日志写到磁盘文件中,再进行实际的写操作流程处理。

如此即使宕机发生了,数据库启动时还可以通过日志文件来恢复。

安全写(同步写)

了解 Redis 的同学都知道它的 AOF 写策略有多种配置,取决于日志文件同步磁盘的频率。频率越高,遇到宕机时丢失的数据就越少。操作系统要将内核中文件的脏数据同步到磁盘需要进行磁盘 IO,这会影响访问性能,所以通常都不会同步的太频繁。

LevelDB 也是类似的,如果使用前面的非安全写,虽然 API 调用成功了,但是遇到宕机问题,有可能对应的操作日志会丢失。所以它提供了安全写操作,代价就是性能会变差。

class LevelDB {
  ...
  void putSync(byte[] key, byte[] value);
  void deleteSync(byte[] key);
  void writeSync(WriteBatch wb);
}

并发

LevelDB 的磁盘文件会放在一个文件目录中,里面有很多相关的数据和日志文件。它不支持多进程同时打开这个目录来使用 LevelDB API 进行读写访问。但是对于同一个进程 LevelDB API 是支持多线程安全读写的。LevelDB 内部会使用特殊的锁来控制并发操作。

遍历

LevelDB 中的 Key 都是有序的,按照字典序从小到大整齐排列。LevelDB 提供了遍历 API 可以逐个顺序访问所有的键值对,可以指定从中间开始遍历。

class LevelDB {
  ...
  Iterator<KV> scan(byte[] startKey, byte[] endKey, int limit);
}

快照隔离

LevelDB 支持多线程并发读写,这意味着连续的两个同样 key 的读操作读到的数据可能不一样,因为两个读操作中间数据可能被其它线程修改了。这在数据库理论中称为「重复读」。LevelDB 提供了快照隔离机制,在同一个快照范围内保证连续的读写操作不受其它线程修改操作的影响。

class Snapshot {
  byte[] get(byte[] key)
  void put(byte[] key, byte[] value)
  void delete(byte[] key)
  void write(WriteBatch wb);
  ...
  void close();  // 关闭快照
}

class LevelDB {
  ...
  Snapshot getSnapshot();
}

自定义 Key 比较器

LevelDB 的 key 默认使用字典序,不过它也提供了自定义排序规则。你可以自定义一个排序函数注册进去,比如按数字排序。必须尽可能确保排序规则在整个数据库生命周期内保持不变,因为排序会影响到磁盘键值对的存储顺序,磁盘存储顺序是无法动态改变的。

Options options = new Options();
options.comparator = new CustomComparator();
db = LevelDB.open("/tmp/ldb", options);

数据块

LevelDB 的磁盘数据是以数据库块的形式存储的,默认的块大小是 4k。适当提升块大小将有益于批量大规模遍历操作的效率,如果随机读比较频繁,这时候块小点性能又会稍好,这就要求我们自己去折中选择。

Options options = new Options();
options.blockSize = 8092;
db = LevelDB.open("/tmp/ldb", options);

压缩

LevelDB 的磁盘存储默认是开启压缩的,是业界常用的 Snappy 算法,压缩效率非常高,所以无需担心性能损耗问题。如果你不想使用压缩,也可以动态关闭。关闭压缩开关通常不会带来明显的性能提升,所以我们尽可能不要去动它。

Options options = new Options();
options.compression = CompressionType.kSnappyCompression;
// options.compression = CompressionType.kNoCompression; // 关闭压缩
db = LevelDB.open("/tmp/ldb", options);

块缓存

LevelDB 的内存中存储了一笔最近读写的热数据,如果请求的数据在热数据中查不到就需要去磁盘文件中去查找,效率就会大幅降低。LevelDB 为了降低磁盘文件的搜寻次数,增加了块缓存,缓存了近期频繁使用的数据块解压缩之后的内容。

Options options = new Options();
options.blockCache = LevelDB.NewLRUCache(100 * 1024 * 1024); // 100M
db = LevelDB.open("/tmp/ldb", options);

还需要注意遍历操作对缓存的影响,为了避免遍历操作将很多冷门数据刷到块缓存中,可以在遍历的时候设置一个选项 fill_cache,它用来控制磁盘遍历的数据块是否需要同步到缓存。

布隆过滤器

内存读 miss 导致磁盘搜寻是一个比较耗时的操作,LevelDB 为了进一步减少磁盘读的次数,在每个磁盘文件上又加了一层布隆过滤器,它需要消耗一定的磁盘空间,但是在效果上可以直接将磁盘读次数大幅减少。布隆过滤器的数据存储在磁盘文件中数据块的后面。

LevelDB 的磁盘文件是分层存储的,它会先去 Level 0 查找,如果找不到继续去 Level 1 去找,一直递归到最底层。所以如果你去找一个不存在的 key,就需要很多次磁盘文件读操作,会非常耗费时间。而布隆过滤器可以帮你省去95%以上的磁盘文件搜寻的时间。

布隆过滤器类似于一个内存 Set 结构,它里面存储了指定磁盘文件一定范围内所有 Key 的指纹信息。当它发现某个 key 的指纹在 Set 集合里找不到,它就可以断定这个 key 肯定不存在。

如果对应的指纹可以在集合里找到,这并不能确定它就一定存在。因为不同的 Key 可能会生成同样的指纹,这就是布隆过滤器的误判率。误判率越低需要的 Key 指纹信息越多,对应消耗的内存空间也就越大。

如果布隆过滤器能准确知道某个 Key 是否存在,那就不存在误判了,这时候也就不会存在白白浪费的磁盘读操作。这样的极限形式的布隆过滤器就是 HashSet —— 内存里存储了所有的 Key,当然内存空间自然是无法接受的。

Options options = new Options();
// 每个 key 的指纹大小是 10bit
options.filterPolicy = LevelDB.NewBloomFilterPolicy(10);
db = LevelDB.open("/tmp/ldb", options);

默认布隆过滤器没有打开,需要在打开数据库的时候设置 filter_policy 参数才可以生效。布隆过滤器是减少磁盘读操作的最后一层堡垒。布隆过滤器内部的位图数据会存储在磁盘文件中,但是使用是会缓存在内存里面。

数据校验

LevelDB 有严格的数据校验机制,它将校验的单位精确到了 4K 字节的数据块。校验和会浪费一点存储空间和计算时间,但是在遇到数据块损坏时可以较为精确地恢复健康的数据。

class LevelDB {
  ...
  public void static repairDB(String dbDir, Options options);
}

小结

经过了这一节的学习,同学们应该可以在脑海中形成下面这样一张概念图。图中的「热数据」是指最近被修改的键值对,这里面的键值对读取速度是最为快速的。如果热数据中读取不到,就会去块缓存中读取。如果还读不到,就分两种情况,一种是真的不存在,另一个种是存在于磁盘上。如果存在于磁盘上,经过有限层次读取就读取到了,通常越冷的数据越在底层。如果真的不存在就要经过布隆过滤器来大幅减少磁盘搜寻 IO,布隆过滤器的数据和键值对数据共同放在分层的数据文件中。

640?wx_fmt=png
图片

下一节我们使用真实的代码来亲自实践一下 LevelDB。

640?wx_fmt=png

订阅「码洞」公众号,阅读更多 LevelDB 相关内容

Python的levelDB实现——实习笔记 实习做的最靠谱的东西,不过只是其中一个部分,这代码算是公司的吧(之前的软考不是白考的,不过想想也知道~),所以没有贴出来全部,不过他们也说了要放到github上,只是时间问题,- -我个人觉得是我代码太丑了,所以他们就没好意思放上去。。。。 确实写的很丑,风格丑!!!!不是效率低。。。感觉Python的风格和Java的是两个极端,被Java先入为主了,所以Python的风格就很差劲。。。 阅读详情

相关推荐

一次点查要翻几本账:LevelDB的内存双表、布隆过滤器、分层SSTable与两级缓存解析

LevelDB以追加写换取高吞吐,读却要跨内存与多层文件找最新版本。本文依据1.23源码,梳理一次点查的完整路径:预写日志与组提交、内部键与快照、跳表MemTable与双表切换、SSTable块结构、分层合并的大小触发与查找触发、L0的三道警戒线、布隆过滤器与两级LRU缓存。复刻实验表明:每键10位过滤器误判率约0.76%,不存在键的读块次数降到约1/120;分层模拟写放大约7.1倍;块缓存命中率取决于热点分布,扫描宜关闭fill_cache。文末给出调优建议、常见误区与RocksDB对照。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 11万+

LevelDB库简介

LevelDB库简介     一、LevelDB入门 LevelDB是Google开源的持久化KV单机数据库,具有很高的随机写,顺序读/写性能,但是随机读的性能很一般,也就是说,LevelDB很适合应用在查询较少,而写很多的场景。LevelDB应用了LSM (Log Structured Merge) 策略,lsm_tree对索引变更进行延迟及批量处理,并通过一种类似于归并排序的方式高...

weixin_34183910的博客 3059

jleveldb:Leveldb的纯Java版本

jleveldb 纯Java版本的Leveldb

leveldb 原理解析

LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.

salyty的博客 5420

leveldb:LevelDB到Java的端口

Java中的LevelDB 这是Java中的重写(端口)。 这个目标是要有一个功能完整的实现,该实现在C ++原始性能的10%以内,并生成C ++代码的逐字节精确副本。 当前状态 当前,代码库基本上是功能性的,但仅经过了微不足道的测试。 在某些地方,此代码是C ++代码的文字转换,而在其他地方,则已转换为更自然的Java样式。 计划是使代码更接近C ++原始代码,直到建立基线性能为止。 API用法: 推荐包装进口: import org.iq80.leveldb.* ; import static org.iq80.leveldb.impl.Iq80DBFactory.* ; import java.io.* ; 打开和关闭数据库。 Options options = new Options (); options . createIfMissing( true ); DB db

用示波器抓一次MIPI D-PHY的波形,手把手教你读懂HS模式和LP模式的切换时序

本文详细解析了MIPI D-PHY信号的双模切换机制,包括高速模式(HS)和低功耗模式(LP)的波形捕获与诊断技巧。通过示波器设置、关键状态分析和实战案例,帮助工程师快速定位信号完整性问题,提升调试效率。

weixin_30696427的博客 460

go leveldb key 重复_LevelDB 入门 —— 全面了解 LevelDB 的功能特性

本节我们将全面了解一下 LevelDB 的各种特性。LevelDB 的开发语言是 C++,考虑到会使用 C++ 语言的同学不是很多,在本节我们将使用 Java 语言来描述 LevelDB 的特性。其它语言栈的同学也不必担心,因为不同语言操纵 LevelDB 的接口 API 都是一样的,使用起来大同小异。打开和关闭LevelDB 的数据存储在一个特定的目录中,里面有很多数据文件、日志文件等。使用 L...

weixin_30733115的博客 542

stm32f407等芯片(HAL库)时钟频率修改(乱码)

其他片子及库文件未知、未验证,只是在使用stm32f407ZG配置串口打印的时候,出现乱码,就从以下几方面定位问题: 1. 确认串口GPIO相关配置; 2. 确认波特率等参数; 3. 确认时钟频率; 结果这次使用YH的串口打印程序在ZDYZ的开发板调试项目工程(有点另类...),做功能验证,就出现了以上问题,出于好奇开始调试,最终发现是时钟频率问题。 看到下图这个配置,因为ZDYZ开发板使用的是8MHz外部晶振(好像默认的是25MHz,如图2),所以他这里PLL_M是25,不是推荐值,感...

bulefire2009的博客 5517

LevelDB 入门指南(二)

我们在三种主流脚本语言中看到了不同的编码风格。抓住机会进一步探索那些链接,并考虑使用脚本语言作为 REPL 来探索 LevelDB 中的想法。你可能想用它快速生成大量数据库或玩转不同的键结构。

龙哥盟 1369

银河麒麟V10系统grub崩溃急救指南:从光盘救援到完整恢复(附常见错误排查)

本文详细介绍了银河麒麟V10系统grub崩溃的急救方法,从使用安装光盘进入救援环境到完整恢复系统的全流程。针对不同损坏程度(轻度、中度、严重)提供了分级恢复策略,包括grub2-install和grub2-mkconfig等关键命令的使用,并附有常见错误排查表,帮助用户快速解决引导问题。

weixin_30955617的博客 483

泄露测试仪CTS的Sentinel I28使用

本文介绍:泄露测试仪CTS的Sentinel I28使用

qq_34047402的博客 2206

大白话解析LevelDB: TableBuilder

LevelDB将`MemTable`生成`SST`的相关操作封装成了`TableBuilder`类

sinat_38293503的博客 1605

【工具】GitHub学生认证+PyCharm配置Copilot全流程指南

本文提供了一份详细的GitHub学生认证及在PyCharm中配置Copilot的完整指南。通过完成A2F认证、准备有效材料并使用干净网络环境,学生可免费获取GitHub Copilot Pro订阅,极大提升编程学习与开发效率。

w7x8y9z的博客 1459

深入leveldb-初步认识leveldb

文章参考http://blog.chinaunix.net/uid-26575352-id-3245476.html1. leveldb简介    leveldb是google两位工程师实现的单机版k-v存储系统,具有以下几个特点    1. key和value都是任意的字节数组,支持内存和持久化存储    2. 数据都是按照key排序    3. 用户可以重写排序函数    4. 包含基本的数据

藏经阁 | 玄苦 7278

DM-VIO论文精读:从‘延迟边缘化’到‘位姿图BA’,手把手拆解单目VIO性能超越双目的秘密

本文深入解析DM-VIO技术如何通过延迟边缘化和位姿图BA创新,解决单目视觉惯性里程计(VIO)的尺度不可观性问题,并在精度上超越传统双目系统。文章详细介绍了延迟边缘化的双因子图结构设计、位姿图BA的多级初始化策略,以及系统级优化带来的性能提升,为VIO研究与实践提供了重要参考。

weixin_30616969的博客 428

基于simulink 的不间断电源ups的项目实例

UPS系统的核心组件包括整流器、逆变器、电池管理系统和控制系统。- **Three-Phase Controlled Rectifier**:设置触发角为0度,用于控制整流器的输出电压。- **Three-Phase Inverter**:设置逆变器的输出频率为60Hz,用于将直流电转换为交流电。- **Control System**:编写MATLAB函数,用于监测市电状态并控制各模块的工作模式。- **Step**:设置阶跃时间,例如0.05秒,阶跃前后的值分别为0和1,用于模拟市电中断。

xiaoheshang_123的博客 711

实验三十二 LevelDB实验:读写LevelDB

实验指导: 32.1 实验目的 1.了解LevelDB的使用场景; 2.理解LevelDB数据存储结构; 3.比较LevelDB和redis的区别; 4.能对LevelDB的整体架构有一定的了解; 5.能正确的使用LevelDB并能进行简单使用。 32.2 实验要求 本实验要求同学能够使用C++语言完成对LevelDB库完成以下操作: 1.连接到LevelDB数据库; 2.写入...

WistWill的博客 1352

Xilinx FPGA平台GTX简易使用教程(四)GTX IP核配置教程

干货来了,GTX IP核配置,搬砖全靠它~~

数字IC/FPGA杂货铺,找一找,或许有你想要的~ 1万+

LevelDB 入门指南(一)

LevelDB 是跨平台最简单且潜在上最强大的数据库技术,适用于移动设备使用。本书通过 iOS 和 OS X 示例教你所有关于 LevelDB 的知识。如果你需要将数据存储在持久字典中,构建难以用 SQL 建模的复杂数据结构,或者只是推动性能边界,LevelDB 提供了构建块。要超越基础,你需要理解允许在键值存储中进行更复杂数据建模的编程模式。本书提供了理解和编码工具,以充分利用 LevelDB。它所教授的原则也可以应用于其他排序键值存储。

龙哥盟 1084

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

LevelDB-CLI:调试LevelDB的神器

LevelDB-CLI:调试LevelDB的神器 在追求高效数据管理的道路上,LevelDB以其简洁和高性能成为了众多开发者的首选。然而,在复杂应用的开发与维护过程中,数据库的调试往往成为一大挑战。就此,我们带来了LevelDB-CLI —— 一个专为LevelDB设计的命令行实用工具,它简化了LevelDB的交互过程,让调试变得轻松愉快。 项目技术分析 LevelDB-CLI是基于Go语言编写的...

gitblog_00154的博客 1239

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

LevelDb

LevelDb日知录之一:LevelDb 101   说起LevelDb也许您不清楚,但是如果作为IT工程师,不知道下面两位大神级别的工程师,那您的领导估计会Hold不住了:Jeff Dean和Sanjay Ghemawat。这两位是Google公司重量级的工程师,为数甚少的Google Fellow之二。   Jeff Dean其人:http://research.g

swpihchj的专栏 9069

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

上一篇: 每个阿里程序员都必须搞懂的Maven基础知识
下一篇: SpringBoot 究竟是如何跑起来的?
码洞
博客等级 码龄10年 41粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值