R-store

来源:互联网 发布:疯狂挂机赚钱软件 编辑:程序博客网 时间:2024/04/28 08:08

可扩展的分布式RTOLAP系统 r-store,支持多版本,每个版本有时间戳。

每个OLAPquery在他提交的时间点已经存在版本的数据

而每个OLTP创建新的版本。

使用MR框架,OLAPmapper直接访问存储在存储系统中的实时数据

存储系统是由Hbase扩展的

 

A.R-store架构


4个部分:分布式kvstorestreaming系统保存real-time data cubeMR系统处理大规模OLAP请求,MetaStore存储全局变量和配置信息。

OLTP请求直接提交给KvstoreOLAP请求由MR处理。

最简单的方式就是MR扫描所有的real-time数据找到OLAP提交之前的最新版本。

Kvstore需要多版本并行控制避免OLAPOLTP不会相互block,但是这个非常低效。

改进:将real-timetable物化为data cube成为历史数据。当OLAP提交时,先从MetaStore获得query的时间戳,经过costmodel优化,OLAP转换成Mrjobinput由历史数据datacube和实时数据real-timedata组成。为了能够高效的访问real-time datakvstore支持增量扫描。扫描Real-time data使用的是IncrementalScan操作,扫描data cube使用FullScan

接下来介绍的是如何将real-timedata合并到datacube中。我们希望能够加速这一操作。

为了能够高效的更新datacube,对于kvstore的更新会stream到流系统中,real-time data cube会保存在流系统中,real-timedata会周期的物化来更新datacube。这样比重新算datacube快多了,吞吐量也足够处理来自kvstore的更新流。

一旦更新完成,data cube的最近时间戳就传到metaStore中,然后唤醒压缩进程来压缩real-timedataMetaStore还存放其他全局信息包括每个OLAP的提交时间,datacube的更新频率。

B.存储设计

Kvstore必须支持multi-version concurrency control来保证OLAPOLTP不会相互block

另外还要考虑到许多东西,高效的文件扫描操作,compaction scheme负载均衡。

1Full and Incremental Scan

FullscantiTi作为input,返回所有key的在Ti之前的最新版本,这个数据是用来计算data cube用的。

IncrementalScanT1,T2)拿T1T2作为输入,对于每个key返回T1之后的两个版本号。一个是T2之前的最新版本,另一个是T1之前的最新版本。这个操作用于RTOLAP请求的处理算法。

2global and local compactions

Global compaction:这个进程在每次data cube更新之后都会执行。对于同一个插入data cube中的key的所有版本,都合并成一个版本Vdc,与data cube对应,用于更新datacube

Local compaction本地压缩进程在每个节点上都被唤醒。首先,压缩程序会获得当前正在运行的扫描进程的提交时间。对于每一个keyTscan提交之前的最新版本的数据都会被这个进程访问。因此本地压缩进程就之访问那些scan进程不会访问的数据。还有就是Vdc不会改变。

3)负载均衡:有一些app里面某些范围的key会被经常改动,造成节点上的负载不均。另外由于update采用的是insert新版本数据所以节点上的会有数据的倾斜(某些key的版本要比其他多)。这会影响到scan的效率。解决方法就是把经常被更新的范围分散到多个节点上。。。。。。

  1. Data Cube Maintenance

为了提高OLAP的执行效率,data cube保存在kvstore中。Datacube可以使full Iceberg或者closed cube。根据应用来选择最合适的datacube类型。我们只考虑fulldata cubewhich consists of a lattice of cuboids。有两种更新data cube 的方式。

但是,并不是所有的cube都能增量更新。增量更新只能用于self-maintainable aggregate functions(新值可以从老的值计算出来)比如SUM,COUNT等等。

R-store中,重新计算的方式用于第一次建立datacube,增量更新的方法用于在流处理模块中维护real-timedatacube。流系统使用从kvstore来的流来更新自己的datacube,并且周期性的将其物化到存储系统中。由于data cube的更新包含两个阶段,因此可以自然地使用MR来处理,流版本的MR用于R-store的流处理模块。

 

R-store的实现

Hbase开源分布式kvstore。简单介绍一下Hbase的数据结构。

增量scan:对于store并行的访问storefilesmemstorekey按照升序扫描,大的时间戳能早一点扫描到。扫描key的所有版本,和时间戳作比较返回需要的两个版本。如果key只有一个版本,那就只返回这个版本。

对于data cube更新扫描kv对是开销非常大的一步。所以要提升增量scan的性能非常重要,我们提出了一个合适的增量scan算法。

首先我们使用一个in-memory的结构来评估dT),上一次datacube更新之后到现在的更新的不同key的数量。使用一个bitarray,因为每个regionkey都是连续的,所以其实就可以给他们hash0-M-1的范围中,one billion key on one node needs 128MB

为了提升性能,T1设置为TdcT2设置为Tq(提交时间)。先扫描memstore中的kv对。Memstore中有很多个版本,只有最新的版本放在kvMap中。然后计算Tdc之后更新的但是没有记录在memstore中的数量,然后估算随机读取这些kv对的代价。如果代价比扫描TdcTq之间所有的数据的代价小,那么就使用storefile的索引来直接读取这些kv对。这样用于更新的最新版本的key值就得到了。然后只要简单的扫描Tdc之前的数据,就可以把Tdc之前的最新版本返回给客户端了。


普通方式:并行的扫描memstorestorefile找到想要的版本

改进版:先扫描memstore评估的d(T)计算随机读cost如果小于扫描就随机读。


 

压缩:Hbase默认压缩进程将所有的storefile压缩到一个文件,并且每个key只保留一个版本。全局压缩类似于默认值,但是触发情况不一样;本地压缩之压缩某个时间戳之前的版本。为了保证压缩进程不会blockscan进程,压缩数据放在不同的文件中,而不是直接替换掉未压缩的数据。老版本被压缩文件替换掉当他们不再被任何scan进程访问时。由于压缩进程与OLAP争夺CPUIO资源,压缩的频率和整个系统的性能就存在一个tradeoff。当


(平均每个key的版本数超过阈值)超过阈值时本地压缩进程被触发。

负载均衡:Hbase的默认region大小是256MB。大于这个值就分裂,放到不同节点上。Hbase默认设置只能存放一定版本数量的key。更多之后就强制把老版本删除,这就需要用户手动分裂hot regionR-store就不要求强制移除老版本。等到size到了上界自行分裂。。。。。。你在逗我。。

  1.  Real-Time Data Cube Maintenance

R-store使用Hstreaming来存放real-time data cube(其他流式mr系统也可以用)。Hstreaming的每个mapper负责处理一定范围内key的更新。当一个keyupdate的请求到达,这个key的旧值is retrieved 从本地存储中检索,如果存在的话。为了高效的检索老数据,需要给kv对建立聚集索引,经常更新的key会缓存在内存中。在实际情况中,更新通常发生在小范围的key中,旧值有很高的概率需要从cache中检索到。Mapper:如果key是新的,对于每个cuboid,创建一个kv对然后shufflereducer中。Map输出的key

Cuboid+kv.valuevalue就是kv.value

Reducer:每隔wr时间invoke一次。另一个时间间隔wcube定义data cube的物化间隔。算法3说的是reduce函数如何增量更新DC。如果是在下一次Tdc发生之前产生的updatareducer就把local DCmapper给的中间值merge起来作为DC,否则存放在DC‘。当所有mapper上的update时间戳都要大于等于下一次Tdc时,data refresh进程就被唤醒,将local DC写到Hbase-R中。在refresh进程运行的过程中到来的update仍然写进DC’中,因为他们的时间戳不可能比Tdc还小。当refresh结束,Tdc增加,DCDC’merge在一起。

传统的流式系统中要容错,计算的状态就要周期性的checkpointCheckpoint之后的数据流写进log中用于恢复。R-storeDC物化到kvstore中实际就是对real-time dc的进行checkpoint。由于上次DC更新后的kv对还存放在real-time data虽然可能会有一些压缩少了一些值,但是该有的还都在。所以real-time dc的恢复只需要用dcreal-timedc就可以恢复了。

  1.  Data Flow of R-Store

图二描述了Hbase-RHsreamingMR的数据流动。


每个regionserver处理几个region。有一些是real-timedata的,有一些是DC的。OLTP提交到某个region server上,存放在这个regionmemstore中。如果memstore超过了上界就写到storefile中存在HDFS里。一旦把更新写入Hbase-R,就把以流的形式输入Hstreamingmapper中,每个cuboid的改变都会计算并shufflereducer里。Reducer这边,real-time datacube把这些更新的信息存放在本地。每隔一段时间,Hstreaming就把本地的datacube物化到Hbase-R里,然后把最新的DC时间戳通知MetaStore。压缩进程开始启动,将DC更新之前的版本压缩掉。

 

real-timeOLAP

之前说的是R-strore的架构。本节讨论real-time OLAP是如何执行的。在R-Store中如果MR job的输入只有DC,那么在扫描阶段 map端的performance是最大化的,但是结果可能就比较老旧。为了最大化OLAPquery的新鲜度,所有在query提交之前的kv对就都应该考虑在内。因此除了DC real-timetable也必须扫描。

假设DC的创建时间是Tdc OLAP的提交时间是Tq。对于Tdc之后更新的key,如果TqTdc设置的不一样的话,那么在realtime data 上执行的IncrementalScan会返回Tdc之前的版本和Tq之前的最新版本。通过使用这两个版本和每个cuboid上的值merge一下就可以得到需要的value,并且满足OLAPfreshness的需求。下面的小节介绍了query processing algorithm 使用了IncrementalScan操作,该算法叫做IncreQuerying

 

  1.  Querying incrementally-Maintained Cube

实现了MultiTableInputFormat每个MR job都可以扫描多个table上的数据,并且扫描操作可以使full或增量scan。这样就可以通过fullscan访问cuboid表上的数据,增量scan就可以访问real-time表上的数据。

算法4描述了mapMapper根据filter

The mappers增加filter来区别数据来自cell还是tuple。对于用来计算聚集函数的celltuple把它们分配到同一个reducer上。Cell的输出就是the selected numeric valuetuple的输出是原值,用来重新计算numeric valueValue加上tag Q+-Q表示是否是cell的值,-代表旧值,+代表新值。过程与增量update比较相似,除了增加一个filter并且partition keyDC的维度数不一样。???

ReduceReduce根据每个cell的老值、cell的变化量及聚集函数计算出新值。Cell keyreduce和算法3不同。

For example, for the TPCH part table,to compute a rectangular subset of the cube

(mfgr =“Manufacturer#13”), the key of the reduce function

is the combination of the attributes (brand to container) after

removing mfgr.

图三show the data flow OLAPquery on a二维cuboidmfgrbrand


计算每个由M1生产的牌子的price的和。为了保证结果的freshness,两个表都要扫描。注意到cuboid的列key是二维属性的结合。因此,如果filtercondition里面包含一些

“Manufacturer#1” and “Brand#13”这样的限制,能够作为row key的前缀,Hbase-R中的扫描就可以避免扫描整个DC

The min key for the range scan is “Manufacturer#1,Brand#13”,

and the max key is “Manufacturer#1,Brand#14”.

我们把merge real-time数据和DC的操作user透明,我们封装了一些新的DC操作,并且自动的将这些操作转化成Mrjob。算法5

  1. Query结果的准确性

OLAP提交时这个queryMetaStore拿一个Tq的时间戳。为了保证正确性,如果query需要多次扫描一个表,每个node上的扫描进程总会返回Tq之前的数据。然而,在分布式系统中,尽管可以在一定程度上同步时钟,不同节点上可能还是有不同。如果节点k上的当前时间戳TkTq小,那么多次扫描节点k的表就会导致不一致。解决方法就是等到tq小于等于tk。在局域网时钟同步能够达到1ms的准确性,因此相比于执行时间,这个延迟可以忽略。

  1. Cost Model

IncreQuerying算法并不总是好的。增量扫描不仅扫描real-time table也扫描DC,导致更高的代价。另外他一个keyshuffle2个版本的数据到MR中。当只有少量的OLTPOLTP之访问比较小范围的key时,IQ算法比较好因为IS只发送少量的数据。另一种real-time querying的实现方案类似于重新计算DC:使用fullscan,不论他是否被更新过,每个KV对只返回一个版本。当update均匀分布在所有key上时,这个实现方式更加高效。为了选择一种更为高效的方式,我们提出了costmodel。最重要的是是sT=dT/|T|DC更新后更新过的key占的百分比。

  1. )基础方法:用普通的IS还是使用adaptiveIS取决于节点的状态,因此我们就都当做是普通的IS。所以开销我们就按照传输的tuple数量来计算。Mapper扫描,mapper输出,外部排序,mapper shufflereducer,归并,写入文件系统

把每个key传输一个版本,MR job扫描阶段的开销就是

Cscan= shHBase× |T | × f(T)

Mapper的输出是每个tuple一个kv对,因此map的输出大小就是

SMO= s(Q)×(|T|/mT)× (d(Q)+n(Q))

外部排序map的输出开销:

Csortmap= mT× 2cL× ((SMO× logB(SMO/(B+ 1)))

mapper结束,reducer开始。Shuffle的开销:

Cshuffling= shMR× s(Q)× |T| × (d(Q)+n(Q))

拉过来的数据放在本地文件系统,开销可以忽略,

shuffle和本地写是流水线方式的。数据用多路归并,只需读写文件一次:

Creducemerge= 2cL× s(Q)× |T| × (d(Q) + n(Q))

最后结果表写入Hbase-R,开销:

Creducewrite= wHBase× |Q| ×(d(Q) + n(Q))

  1. )IQ算法:Mpjob会读DCupdated数据。Mapper扫描real-time dataDC

把数据shufflemapper的开销是

CscanR= shHBase× 2|T| × f(T)× s(T)

扫描CD的开销时:

CscanC= shHBase× |C| × (d(C) + n(C))

Map的输出大小是:

SMOR= 2 ×(s(Q)× |T| × s(T)/mT) ×(d(Q) + n(Q))

SMOC= (|C|/mC)× s(Q)× (d(Q) + n(Q))

外部排序开销:

SMOR= 2 ×(s(Q)× |T| × s(T)/mT) ×(d(Q) + n(Q))

SMOC= (|C|/mC)× s(Q)× (d(Q) + n(Q))

Mapperreducershufflecost

Cshuffling=shMR× s(Q)×((2× |T| × s(T) +|C|)× (d(Q) + n(Q))

Reduce阶段,sortmergecost

Cshuffling=shMR× s(Q)×

((2 × |T| × s(T) +|C|)× (d(Q) +n(Q))

写进HDFS的代价:

Creducewrite= wHBase× |Q| × (d(Q) + n(Q))

根据这个cost model,就能动态决定real-time query提交之后选择哪种方式。

0 0
原创粉丝点击