Hbase总结

Hbase总结 --huzhan

一、Hbase的六大特点:

(1)、表大:一个表可以有数亿行,上百万列。

(2)、无模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态增加,同一个表中的不同行的可以有截然不同的列。

(3)、面向列:HBase是面向列的的存储和权限控制,列族独立索引。

(4)、稀疏:空(null)列并不占用空间,表可以设计的非常稀疏。

(5)、数据类型单一:HBase中的数据都是字符串,没有类型。

(6)、数据多版本:每个单元中的数据可以有多个版本,默认情况下版本号自动分配,是单元格插入时的时间戳。

二、Hbase与Hive的对比:

(1)、整体对比:

Hbase总结

(2)、Hive是一种构建在Hadoop基础设施之上的数据仓库,通过Hive可以使用HQL语言查询存放在HDFS上面的数据。HBase能够在它的数据库上面实时运行,HBase被分区为表格,表格有进一步分割为列簇,列族必须需要用schema定义。一个列簇可以包含很多列,每个key/value在HBase中都被定义成一个cell,每一个cell都有一个rowkey,一个columnFamily,一个value值,一个timestamp。rowkey不能为空且唯一。

(3)、Hive把HQL解析成MR程序,因为它是兼容JDBC,所有可以和很多JDBC程序做集成,它只能做离线查询,不能做实时查询,默认查询Hive是查询所有的数据,这个可以通过分区来控制。HBase通过存储的key/value来工作的,它支持主要的四种操作,增删改查。

(4)、Hive目前不支持更新操作,花费时间长,必须要先设置schema将文件和表映射,Hive和ACID不兼容。HBase必须需要zk的支持,查询语句需要重新学,如果要使用sql查询,可以使用Apache Phonenix,但会以schema作为代价。

(5)、Hive适用于一段时间内的数据进行分析查询,HBase适用于大规模数据的实时查询。

三、Hbase的使用场景:

(1)、半结构化数据和非结构化数据,可以进行动态扩展。

(2)、记录非常的稀疏。

(3)、多版本数据。

(4)、超大数据容量:HBase会自动水平切分扩展,跟Hadoop的无缝集成保证了其数据的可靠性和海量数据分析的高性能。

四、Hbase的rowkey设计原则:

(1)、rowkey长度原则:rowkey是一个二进制流,长度开发者建议是10-100字节,不过建议越短越好,最好不超过16字节。原因是:数据持久化文件HFile中是按照按照key/value存储的,如果rowkey太长的话就会影响HFile的存储效率。Memstore将缓存数据到内存,如果rowkey字段过长内存的有效利用会降低,系统将会无法缓存更多的数据,降低检索的效率。

(2)、rowkey散列原则:如果rowkey是按照时间戳方式递增的话,不要将时间放在二进制码的前面,建议将rowkey的高位作为散列字段,如果没有散列字段就会出现一个regionServer上堆积的热点现象。

(3)、rowkey的唯一原则:rowkey不能为空且唯一。

五、Hbase的查询方式:

1、全表查询:scan tableName

2、基于rowkey的单行查询:get tableName,'1’

3、基于rowkey的范围扫描:scan tableName, {STARTROW=>‘1’,STOPROW=>‘2’}

4、get和scan方法:

(1)、按指定的rowkey获取唯一一条数据,get方法:分为两种,分别是设置了closestRowBefore和没有设置的rowlock,只要保证行的事务性,即每一个get是以一个row来标记的,一个row中可以有多个family和column。

(2)、按指定的条件获取一批记录,条件查询。1、scan可以通过setCaching和setBatch方法来提高速度;2、scan也可以通过setStartRow和setEndRow来限定范围(左闭右开),3、scan还可以通过setFileter方法来添加过滤器。

ps:setCache和setBatch方法:
setCache方法:这个方法设置即一次RPC请求放回的行数,对于缓存操作来说,如果返回行数太多了,就可能内存溢出,那么这个时候就需要setBatch方法,。

setBatch:设置这个之后客户端可以选择取回的列数,如果一行包括的列数超过了设置的值,那么就可以将这个列分片。例如:如果一行17列,如果batch设置为5的话,就会返回四组,分别是5,5,5,2。、

※:Cache设置了服务器一次返回的行数,而Batch设置了服务器一次返回的列数。

ps:Batch参数决定了一行数据分为几个result,它只针对一行数据,Cache决定了一次RPC返回的result个数。

RPC请求次数 = (行数 * 每行列数) / Min(每行的列数,批量大小) / 扫描器缓存

六、Hbase的cell结构:

1、什么是Hbase中的cell:Hbase中通过row和columns确定一个存贮单元成为cell,cell由{{rowkey, column(= +

2、Hbase中表示行的集合,行是列族的集合,列族是列的集合,列是键值对的集合,如图:

Hbase总结

七、Hbase的读写流程:

1、HBase的读流程:

(1)、HRegisonServer保存着.meta.表及数据表,首先client先访问zk,访问-ROOT-表,然后在zk上面获取.meta.表所在的位置信息,找到这个meta表在哪个HRegionServer上面保存着。

(2)、接着client访问HRegionServer表从而读取.meta.进而获取.meta.表中存放的元数据。

(3)、client通过.meta.中的元数据信息,访问对应的HRegionServer,然后扫描HRegionServer的Memstore和StoreFile来查询数据。

(4)、最后把HRegionServer把数据反馈给client。

2、HBase的写流程:

(1)、client访问zk中的-ROOT-表,然后后在访问.meta.表,并获取.meta.中的元数据。

(2)、确定当前要写入的HRegion和HRegionServer。

(3)、clinet向HRegionServer发出写相应的请求,HRegionServer收到请求并响应。

(4)、client先将数据写入到HLog中,以防数据丢失。

(5)、然后将数据写入到MemStore中。

(6)、如果HLog和MemStore都写入成功了,那么表示这个条数据写入成功了。

(7)、如果MemStore写入的数据达到了阈值,那么将会flush到StoreFile中。

(8)、当StoreFile越来越多,会触发Compact合并操作,将过多的StoteFile合并成一个大的StoreFile。

(9)、当StoreFile越来越多时,Region也会越来越大,当达到阈值时,会触发spilit操作,将这个Region一分为二。

ps:HBase中所有的更新和删除操作都会在后续的compact中进行,使得用户的写操作只需要进入内存中就行了。实现了HBase的 I/O高性能。

八、Hbase的结构:

1、HMaster:

(1)、为所有的RegionServer分配Region。

(2)、负责RegionServer的负载均衡。

(3)、发现失效的RegionServer并重新分配其上的Region。

(4)、HDFS上的垃圾文件。

(5)、处理Schema更新请求(表的创建,删除,修改,列族的增加等)。

2、HRegionServer:

(1)HRegion:

(1)、简介:Table在行的方向上分隔为多个Region,Region是HBase中分布式存储和负载均衡的最小单元,即不同的Region可以分在不同的RegionServer上面,但同一个Region是不会拆分到多个Server上面的。随着数据的增多,某个列族的达到一个阈值就会分成两个新的Region。结构:<表名,startRowkey,创建时间>,由目录表(-ROOT-,.META.)记录该Region的endRowkey
(2)、Store:

(1)简介:每一个Region由一个或则多个Store组成,至少是一个Store,HBase会把访问的数据存放在Store中,即每一个列族建一个Store,如果有多个ColumnFamily,就多多个Store,一个Store由一个MemStore和0或则多个StoreFile组成。HBase通过Store的大小判断是否需要切分Region。

(2)MemStore:它是放在内存中的,保存修改的数据,即key/values。当MemStore的大小达到一定的阈值的时候(默认128M),MemStore会被Flush到文件,即生成一个快照StoreFile,Flush过程由一个线程完成。

(3)StoreFile:StoreFile底层是HFile,HFile是Hadoop的二进制格式文件,

(2)HLog:WAL文件,用来灾难恢复使用,HLog记录数据的所有变更,一旦RegionServer宕机,就从HLog中进行恢复,HLog文件就是一个普通的Hadoop Sequence File,Sequence File记录了写入数据的归属信息,除了Table和Region名字外,还同时包括了Sequence Number和TimeStamp,Sequence File的value是HBase的key/value对象,即对应的HFile中的key/value。

3、Zookeeper:

(1)、保证任何时候集群中只有一个活跃的Master。

(2)、存储所有的Region的寻址入口,知道哪个Region在哪台机器上。

(3)、实时监控RegionServer的状态,将RegionServer的上下线的信息汇报给HMaster,RegionServer不直接向HMaster汇报信息,减轻HMaster的压力,而是通过向ZK发送信息。

(4)、存储HBase的元数据结构(schema),知道集群中有哪些Table,每个Table有哪些Column Family。

4、结构图:

Hbase总结

九、Hbase中的Compact机制:

1、当HBase中的memstore数据flush到磁盘的时候,就会形成一个storefile,当storefile的数量达到一定程度的时候,就需要将storefile文件进行compaction操作,Compact作用:合并文件、清楚过期,多余版本数据、提高读写效率。

2、compact操作的实现:①minor:Minor 操作只用来做部分文件的合并操作以及包括 minVersion=0 并且设置 ttl 的过期版本清理,不做任何删除数据、多版本数据的清理工作。②major:Major 操作是对 Region 下的HStore下的所有StoreFile执行合并操作,最终的结果是整理合并出一个文件。

十、Hbase中的数据模型:

1、逻辑视图:转载:

Hbase总结

2、物理视图:(1)、每个columnFamily存储在HDFS上的一个单独文件,空值不会被保留。(2)、key和versionNumber在每个columnFamily中单独一份。(3)、HBase每个值维护多级索引,即<key,columnFamily,columnName,timeStamp>。(4)、表在行的方向上分割为多个Region。(5)、Region是HBase分布式存储和负载均衡的最小单元,不同Region分布在不同的RegionServer中。(6)、Region虽然是分布式存储的最小单元,但并不是最小存储单元,一个Region中包含多个Store对象,每个Store包含一个MemStore和若干个StoreFile,StoreFile包含一个或多个HFile。MemStore存放在内存中,StoreFile存储在HDFS上面。

3、HBase中的-ROOT-表和.META.表:HBase中的Region元数据都存储在.META.表中,随着Region的增加,.META.表也会越来越多。为了定位.META.表中各个Region的位置,把.META.表中所有Region的元数据保存在-ROOT-表中,最后由Zookeeper记录-ROOT-表的位置信息。所有客户端访问用户数据前,需要首先访问Zookeeper获得-ROOT-的位置,然后访问-ROOT-表获得.META.表的位置,最后根据.META.表中的信息确定用户数据存放的位置。-ROOT-表是不会分割的,它只有一个Region。为了加快访问速度,.META.表的所有Region全部保存在内存中。客户端会将查询过的位置信息缓存起来,且缓存不会主动失效。如果客户端根据缓存信息还访问不到数据,则询问相关.META.表的Region服务器,试图获取数据的位置,如果还是失败,则询问-ROOT-表相关的.META.表在哪里。

十一、Hbase中的优化:

1、读写性能优化:

(1)、开启bloomfilter过滤器。

(2)、在条件允许的情况下,给HBase足够的内存。修改配置文件hbase-env.sh中的export HBASE_HEAPSIZE=1000

(3)、增加RPC的数量。通过修改hbase-site.xml中的hbase.regionserver.handler.count属性可以适当的放大RPC数量,默认是10。

(4)、HBase中的region太小会造成多次spilit,region就会下线。如果HBase中的region过大,就会发生多次的compaction,将数据读一遍重写一遍到HDFS上面,占用io。

2、预设分区:

(1)、shell方法:例如:create ‘tb_split’,{NAME=>‘cf’, VERSION=>3},{SPLITS=>[‘10’,‘20’,‘30’]}

(2)、java程序控制:https://blog.csdn.net/javajxz008/article/details/51913471

3、其他优化方法:

(1)、减少调整:可以调整region和HFile。因为region的分裂会导致I/O开销,如果没有预设分区的话,随着region中条数的增,region会进行分裂,解决方法就是根据rowkey设计来进行预建分区,减少region的动态分裂。HFile会随着memstore进行刷新时生成一个HFile,当HFile增加到一定量的时候,会将属于一个region的HFile合并,HFile是不可避免的,但是如果HFile大于设置得值,就会导致HFile分裂,这样就会导致I/O的开销增大。

(2)、减少启停:对于HBase会有compact机制,会合并HFile,但是我们可以手动关闭compact,减少I/O。如果是批量数据的写入,我们可以用BulkLoad来批量插入数据。(BulkLoad的使用:https://blog.csdn.net/shixiaoguo90/article/details/78038462

(3)、减少数据量:开启过滤,提高查询效率。(开启BloomFilter,这个是列簇级别的过滤,在生成一个StoreFile同时会生成一个MetaBlock,用于查询时的过滤)。使用压缩,一般使用snappy和lzo压缩。

(4)、合理设计:rowkey的设计:(散列性、简短性、唯一性、业务性),列族的设计:(多列族的优势是:在进行查表的时候,只需要扫描那一列就行了,就不需要全盘扫描,减少I/O,劣势是:降低了写的I/O,原因是:数据写到stroe以后会缓存到memstore中,)

十二、为什么有HDFS还要用HBase?

  • 延迟: Mapreduce编程框架延迟较高,无法满足大规模数据实时处理应用的需求
  • 访问: HDFS面向批量访问而不是随机访问

十三、为什么用HBase而不用传统关系型数据库? / 关系型数据库和HBase有什么区别?

  • 数据类型: 传统关系型数据库有丰富的数据类型,HBase把数据存储为未经解释的字符串
  • 数据操作: 关系数据库包含了丰富的操作,可涉及复杂的多表连接,而HBase只有简单的插入查询删除清空等,不涉及表与表的连接
  • 存储模式: 关系数据库基于行存储,HBase基于列存储
  • 数据索引: 关系数据库可构建复杂的多个索引以提高检索效率;HBase只有一个索引:行键(RowKey),经过巧妙地设计,通过rowkey索引或扫描,不会使系统慢下来
  • 数据维护: 关系数据库更新会覆盖原值,HBase则是生成一个新的版本,旧数据依然保留
  • 可伸缩性: 关系数据库很难实现横向扩展,而HBase能够容易地通过在集群中增加或减少硬件实现性能地伸缩

十四、 每天百亿数据存入HBase,如何保证数据的存储正确和在规定的时间里全部录入完毕,不残留数据

答:看到这个题目的时候我们要思考的是它在考查什么知识点?
我们来看看要求:
1)百亿数据:证明数据量非常大
2)存入HBase:证明是跟HBase的写入数据有关
3)保证数据的正确:要设计正确的数据结构保证正确性
4)在规定时间内完成:对存入速度是有要求的

那么针对以上的四个问题我们来一一分析
1)数据量百亿条,什么概念呢?假设一整天60x60x24 = 86400秒都在写入数据,那么每秒的写入条数高达100万条,HBase当然是支持不了每秒百万条数据的,所以这百亿条数据可能不是通过实时地写入,而是批量地导入。批量导入推荐使用BulkLoad方式(推荐阅读:Spark之读写HBase),性能是普通写入方式几倍以上
2)存入HBase:普通写入是用JavaAPI put来实现,批量导入推荐使用BulkLoad
3)保证数据的正确:这里需要考虑RowKey的设计、预建分区和列族设计等问题
4)在规定时间内完成也就是存入速度不能过慢,并且当然是越快越好,使用BulkLoad

十五、 HBase 如何给WEB前端提供接口来访问?

答:使用JavaAPI来编写WEB应用;使用HBase提供的RESTful接口

十六、 HBase优化方法

答:优化手段主要有以下四个方面

1)减少调整

减少调整这个如何理解呢?HBase中有几个内容会动态调整,如region(分区)、HFile,所以通过一些方法来减少这些会带来I/O开销的调整

  • Region
    如果没有预建分区的话,那么随着region中条数的增加,region会进行分裂,这将增加I/O开销,所以解决方法就是根据你的RowKey设计来进行预建分区,减少region的动态分裂
  • HFile
    HFile是数据底层存储文件,在每个memstore进行刷新时会生成一个HFile,当HFile增加到一定程度时,会将属于一个region的HFile进行合并,这个步骤会带来开销但不可避免,但是合并后HFile大小如果大于设定的值,那么HFile会重新分裂。为了减少这样的无谓的I/O开销,建议估计项目数据量大小,给HFile设定一个合适的值
2)减少启停

数据库事务机制就是为了更好地实现批量写入,较少数据库的开启关闭带来的开销,那么HBase中也存在频繁开启关闭带来的问题。

  • 关闭Compaction,在闲时进行手动Compaction
    因为HBase中存在Minor Compaction和Major Compaction,也就是对HFile进行合并,所谓合并就是I/O读写,大量的HFile进行肯定会带来I/O开销,甚至是I/O风暴,所以为了避免这种不受控制的意外发生,建议关闭自动Compaction,在闲时进行compaction
  • 批量数据写入时采用BulkLoad
    如果通过HBase-Shell或者JavaAPI的put来实现大量数据的写入,那么性能差是肯定并且还可能带来一些意想不到的问题,所以当需要写入大量离线数据时建议使用BulkLoad
3)减少数据量

虽然我们是在进行大数据开发,但是如果可以通过某些方式在保证数据准确性同时减少数据量,何乐而不为呢?

  • 开启过滤,提高查询速度
    开启BloomFilter,BloomFilter是列族级别的过滤,在生成一个StoreFile同时会生成一个MetaBlock,用于查询时过滤数据
  • 使用压缩:一般推荐使用Snappy和LZO压缩
4)合理设计

在一张HBase表格中RowKey和ColumnFamily的设计是非常重要,好的设计能够提高性能和保证数据的准确性

  • RowKey设计:应该具备以下几个属性
    • 散列性:散列性能够保证相同相似的rowkey聚合,相异的rowkey分散,有利于查询
  • 简短性:rowkey作为key的一部分存储在HFile中,如果为了可读性将rowKey设计得过长,那么将会增加存储压力
  • 唯一性:rowKey必须具备明显的区别性
  • 业务性:举些例子
    • 假如我的查询条件比较多,而且不是针对列的条件,那么rowKey的设计就应该支持多条件查询
    • 如果我的查询要求是最近插入的数据优先,那么rowKey则可以采用叫上Long.Max-时间戳的方式,这样rowKey就是递减排列
  • 列族的设计
    列族的设计需要看应用场景
    • 多列族设计的优劣
      • 优势:HBase中数据时按列进行存储的,那么查询某一列族的某一列时就不需要全盘扫描,只需要扫描某一列族,减少了读I/O;其实多列族设计对减少的作用不是很明显,适用于读多写少的场景
    • 劣势:降低了写的I/O性能。原因如下:数据写到store以后是先缓存在memstore中,同一个region中存在多个列族则存在多个store,每个store都一个memstore,当其实memstore进行flush时,属于同一个region
      的store中的memstore都会进行flush,增加I/O开销

十七、 HBase中RowFilter和BloomFilter原理

答:

1)RowFilter原理简析

RowFilter顾名思义就是对rowkey进行过滤,那么rowkey的过滤无非就是相等(EQUAL)、大于(GREATER)、小于(LESS),大于等于(GREATER_OR_EQUAL),小于等于(LESS_OR_EQUAL)和不等于(NOT_EQUAL)几种过滤方式。Hbase中的RowFilter采用比较符结合比较器的方式来进行过滤。

比较器的类型如下:

  • BinaryComparator
  • BinaryPrefixComparator
  • NullComparator
  • BitComparator
  • RegexStringComparator
  • SubStringComparator

例子:

Filter rowFilter = new RowFilter(CompareFilter.CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes(rowKeyValue)));
Scan scan = new Scan();
scan.setFilter(rowFilter)
...

在上面例子中,比较符为EQUAL,比较器为BinaryComparator

2)BloomFilter原理简析
  • 主要功能:提供随机读的性能

  • 存储开销:BloomFilter是列族级别的配置,一旦表格中开启BloomFilter,那么在生成StoreFile时同时会生成一份包含BloomFilter结构的文件MetaBlock,所以会增加一定的存储开销和内存开销

  • 粒度控制:ROW和ROWCOL

  • BloomFilter的原理

    简单说一下BloomFilter原理

    • 内部是一个bit数组,初始值均为0
    • 插入元素时对元素进行hash并且映射到数组中的某一个index,将其置为1,再进行多次不同的hash算法,将映射到的index置为1,同一个index只需要置1次。
    • 查询时使用跟插入时相同的hash算法,如果在对应的index的值都为1,那么就可以认为该元素可能存在,注意,只是可能存在
    • 所以BlomFilter只能保证过滤掉不包含的元素,而不能保证误判包含
  • 设置:在建表时对某一列设置BloomFilter即可

十八、 HBase的导入导出方式

答:
1)导入:bin/hbase org.apache.hadoop.hbase.mapreduce.Driver import 表名 路径

路径:来源

2)导出:bin/hbase org.apache.hadoop.hbase.mapreduce.Driver export 表名 路径

路径:目的地

十九、 Region如何预建分区

预建分区的方法很简单,有以下两种
  • hbase shell
  • create ‘t1’, ‘f1’,SPLITS=>[‘10’,‘20’,‘30’]
  • create ‘t1’,‘f1’,SPLITS_FILE =>‘splits.txt’
  • Java API
    • 创建一个byte[][] splitKeys = {{1,2,3},{4,5,6}}
    • admin.createTable(tableDesc,splitKeys)
预建分区的难点在于key如何设计,分多少个和如何分的问题,那么下面我们就对这三个问题一一分析:

1)如何设计Key,我们设计Key的原则就是要让Key足够散列,但同时又要保持Key的长度适中,这里给出一个方法,样本取自Spark读写HBase中的数据

01055HAXMTXG10100001@KEY_VOLTAGE_TEC_PWR@1.60@1.62@1.75@1.55

我想要的rowKey是:01055HAXMTXG10100001KEY_VOLTAGE_TEC_PWR

但是很明显这样肯定是不会足够散列的,那么我们可以对上面那个Key进行MD5,然后取前面三个字符(为了更加散列,可以取1,3,5或者其他组合)再加上原来的Key

DigestUtils.md5Hex(x(0)+x(1)).substring(0,3)+x(0)+x(1)

这样的话我们就可以得到足够散列的数据,并且MD5取得的是十六进制字符串,那么Key的范围就是(0,0,0)至(f,f,f)

2)分多少个:这个需要我们就要根据我们集群规模来进行安排,假设我们有5regionServer,每个regionServer有20个region,那么总共就是100个region,最后的工作就是将000-fff分成100份。

3)如何分:就是生成一个byte[][],用于创建表格,这个我将会些一篇另外的博文来介绍,敬请期待

二十、HRegionServer宕机如何处理?

1)ZooKeeper会监控HRegionServer的上下线情况,当ZK发现某个HRegionServer宕机之后会通知HMaster进行失效备援;
2)该HRegionServer会停止对外提供服务,就是它所负责的region暂时停止对外提供服务
3)HMaster会将该HRegionServer所负责的region转移到其他HRegionServer上,并且会对HRegionServer上存在memstore中还未持久化到磁盘中的数据进行恢复
4)这个恢复的工作是由WAL重播来完成,这个过程如下:

  • wal实际上就是一个文件,存在/hbase/WAL/对应RegionServer路径下
  • 宕机发生时,读取该RegionServer所对应的路径下的wal文件,然后根据不同的region切分成不同的临时文件recover.edits
  • 当region被分配到新的RegionServer中,RegionServer读取region时会进行是否存在recover.edits,如果有则进行恢复

二十一、 HBase简单读写流程

读:

找到要读取数据的region所在的RegionServer,然后按照以下顺序进行读取:先去BlockCache读取,若BlockCache没有,则到Memstore读取,若MemStore中没有,则到HFile中读取。

写:

找到要写入数据的region所在的RegionServer,然后将数据先写到WAL中,然后再将数据写到MemStore等待刷新,回复客户端写入完成。

9 HBase和Hive的对比

HBase Hive
类型 列式数据库 数据仓库
内部机制 数据库引擎 MapReduce
增删改查 都支持 只支持导入和查询
Schema 只需要预先定义列族,不需要具体到列列可以动态修改 需要预先定义表格
应用场景 实时 离线处理
特点 以K-V形式存储 类SQL

二十二、HBase首次读写流程

  • Client从ZooKeeper中读取hbase:meta表
  • Client从hbase:meta中获取想要操作的region的位置信息,并且将hbase:meta缓存在Client端,用于后续的操作
  • 当一个RegionServer宕机而执行重定位之后,Client需要重新获取新的hase:meta信息进行缓存

二十三、 HBase搭建过程中需要注意什么?

hbase-env.sh的配置
  • 是否使用外部ZooKeeper,这个一般使用Hadoop集群的ZooKeeper集群即可。
    • HBASE_MANAGES_ZK=false
hbase-site.sh的配置
  • hbase.zookeeper.quorum=“host1:2181,host2:2181”
上一篇:HBase快速导入巨量数据—— Bulk Loading


下一篇:C++获取某个目录下的所有图片