Hamsterdb vs. LevelDB:且看非主流数据库的自白和逆袭

【编者按】虽已问世9年之久,但是相较MongoDB,Hamsterdb的知名度仍然有所欠缺,更一度被评为非主流数据库。Hamsterdb是个开源的键值类型数据库。但是区别于其他NoSQL,Hamsterdb是单线程和非分布式的,其特性设计也更像是一个列存储数据库,同时还支持read-committed隔离级别的ACID事务。那么对比LevelDB,Hamsterdb又会有什么优势,这里我们走进项目参与者之一Christoph Rupp的分享。

以下为译文:

在这篇文章中,我想向大家介绍Hamsterdb——一个基于Apache 2-licensed协议的嵌入式分析型键值数据库,类似于谷歌的LevelDB和甲骨文的BerkeleyDB。

Hamsterdb并不是一个新的竞争者。事实上,Hamsterdb已经问世了9年。这一次,它成长得很快,并且专注于键值存储的数据库分析技术,类似于列存储数据库。

Hamsterdb是单线程和非分布式的,它可以直接连接到用户应用程序中。Hamsterdb提供一种独特的事务实现,以及有类似于列存储数据库所具备的特性,非常适合于分析型工作负载。它可以被C/C++原生调用,也面向Erlang、Python、Java、NET、甚至是Ada等编程语言。同时,它还在嵌入式设备和前置应用程序中得到了上千万的部署,以及服务于云端——例如高速缓存和索引,已经有数以百万计的部署。

Hamsterdb在键值存储中有一个独特的功能:它能识别架构信息。尽管大多数数据库无法分析出或关注被插入键类型,但是hamsterdb支持两种类型的键值:binary key(固定长度VS.可变长度)和numerical key键(比如uint32、uint64、real32、real64)。

Hamsterdb的数据库也是被存储在文件或存储器的Btree索引。使用Btree让hamsterdb的分析能力变得强大。Btree索引应用了C++模块,该模块参数取决于键类型和日志的大小(固定长度vs.可变长度),与键是否重复无关,因而每一个Btree节点对于工作负载来说是高可用的。因为键的定长,所以每一个键是零负载的,而且键被排列得像简单数组。在聚焦索引的最底层,uint64键数据库支持 uint64_t类型的C数组。

这种实现减少了I/O并更加有效地利用了CPU缓存。当今的CPU需要对内存性能进行优化处理,这也是Hamsterdb的一大优势。例如,通过搜索叶节点时,二进制搜索在可用内存达到一定阀值时会被跳过,取而代之的是线性搜索。而且,hamsterdb具有等价于SQL commands COUNT、COUNT DISTINCT、SUM 和AVERAGE的API,鉴于直接在Btree上运行,使得它能够快速地工作在固定长度的键上。

Hamsterdb也支持可变长度的键。因此,每个Btree节点有一个非常小的索引提前指向节点的有效负载。这可能导致现有键长度调整或删除后的重组,因此必须对节点做“抽空(vacuumized)”操作,从而避免浪费空间。这个操作会成为一个性能杀手,在速度提升上面临着巨大挑战,因此能少用则少用。

Hamsterdb允许副本键,这意味着某个键可能指向多条记录,键的所有记录都会被组织在一起。他们可用于处理可变长度键的索引结构。(如果一个键有许多备份记录,他们将被从Btree中删除并存储于独立的溢出区)

Hamsterdb支持read-committed隔离级别的ACID事务。事务更新可作为delta-operations存储于存储器中。每个数据库都会有独立的事务索引,这些事务中的更新比BTree中有着更高的优先级。中止事务只意味着放弃事务索引中该事务的更新,并把事务更新交给Btree。

独特的设计选择带来强大的优势。事务升级留在RAM中而不是请求I/O。不再需要事务终止逻辑,因为事务一旦被终止就不会继续执行。恢复逻辑使用了一份简单的逻辑日志,但也存在着一个重要挑战:运行时,两个树必须被合并。想象使用数据库cursor 去完成一个全面扫描,这样的结果是非常复杂的。一些键存在于Btree中,一些在事务树里。在事务树中,Btree里的键可以被重写或者删除,甚至会存在被其他键修改的情况。因此,在涉及到多个键时,这点非常困扰。

Hamsterdb最强力的特性是可测试性。数据库的基本准则是不能丢失数据,这点比性能尤为重要。关键性的Bugs都可被解决的。另外,在九年的开发过程中,为了解决技术负债问题,那些在特定情况下出现的拙劣设计基本上被祛除了,正以敏捷、快速反应的姿态响应用户的需求和新理念,我一直在重写部分代码或者尝试新的想法。高可测试覆盖给了我很大的信心,因为我的更改不会破坏任何东西。

专注于可测试性和高度自动化使我处理好很多事情。在最糟糕时,Hamsterdb debug充斥大量的assert和完整性检查,大约有1800个单元测试和35000个验收测试。那些验收测试中运行着几十个不同的结构,并在BerkeleyDB中并行执行。我们会持续检查两个数据库中数据的一致性,所以任何新进bug都会被马上显示出来。另外,每个测试都会给出一个细节明细表,包括内存消耗、堆分配数目、被分配页数目、Blobs(二进制大对象存储)、btree 的分裂和合并等。

有些测试可以使用valgrind。我们会对比valgrind使用前后的性能,从而快速找出问题发生的地方,并做性能修复。

另外,通过测试模拟数据库崩溃可测试hamsterdb的可恢复性。最后但同样值得关注的是,我可以使用 QuviQ的QuickCheck,一个基于Erlang语言的性能检测工具。QuickCheck让你得知软件的性能情况,然后运行pseudo-randomized指令,不断的核查完整性。

静态代码分析可与Coverity的开源产品和clang的scan-build工具一起使用。他们能发现一些细枝末节问题。

在发布前,所有的测试都是全自动和高性能的。一个完整的发布周期通常要花上几天,且每两个月都要用掉一个硬盘。

总结我学到的知识,测试编写将是一件非常有趣的事情。没有可靠性测试的迭代开发是无法简化的。

我也来介绍下hamsterdb的商业版本 Hamsterdb pro,该版本针对键、记录和日志提供了重度压缩 (zlib、snappy、lzf和lzo),以及AES加密和针对叶节点查找的SIMD优化。还有更多的压缩算法( bitmap compression和prefix compression)正在进行或计划中。网页上有更多的信息。

到目前为止尚不错,但hamsterdb的性能到底如何?我用谷歌的基准测试将Hamsterdb 2.1.8与LevelDB 1.15作了性能对比。压缩被禁用(Hamsterdb 暂未提供压缩,但是Hamsterdb pro提供了)。Fsyncs同样被禁止,它是hamsterdb的一个修复功能(通过预写日志实现)。测试大小范围从较小的键/记录到具有中等大小键和较大的记录,并且插入数据,范围从100K到100M级别。另外,我运行了两个Hamsterdb 的分析函数,LevelDB也是。所有测试运行的缓存大小从4MB到1GB,机器配备一个HDD和一个SSD。

Hamsterdb的配置总是基于定长键——为8字节键hamsterdb存储的uint64 numbers。自从LevelDB需要number转换成string后,这也就成为了hamsterdb的优势之一。

我也还增加了较小记录(size 8)的测试,因为它们含有主键时,通常会被用于辅助索引。两个机器分别使用了不同硬盘:HDD(Core i7-950 8核和8MB缓存)和一个SSD(Core i5-3550 4核和8MB缓存),下面是部分基准测试结果,详情可以看这里。

持续写;键大小:16;日志大小:100(HDD,1 GB缓存)

连续读;键大小:16;日志大小:100(HDD,1GB缓存)

随机写;键大小:16;日志大小:100(HDD,1GB缓存)

随机读;键大小:16;日志大小:100(HDD,1GB缓存)

计算所有键的综合(HDD,4MB缓存)

计算末尾是“77”的键(SSD,1GB缓存)

对于随机读,Hamsterdb的性能要好于LevelDB。对于随机写,只要数据量不是太大的时候,Hamsterdb 要快于LevelDB。而从1千万键以上开始,hamsterdb就会遭受BTree数据库的传统问题:大量的非序连续I/O的高磁盘寻道延迟。

话虽这么说,这个测试也很好地证明了Hamsterdb的分析能力。尤其是sum和count运算都可以很好地扩展。连续插入和扫描也是Hamsterdb的亮点,且不管数据量多大,它都可以非常快。

未来的工作

这个基准测试让我们发现了很多问题:通过并行hamsterdb,优化随机读/写。这将成为我工作的主要部分,而且我已经草拟一个设计方法,以及在产品发布前进行重构。

原文链接: Hamsterdb: An Analytical Embedded Key-Value Store(http://highscalability.com/blog/2014/8/13/hamsterdb-an-analytical-embedded-key-value-store.html)

(翻译/童阳 责编/仲浩)

原文发布于微信公众号 - CSDN技术头条(CSDN_Tech)

原文发表时间:2014-08-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

【Go 语言社区】在 Go 语言中,如何正确的使用并发

Glyph Lefkowitz最近写了一篇启蒙文章,其中他详细的说明了一些关于开发高并发软件的挑战,如果你开发软件但是没有阅读这篇问题,那么我建议你阅读一篇。这...

36690
来自专栏程序生活

Python爬虫系列(一)初期学习爬虫的拾遗与总结(11.4更)

---- 最近,为了提取裁判文书网的有关信息,自己迈入Python的学习之路,写了快两周的代码,自己写这篇文章总结下踩过的坑,还有遇到一些好的资料和博客等总结下...

41550
来自专栏Rainbond开源「容器云平台」

搬运向 | 浅析serverless架构与实践

1.2K50
来自专栏腾讯云数据库团队的专栏

PostgreSQL 的空闲数据块管理机制解析

PostgreSQL是通过 MVCC (Multi-Version Concurrency Control) 来保证事务的原子性和隔离性,本文通过一些事例对 M...

75510
来自专栏涤生的博客

天池中间件大赛Golang版Service Mesh思路分享

这次天池中间件性能大赛初赛和复赛的成绩都正好是第五名,出乎意料的是作为Golang是这次比赛的“稀缺物种”,这次在前十名中我也是侥幸存活在C大佬和Java大佬的...

19140
来自专栏程序人生

谈谈编译和运行

[作者按] 今天 hacker news 爆炸性的新闻是我们敬爱的葛老头:Andy Grove 去了。70后,80后大多听过这个响当当的名字,也听过(或者读过)...

41090
来自专栏小文博客

SkinMaster(原LOL换肤大师)同步更新——小文’s blog

1.1K60
来自专栏架构师之旅

3个面试中遇到的问题《JAVA面试题》

面试官:“一个http 请求,接受json数组,数组内容是id,返回用户信息,在测试上是ok的,到预生产就报错了,可能是什么问题?” 我想了想说:“代码一致吗?...

92150
来自专栏即时通讯技术

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

本系列文章引用了腾讯技术专家樊华恒《海量之道系列文章之弱联网优化 gad.qq.com/article/detail/29546》的章节,感谢原作者。

29230
来自专栏Python中文社区

用Python玩转微信的正确姿势!

0. itchat 最近研究了一些微信的玩法,我们可以通过网页版的微信微信网页版,扫码登录后去抓包爬取信息,还可以post去发送信息。 然后发现了itchat这...

62580

扫码关注云+社区

领取腾讯云代金券