LevelDB的一些简单总结

LevelDB特点

  1. key value记录持久化存储,记录可压缩
  2. 支持高写入的场合
  3. 具有插入Put,删除Delete,以及读取Get记录三种基本操作。不包含更新操作,可以直接插入新的value表示更新。支持批量写入,利用WriteBatch将多个写操作合并到一起
  4. 默认写入为异步写入,速度快,先写入日志再写入内存,同步写入极慢。
  5. 支持快照操作。可通过快照保持读取数据的一致性,不受到中间写入过程的影响
  6. 单进程多线程操作一个库是安全的,多进程是需要用户自己管理并发的。
  7. 仅仅是一个库而已,没有自己的服务进程

Level存储结构

1,内存的数据

内存中有两个表MemTable和Immutable MemTable
MemTable代表当前活跃的表,它主要包含Log, Manifest,以及Current三个硬盘文件,以及内存中的一个跳表SkipList。
Log是用来记录用户的写入或者删除操作,先写入log文件(按操作的顺序),再写入MemTable的SkipList中(根据key有序插入到相应的跳表位置)。

当MemTable的容量达到一定程序后,此Memtable被转换为Immutable MemTable,仍然在内存中,但可读不可写。新的MemTable被创建,并用来服务新的写入请求,至于Immutable MemTable什么时候会被写入到硬盘中,可参见数据的合并中simple compaction操作。

2,硬盘中的数据

硬盘中有多级Level的数据表,叫做SSTable
它从Level 0 到Level N,每一个级别都可能有多个sst数据表。
Level 1到Level N: 它们的每级内部的数据表之间的key是无交叉的(具体参见数据的合并)。
Level 0: Level 0比较特别,它的多个数据表的key有交叉。Level 0的每一个数据表都是直接来源于Immutable MemTable,当系统进行记录的简单合并操作时候,直接将Immutable MemTable中的跳表转换为一个sst,因此Level 0中的多个sst的key可能有交叉。

知识点

数据的合并Compaction

当需要删除数据时候,系统直接插入删除标记即可,那旧的数据什么时候才会被清除呢?这就要用到Compaction操作。有两种合并,一种是simple,一种是major。
simple compaction操作就是Immutable MemTable中的跳表转换为Level 0的一个sst(内存到硬盘)。
major compaction操作指的是Level L与Level L+1的合并操作,是层级之间的合并操作(硬盘到硬盘)。当L >=1的时候,首先选取Level L中的一个数据表,然后寻找Level L+1中的所有与Level L的key有交叉的数据表,进行多路合并。合并的一个原则就是,如果Level L中有一个key在Level L+1中存在,那么将Level L+1中的所有这样的key记录都删除即可。当L = 0,它和Level 1的合并有些特殊,我们需要选取Level 0的多个数据表(由于Level 0的key是有交叉的),与Level 1的多个数据表进行合并。

SSTable数据表的结构

数据表有多个数据块,存储有Block的索引,以及相应Block的数据。Block的大小为32KB。

缓存

有两个级别的缓存,数据表的索引缓存,数据Block的缓存。索引的缓存是默认,Block的缓存可配置。

为什么写入性能较好?

跳表是在内存中,利用了多级链表的结构,查找和插入效率高,比平衡树减少了很多节点移动的操作,因此插入速度极快;日志的写入虽然是磁盘写入,但由于是顺序写入,因此性能也很好。

为什么读取比较慢?

首先查找MemTable和Immutable MemTable,没有找到的话进入cache中查找,仍然没有找到,那么只能通过硬盘查找了。
硬盘查找首先查找Level 0,如果没有继续Level 1,直到最后一层Level,还没找到,那么不存在,如果中间任何一个地方找到了,那么直接返回。这个顺序时根据数据的新旧顺序而来的。 对于某一个Level的数据表具体查找如何执行的呢? 首先载入这个数据表的索引到内存中,查看key位于哪一个Block中,然后将相应的Block载入到内存中,逐个查找记录。 至少需要两次硬盘读取操作,很慢,顺序读因为有缓存的缘故,性能相对较好。

官方的性能数据

这一个部分摘取的一个博客的内容(感谢其整理翻译):
作者:Jeff Dean, Sanjay Ghemawat
原文:http://leveldb.googlecode.com/svn/trunk/doc/index.html
译者:phylips@bmy 2011-8-16
译文:http://duanple.blog.163.com/blog/static/70971767201171705113636

测试环境

使用一个具有百万条记录的数据库,每条记录有一个16字节的key及100字节的value。对于values值压缩后可能大概只有原始大小的一半。
LevelDB: version 1.1
Date: Sun May 1 12:11:26 2011
CPU: 4 x Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz
CPUCache: 4096 KB
Keys: 16 bytes each
Values: 100 bytes each (50 bytes after compression)
Entries: 1000000
Raw Size: 110.6 MB (estimated)
File Size: 62.9 MB (estimated)

写性能

“fill” benchmarks会以顺序地或者随机的方式创建一个全新的数据库。”fillsync” benchmark 的每次操作都会将数据从操作系统flush到磁盘;其他的写操作会允许数据在操作系统buffer中停留一段时间。”overwrite” benchmark 会进行随机的写入以更新数据库中现有的key值。
fillseq : 1.765 micros/op; 62.7 MB/s
fillsync : 268.409 micros/op; 0.4 MB/s (10000 ops)
fillrandom : 2.460 micros/op; 45.0 MB/s
overwrite : 2.380 micros/op; 46.5 MB/s
上面的一次”op”意味着对于单个key/value对的一次写人。比如随机写benchmark每秒大概可以近似达到400,000写操作。
每个”fillsync”操作花费(0.3ms)远小于一次磁盘seek操作(通常需要10ms)。我们怀疑这是因为硬盘本身会将这些更新缓存到它的memory里,在数据真正写入到扇区之前就做出了响应。这种情况下的安全性取决于硬盘在电力供应出问题时是否有足够的电力去保存它的memory中的数据。

读性能

我们列出了正向及反向顺序读的性能,以及随机查找的性能。需要注意的是,由benchmark创建的数据库是很小的。因此这个报告只是刻画了工作集可以载入到内存时的LevelDB的性能。对于那些未命中操作系统缓存的单片数据读取操作来说,开销主要是由为从磁盘获取数据所需进行的一次或两次磁盘seek操作造成的。而写操作性能几乎不受工作集能否载入到内存的影响。
readrandom : 16.677 micros/op; (每秒大概60,000 reads)
readseq : 0.476 micros/op; 232.3 MB/s
readreverse : 0.724 micros/op; 152.9 MB/s
LevelDB为提高读性能会在后台压缩它的底层存储数据。上面的测试是在进行过大量的随机写操作之后立即进行的。在进行过compactions(通常是自动触发的)再进行测试结果会更好些。
readrandom : 11.602 micros/op; (每秒大概85,000 reads)
readseq : 0.423 micros/op; 261.8 MB/s
readreverse : 0.663 micros/op; 166.9 MB/s
某些读操作的高花费是由于从硬盘读取出的blocks的重复解压导致的。如果我们可以为LevelDB提供足够的缓存使得它可以将所有的未压缩块放入内存,那么读性能会有更大地改善:
readrandom : 9.775 micros/op; (每秒大概 100,000 reads before compaction)
readrandom : 5.215 micros/op; (每秒大概190,000 reads after compaction)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中,"import leveldb"是用于导入LevelDB的Python开发包,使得我们可以在代码中使用LevelDB的功能和方法。 当我们在代码中使用"import leveldb"时,我们可以通过创建一个LevelDB对象来打开一个数据库连接,从而可以对数据库进行读写操作。然而,如果我们尝试在已经打开的连接上再次打开连接,就会引发错误。这是因为LevelDB只允许一个进程同时持有一个数据库的锁定。如果数据库已经被其他进程锁定,就会出现"leveldb.LevelDBError: IO error: lock /var/tmp/ldb1.ldb/LOCK: already held by process"的错误提示。 此外,LevelDB还提供了一些API用法。在使用LevelDB之前,我们可以包装相关的import语句和Options对象来打开和关闭数据库连接,以及其他操作。具体的API用法可以参考LevelDB的官方文档或相关教程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [LevelDB的Python开发包 py-leveldb基本使用方法的代码](https://blog.csdn.net/weixin_43896490/article/details/121946555)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [leveldb 的部署和使用](https://blog.csdn.net/Moolight_shadow/article/details/119276763)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [leveldb:LevelDB到Java的端口](https://download.csdn.net/download/weixin_42098892/18545599)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值