网易视频云是网易公司旗下的视频云服务产物,以Paas服务模式,向开辟者提供音视频编解码SDK和开放API,助力APP接入音视频功能。
如今,网易视频云的技能专家给各人分享一篇技能性文章:HBaseBlockCache系列-性能对比测试陈诉.
HBaseBlockCache系列文章到了闭幕篇,几个主角的是黑白非也该有个了断了,在SlabCache被早早地镌汰之后,站在西岳之巅的也就仅剩LRU君(LRUBlockCache)和CBC君(CombinedBlockCache)。谁赢谁输,我说了不算,你说了也不算,那就来让数听说话。这篇文章重要对比LRU君和CBC君(offheap模式)分别在四种场景下几种指标(GC、Throughput、Latency、CPU、IO等)的表现环境。四种场景分别是缓存全部掷中、少大部分缓存掷中、少量缓存掷中、缓存根本未掷中。
必要留意的是,本文的全部数据都来自社区文档,在这里分享也只是给各人一个参考,更加具体的测试数据可以阅读文章《ComparingBlockCacheDeploys》和HBASE-11323附件陈诉。
阐明:本文全部图都以时间为横坐标,纵坐标为对应指标。每张图都会分别表现LRU君和CBC君的四种场景数据,总计八种场景,下面数据表现LRU君的四种场景分布在时间段21:36:39~22:36:40,CBC君的四种场景分布在时间段23:02:16~00:02:17,看图的时间必要特别留意。
LRU君:
TueJul2221:36:39PDT2014runsize=32,clients=25;lrubctime=1200缓存全部掷中
TueJul2221:56:39PDT2014runsize=72,clients=25;lrubctime=1200大量缓存掷中
TueJul2222:16:40PDT2014runsize=144,clients=25;lrubctime=1200少量缓存掷中
TueJul2222:36:40PDT2014runsize=1000,clients=25;lrubctime=1200缓存根本未掷中
CBC君:
TueJul2223:02:16PDT2014runsize=32,clients=25;buckettime=1200缓存全部掷中
TueJul2223:22:16PDT2014runsize=72,clients=25;buckettime=1200大量缓存掷中
TueJul2223:42:17PDT2014runsize=144,clients=25;buckettime=1200少量缓存掷中
WedJul2300:02:17PDT2014runsize=1000,clients=25;buckettime=1200缓存根本未掷中
GC
GC指标是HBase运维最关心的指标,出现一次长时间的GC就会导致这段时间内业务方的全部读写哀求失败,假如业务方没有很好的容错,就会出现丢数据的环境出现。根据下图可知,只有在‘缓存全部掷中’的场景下,LRU君总GC时间25ms比CBC君的75ms短;其他三种场景下,LRU君表现都没有CBC君好,总GC时间根本均是CBC君的3倍左右。
Thoughput
吞吐量大概是全部HBase用户初次利用最关心的题目,这根本反映了HBase的读写性能。下图是随机读测试的吞吐量曲线,在‘缓存全部掷中’以及‘大量缓存掷中’这两种场景下,LRU君可谓是完胜CBC君,特别是在‘缓存全部掷中’的场景下,LRU君的吞吐量乃至是CBC君的两倍;而在‘少量缓存掷中’以及‘缓存根本未掷中’这两种场景下,两者的表现根本相称;
Latency
读写耽误是另一个用户很关心的指标,下图表现在全部四种环境下LRU君和CBC君都在伯仲之间,LRU君略胜一筹。
IO
接下来两张图是资源利用图,运维同砚大概会比力关心。从IO利用环境来看,两者在四种场景下也根本雷同。
CPU
再来看看CPU利用环境,在‘缓存全部掷中’以及‘大量缓存掷中’这两种场景下,LRU君依然完胜CBC君,特别是在‘缓存全部掷中’的场景下,CBC君差不多做了两倍于LRU君的工作;而在‘少量缓存掷中’以及‘缓存根本未掷中’这两种场景下,两者的表现根本相称;
结论
看完了全部比力紧张的指标对比数据,我们可以得出以下两点:
1.在’缓存全部掷中’场景下,LRU君可谓完胜CBC君。因此假如总数据量相比JVM内存容量很小的时间,选择LRU君;
2.在全部其他存在缓存未掷中环境的场景下,LRU君的GC性能险些只有CBC君的1/3,而吞吐量、读写耽误、IO、CPU等指标两者根本相称,因此发起选择CBC。
至此,HBaseBlockCache系列文章就竣事了,假如各人尚有什么交换讨论大概增补的,可以留言大概发邮件至libisthanks@gmail.
Categories:HBase,性能Tags:blockcache
HBaseBlockCache系列-探求BlockCache实现机制
April26th,2016范欣欣阅读(0)Commentsoff
HBaseBlockCache系列第一篇文章《走进BlockCache》从全局视角对HBase中缓存、Memstore等作了扼要概述,并重点先容了几种BlockCache方案及其演进过程,对此还不相识的可以点这里。本文在上文的底子上深入BlockCache内部,对各种BlockCache方案具体工作原理举行具体分析。Note:由于SlabCache方案在0.98版本已经不被发起利用,因此本文不针对该方案举行讲授;至于LRU方案和Bucket方案,由于后者更加复杂,本文也会花更多篇幅具体先容该方案的实现细节。
LRUBlockCache
LRUBlockCache是HBase如今默认的BlockCache机制,实现机制比力简单。它利用一个ConcurrentHashMap管理BlockKey到Block的映射关系,缓存Block只必要将BlockKey和对应的Block放入该HashMap中,查询缓存就根据BlockKey从HashMap中获取即可。同时该方案采取严格的LRU镌汰算法,当BlockCache总量到达肯定阈值之后就会启动镌汰机制,近来最少利用的Block会被置换出来。在具体的实现细节方面,必要关注三点:
1.缓存分层战略
HBase在LRU缓存底子上,采取了缓存分层计划,将整个BlockCache分为三个部分:single-access、mutil-access和inMemory。必要特别留意的是,HBase体系元数据存放在InMemory区,因此设置数据属性InMemory=true必要非常审慎,确保此列族数据量很小且访问频仍,否则有大概会将hbase.meta元数据挤出内存,严峻影响全部业务性能。
2.LRU镌汰算法实现
体系在每次cacheblock时将BlockKey和Block放入HashMap后都会查抄BlockCache总量是否到达阈值,假如到达阈值,就会唤醒镌汰线程对Map中的Block举行镌汰。体系设置三个MinMaxPriorityQueue队列,分别对应上述三个分层,每个队列中的元素按照近来最少被利用分列,体系会优先poll出近来最少利用的元素,将其对应的内存开释。可见,三个分层中的Block会分别实行LRU镌汰算法举行镌汰。
3.LRU方案优缺点
LRU方案利用JVM提供的HashMap管理缓存,简单有效。但随着数据从single-access区提拔到mutil-access区,根本就陪伴着对应的内存对象从young区到old区,提拔到old区的Block被镌汰后会变为内存垃圾,终极由CMS采取掉(ConccurentMarkSweep,一种标记打扫算法),然而这种算法会带来大量的内存碎片,碎片空间不停累计就会产生污名昭著的FullGC。尤其在大内存条件下,一次FullGC很大概会连续较长时间,乃至到达分钟级别。各人知道FullGC是会将整个进程停息的(称为stop-the-wold停息),因此长时间FullGC肯定会极大影响业务的正常读写哀求。也正由于如许的弊端,SlabCache方案和BucketCache方案才会横空出世。
BucketCache
相比LRUBlockCache,BucketCache实现相对比力复杂。它没有利用JVM内存管理算法来管理缓存,而是本身对内存举行管理,因此不会由于出现大量碎片导致FullGC的环境发生。本节重要先容BucketCache的具体实现方式(包罗BucketCache的内存构造情势、缓存写入读取流程等)以及怎样设置利用BucketCache。
内存构造情势
下图是BucketCache的内存构造情势图,此中上面部分是逻辑构造布局,下面部分是对应的物理构造布局。HBase启动之后会在内存中申请大量的bucket,如下图中黄色矩形所示,每个bucket的巨细默认都为2MB。每个bucket会有一个baseoffset变量和一个size标签,此中baseoffset变量表现这个bucket在实际物理空间中的起始地点,因此block的物理地点就可以通过baseoffset和该block在bucket的偏移量唯一确定;而size标签表现这个bucket可以存放的block块的巨细,比如图中左侧bucket的size标签为65KB,表现可以存放64KB的block,右侧bucket的size标签为129KB,表现可以存放128KB的block。
HBase中利用BucketAllocator类实现对Bucket的构造管理:
1.HBase会根据每个bucket的size标签对bucket举行分类,雷同size标签的bucket由同一个BucketSizeInfo管理,如上图,左侧存放64KBblock的bucket由65KBBucketSizeInfo管理,右侧存放128KBblock的bucket由129KBBucketSizeInfo管理。
2.HBase在启动的时间就决定了size标签的分类,默认标签有(4+1)K、(8+1)K、(16+1)K…(48+1)K、(56+1)K、(64+1)K、(96+1)K…(512+1)K。而且体系会起首从小到大遍历一次全部size标签,为每种size标签分配一个bucket,末了全部剩余的bucket都分配最大的size标签,默认分配(512+1)K,如下图所示:
3.Bucket的size标签可以动态调解,比如64K的block数量比力多,65K的bucket被用完了以后,其他size标签的完全空闲的bucket可以转换成为65K的bucket,但是至少保存一个该size的bucket。
Block缓存写入、读取流程
下图是block写入缓存以及从缓存中读取block的流程表示图,图中重要包罗5个模块,此中RAMCache是一个存储blockkey和block对应关系的HashMap;WriteThead是整个block写入的中心枢纽,重要负责异步的写入block到内存空间;BucketAllocator在上一节具体先容过,重要实现对bucket的构造管理,为block分配内存空间;IOEngine是具体的内存管理模块,重要实现将block数据写入对应地点的内存空间;BackingMap也是一个HashMap,用来存储blockKey与对应物理内存偏移量的映射关系,用来根据blockkey定位具体的block;此中紫线表现cacheblock流程,绿线表现getblock流程。
Block缓存写入流程
1.将block写入RAMCache。实际实现中,HBase设置了多个RAMCache,体系起首会根据blockkey举行hash,根据hash结果将block分配到对应的RAMCache中;
2.WriteThead从RAMCache中取出全部的block。和RAMCache雷同,HBase会同时启动多个WriteThead并发的实行异步写入,每个WriteThead对应一个RAMCache;
3.每个WriteThead会将遍历RAMCache中全部block数据,分别调用bucketAllocator为这些block分配内存空间;
4.BucketAllocator会选择与block巨细对应的bucket举行存放(具体细节可以参考上节‘内存构造情势’所述),而且返回对应的物理地点偏移量offset;
5.WriteThead将block以及分配好的物理地点偏移量传给IOEngine模块,实行具体的内存写入操纵;
6.写入乐成后,将雷同blockkey,offset如许的映射关系写入BackingMap中,方便后续查找时根据blockkey可以直接定位;
Block缓存读取流程
1.起首从RAMCache中查找。对于还没有来得及写入到bucket的缓存block,肯定存储在RAMCache中;
2.假如在RAMCache中没有找到,再在BackingMap中根据blockKey找到对应物理偏移地点offset;
3.根据物理偏移地点offset可以直接从内存中查找对应的block数据;
BucketCache工作模式
BucketCache默认有三种工作模式:heap、offheap和file;这三种工作模式在内存逻辑构造情势以及缓存流程上都是雷同的,拜见上节讲授。差别的是三者对应的终极存储介质有所差别,即上述所讲的IOEngine有所差别。
此中heap模式和offheap模式都利用内存作为终极存储介质,内存分配查询也都利用JavaNIOByteBuffer技能,差别的是,heap模式分配内存会调用byteBuffer.allocate方法,从JVM提供的heap区分配,而后者会调用byteBuffer.allocateDirect方法,直接从操纵体系分配。这两种内存分配模式会对HBase实际工作性能产生肯定的影响。影响最大的无疑是GC,相比heap模式,offheap模式由于内存属于操纵体系,以是根本不会产生CMSGC,也就在任何环境下都不会由于内存碎片导致触发FullGC。除此之外,在内存分配以及读取方面,两者性能也有差别,比如,内存分配时heap模式必要起首从操纵体系分配内存再拷贝到JVMheap,相比offheap直接从操纵体系分配内存更耗时;但是反过来,读取缓存时heap模式可以从JVMheap中直接读取,而offheap模式则必要起首从操纵体系拷贝到JVMheap再读取,显得后者更费时。
file模式和前面两者差别,它利用Fussion-IO大概SSD等作为存储介质,相比昂贵的内存,如许可以提供更大的存储容量,因此可以极大地提拔缓存掷中率。
BucketCache设置利用
BucketCache方案的设置阐明不停被HBaser所诟病,官方不停没有相干文档对此举行先容。本人也是不停被其所困,厥后通过查察源码才根本相识清楚,在此分享出来,以便各人学习。必要留意的是,BucketCache三种工作模式的设置会有所差别,下面也是分开先容,而且没有列出很多不紧张的参数:
heap模式
hbase.bucketcache.ioengineheap/hbase.bucketcache.ioengine
//bucketcache占用整个jvm内存巨细的比例
hbase.bucketcache.size0.4/hbase.bucketcache.size
//bucketcache在combinedcache中的占比
hbase.bucketcache.combinedcache.percentage0.9/hbase.bucketcache.combinedcache.percentage
offheap模式
hbase.bucketcache.ioengineoffheap/hbase.bucketcache.ioengine
hbase.bucketcache.size0.4/hbase.bucketcache.size
hbase.bucketcache.combinedcache.percentage0.9/hbase.bucketcache.combinedcache.percentage
file模式
hbase.bucketcache.ioenginefile:/cache_path/hbase.bucketcache.ioengine
//bucketcache缓存空间巨细,单位为MB
hbase.bucketcache.size10*1024/hbase.bucketcache.size
//高速缓存路径
hbase.bucketcache.persistent.pathfile:/cache_path/hbase.bucketcache.persistent.path
总结
HBase中缓存的设置对随机读写性能至关紧张,本文通过对LRUBlockCache和BucketCache两种方案的实现举行先容,盼望可以或许让各位看官更加深入地相识BlockCache的工作原理。BlockCache系列颠末两篇内容的先容,根本已经分析完毕,那在实际线上应用中到底应该选择哪种方案呢?下一篇文章让我们一起看看HBase社区发布的BlockCache陈诉!
Categories:BucketCache,HBase,LRUBlockCacheTags:blockcache
HBase–RegionServer宕机案件侦查
April15th,2016范欣欣阅读(0)Commentsoff
原来安谧的晚上,吃着葡萄干看着球赛,多么惬意。可偏偏一条报警短信如闪电一样平常冲破了夜晚的寂静,线上集群一台RS宕了!于是倏地从床上坐起来,看了看监控,刹时惊呆了:单台呆板的读写吞吐量竟然到达了5wops/sec!RS宕机是由于这么大的写入量造成的?假如真是如许,它是怎么造成的?假如不是如许,那又是什么缘故起因?各种疑问刹时从脑筋里逐一闪过,甭管那么多,先把日记备份一份,再把RS拉起来。接下来还是Bug排查老套路:日记、监控和源码三管齐下,来看看到底发生了什么!
案件现场篇
下图是利用监控工具Ganglia对事发RegionServer当时读写吞吐量的监控曲线,从图中可以看出,约莫在19点~21点半的时间段内,这台RS的吞吐量都维持了3wops/sec左右,峰值更是到达了6wops/sec。之前我们就线上单台RS可以或许遭受的最大读写吞吐量举行过测定,根本也就维持在2w左右,重要是由于网络带宽瓶颈。而在宕机前这台RS的读写吞吐量超出这么多,直觉告诉我RS宕机缘故起因就是它!
接着就赶紧把日记拉出来看,满屏的responseTooSlow,如下图所示:
很显然,这种非常最大大概缘故起因就是FullGC,果然,颠末耐烦地排查,可以看到很多如下所示的FullGC日记片断:
2016-04-1421:27:13,174WARN[JvmPauseMonitor]util.JvmPauseMonitor:DetectedpauseinJVMorhostmachine(egGC):pauseofapproximately20542ms
GCpool'ParNew'hadcollection(s):count=1time=0ms
GCpool'ConcurrentMarkSweep'hadcollection(s):count=2time=20898ms
2016-04-1421:27:13,174WARN[regionserver60020.periodicFlusher]util.Sleeper:Weslept20936msinsteadof100ms,thisislikelyduetoalonggarbagecollectingpauseandit'susuallybad,seehttps://hbase.apache.org/book.html#trouble.rs.runtime.zkexpired
可以看出,HBase实行了一次CMSGC,导致整个进程全部线程被挂起了20s。通过对MemStore的监控也可以看出这段时间GC力度之大,如下图所示:
GC时间长最显着的危害是会造成上层业务的壅闭,通过日记也可以看出些许端倪:
java.io.IOException:Connectionresetbypeer
atsun.nio.ch.FileDispatcherImpl.read0(NativeMethod)
atsun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
atsun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
atsun.nio.ch.IOUtil.read(IOUtil.java:197)
atsun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:384)
atorg.apache.hadoop.hbase.ipc.RpcServer.channelRead(RpcServer.java:2246)
atorg.apache.hadoop.hbase.ipc.RpcServer$Connection.readAndProcess(RpcServer.java:1496)
....
2016-04-1421:32:40,173WARN[B.DefaultRpcServer.handler=125,queue=5,port=60020]ipc.RpcServer:RpcServer.respondercallId:7540service:ClientServicemethodName:Multisize:100.2Kconnection:10.160.247.139:56031:outputerror
2016-04-1421:32:40,173WARN[B.DefaultRpcServer.handler=125,queue=5,port=60020]ipc.RpcServer:B.DefaultRpcServer.handler=125,queue=5,port=60020:caughtaClosedChannelException,thismeansthattheserverwasprocessingarequestbuttheclientwentaway.Theerrormessagewas:null
上述日记表现HBase服务端由于FullGC导致不停无法相应用户哀求,用户客户端程序在肯定时间过后就会SocketTimeout并断掉此Connection。毗连断掉之后,服务器端就会打印如上日记。然而,这些和我们的终极目标好像并没有太大关系,别忘了我们的目标是找到RS宕机的缘故起因哦!
破案铺垫篇
颠末对案件现场的排查,唯一有效的线索就是HBase在宕机前履历了很严峻、很频仍的FullGC,从下面日记可以进一步看出,这些FullGC都是在concurrentmodefailure模式下发生的,也就是假造机还未实行完本次GC的环境下又来了大量数据导致JVM内存不敷,此时假造机遇将全部用户线程挂起,实行长时间的FullGC!
(concurrentmodefailure):45876255K-21800674K(46137344K),10.0625300secs]48792749K-21800674K(49283072K),[CMSPerm:43274K-43274K(262144K)],10.2083040secs][Times:user=12.02sys=0.00,real=10.20secs]
2016-04-1421:22:43,990WARN[JvmPauseMonitor]util.JvmPauseMonitor:DetectedpauseinJVMorhostmachine(egGC):pauseofapproximately10055ms
GCpool'ParNew'hadcollection(s):count=2time=244ms
GCpool'ConcurrentMarkSweep'hadcollection(s):count=1time=10062ms
上文提到FullGC会对上层业务产生很严峻的影响,那有没有大概会对下层依靠方也产生很大的影响呢?究竟是Yes!而且,RS宕机的大部分缘故起因也要归咎于此!
进一步查察日记,发现HBase日记中出现下述非常:
2016-04-1421:22:44,006WARN[ResponseProcessorforblockBP-632656502-10.160.173.93-1448595094942:blk_1073941840_201226]hdfs.DFSClient:DFSOutputStreamResponseProcessorexceptionforblockBP-632656502-10.160.173.93-1448595094942:blk_1073941840_201226java.io.IOException:BadresponseERRORforblockBP-632656502-10.160.173.93-1448595094942:blk_1073941840_201226fromdatanode10.160.173.93:50010
atorg.apache.hadoop.hdfs.DFSOutputStream$DataStreamer$ResponseProcessor.run(DFSOutputStream.java:732)
从日记内容来看应该是hbase调用DFSClient从datanode加载block数据”BP-632656502-10.160.173.93-1448595094942:blk_1073941840_201226″,但是datanode返回失败。具体失败缘故起因必要查察datanode节点日记,如下所示:
2016-04-1421:22:43,789INFOorg.apache.hadoop.hdfs.server.datanode.DataNode:opWriteBlockBP-632656502-10.160.173.93-1448595094942:blk_1073941840_201226receivedexceptionjava.net.SocketTimeoutException:10000millistimeoutwhilewaitingforchanneltobereadyforread.ch:java.nio.channels.SocketChannel[connectedlocal=/10.160.173.94:50010remote=/10.160.173.94:30110]
2016-04-1421:22:43,779ERRORorg.apache.hadoop.hdfs.server.datanode.DataNode:hz-hbase4.photo.163.org:50010:DataXceivererrorprocessingWRITE_BLOCKoperationsrc:/10.160.173.94:30123dest:/10.160.173.94:50010
java.net.SocketTimeoutException:10000millistimeoutwhilewaitingforchanneltobereadyforread.ch:java.nio.channels.SocketChannel[connectedlocal=/10.160.173.94:50010remote=/10.160.173.94:30123]
很显然,从日记可以看出,datanode不停在等待来自客户端的read哀求,但是直至SocketTimeout,哀求都没有过来,此时datanode会将该毗连断开,导致客户端收到上述”BadresponseERROR***”的非常。
那这和FullGC有什么关系呢?很简单,就是由于FullGC导致HBase全部内部线程挂起,因此发往datanode的read哀求也被挂起了,datanode就等啊等,左等右等都等不到,万不得已才将毗连断掉。
查察Hadoop客户端源码可知,假如DFSClient发生上述非常,DFSClient会将一个全局标记errorIndex设为一个非零值。具体可拜见DFSOutputStream类中如下代码片断:
破案了局篇
上述铺垫篇末了的结果就是Hadoop客户端会将一个全局标记errorIndex设为一个非零值,那这到底和终极RS宕掉有什么关系呢?来继承往下看。下图HBase日记相干片断截图,记录了比力具体的RS宕机非常信息,我们就以这些非常信息作为切入点举行分析,可以看出至少三条有效的线索,如下图所示:
线索一:RS宕机最直接的缘故起因是由于体系在关闭LogWriter(之后会重新开启一个新的HLog)的时间失败
线索二:实行LogWriter关闭失败的缘故起因是”writingtrailer”时发生IOException非常
线索三:而发生IOException非常的缘故起因是”Alldatanodes***arebad”
到这里为止,我们可以或许得到的最靠谱的谍报就是RS宕机本质是由于”Alldatanodes***arebad”造成的,看字面意思就是这台datanode由于某种缘故起因坏掉了,那我们赶紧去看看datanode的日记,看看谁人时间段有没有相干的非常大概错误日记。
然而很遗憾,datanode日记在谁人时间点没有打印任何非常大概错误日记,而且表现全部服务都正常,信息如下所示:
2016-04-1421:32:38,893INFOorg.apache.hadoop.hdfs.server.datanode.DataNode.clienttrace:src:127.0.0.1,dest:127.0.0.1,op:REQUEST_SHORT_CIRCUIT_FDS,blockid:1073941669,srvID:DS-22834907-10.160.173.94-50010-1448595406972,success:true
2016-04-1421:32:38,894INFOorg.apache.hadoop.hdfs.server.datanode.DataNode.clienttrace:src:127.0.0.1,dest:127.0.0.1,op:REQUEST_SHORT_CIRCUIT_FDS,blockid:1073941669,srvID:DS-22834907-10.160.173.94-50010-1448595406972,success:true
...
看到这里,是不是有点蒙圈:HBase日记内里显着打印说这台datanode坏掉了,但是实际datanode日记表现服务统统正常。这个时间就得翻翻源码了,看看HBase在那边打印的”Alldatanodes***arebad“,通过查察源码,可以看出终极首恶就是上文提到的errorIndex,如下图所示:
终于拨开天日了,再不完结就要晕了!上文铺垫篇铺垫到末了就得出来由于FullGC终极导致DFSClient将一个全局标记errorIndex设为一个非零值,在这里终于见面了,简直泪流满面!
案件梳理篇
整个流程走下来本人都有点晕晕的,涉及的方方面面太多,因此有须要把整个流程完备的梳理一遍,下面简单画了一个表示图:
颠末对整个案件的整理分析,一方面再次锻炼了怎样通过监控、日记以及源码定位排查问题的功底,另一方面在HBase运维过程中也必要特别关注如下几点:
1.FullGC不但会严峻影响上层业务,造成业务读写哀求的卡顿。别的尚有大概造成与HDFS之间数据哀求的各种非常,这种非常严峻的时间乃至会导致RegionServer宕机。
2.上文中提到FullGC根本是由于ConcurrentModeFailure造成,这种FullGC场景比力少见,通常可以通过减小JVM参数XX:CMSInitiatingOccupancyFraction来克制,这个参数用来设置CMS垃圾采取机遇,假如此时设置为60,表现JVM内已利用内存占到总内存的60%的时间就会举行垃圾采取,镌汰该值可以使得垃圾采取更早举行。
3.肯定要严格限定业务层面的流量。一方面必要和业务方交换,由业务方举行限定,另一方面可以探索HBase业务资源隔离的新方案;
Categories:HBase,RegionServer,宕机Tags:
HBaseBlockCache系列–走进BlockCache
April14th,2016fanxinxin阅读(191)Nocomments
和其他数据库一样,优化IO也是HBase提拔性能的不二法宝,而提供缓存更是优化的重中之重。最抱负的环境是,全部数据都可以或许缓存到内存,如许就不会有任何文件IO哀求,读写性能肯定会提拔到极致。然而实际是暴虐的,随着哀求数据的不绝增多,将数据全部缓存到内存显得不合实际。荣幸的是,我们并不必要将全部数据都缓存起来,根据二八法则,80%的业务哀求都会合在20%的热门数据上,因此将这部分数据缓存起就可以极大地提拔体系性能。
HBase在实现中提供了两种缓存布局:MemStore和BlockCache。此中MemStore称为写缓存,HBase实行写操纵起首会将数据写入MemStore,并次序写入HLog,等满意肯定条件后同一将MemStore中数据革新到磁盘,这种计划可以极大地提拔HBase的写性能。不但云云,MemStore对于读性能也至关紧张,假如没有MemStore,读取刚写入的数据就必要从文件中通过IO查找,这种代价显然是昂贵的!BlockCache称为读缓存,HBase会将一次文件查找的Block块缓存到Cache中,以便后续同一哀求大概相近数据查找哀求,可以直接从内存中获取,克制昂贵的IO操纵。MemStore相干知识可以戳这里,本文将重点分析BlockCache。
在先容BlockCache之前,简单地回顾一下HBase中Block的概念,具体先容戳这里。Block是HBase中最小的数据存储单位,默以为64K,在建表语句中可以通过参数BlockSize指定。HBase中Block分为四种范例:DataBlock,IndexBlock,BloomBlock和MetaBlock。此中DataBlock用于存储实际数据,通常环境下每个DataBlock可以存放多条KeyValue数据对;IndexBlock和BloomBlock都用于优化随机读的查找路径,此中IndexBlock通过存储索引数据加快数据查找,而BloomBlock通过肯定算法可以过滤掉部分肯定不存在待查KeyValue的数据文件,镌汰不须要的IO操纵;MetaBlock重要存储整个HFile的元数据。
BlockCache是RegionServer级别的,一个RegionServer只有一个BlockCache,在RegionServer启动的时间完成BlockCache的初始化工作。到如今为止,HBase先后实现了3种BlockCache方案,LRUBlockCache是最初的实现方案,也是默认的实现方案;HBase0.92版本实现了第二种方案SlabCache,见HBASE-4027;HBase0.96之后官方提供了另一种可选方案BucketCache,见HBASE-7404。
这三种方案的差别之处在于对内存的管理模式,此中LRUBlockCache是将全部数据都放入JVMHeap中,交给JVM举行管理。而后两者采取了差别机制将部分数据存储在堆外,交给HBase本身管理。这种演变过程是由于LRUBlockCache方案中JVM垃圾采取机制常常会导致程序长时间停息,而采取堆外内存对数据举行管理可以有效克制这种环境发生。
LRUBlockCache
HBase默认的BlockCache实现方案。Block数据块都存储在JVMheap内,由JVM举行垃圾采取管理。它将内存从逻辑上分为了三块:single-access区、mutil-access区、in-memory区,分别占到整个BlockCache巨细的25%、50%、25%。一次随机读中,一个Block块从HDFS中加载出来之后起首放入signle区,后续假如有多次哀求访问到这块数据的话,就会将这块数据移到mutil-access区。而in-memory区表现数据可以常驻内存,一样平常用来存放访问频仍、数据量小的数据,比如元数据,用户也可以在建表的时间通过设置列族属性IN-MEMORY=true将此列族放入in-memory区。很显然,这种计划战略雷同于JVM中young区、old区以及perm区。无论哪个区,体系都会采取严格的Least-Recently-Used算法,当BlockCache总量到达肯定阈值之后就会启动镌汰机制,最少利用的Block会被置换出来,为新加载的Block预留空间。
SlabCache
为了办理LRUBlockCache方案中由于JVM垃圾采取导致的服务停止,SlabCache方案利用JavaNIODirectByteBuffer技能实现了堆外内存存储,不再由JVM管理数据内存。默认环境下,体系在初始化的时间会分配两个缓存区,分别占整个BlockCache巨细的80%和20%,每个缓存区分别存储固定巨细的Block块,此中前者重要存储小于便是64K巨细的Block,后者存储小于便是128KBlock,假如一个Block太大就会导致两个区都无法缓存。和LRUBlockCache雷同,SlabCache也利用Least-Recently-Used算法对逾期Block举行镌汰。和LRUBlockCache差别的是,SlabCache镌汰Block的时间只必要将对应的bufferbyte标记为空闲,后续cache对其上的内存直接举行覆盖即可。
线上集群环境中,差别表差别列族设置的BlockSize都大概差别,很显然,默认只能存储两种固定巨细Block的SlabCache方案不能满意部分用户场景,比如用户设置BlockSize=256K,简单利用SlabCache方案就不能到达这部分Block缓存的目标。因此HBase实际实现中将SlabCache和LRUBlockCache搭配利用,称为DoubleBlockCache。一次随机读中,一个Block块从HDFS中加载出来之后会在两个Cache中分别存储一份;缓存读时起首在LRUBlockCache中查找,假如CacheMiss再在SlabCache中查找,此时假如掷中再将该Block放入LRUBlockCache中。
颠末实际测试,DoubleBlockCache方案有很多弊端。比如SlabCache计划中固定巨细内存设置会导致实际内存利用率比力低,而且利用LRUBlockCache缓存Block依然会由于JVMGC产生大量内存碎片。因此在HBase0.98版本之后,该方案已经被不发起利用。
BucketCache
SlabCache方案在实际应用中并没有很洪流平改善原有LRUBlockCache方案的GC弊端,还额外引入了诸如堆外内存利用率低的缺陷。然而它的计划并不是一无可取,至少在利用堆外内存这个方面给予了阿里大牛们很多开导。站在SlabCache的肩膀上,他们开辟了BucketCache缓存方案并贡献给了社区。
BucketCache通过设置可以工作在三种模式下:heap,offheap和file。无论工作在那种模式下,BucketCache都会申请很多带有固定巨细标签的Bucket,和SlabCache一样,一种Bucket存储一种指定BlockSize的数据块,但和SlabCache差别的是,BucketCache会在初始化的时间申请14个差别巨细的Bucket,而且纵然在某一种Bucket空间不敷的环境下,体系也会从其他Bucket空间借用内存利用,不会出现内存利用率低的环境。接下来再来看看差别工作模式,heap模式表现这些Bucket是从JVMHeap中申请,offheap模式利用DirectByteBuffer技能实现堆外内存存储管理,而file模式利用雷同SSD的高速缓存文件存储数据块。
实际实现中,HBase将BucketCache和LRUBlockCache搭配利用,称为CombinedBlockCache。和DoubleBlockCache差别,体系在LRUBlockCache中重要存储IndexBlock和BloomBlock,而将DataBlock存储在BucketCache中。因此一次随机读必要起首在LRUBlockCache中查到对应的IndexBlock,然后再到BucketCache查找对应数据块。BucketCache通过更加公道的计划修正了SlabCache的弊端,极大低落了JVMGC对业务哀求的实际影响,但也存在一些题目,比如利用堆外内存会存在拷贝内存的题目,肯定程度上会影响读写性能。固然,在厥后的版本中这个题目也得到了办理,见HBASE-11425。
本文是HBaseBlockCache系列文章的第一篇,重要概述了HBase中MemStore和BlockCache,再分别对三种BlockCache方案举行了根本先容。接下来第二篇文章会重要对LRUBlockCache和BucketCache两种方案举行具体的先容,敬请等待!
Categories:HBaseTags:blockcache,hbase
MySQLXPlugin来也
April12th,2016AskInside阅读(0)Commentsoff
MySQL5.7.12版本发布,固然之前5.7已经GA,但这个版本依然承上启下,举足轻重,由于MySQLXPlugin来了。
XPluginextendsMySQLServertobeabletofunctionasad[......]
阅读全文
Categories:MySQLTags:
HBaseBlockCache系列–走进BlockCache
April8th,2016范欣欣阅读(0)Commentsoff
和其他数据库一样,优化IO也是HBase提拔性能的不二法宝,而提供缓存更是优化的重中之重。最抱负的环境是,全部数据都可以或许缓存到内存,如许就不会有任何文件IO哀求,读写性能肯定会提拔到极致。然而实际是暴虐的,随着哀求数据的不绝增多,将数据全部缓存到内存显得不合实际。荣幸的是,我们并不必要将全部数据都缓存起来,根据二八法则,80%的业务哀求都会合在20%的热门数据上,因此将这部分数据缓存起就可以极大地提拔体系性能。
HBase在实现中提供了两种缓存布局:MemStore和BlockCache。此中MemStore称为写缓存,HBase实行写操纵起首会将数据写入MemStore,并次序写入HLog,等满意肯定条件后同一将MemStore中数据革新到磁盘,这种计划可以极大地提拔HBase的写性能。不但云云,MemStore对于读性能也至关紧张,假如没有MemStore,读取刚写入的数据就必要从文件中通过IO查找,这种代价显然是昂贵的!BlockCache称为读缓存,HBase会将一次文件查找的Block块缓存到Cache中,以便后续同一哀求大概相近数据查找哀求,可以直接从内存中获取,克制昂贵的IO操纵。MemStore相干知识可以戳这里,本文将重点分析BlockCache。
在先容BlockCache之前,简单地回顾一下HBase中Block的概念,具体先容戳这里。Block是HBase中最小的数据存储单位,默以为64K,在建表语句中可以通过参数BlockSize指定。HBase中Block分为四种范例:DataBlock,IndexBlock,BloomBlock和MetaBlock。此中DataBlock用于存储实际数据,通常环境下每个DataBlock可以存放多条KeyValue数据对;IndexBlock和BloomBlock都用于优化随机读的查找路径,此中IndexBlock通过存储索引数据加快数据查找,而BloomBlock通过肯定算法可以过滤掉部分肯定不存在待查KeyValue的数据文件,镌汰不须要的IO操纵;MetaBlock重要存储整个HFile的元数据。
BlockCache是RegionServer级别的,一个RegionServer只有一个BlockCache,在RegionServer启动的时间完成BlockCache的初始化工作。到如今为止,HBase先后实现了3种BlockCache方案,LRUBlockCache是最初的实现方案,也是默认的实现方案;HBase0.92版本实现了第二种方案SlabCache,见HBASE-4027;HBase0.96之后官方提供了另一种可选方案BucketCache,见HBASE-7404。
这三种方案的差别之处在于对内存的管理模式,此中LRUBlockCache是将全部数据都放入JVMHeap中,交给JVM举行管理。而后两者采取了差别机制将部分数据存储在堆外,交给HBase本身管理。这种演变过程是由于LRUBlockCache方案中JVM垃圾采取机制常常会导致程序长时间停息,而采取堆外内存对数据举行管理可以有效克制这种环境发生。
LRUBlockCache
HBase默认的BlockCache实现方案。Block数据块都存储在JVMheap内,由JVM举行垃圾采取管理。它将内存从逻辑上分为了三块:single-access区、mutil-access区、in-memory区,分别占到整个BlockCache巨细的25%、50%、25%。一次随机读中,一个Block块从HDFS中加载出来之后起首放入signle区,后续假如有多次哀求访问到这块数据的话,就会将这块数据移到mutil-access区。而in-memory区表现数据可以常驻内存,一样平常用来存放访问频仍、数据量小的数据,比如元数据,用户也可以在建表的时间通过设置列族属性IN-MEMORY=true将此列族放入in-memory区。很显然,这种计划战略雷同于JVM中young区、old区以及perm区。无论哪个区,体系都会采取严格的Least-Recently-Used算法,当BlockCache总量到达肯定阈值之后就会启动镌汰机制,最少利用的Block会被置换出来,为新加载的Block预留空间。
SlabCache
为了办理LRUBlockCache方案中由于JVM垃圾采取导致的服务停止,SlabCache方案利用JavaNIODirectByteBuffer技能实现了堆外内存存储,不再由JVM管理数据内存。默认环境下,体系在初始化的时间会分配两个缓存区,分别占整个BlockCache巨细的80%和20%,每个缓存区分别存储固定巨细的Block块,此中前者重要存储小于便是64K巨细的Block,后者存储小于便是128KBlock,假如一个Block太大就会导致两个区都无法缓存。和LRUBlockCache雷同,SlabCache也利用Least-Recently-Used算法对逾期Block举行镌汰。和LRUBlockCache差别的是,SlabCache镌汰Block的时间只必要将对应的bufferbyte标记为空闲,后续cache对其上的内存直接举行覆盖即可。
线上集群环境中,差别表差别列族设置的BlockSize都大概差别,很显然,默认只能存储两种固定巨细Block的SlabCache方案不能满意部分用户场景,比如用户设置BlockSize=256K,简单利用SlabCache方案就不能到达这部分Block缓存的目标。因此HBase实际实现中将SlabCache和LRUBlockCache搭配利用,称为DoubleBlockCache。一次随机读中,一个Block块从HDFS中加载出来之后会在两个Cache中分别存储一份;缓存读时起首在LRUBlockCache中查找,假如CacheMiss再在SlabCache中查找,此时假如掷中再将该Block放入LRUBlockCache中。
颠末实际测试,DoubleBlockCache方案有很多弊端。比如SlabCache计划中固定巨细内存设置会导致实际内存利用率比力低,而且利用LRUBlockCache缓存Block依然会由于JVMGC产生大量内存碎片。因此在HBase0.98版本之后,该方案已经被不发起利用。
BucketCache
SlabCache方案在实际应用中并没有很洪流平改善原有LRUBlockCache方案的GC弊端,还额外引入了诸如堆外内存利用率低的缺陷。然而它的计划并不是一无可取,至少在利用堆外内存这个方面给予了阿里大牛们很多开导。站在SlabCache的肩膀上,他们开辟了BucketCache缓存方案并贡献给了社区。
BucketCache通过设置可以工作在三种模式下:heap,offheap和file。无论工作在那种模式下,BucketCache都会申请很多带有固定巨细标签的Bucket,和SlabCache一样,一种Bucket存储一种指定BlockSize的数据块,但和SlabCache差别的是,BucketCache会在初始化的时间申请14个差别巨细的Bucket,而且纵然在某一种Bucket空间不敷的环境下,体系也会从其他Bucket空间借用内存利用,不会出现内存利用率低的环境。接下来再来看看差别工作模式,heap模式表现这些Bucket是从JVMHeap中申请,offheap模式利用DirectByteBuffer技能实现堆外内存存储管理,而file模式利用雷同SSD的高速缓存文件存储数据块。
实际实现中,HBase将BucketCache和LRUBlockCache搭配利用,称为CombinedBlockCache。和DoubleBlockCache差别,体系在LRUBlockCache中重要存储IndexBlock和BloomBlock,而将DataBlock存储在BucketCache中。因此一次随机读必要起首在LRUBlockCache中查到对应的IndexBlock,然后再到BucketCache查找对应数据块。BucketCache通过更加公道的计划修正了SlabCache的弊端,极大低落了JVMGC对业务哀求的实际影响,但也存在一些题目,比如利用堆外内存会存在拷贝内存的题目,肯定程度上会影响读写性能。固然,在厥后的版本中这个题目也得到了办理,见HBASE-11425。
本文是HBaseBlockCache系列文章的第一篇,重要概述了HBase中MemStore和BlockCache,再分别对三种BlockCache方案举行了根本先容。接下来第二篇文章会重要对LRUBlockCache和BucketCache两种方案举行具体的先容,敬请等待!。
Categories:BucketCache,HBase,LRUBlockCache,SlabCacheTags:blockcache
开源MySQL多线程逻辑导入工具myloader原理与改进
April5th,2016wzpywzh阅读(0)Commentsoff
在上一篇中,先容了多线程备份工具mydumper的实现及网易对其所做的优化,本篇聊聊与mydumper共同利用的myloader工具。
myloader是MySQL范畴少有的多线程的规复工具,为了可以或许更好的明白其怎样举行工作,有须要对mydumper[……]
阅读全文
Categories:MySQLTags:
支持redis节点高可用的twemproxy
April5th,2016何李夫阅读(419)Nocomments
原生twemporxy
twemproxy支持一个proxy实例同时署理多个分布式集群(serverpools),每个集群利用差别的网络端口实现数据流的隔离,下图中port1应用于cluster1署理,port2应用于cluster2署理:
本日要先容的是twemproxy对redis节点高可用的支持,拿上图的此中一个分布式集群举行示例,逻辑布局如下:
客户端client流入的哀求,在proxy上举行路由分片,然后转发到后端的redis节点上存储大概读取。究竟上,各人已经留意到后端的redis节点只有一个点,在出现非常环境下,是很轻易掉线的。按twemproxy的计划,它可以主动辨认失效节点并将其剔除,同时落在原来节点上的哀求会分摊到别的的节点上。这是分布式缓存体系的一种通用做法,但必要忍受这个失效节点上的数据丢失,这种环境是否可以担当?
在业内,redis固然被定位为缓存体系,但究竟上,无论哪种业务场景(我们打仗过的)都不肯意担当节点掉线带来的数据丢失,由于那样对他们体系的影响着实太大了,更有甚者在压力大的时间引起后端数据库被击穿的风险。以是,我们筹划改造twemproxy,前后统共有几个版本,下面分享给各位的是我们如今线上在跑的版本。
定制化改造
在上图的底子上,我们增长了与manager交互的模块、增长了与sentinel(redis-sentinel)交互的模块,修改了redis连担当理模块,图中三个赤色虚线框所示:
manager交互模块
增长毗连manager的客户端交互模块,用于发送心跳消息,从心跳应答包里获取group名称列表和sentinel列表(IP/PORT信息),即整个分布式集群的设置信息,此中心跳消息带有版本信息,发送隔断可设置。
sentinel交互模块
增长与sentinel客户端交互模块(IP/PORT信息来自于manager),发送group名称给sentinel获取redis主节点的IP/PORT信息,一个group对应一个主节点。取到全部主节点后,订阅主从切换频道,获取切换消息用于触发proxy和主节点间的毗连切换。这里必要分析sentinel的相应消息,会比力繁琐一些。当proxy开始与sentinel节点的交互过程,必要启动定时器,用以控制交互结果,当定时器超时交互未竣事(大概proxy未正常工作),proxy将主动切换到下一个sentinel节点,并启动新的交互过程。思量到proxy与sentinel之间网络毗连的紧张性(毗连假死,proxy收不到主从切换消息,不能正常切换),增长了定时心跳机制,确保这条TCP链路的可用性。
redis连担当理模块
原先redis节点的IP/PORT信息来自于静态设置文件,是固定的,而改造以后这些信息是从sentinel节点获取。为了确保获取到的IP/PORT信息的正确性,必要向IP/PORT对应的节点验证是否是主节点的逻辑,只有返回确认是主节点,才以为是合法的。整个过程,按官方引导实现,不存在弊端。
具体消息流
为了清楚的形貌proxy的内部处理惩罚逻辑,制作了如下消息流图:
绿色为业务通道,用于透传业务层数据;
紫色为下令通道(红线的细化),用于初始化和节点主从切换:
箭头1:managerheartbeatreq;
箭头2:managerheartbeatrsp;
箭头3:sentinelget-master-addr-by-namereq;
箭头4:sentinelget-master-addr-by-namersp;
箭头5:redisauthrolereq;
箭头6:redisauthrolersp;
箭头7:sentinelpsubscribe+switch-masterreq;
箭头8:sentinelpsubscribe+switch-masterrsp;
箭头9:sentinelpmessage;
下令通道下令次序按数字1-8举行,7/8是proxy与sentinel的心跳消息,9是主从切换消息;
高可用影响面分析
在sentinel节点切换的过程中,存在proxy正在对外提供业务服务的状态,这时间正在处理惩罚的数据将继承处理惩罚,不会受到影响,而新接入的客户端毗连将会被拒绝,已有的客户端毗连上的新的业务哀求数据也会被拒绝。sentinel节点切换,对体系的影响是毫秒级别,前面的计划对业务体系来讲会显得比力友爱、不那么粗鲁;
而redis节点的主从切换对体系的影响,重要会合在proxy发现主节点非常到sentinel集群做出主从切换这个过程,这段时间内落在该节点上的业务都将失败,而该时间段的长度重要依靠在sentinel节点上的down-after-milliseconds设置字段;
履历总结
作为署理中心件,支持pipeline的本领有限,轻易产生消息积存,导致客户端大量超时,以是慎用pipeline功能;
高负荷下轻易吃内存,structmsg和structmbuf对象会被大量缓存在进程内(内存池化);
zerocopy,对于多个连续哀求(TCP粘包)举行拆分,拷贝是无法克制的,但是有优化空间;
问卷观察
Readmore…
Categories:redisTags:
HBase–探索HFile索引机制
April3rd,2016范欣欣阅读(0)Commentsoff
HFile索引布局分析
HFile中索引布局根据索引层级的差别分为两种:single-level和mutil-level,前者表现单层索引,后者表现多级索引,一样平常为两级或三级。HFileV1版本中只有single-level一种索引布局,V2版本中引入多级索引。之以是引入多级索引,是由于随着HFile文件越来越大,DataBlock越来越多,索引数据也越来越大,已经无法全部加载到内存中(V1版本中一个RegionServer的索引数据加载到内存会占用险些6G空间),多级索引可以只加载部分索引,低落内存利用空间。上一篇文章《HBase-存储文件HFile布局分析》,我们提到BloomFilter内存利用题目是促使V1版本升级到V2版本的一个缘故起因,再加上这个缘故起因,这两个缘故起因就是V1版本升级到V2版本最紧张的两个因素。
V2版本IndexBlock有两类:RootIndexBlock和NonRootIndexBlock,此中NonRootIndexBlock又分为IntermediateIndexBlock和LeafIndexBlock两种。HFile中索引布局雷同于一棵树,RootIndexBlock表现索引数根节点,IntermediateIndexBlock表现中心节点,LeafIndexblock表现叶子节点,叶子节点直接指向实际数据块。
HFile中除了DataBlock必要索引之外,上一篇文章提到过BloomBlock也必要索引,索引布局实际上就是采取了single-level布局,文中BloomIndexBlock就是一种RootIndexBlock。
对于DataBlock,由于HFile刚开始数据量较小,索引采取single-level布局,只有RootIndex一层索引,直接指向数据块。当数据量渐渐变大,RootIndexBlock满了之后,索引就会变为mutil-level布局,由一层索引变为两层,根节点指向叶子节点,叶子节点指向实际数据块。假如数据量再变大,索引层级就会变为三层。
下面就针对RootindexBlock和NonRootindexBlock两种布局举行分析,由于RootIndexBlock已经在上面一篇文章中分析过,此处简单带过,重点先容NonRootIndexBlock布局(InterMediateIndexBlock和IeafIndexBlock在内存和磁盘中存储格式雷同,都为NonRootIndexBlock格式)。
RootIndexBlock
RootIndexBlock表现索引树根节点索引块,可以作为bloom的直接索引,也可以作为data索引的根索引。而且对于single-level和mutil-level两种索引布局对应的RootIndexBlock略有差别,本文以mutil-level索引布局为例举行分析(single-level索引布局是mutual-level的一种简化场景),在内存和磁盘中的格式如下图所示:
此中IndexEntry表现具体的索引对象,每个索引对象由3个字段构成,BlockOffset表现索引指向数据块的偏移量,BlockDataSize表现索引指向数据块在磁盘上的巨细,BlockKey表现索引指向数据块中的第一个key。除此之外,尚有别的3个字段用来记录MidKey的相干信息,MidKey表现HFile全部DataBlock中中心的一个DataBlock,用于在对HFile举行split操纵时,快速定位HFile的中心位置。必要留意的是single-level索引布局和mutil-level布局相比,就只缺少MidKey这三个字段。
RootIndexBlock会在HFile分析的时间直接加载到内存中,此处必要留意在TrailerBlock中有一个字段为dataIndexCount,就表现此处IndexEntry的个数。由于IndexEntry并不定长,只有知道Entry的个数才华精确的将全部IndexEntry加载到内存。
NonRootIndexBlock
当HFile中DataBlock越来越多,single-level布局的索引已经不敷以支持全部数据都加载到内存,必要分化为mutil-level布局。mutil-level布局中NonRootIndexBlock作为中心层节点大概叶子节点存在,无论是中心节点还是叶子节点,其都拥有雷同的布局,如下图所示:
和RootIndexBlock雷同,NonRootIndexBlock中最核心的字段也是IndexEntry,用于指向叶子节点块大概数据块。差别的是,NonRootIndexBlock布局中增长了block块的内部索引entryOffset字段,entryOffset表现indexEntry在该block中的相对偏移量(相对于第一个indexEntry),用于实现block内的二分查找。全部非根节点索引块,包罗Intermediateindexblock和leafindexblock,在其内部定位一个key的具体索引并不是通过遍历实现,而是利用二分查找算法,如许可以更加高效快速地定位到待查找key。
HFile数据完备索引流程
相识了HFile中数据索引块的两种布局之后,就来看看怎样利用这些索引数据块举行数据的高效检索。整个索引体系雷同于MySQL的B+树布局,但是又有所差别,比B+树简单,并没有复杂的分裂操纵。具体见下图所示:
图中上面三层为索引层,在数据量不大的时间只有最上面一层,数据量大了之后开始分裂为多层,最多三层,如图所示。最下面一层为数据层,存储用户的实际keyvalue数据。这个索引树布局雷同于InnoSQL的聚集索引,只是HBase并没有辅助索引的概念。
图中红线表现一次查询的索引过程(HBase中相干类为HFileBlockIndex和HFileReaderV2),根本流程可以表现为:
1.用户输入rowkey为fb,在rootindexblock中通过二分查找定位到fb在’a’和’m’之间,因此必要访问索引’a’指向的中心节点。由于rootindexblock常驻内存,以是这个过程很快。
2.将索引’a’指向的中心节点索引块加载到内存,然后通过二分查找定位到fb在index‘d’和’h’之间,接下来访问索引’d’指向的叶子节点。
3.同理,将索引’d’指向的中心节点索引块加载到内存,一样通过二分查找定位找到fb在index‘f’和’g’之间,末了必要访问索引’f’指向的数据块节点。
4.将索引’f’指向的数据块加载到内存,通过遍历的方式找到对应的keyvalue。
上述流程中由于中心节点、叶子节点和数据块都必要加载到内存,以是io次数正常为3次。但是实际上HBase为block提供了缓存机制,可以将频仍利用的block缓存在内存中,可以进一步加快实际读取过程。以是,在HBase中,通常一次随机读哀求最多会产生3次io,假如数据量小(只有一层索引),数据已经缓存到了内存,就不会产生io。
索引块分裂
上文中已经提到,当数据量少、文件小的时间,只必要一个rootindexblock就可以完成索引,即索引树只有一层。当数据不绝写入,文件变大之后,索引数据也会相应变大,索引布局就会由single-level变为mulit-level,期间涉及到索引块的写入和分裂,本节来关注一下数据写入是怎样引起索引块分裂的。
假如各人之前看过HBase系列另一篇博文《HBase数据写入之MemstoreFlush》,可以知道memstoreflush重要分为3个阶段,第一个阶段会讲memstore中的keyvalue数据snapshot,第二阶段再将这部分数据flush的HFile,并天生在临时目次,第三阶段将临时文件移动到指定的ColumnFamily目次下。很显然,第二阶段将keyvalue数据flush到HFile将会是关注的重点(flush相干代码在DefaultStoreFlusher类中)。整个flush阶段又可以分为两阶段:
1.append阶段:memstore中keyvalue起首会写入到HFile中数据块
2.finalize阶段:修改HFlie中meta元数据块,索引数据块以及Trailer数据块等
append流程
具体keyvalue数据的append以及finalize过程在HFileWriterV2文件中,此中append流程可以大要表征为:
a.预查抄:查抄key的巨细是否大于前一个key,假如大于则不符合HBase次序分列的原理,抛出非常;查抄value是否是null,假如为null也抛出非常
b.block是否写满:查抄当前DataBlock是否已经写满,假如没有写满就直接写入keyvalue;否则就必要实行数据块落盘以及索引块修改操纵;
c.数据落盘并修改索引:假如DataBlock写满,起首将block块写入流;再天生一个leafindexentry,写入leafIndexblock;再查抄该leafindexblock是否已经写满必要落盘,假如已经写满,就将该leafindexblock写入到输出流,而且为索引树根节点rootindexblock新增一个索引,指向叶子节点(second-levelindex)
d.天生一个新的block:重新reset输出流,初始化startOffset为-1
e.写入keyvalue:将keyvalue以流的方式写入输出流,同时必要写入memstoreTS;除此之外,假如该key是当前block的第一个key,必要赋值给变量firstKeyInBlock
finalize阶段
memstore中全部keyvalue都颠末append阶段输出到HFile后,会实行一次finalize过程,重要更新HFile中meta元数据块、索引数据块以及Trailer数据块,此中对索引数据块的更新是我们关心的重点,此处具体分析,上述append流程中c步调’数据落盘并修改索引’会使得rootindexblock不绝增多,当增大到肯定程度之后就必要分裂,分裂表示图如下图所示:
上图所示,分裂前索引布局为second-level布局,图中没有画出DataBlocks,根节点索引指向叶子节点索引块。finalize阶段体系会对RootIndexBlock举行巨细查抄,假如巨细大于规定的巨细就必要举行分裂,图中分裂过程实际上就是将原来的RootIndexBlock块分割成4块,每块独立形成中心节点InterMediateIndexBlock,体系再重新天生一个RootIndexBlock(图中赤色部分),分别指向分割形成的4个interMediateIndexBlock。此时索引布局就变成了third-level布局。
总结
这篇文章是HFile布局分析的第二篇文章,重要会合先容HFile中的数据索引块。起首分RootIndexBlock和NonRootIndexBlock两部分对HFile中索引块举行了分析,紧接着基于此先容了HBase怎样利用索引对数据举行检索,末了连合MemstoreFlush的相干知识分析了keyvalue数据写入的过程中索引块的分裂过程。盼望通过这两篇文章的先容,可以或许对HBase中数据存储文件HFile有一个更加全面深入的认识。
Categories:HBaseTags:HFile,索引
新一代列式存储格式Parquet
March28th,2016fengyu阅读(387)Nocomments
ApacheParquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数盘算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、Impala、Drill等),而且它是语言寂静台无关的。Parquet最初是由Twitter和Cloudera(由于Impala的缘故)相助开辟完成并开源,2015年5月从Apache的孵化器里毕业成为Apache顶级项目,最新的版本是1.8.1。
Parquet是什么
Parquet的灵感来自于2010年Google发表的Dremel论文,文中先容了一种支持嵌套布局的存储格式,而且利用了列式存储的方式提拔查询性能,在Dremel论文中还先容了Google怎样利用这种存储格式实现并行查询的,假如对此感爱好可以参考论文和开源实现ApacheDrill。
嵌套数据模子
在打仗大数据之前,我们简单的将数据分别为布局化数据和非布局化数据,通常我们利用关系数据库存储布局化数据,而关系数据库中利用数据模子都是扁平式的,碰到诸如List、Map和自界说Struct的时间就必要用户在应用层分析。但是在大数据环境下,通常数据的泉源是服务端的埋点数据,很大概必要把程序中的某些对象内容作为输出的一部分,而每一个对象都大概是嵌套的,以是假如可以或许原生的支持这种数据,如许在查询的时间就不必要额外的分析便能得到想要的结果。比方在Twitter,在他们的生产环境中一个典范的日记对象(一条记录)有87个字段,此中嵌套了7层,如下图:
别的,随着嵌套格式的数据的需求日益增长,如今Hadoop生态圈中主流的查询引擎都支持更丰富的数据范例,比方Hive、SparkSQL、Impala等都原生的支持诸如struct、map、array如许的复杂数据范例,如许也就使得诸如Parquet这种原生支持嵌套数据范例的存储格式也变得至关紧张,性能也会更好。
列式存储
列式存储,顾名思义就是按照罗列行存储数据,把某一列的数据连续的存储,每一行中的差别列的值离散分布。列式存储技能并不奇怪,在关系数据库中都已经在利用,尤其是在针对OLAP场景下的数据存储,由于OLAP场景下的数据大部分环境下都是批量导入,根本上不必要支持单条记录的增编削操纵,而查询的时间大多数都是只利用部分罗列行过滤、聚合,对少数罗列行盘算(根本不必要select*fromxx之类的查询)。列式存储可以大大提拔这类查询的性能,较之于行是存储,列式存储可以或许带来这些优化:
1、由于每一列中的数据范例雷同,以是可以针对差别范例的列利用差别的编码和压缩方式,如许可以大大低落数据存储空间。
2、读取数据的时间可以把映射(Project)下推,只必要读取必要的列,如许可以大大镌汰每次查询的I/O数据量,更乃至可以支持谓词下推,跳过不满意条件的列。
3、由于每一列的数据范例雷同,可以利用更加得当CPUpipeline的编码方式,减小CPU的缓存失效。
Parquet的构成
Parquet仅仅是一种存储格式,它是语言、平台无关的,而且不必要和任何一种数据处理惩罚框架绑定,如今可以或许和Parquet适配的组件包罗下面这些,可以看出根本上通常利用的查询引擎和盘算框架都已适配,而且可以很方便的将别的序列化工具天生的数据转换成Parquet格式。
查询引擎:Hive,Impala,Pig,Presto,Drill,Tajo,HAWQ,IBMBigSQL
盘算框架:MapReduce,Spark,Cascading,Crunch,Scalding,Kite
数据模子:Avro,Thrift,ProtocolBuffers,POJOs
项目构成
Parquet项目由以下几个子项目构成:
parquet-format项目由java实现,它界说了全部Parquet元数据对象,Parquet的元数据是利用ApacheThrift举行序列化并存储在Parquet文件的尾部。
parquet-mr项目由java实现,它包罗多个模块,包罗实现了读写Parquet文件的功能,而且提供一些和别的组件适配的工具,比方HadoopInput/OutputFormats、HiveSerde(如今Hive已经自带Parquet了)、Pigloaders等。
parquet-compatibility项目,包罗差别编程语言之间(JAVA和C/C++)读写文件的测试代码。
parquet-cpp项目,它是用于用于读写Parquet文件的C++库。
下图展示了Parquet各个组件的条理以及从上到下交互的方式。
数据存储层界说了Parquet的文件格式,此中元数据在parquet-format中界说,包罗Parquet原始范例界说、Page范例、编码范例、压缩范例等等。
对象转换层完成其他对象模子与Parquet内部数据模子的映射和转换,Parquet的编码方式利用的是stripingandassembly算法。
对象模子层界说了怎样读取Parquet文件的内容,这一层转换包罗Avro、Thrift、PB等序列化格式、Hiveserde等的适配。而且为了资助各人明白和利用,Parquet提供了org.apache.parquet.example包实现了java对象和Parquet文件的转换。
数据模子
Parquet支持嵌套的数据模子,雷同于ProtocolBuffers,每一个数据模子的schema包罗多个字段,每一个字段又可以包罗多个字段,每一个字段有三个属性:重复数、数据范例和字段名,重复数可以是以下三种:required(出现1次),repeated(出现0次或多次),optional(出现0次或1次)。每一个字段的数据范例可以分成两种:group(复杂范例)和primitive(根本范例)。比方Dremel中提供的Document的schema示例,它的界说如下:
messageDocument{
requiredint64DocId;
optionalgroupLinks{
repeatedint64Backward;
repeatedint64Forward;
}
repeatedgroupName{
repeatedgroupLanguage{
requiredstringCode;
optionalstringCountry;
}
optionalstringUrl;
}
}
可以把这个Schema转换成树状布局,根节点可以明白为repeated范例,如下图:
可以看出在Schema中全部的根本范例字段都是叶子节点,在这个Schema中一共存在6个叶子节点,假如把如许的Schema转换成扁平式的关系模子,就可以明白为该表包罗六个列。Parquet中没有Map、Array如许的复杂数据布局,但是可以通过repeated和group组合来实现如许的需求。在这个包罗6个字段的表中有以下几个字段和每一条记录中它们大概出现的次数:
DocIdint64只能出现一次
Links.Backwardint64大概出现恣意多次,但是假如出现0次则必要利用NULL标识
Links.Forwardint64同上
Name.Language.Codestring同上
Name.Language.Countrystring同上
Name.Urlstring同上
由于在一个表中大概存在出现恣意多次的列,对于这些列必要标示出现多次大概便是NULL的环境,它是由Striping/Assembly算法实现的。
Striping/Assembly算法
上文先容了Parquet的数据模子,在Document中存在多个非required列,由于Parquet一条记录的数据分散的存储在差别的列中,怎样组合差别的列值构成一条记录是由Striping/Assembly算法决定的,在该算法中列的每一个值都包罗三部分:value、repetitionlevel和definitionlevel。
RepetitionLevels
为了支持repeated范例的节点,在写入的时间该值便是它和前面的值在哪一层节点是不共享的。在读取的时间根据该值可以推导出哪一层上必要创建一个新的节点,比方对于如许的一个schema和两条记录。
messagenested{
repeatedgroupleve1{
repeatedstringleve2;
}
}
r1:[[a,b,c,],[d,e,f,g]]
r2:[[h],[i,j]]
盘算repetitionlevel值的过程如下:
value=a是一条记录的开始,和前面的值(已经没有值了)在根节点(第0层)上是不共享的,以是repeatedlevel=0.
value=b它和前面的值共享了level1这个节点,但是level2这个节点上是不共享的,以是repeatedlevel=2.
同理value=c,repeatedlevel=2.
value=d和前面的值共享了根节点(属于雷同记录),但是在level1这个节点上是不共享的,以是repeatedlevel=1.
value=h和前面的值不属于同一条记录,也就是不共享任何节点,以是repeatedlevel=0.
根据以上的分析每一个value必要记录的repeatedlevel值如下:
在读取的时间,次序的读取每一个值,然后根据它的repeatedlevel创建对象,当读取value=a时repeatedlevel=0,表现必要创建一个新的根节点(新记录),value=b时repeatedlevel=2,表现必要创建一个新的level2节点,value=d时repeatedlevel=1,表现必要创建一个新的level1节点,当全部列读取完成之后可以创建一条新的记录。本例中当读取文件构建每条记录的结果如下:
可以看出repeatedlevel=0表现一条记录的开始,而且repeatedlevel的值只是针对路径上的repeated范例的节点,因此在盘算该值的时间可以忽略非repeated范例的节点,在写入的时间将其明白为该节点和路径上的哪一个repeated节点是不共享的,读取的时间将其明白为必要在哪一层创建一个新的repeated节点,如许的话每一列最大的repeatedlevel值就便是路径上的repeated节点的个数(不包罗根节点)。减小repeatedlevel的长处可以或许使得在存储利用更加紧凑的编码方式,节流存储空间。
DefinitionLevels
有了repeatedlevel我们就可以构造出一个记录了,为什么还必要definitionlevels呢?由于repeated和optional范例的存在,大概一条记录中某一列是没有值的,假设我们不记录如许的值就会导致本该属于下一条记录的值被当做当前记录的一部分,从而造成数据的错误,因此对于这种环境必要一个占位符标示这种环境。
definitionlevel的值仅仅对于空值是有效的,表现在该值的路径上第几层开始是未界说的,对于非空的值它是没故意义的,由于非空值在叶子节点是界说的,全部的父节点也肯定是界说的,因此它总是便是该列最大的definitionlevels。比方下面的schema。
messageExampleDefinitionLevel{
optionalgroupa{
optionalgroupb{
optionalstringc;
}
}
}
它包罗一个列a.b.c,这个列的的每一个节点都是optional范例的,当c被界说时a和b肯定都是已界说的,当c未界说时我们就必要标示出在从哪一层开始时未界说的,如下面的值:
由于definitionlevel只必要思量未界说的值,而对于repeated范例的节点,只要父节点是已界说的,该节点就必须界说(比方Document中的DocId,每一条记录都该列都必须有值,同样对于Language节点,只要它界说了Code必须有值),以是盘算definitionlevel的值时可以忽略路径上的required节点,如许可以减小definitionlevel的最大值,优化存储。
一个完备的例子
本节我们利用Dremel论文中给的Document示例和给定的两个值r1和r2展示盘算repeatedlevel和definitionlevel的过程,这里把未界说的值记录为NULL,利用R表现repeatedlevel,D表现definitionlevel。
起首看DocuId这一列,对于r1,DocId=10,由于它是记录的开始而且是已界说的,以是R=0,D=0,同样r2中的DocId=20,R=0,D=0。
对于Links.Forward这一列,在r1中,它是未界说的但是Links是已界说的,而且是该记录中的第一个值,以是R=0,D=1,在r1中该列有两个值,value1=10,R=0(记录中该列的第一个值),D=2(该列的最大definitionlevel)。
对于Name.Url这一列,r1中它有三个值,分别为url1=’https://A’,它是r1中该列的第一个值而且是界说的,以是R=0,D=2;value2=’https://B’,和上一个值value1在Name这一层是不雷同的,以是R=1,D=2;value3=NULL,和上一个值value2在Name这一层是不雷同的,以是R=1,但它是未界说的,而Name这一层是界说的,以是D=1。r2中该列只有一个值value3=’https://C’,R=0,D=2.
末了看一下Name.Language.Code这一列,r1中有4个值,value1=’en-us’,它是r1中的第一个值而且是已界说的,以是R=0,D=2(由于Code是required范例,这一列repeatedlevel的最大值便是2);value2=’en’,它和value1在Language这个节点是不共享的,以是R=2,D=2;value3=NULL,它是未界说的,但是它和前一个值在Name这个节点是不共享的,在Name这个节点是已界说的,以是R=1,D=1;value4=’en-gb’,它和前一个值在Name这一层不共享,以是R=1,D=2。在r2中该列有一个值,它是未界说的,但是Name这一层是已界说的,以是R=0,D=1.
Parquet文件格式
Parquet文件是以二进制方式存储的,以是是不可以直接读取的,文件中包罗该文件的数据和元数据,因此Parquet格式文件是自分析的。在HDFS文件体系和Parquet文件中存在如下几个概念。
HDFS块(Block):它是HDFS上的最小的副本单位,HDFS会把一个Block存储在本地的一个文件而且维护分散在差别的呆板上的多个副本,通常环境下一个Block的巨细为256M、512M等。
HDFS文件(File):一个HDFS的文件,包罗数据和元数据,数据分散存储在多个Block中。
行组(RowGroup):按照行将数据物理上分别为多个单位,每一个行组包罗肯定的行数,在一个HDFS文件中至少存储一个行组,Parquet读写的时间会将整个行组缓存在内存中,以是假如每一个行组的巨细是由内存大的小决定的,比方记录占用空间比力小的Schema可以在每一个行组中存储更多的行。
列块(ColumnChunk):在一个行组中每一列生存在一个列块中,行组中的全部列连续的存储在这个行组文件中。一个列块中的值都是雷同范例的,差别的列块大概利用差别的算法举行压缩。
页(Page):每一个列块分别为多个页,一个页是最小的编码的单位,在同一个列块的差别页大概利用差别的编码方式。
文件格式
通常环境下,在存储Parquet数据的时间会按照Block巨细设置行组的巨细,由于一样平常环境下每一个Mapper任务处理惩罚数据的最小单位是一个Block,如许可以把每一个行组由一个Mapper任务处理惩罚,增大任务实行并行度。Parquet文件的格式如下图所示。
上图展示了一个Parquet文件的内容,一个文件中可以存储多个行组,文件的首位都是该文件的MagicCode,用于校验它是否是一个Parquet文件,Footerlength了文件元数据的巨细,通过该值和文件长度可以盘算出元数据的偏移量,文件的元数据中包罗每一个行组的元数据信息和该文件存储数据的Schema信息。除了文件中每一个行组的元数据,每一页的开始都会存储该页的元数据,在Parquet中,有三种范例的页:数据页、字典页和索引页。数据页用于存储当前行组中该列的值,字典页存储该列值的编码字典,每一个列块中最多包罗一个字典页,索引页用来存储当前行组下该列的索引,如今Parquet中还不支持索引页,但是在背面的版本中增长。
在实行MR任务的时间大概存在多个Mapper任务的输入是同一个Parquet文件的环境,每一个Mapper通过InputSplit标示处理惩罚的文件范围,假如多个InputSplit超过了一个RowGroup,Parquet可以或许包管一个RowGroup只会被一个Mapper任务处理惩罚。
映射下推(ProjectPushDown)
说到列式存储的上风,映射下推是最突出的,它意味着在获取表中原始数据时只必要扫描查询中必要的列,由于每一列的全部值都是连续存储的,以是分区取出每一列的全部值就可以实现TableScan算子,而克制扫描整个表文件内容。
在Parquet中原生就支持映射下推,实行查询的时间可以通过Configuration转达必要读取的列的信息,这些列必须是Schema的子集,映射每次会扫描一个RowGroup的数据,然后一次性得将该RowGroup里全部必要的列的CloumnChunk都读取到内存中,每次读取一个RowGroup的数据可以或许大大低落随机读的次数,除此之外,Parquet在读取的时间会思量列是否连续,假如某些必要的列是存储位置是连续的,那么一次读操纵就可以把多个列的数据读取到内存。
谓词下推(PredicatePushDown)
在数据库之类的查询体系中最常用的优化本领就是谓词下推了,通过将一些过滤条件尽大概的在最底层实行可以镌汰每一层交互的数据量,从而提拔性能,比方”selectcount(1)fromAJoinBonA.id=B.idwhereA.a10andB.b100″SQL查询中,在处理惩罚Join操纵之前必要起首对A和B实行TableScan操纵,然后再举行Join,再实行过滤,末了盘算聚合函数返回,但是假如把过滤条件A.a10和B.b100分别移到A表的TableScan和B表的TableScan的时间实行,可以大大低落Join操纵的输入数据。
无论是行式存储还是列式存储,都可以在将过滤条件在读取一条记录之后实行以判定该记录是否必要返回给调用者,在Parquet做了更进一步的优化,优化的方法时对每一个RowGroup的每一个ColumnChunk在存储的时间都盘算对应的统计信息,包罗该ColumnChunk的最大值、最小值和空值个数。通过这些统计值和该列的过滤条件可以判定该RowGroup是否必要扫描。别的Parquet将来还会增长诸如BloomFilter和Index等优化数据,更加有效的完成谓词下推。
在利用Parquet的时间可以通过如下两种战略提拔查询性能:1、雷同于关系数据库的主键,对必要频仍过滤的列设置为有序的,如许在导入数据的时间会根据该列的次序存储数据,如许可以最大化的利用最大值、最小值实现谓词下推。2、减小行组巨细和页巨细,如许增长跳过整个行组的大概性,但是此时必要衡量由于压缩和编码服从降落带来的I/O负载。
性能
相比传统的行式存储,Hadoop生态圈比年来也涌现出诸如RC、ORC、Parquet的列式存储格式,它们的性能上风重要表现在两个方面:1、更高的压缩比,由于雷同范例的数据更轻易针对差别范例的列利用高效的编码和压缩方式。2、更小的I/O操纵,由于映射下推和谓词下推的利用,可以镌汰一大部分不须要的数据扫描,尤其是表布局比力巨大的时间更加显着,由此也可以或许带来更好的查询性能。
上图是展示了利用差别格式存储TPC-H和TPC-DS数据会合两个表数据的文件巨细对比,可以看出Parquet较之于其他的二进制文件存储格式可以或许更有效的利用存储空间,而新版本的Parquet(2.0版本)利用了更加高效的页存储方式,进一步的提拔存储空间。
上图展示了Twitter在Impala中利用差别格式文件实行TPC-DS基准测试的结果,测试结果可以看出Parquet较之于其他的行式存储格式有较显着的性能提拔。
上图展示了criteo公司在Hive中利用ORC和Parquet两种列式存储格式实行TPC-DS基准测试的结果,测试结果可以看出在数据存储方面,两种存储格式在都是用snappy压缩的环境下量中存储格式占用的空间相差并不大,查询的结果表现Parquet格式稍好于ORC格式,两者在功能上也都有优缺点,Parquet原生支持嵌套式数据布局,而ORC对此支持的较差,这种复杂的Schema查询也相对较差;而Parquet不支持数据的修改和ACID,但是ORC对此提供支持,但是在OLAP环境下很少会对单条数据修改,更多的则是批量导入。
项目发展
自从2012年由Twitter和Cloudera共同研发Parquet开始,该项目不停处于高速发展之中,而且在项目之初就将其贡献给开源社区,2013年,Criteo公司参加开辟而且向Hive社区提交了向hive集成Parquet的patch(HIVE-5783),在Hive0.13版本之后正式参加了Parquet的支持;之后越来越多的查询引擎对此举行支持,也进一步动员了Parquet的发展。
如今Parquet正处于向2.0版本迈进的阶段,在新的版本中实现了新的Page存储格式,针对差别的范例优化编码算法,别的丰富了支持的原始范例,增长了Decimal、Timestamp等范例的支持,增长更加丰富的统计信息,比方BloonFilter,可以或许尽大概得将谓词下推在元数据层完成。
总结
本文先容了一种支持嵌套数据模子对的列式存储体系Parquet,作为大数据体系中OLAP查询的优化方案,它已经被多种查询引擎原生支持,而且部分高性能引擎将其作为默认的文件存储格式。通过数据编码和压缩,以及映射下推和谓词下推功能,Parquet的性能也较之别的文件格式有所提拔,可以预见,随着数据模子的丰富和Adhoc查询的需求,Parquet将会被更广泛的利用。
更多技能分享,请关注网易视频云官方网站(https://vcloud.163.com/)大概网易视频云官方微信(vcloud163)。
我要评论