Tair ldb(leveldb存储引擎)实现介绍

标签: Tair | 发表时间:2011-12-19 22:13 | 作者:那岩
出处:http://rdc.taobao.com/blog/cs

Tair是淘宝开源的分布式KV缓存系统,内部将功能模块化,抽离出底层存储细节,可以接入不同的存储引擎。 leveldb是Google开源的单机存储引擎,目前,已经作为Tair的持久化存储引擎ldb上线使用,这里对接入leveldb所做的处理以及修改进行介绍。

Tair首先是一个分布式的框架,有一系列策略满足CAP(数据备份,迁移复制等)。另外,还有针对应用场景的功能特性(namespace,数据过期时间,原子计数等)。接入leveldb时主要对KV操作之外的功能做相应的处理。

一. 修改配置

leveldb中有一系列参数会与读写的效率有关,将相关的配置以及编译常量统一修改成可运行时配置参数,测试选取最佳配置值。

二. 实例个数控制

首先确定在一个tair server上要启几个leveldb实例?
Tair中以桶来组织数据,如果按照一个桶一个leveldb实例,在做迁移复制的时候会很方便,但考虑如果在一块磁盘上起多个实例,那么整体看来,多个顺序写变成了随机写,每个实例的compact进程会加剧整个磁盘的随机IO,所以并不采用每个桶一个实例,而是针对磁盘的数量由相关配置控制实例的个数。

三. 内部key的格式

为实现Tair中的功能逻辑,ldb传入leveldb的user-key格式如下:

1)    Tair中的数据可以设置过期时间,过期时间保存可以保存在在value的meta中,但考虑能在leveldb内部提前检查,省去解析value的消耗,将过期时间保存在key中,但并不参与排序。
2)    Tair中的数据组织以及迁移复制都是以桶(bucket)单位,为获得一个桶的数据,添加桶号前缀,保证一个桶的数据都存储在一起。
3)    Tair中的数据区分namespace,会将namespace作为客户端传入key的前缀存储。

四. 自定义comparator

为了实现Tair中的功能逻辑,实现自定义的comparator传入leveldb,实现自定义的排序逻辑(传入leveldb的user-key中表示过期时间的前四个字节不参与排序),并为comparator添加两个判断数据是否有效的逻辑接口(ShouldDrop()/ShouldDropMaybe()),修改leveldb内部做遍历以及compact时判断数据是否有效(kTypeValue/kTypeDeletion)的逻辑。
1)    ShouldDropMaybe(): 用来判断数据是否已经过期。解析key中的expired_time即可。
2)    ShouldDrop(): 用来判断数据是否属于已经清理掉的数据(bucket已经迁移或者namespace已经被清理)。
3)    区分过期数据与清理数据的判断,是因为丢弃过期数据必须保证该key是数据的最后出现,否则删除该数据会让该key失去最后的更新状态,而清理数据有gc信息保证,不需要关心数据的状态。

五. 清理数据/自定义的内部compact逻辑

这里把清理数据的操作称为gc。
1.    迁移的bucket以及清理的namespace中的数据
一旦发生bucket迁移或者清理namespace,会把相应的信息保存下来(GcNode)

 struct GcNode
 {
   // 迁移走的bucket或者清掉的namespace
   int32_t key_;
   // 清理发生时的SequnceNumber,用来判断数据的时间点
   uint64_t sequence_;
   // 清理发生时的FileNumber,用来缩小compact的范围
   uint64_t file_number_;
   // 清理发生时的时间
   uint32_t when_;
 };

1)    Tair中会有桶迁移或者namespace清理的操作,废弃的数据并不会立刻清理,依靠后续的compact进程清理。但同时桶又可能被迁移回来,namespace也可能继续使用。leveldb中的SequnceNumber恰好可以标识数据的时间点,所以在做数据清理的时候,记录下当时的SequnceNumber(sequnce_),在做判断的时候,只有小于sequnce_的数据才认为可以被丢弃。
2)    filenumber_是为了缩小主动compact的范围。
leveldb自身进行compact的过程中,加入自实现comparator的ShouldDropMaybe()/ShouldDrop()判断逻辑,会将对应的gc数据清理。但leveldb自身的compact进程并不能保证将所有的数据清理掉,所以添加compact的定时线程,主动触发compact做数据清理。对于清理的bucket或者namespace,根据key的格式,可以构造出需要compact的key-range,但直接使用leveldb提供的CompactRange有以下问题:
1)    如果某个sstable在记录gc之后已经被compact过,所要清理的数据就已经丢弃掉了,并不需要再做compact。
2)    主动触发的compact并不是基于均衡db状态,所以造成的level迁移可能会有反作用。
对于1)2)的问题,做以下策略:
1)    FileNumber全局递增可以用来标识时间点,gc时,记录下当时的FileNumber,主动compact时,只需要选取符合key-range并且FileNumber小于记录的filenumber_的sstable即可,缩小需要compact的sstable范围。
2)    主动触发的compact只选取level-n中的sstable,compact后,也只生成level-n中的sstable,level之间的均衡,仍由内部compact进程负责。
3)    基于上述1) 2),为leveldb添加CompactRangeSelfLevel()逻辑,实现1) 2)中的策略,主动触发compact以清理数据,整个db的均衡仍由内部的机制保证。
gc信息会同时记binlog,在server重启时replay。

2.    过期的数据
因为过期是一个持续的时间状态,如果要完全回收过期的数据,只能对全db做compact,这样做的性能比不合算,所以目前对过期数据不做特别的主动清理,依靠内部以及外部触发的compact进程中回收空间。

六. 上层cache

leveldb内部有sstable元信息和block数据的cache,优化读的效率,在leveldb上层再嵌入Tair自带的mdb做KV层面的cache,并添加cache的信息统计。当前统计看到,热点数据的读基本落在mdb中。

七. 后续的优化

1)    leveldb本身的一些优化(参见 leveldb的实现解析)。
2)    优化网络的使用,使用新的网络框架。
3)    ssd使用优化。leveldb内部做的一些细节优化针对于sas盘的IO性能,当前使用的ssd IO能也未充分利用。后续针对提升ssd使用性能做相应的IO优化(dio)。
4)     内存的优化使用。大内存的使用有很大的优化余地,避免swap的使用,pagecache的相应回写策略配置。
5)    对不存在数据查找的优化,采用mock value处理或者添加bloomilter。
6)    range 以及数据dump功能的实现。

欢迎大家对leveldb的使用优化提出宝贵建议。

广告时间: Tair现在已经将 Redis的存储部分抽离出来,作为非持久化的存储引擎rdb,即将上线使用,欢迎大家强势围观。

相关 [tair ldb leveldb] 推荐:

Tair ldb(leveldb存储引擎)实现介绍

- - 淘宝核心系统团队博客
Tair是淘宝开源的分布式KV缓存系统,内部将功能模块化,抽离出底层存储细节,可以接入不同的存储引擎. leveldb是Google开源的单机存储引擎,目前,已经作为Tair的持久化存储引擎ldb上线使用,这里对接入leveldb所做的处理以及修改进行介绍. Tair首先是一个分布式的框架,有一系列策略满足CAP(数据备份,迁移复制等).

Google开源LevelDB

- 酿泉 - Solidot
Google宣布在BSD许可证下开源其键值存储引擎LevelDB. LevelDB C++库可用于多种不同环境,如被浏览器用于存储最近访问的网页缓存,或者被操作系统使用去储存安装的软件包和依赖包清单,或被应用程序用于存储用户设置. Google称,即将发布的新版Chrome浏览器,就包含了基于LevelDB的IndexedDB HTML5 API实现.

LevelDB:实现(译)

- 高春辉 - 银河里的星星
  作者:Jeff Dean, Sanjay Ghemawat. 原文:http://leveldb.googlecode.com/svn/trunk/doc/impl.html. 译者:phylips@bmy 2011-8-17. 出处:http://duanple.blog.163.com/blog/static/7097176720112643946178/ .

Tair: 淘宝的key/value解决方案

- duxin - 若海的blog
今天我们对外开源了Tair,Tair是由淘宝开发的key/value解决方案,你可以在这里获取更多信息. Tair在淘宝有着大规模的应用,在你登录淘宝、查看商品详情页面、在淘江湖和好友“捣浆糊”等等时候,后面都在直接或间接的和Tair交互. Tair是一个分布式的key/value结构数据的解决方案,系统默认支持基于内存和文件的存储引擎,对应于通常我们所说的缓存和持久化存储.

LevelDB内部实现

- Ben - NoSQLFan
本文是一篇转载的翻译文章,翻译对象是LevelDB的官方文档中实现一章,主要描述了LevelDB内部的数据结构,文件结构及相关的存储,压缩恢复等功能的实现过程,看完后你就能知道,LevelDB为什么会叫这个名字了. 作者:Jeff Dean, Sanjay Ghemawat. 原文:leveldb.googlecode.com.

cpy-leveldb:Python 版的 LevelDB

- Ken - python.cn(jobs, news)
>>> db.Get("2") '222' >>> db.Get("5") '' >>> db.Write(batch) >>> db.Get("5") 'hello world 5' >>> db.Get("2") 'hello world 2' >>> iter = leveldb.Iterator(db) Iterator_init executed.

LevelDB学习交流

- gnawux - NoSQLFan
下面PPT作者是@淘宝解伦,PPT中对LevelDB的特点、设计思想及实现原理都有所涵盖,是一篇不错的LevelDB入门教材. 对LevelDB感兴趣的同学可以看看. LevelDB中的Skip List(跳跃表). 一个NoSQL与MongoDB的介绍PPT. RethinkDB 与 TokuDB 调研测试报告.

LevelDB实现解析

- - NoSQLFan
LevelDB是Google开发的一个key-value存储,其已经作为存储引擎被Riak和Kyoto Tycoon所支持( 这里和 这里),在国内 淘宝的 Tair开源key-value存储也已经将LevelDB作为其持久化存储引擎,并部署在线上使用. 下面PDF就是 淘宝核心系统研发团队的那岩总结的LevelDB内部实现的长文.

Leveldb的实现原理

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