Tair存储引擎资料分享



Tair存储引擎资料分享。

Tair概述

Tair是一个分布式系统,它从整体来看,是由configserver和dataserver组成的,dataserver负责数据存储,客户端首先去到configserver拿到机群的分布状态,接下来会根据数据来找到现在数据应该在哪个dataserver,然后直接跟dataserver访问。configserver一般分Master和Slave两台,当其中一台有问题的时候,客户端那边会主动上另外一台访问,保证它的容灾性。configserver是一个比较轻量化中心节点,即使两台configserver全部当掉,客户端还是可以继续服务。

dataserver是负责数据存储,Tair在设计架构的时候,真正负责数据存储这一块会有一个抽象层,把定义结果都实现掉,这样可以很方便直接接入。正是因为这些原因,dataserver这边存储引擎也是经历一些变革,到现在为止主要存储引擎可以分三种,可以分成cache和持久化两类。mdb和rdb,mdb是自主研发的系统,支持kv和分级kv,分级kv类似于模拟一个数据结构,在实际应用当中会有这样的需求。rdb抽取Redis存储部分,可以支持Redis原来的复杂数据结构。Ldb接入LeveIDB,进行数据排序。

mdb

mdb是memche系统,在内存里面,真正内存管理使用page和slab。在我们这边会抽样出一个area的概念,有很多应用会共用,一个应用给第一个area,做一个逻辑分区,可以针对area获得配额,进行数据清除,不会影响其他的应用,这样可以做到逻辑分区。有些应用有些情况下,我的一些数据这段时间不想用,可以直接清掉,这样也是可以支持的。

支持数据过期的应用,会有后台的一些逻辑来把它清理掉。它的内存使用率会是一个问题,所以我们会在一定时间去均衡slab,达到内存使用率优化。我们还对它各种操作、统计都做了很详细的监控,可以实时监控到这个机群的情况。

还有后台进程,后台进程能做两个事情,会定期对数据进行清理。另外一个为了内存利用率,会做一些均衡slab的管理,达到内存使用率的均衡。

rdb

我们调研一些产品,选用了redis,有各种复杂的数据结构,redis是一个完整的分布式系统,有网络,也有数据分区,也有存储。我们这边的Tair本身是一个分布式框架,所以只需要它的存储引擎部分,我们这边抽取了它内部存储引擎这一块,然后纳入到存储引擎层下面,这样接入进来。

具体来说rdb,因为是把接口接入,原来redis所有数据结构我们这边也都是支持的。我们不能允许这个应用无限量做使用。我们增加一个概念是logiclock比如想把erea数据都清理掉,可能对当时运行会有影响,当后台再做的时候,可以根据前面访问的时候来比较一下logiclock,来确定这个数据是不是在它的生存周期里面,如果不在生存周期里面可以做清理,就是因为这个数据是不存在的。


因为redis本身为了通用性,它的数据结构比较沉重,所以这边做了一些清量化处理,数据结构用不到的,我们也把它精简掉了。实现了一套完整的Restful协议,我们这边也在考虑做rdb的持久化,复杂数据结构一个持久化处理,我们考虑使用Ldb作为rdb的持久化,这个在我们的计划之内。

在淘宝这边,也有一些应用是需要持久化,所有数据都需要放在这边,所以持久化的需求,促使我们去考虑为Tair加一个持久化的存储,当时调研的一些产品,Google开了自己的单机存储化的存储引擎,LevelDB,当时还是很火,当时LeveIDB并不是一个大存量的,它的应用服务的都是一些小数据的场景。我们这边肯定要支持一个大数据量,所以做了一些修改。

Tair rdb(redis存储引擎)实现介绍

Redis 设计与实现

ldb

LeveIDB的写类型操作不会直接把原来的数据给覆盖掉,而是顺势写下去,由后台做数据合并。整体来说,好比一个写的操作,这个put包括一个写操作,在内存里面是有MemTable的。MemTable会有大小的,如果写满了以后,再用一个新的继续写。MemTable写满了以后,会触发它把内存当中的数据大部分存到磁盘上面去。为什么叫LeveIDB?它在管理磁盘上这些数据文件的时候,是为了独化的应用。这个大家有兴趣,可以由一些实践文档来讲具体细节。这是它的写流程。

它的读流程,比如看到每个小方块前面的首数字,MemTable这个文件,它的开始和结束是哪一部分,对于Get,整体来说就是要符合找到负责这个key的文件,从里面把这个数字给拿出来。比如我要“7”,首先要根据这个数据存在的流程去做,对每一个LO都会去找,当然如果有一步能够找到就会提前返回。对于LeveIDB,会做一些聚合,尽量读一次盘能读少一些。我们调研之后,发现LeveIDB的性能还是可以的,所以接入到Tair当中。

Ldb来做kv层面,先以put为例,找到数据分区,把操作指引给他,同时把结果插入到Mdbcache里。对于Get,首先到Ldb去找,这样的话,持久化存储引擎的效率跟缓存性效率是一样的,如果数据有访问热点的话,访问的IP可以得到很好的保证。

Ldb这边做了哪些事情?配置使用上来说,我们会多实例配置使用,充分利用IO,每个盘上能够充分利用,我们会把mdb内嵌,作为KV级别cache。内部一些阐述的配置,当时设计之初的参考,它其实并不是针对大数据这样一个情况去做的,很多情况是针对一些小数据。我们这边使用的时候,是进行一些详细测试,推出一些适合于我们某些场景的配置,对一些参数进行调优,会做一些灵活的配置。

另外就是它的排序算法,你去使用肯定要自己实践排序算法,排序算法有很多种,也可以进行默认的排序,但是像我们真正使用情况下,某些应用场景下面它会有一定的规律,如果是这样的情况下,我们根据这个规律去做一些它专有的平台,因为随机性而导致很复杂的情况。我们这样做效果是比较好的,比如写入的k是递增的情况下,我们可以根据数来改,这就是一个顺序写,顺序写是最优的场景。

Ldb的新功能,我们数据会有一些过期时间,嵌入一个datafilter逻辑,得到这个数据的时候会先过滤一下,比如设置一些过期数据,这个数据如果已经过期,它就会跳过去,就认为是不存在的。虽然持久化,但是就想把之前数据全部清掉,然后我再写入新的,这样是有异步清理。它本身的compact是自己做的,有它内部自己的过程在level-n上做,这个过程当中现在主要做的工作就是把一些垃圾数据给清理了,在做机群变动的时候,因为Tair当掉一台机器会做数据的重分布,导致数据备份的完整性和前端服务的可用性,这个过程可以把垃圾数据可以清理掉。如果按照自己的过程它不是很敏感,我们就要做高Levelcompact,我们会主动出发,加速一些range合并。使用binlog做异步跨集群数据同步。