本文已收录至Github,举荐浏览 👉 Java随想录
微信公众号:Java随想录
HBase(Hadoop Database)是一个开源的、分布式的、面向列的NoSQL数据库,它是构建在Hadoop之上的。HBase旨在提供牢靠的、高性能的、可扩大的存储和拜访大规模数据集的能力。
HBase个性
以下是HBase的一些要害个性和概念:
- 分布式架构:HBase是一个分布式数据库,它能够在一个集群中运行在多个机器上。数据以程度分片的形式散布在不同的机器上,这样能够实现数据的高可用性和横向扩展性。
- 列存储:HBase是面向列的数据库,它将数据存储在表中的列族中。每个列族能够蕴含多个列,这样能够不便地存储和检索具备不同构造的数据。HBase的列存储个性使得能够高效地读取和写入大量数据。
- 强一致性:HBase提供强一致性的读写操作。当数据被写入或读取时,HBase会确保所有相干的正本都是最新的。这使得HBase非常适合须要强一致性的利用场景,如金融、电信等畛域。
- 高可扩展性:HBase能够轻松地扩大到大规模的数据集和集群。通过增加更多的机器和分片数据,能够线性地扩大存储容量和吞吐量。
- 疾速读写:HBase是为了高性能而设计的。它应用了内存和硬盘的组合来存储数据,能够实现疾速的读写操作。此外,HBase还反对批量写入和异步写入,进一步提高了写入性能。
- 灵便的数据模型:HBase提供了灵便的数据模型,能够依据应用程序的需要设计表构造。它反对动静增加列,并且能够高效地执行范畴查问和单行读写操作。
- 数据一致性:HBase通过应用ZooKeeper来治理集群的元数据和协调分布式操作,确保数据的一致性和可用性。
- 集成Hadoop生态系统:HBase与Hadoop生态系统严密集成,能够与Hadoop分布式文件系统(HDFS)和Hadoop的计算框架(如MapReduce)无缝配合应用。这使得HBase可能解决大规模的数据存储和剖析工作。
Hadoop的限度
只管Hadoop是一个弱小的分布式计算框架,但它也存在一些不足之处,与HBase相比,以下是一些Hadoop的限度:
- 实时性:Hadoop次要用于批处理工作,对于实时性要求较高的利用场景,如实时数据分析和流式解决,Hadoop的提早可能会比拟高。Hadoop的MapReduce模型通常不适宜解决须要即时响应的数据处理工作。
- 存储效率:Hadoop在存储效率方面存在一些问题。为了提供容错性和可靠性,Hadoop将数据复制屡次存储在不同的节点上,这会导致存储开销减少。绝对于HBase的列存储模型,Hadoop的存储效率可能较低。
- 复杂性:Hadoop的配置和治理绝对简单,须要专业知识和教训。搭建和保护一个Hadoop集群须要解决许多参数和组件,对于初学者来说可能存在肯定的学习曲线。
- 扩展性限度:尽管Hadoop具备良好的可扩展性,能够通过增加更多的节点来扩大集群的存储和计算能力,但在某些状况下,随着集群规模的减少,治理和调度节点可能变得更加艰难。
- 解决简单查问的限度:Hadoop的次要计算模型是MapReduce,它适宜解决简略的计算工作,但对于简单的查问和数据分析,如简单聚合、连贯和实时查问等,Hadoop的性能可能不如专门设计的剖析数据库。
基本概念
NameSpace
命名空间,相似于关系型数据库的Database概念,每个命名空间下有多个表。
HBase自带两个命名空间,别离是hbase和default,hbase 中寄存的是HBase内置的表,default表是用户默认应用的命名空间,这2个命名空间默认是不展现的。
Table
相似于关系型数据库的表概念。不同的是,HBase定义表时只须要申明列族即可,不须要申明具体的列。因为数据存储时稠密的,空(null)列不占用存储空间,所有往HBase写入数据时,字段能够动静、按需指定。因而,和关系型数据库相比,HBase 可能轻松应答字段变更的场景。
RowKey
HBase表中的每行数据都由一个RowKey和多个Column(列)组成,数据是依照RowKey的字典顺序存储的,并且查问数据时只能依据RowKey进行检索,所以RowKey的设计非常重要。
Column
HBase中的每个列都由Colunn Family (列族)和Column Qualifier (列限定符)进行限定,例如info: name, info: age。 建表时,只需指明列族,而列限定符无需事后定义。
TimeStamp
用于标识数据的不同版本(version),每条数据写入时,零碎会主动为其加上该字段,其值为写入HBase的工夫。
Cell
由{rowkey, column Family:column Qualifier, timestamp} 惟一确定的单元,Cell 中的数据全副是字节码模式存贮。
一条数据有多个版本,每个版本都是一个Cell。
存储构造
HBase存储构造如下:
下面的这种数据会存储为上面这样,底层存储为Byte:
行分为Region,列分为Store,Region能够放在其余机器上。
HBase是基于HDFS的,而HDFS是不可能批改数据的,所以HBase其实也是不能批改数据的。HBase应用工夫戳实现批改性能。取数据的时候取最新工夫戳的数据,取出来的就是最新的数据。
HBase 数据拜访模式
HBase数据拜访能够通过以下几种模式进行:
- 单行读写(Get和Put):应用HBase提供的API,能够通过指定行键(Row Key)来读取和写入单行数据。Get操作能够依据行键从表中获取特定行的数据,而Put操作能够将数据写入表的指定行。
- 批量读写(Scan和Batch Put):HBase反对批量读写操作,能够一次性读取或写入多行数据。Scan操作能够依照肯定的条件扫描表中的多行数据,而Batch Put操作能够一次性写入多行数据。
- 全表扫描(Scan):通过Scan操作,能够遍历整个表的数据,依照指定的条件进行过滤和筛选。能够设置起始行键和完结行键,还能够应用过滤器(Filter)进行更准确的数据查问。
- 列族范畴扫描(Scan):HBase中的数据以列族(Column Family)为单位进行存储,能够通过Scan操作对指定列族的数据进行范畴扫描。这种形式能够进步数据查问的效率,只获取所需列族的数据,而不用读取整个表的数据。
- 过滤器(Filter):HBase反对多种过滤器来进行数据的准确查问和过滤。能够应用行键过滤器(Row Filter)依照行键的条件进行数据过滤,还能够应用列族过滤器(Family Filter)、列限定符过滤器(Qualifier Filter)和值过滤器(Value Filter)等进行更细粒度的数据过滤。
- 原子性操作(Check-and-Put和Check-and-Delete):HBase反对原子性操作,例如Check-and-Put和Check-and-Delete。这些操作容许在写入数据之前进行查看,只有在满足指定条件的状况下才执行写入操作。
以上模式提供了不同的数据拜访形式,能够依据具体的需要和查问条件抉择适宜的形式来拜访和操作HBase中的数据。
架构体系
HBase的架构体系是基于分布式存储和解决的设计。它蕴含了以下几个重要的组成部分:
- HMaster:HMaster是HBase集群的主节点,负责管理整个集群的元数据和协调各个RegionServer的工作。它保护了表的构造信息、分片规定、RegionServer的负载平衡等,并协调分布式操作,如Region的决裂和合并。
- RegionServer:RegionServer是HBase集群中的工作节点,负责存储和解决数据。每个RegionServer治理多个Region,每个Region负责存储表中的一部分数据。RegionServer解决客户端的读写申请,负责数据的存储、读取和写入操作。
- ZooKeeper:ZooKeeper是一个分布式协调服务,被HBase用于治理集群的元数据和协调分布式操作。HBase应用ZooKeeper来进行主节点的选举、故障检测、集群配置的同步等工作。
- HDFS(Hadoop Distributed File System):HBase应用HDFS作为底层的分布式文件系统,用于存储数据。HDFS将数据宰割成块并散布在不同的节点上,提供高可靠性和可扩展性的存储。
- HBase客户端:HBase客户端是与HBase交互的应用程序或工具,用于发送读写申请和接管查问后果。客户端能够通过HBase的Java API或者命令行工具(如HBase shell)来拜访和操作HBase表。
- 表和列族:HBase数据模型是基于表的,表由一个或多个列族(Column Family)组成。每个列族能够蕴含多个列(Column),列存储着理论的数据。表被宰割成多个Region存储在不同的RegionServer上,每个Region负责存储一部分行数据。
这些组成部分独特形成了HBase的架构体系,实现了分布式存储和解决大规模数据集的能力。HMaster负责管理元数据和协调工作,RegionServer存储和解决数据,ZooKeeper提供分布式协调服务,HDFS提供底层的分布式文件存储,而HBase客户端用于与HBase进行交互。表和列族的概念提供了数据的组织和存储形式。
HBase组件
- MemStore:每个RegionServer都有一个MemStore,它是位于内存中的长期数据存储区域。当客户端写入数据时,数据首先被写入到MemStore中,以提供疾速的写入性能。
- WAL(Write-Ahead-Log):WAL是HBase的日志文件,用于记录所有的写操作。当数据被写入到MemStore时,相应的写操作也会被写入WAL中,以保证数据的持久性和故障恢复能力。
- StoreFile:当MemStore中的数据达到肯定大小阈值后,会被刷新到磁盘上的StoreFile中。StoreFile是HBase中理论长久化存储数据的文件模式,它蕴含了曾经写入的数据和相应的索引。
- HFile:HFile是StoreFile的底层存储格局,采纳了块索引和工夫范畴索引的形式,提供了高效的数据查找和扫描能力。HFile应用块(Block)来组织数据,并采纳压缩和编码技术来减小存储空间。
MemStore提供了长期的内存存储,StoreFile提供了长久化的磁盘存储,WAL用于保证数据的持久性。这种架构设计使得HBase可能提供高可用性、高性能和可扩展性的分布式存储和解决能力。
HBase读写流程
读流程
- 客户端发送读取申请:客户端向HBase集群发送读取申请,包含所需的表名、行键(Row Key)以及其余可选的参数(如列族、列限定符等)。
- 定位RegionServer和Region:HBase的客户端会与ZooKeeper进行通信,获取到存储有所需数据的Region所在的RegionServer的信息。
- RegionServer解决申请:客户端发送的读取申请达到对应的RegionServer,RegionServer会依据申请的行键定位到蕴含所需数据的Region。
- 数据读取:RegionServer首先会从MemStore中查找数据,如果数据在MemStore中找到,则间接返回给客户端。如果数据不在MemStore中,RegionServer会在磁盘上的StoreFile中进行查找,依据索引定位到所需的数据块,并将数据块读取到内存中进行解决。
- 数据返回给客户端:RegionServer将读取到的数据返回给客户端,客户端能够依据须要对数据进行进一步的解决和剖析。
写流程
- 客户端发送写入申请:客户端向HBase集群发送写入申请,包含表名、行键、列族、列限定符和对应的值等信息。
- 定位RegionServer和Region:客户端与ZooKeeper通信,获取存储指标数据的Region所在的RegionServer的信息。
- RegionServer解决申请:客户端发送的写入申请达到对应的RegionServer,RegionServer依据行键定位到指标Region。
- 写入到MemStore:RegionServer将写入申请中的数据写入到指标Region对应的内存中的MemStore。写入到MemStore是一个追加操作,将数据追加到内存中的MemStore中,并不间接写入磁盘。
- WAL日志记录:同时,RegionServer将写入申请中的操作写入WAL(Write-Ahead-Log)日志文件,确保数据的持久性和故障恢复能力。
- MemStore刷新到磁盘:当MemStore中的数据达到肯定的大小阈值时,RegionServer会将MemStore中的数据刷新到磁盘上的StoreFile中。刷新过程将内存中的数据写入到磁盘上的StoreFile,并生成相应的索引。
- 数据返回给客户端:写入实现后,RegionServer向客户端发送写入胜利的响应,示意数据已胜利写入。
MemStore Flush
在HBase中,MemStore Flush是将内存中的数据刷新到磁盘上的StoreFile的过程。当MemStore中的数据达到肯定大小阈值时,或者达到了肯定的工夫限度,HBase会触发MemStore Flush操作,以将数据长久化到磁盘,确保数据的持久性和可靠性。
上面是MemStore Flush的根本过程:
- MemStore Flush触发:当MemStore中的数据量达到肯定的阈值(由配置参数管制)或者达到了肯定的工夫限度时,HBase会触发MemStore Flush操作。这个阈值和工夫限度能够依据需要进行配置,以均衡写入性能和数据持久性的要求。
- 写入内存快照:在触发Flush操作时,HBase会先将MemStore中的数据做一个内存快照(Snapshot),以保障在Flush期间持续接管新的写入申请。
- 刷写到磁盘:内存快照实现后,HBase会将内存中的数据依照列族的维度划分为多个KeyValue,而后将这些KeyValue写入磁盘上的StoreFile。StoreFile采纳HFile格局,用于长久化存储数据。
- 更新Region元数据:实现刷写到磁盘后,HBase会更新Region的元数据,包含最新的StoreFile列表和相应的工夫戳等信息。
- MemStore清空:一旦数据刷写到磁盘上的StoreFile,HBase会清空相应的MemStore,以开释内存空间用于接管新的写入申请。
通过MemStore Flush操作,HBase能够将内存中的数据长久化到磁盘,以确保数据的持久性和可靠性。Flush操作的频率和老本能够通过配置参数进行调整,以适应不同的利用场景和性能需求。频繁的Flush操作可能会影响写入性能,而较长的Flush距离可能会减少数据失落的危险。因而,依据理论状况,须要正当设置Flush操作的参数,以均衡数据的持久性和写入性能的要求。
参数阐明
MemStore Flush在HBase中由以下几个参数进行管制,它们的含意如下:
- hbase.hregion.memstore.flush.size:该参数指定了MemStore的大小阈值。当MemStore中的数据量达到或超过这个阈值时,将触发MemStore Flush操作。该参数的默认值为 128MB。这个参数在HBase 0.98版本及更高版本中失效。在旧版本中,相似的参数名为 hbase.hregion.memstore.flush.size.upper,但其含意和作用雷同。
- hbase.hregion.memstore.block.multiplier:该参数是用来设置MemStore大小阈值的倍数。当MemStore的大小超过 hbase.hregion.memstore.flush.size 乘以 hbase.hregion.memstore.block.multiplier 时,将触发MemStore Flush操作。默认值为2。这个参数在HBase 0.98版本及更高版本中失效。
- hbase.hregion.memstore.flush.size.lower.limit:该参数定义了MemStore大小的上限限度。当MemStore中的数据量小于此上限时,不会触发MemStore Flush操作。该参数的默认值为0。在HBase 2.0版本及更高版本中失效。
- hbase.hregion.memstore.flush.size.upper.limit:该参数定义了MemStore大小的下限限度。当MemStore中的数据量超过此下限时,将强制触发MemStore Flush操作。该参数的默认值为Long.MAX_VALUE。在HBase 2.0版本及更高版本中失效。
上述的1和2,满足任一条件都会触发MemStore Flush操作。
这些参数须要依据具体的利用场景和性能要求进行正当的设置。较小的Flush阈值能够进步数据的持久性,但可能会减少Flush的频率和写入的开销;较大的Flush阈值能够缩小Flush的频率和开销,但可能会减少数据失落的危险。因而,须要依据利用的读写特色和数据的重要性,抉择适合的参数值。
StoreFile Compaction
StoreFile Compaction(文件合并)是 HBase 中的一个重要操作,它用于合并和优化存储在磁盘上的数据文件(StoreFile)。StoreFile Compaction 能够帮忙缩小磁盘空间占用、进步读取性能,并且在某些状况下能够进步写入性能。
StoreFile Compaction 的根本过程如下:
- Compact Selection(抉择合并):在进行 Compaction 之前,HBase 首先进行选择性合并。它会依据肯定的策略,如大小、工夫戳等,抉择一组须要合并的 StoreFile。这样能够限度合并的数据量,防止一次合并过多数据。
- Minor Compaction(小规模合并):Minor Compaction 次要合并较少数量的 StoreFile。它通过创立一个新的 StoreFile,并从多个旧的 StoreFile 中抉择合并的数据,将其合并到新的文件中。这个过程中,旧的 StoreFile 不会被删除,新的 StoreFile 会被创立并写入新的数据。
- Major Compaction(大规模合并):Major Compaction 是一种更为综合和耗时的合并操作。它会合并一个或多个 HBase 表的所有 StoreFile。Major Compaction 将会创立一个新的 StoreFile,并将所有旧的 StoreFile 中的数据合并到新的文件中。与 Minor Compaction 不同,Major Compaction 还会删除旧的 StoreFile,从而开释磁盘空间。
- Compaction Policy(合并策略):HBase 提供了不同的合并策略,能够依据数据特点和利用需要进行抉择。常见的合并策略包含 SizeTieredCompactionPolicy(按大小合并)和 DateTieredCompactionPolicy(按工夫戳合并)等。
通过 StoreFile Compaction,HBase 能够缩小磁盘上的存储空间占用,进步读取性能,同时合并操作还能够优化数据布局,减速数据的拜访。适合的合并策略的抉择能够依据数据的拜访模式和利用需要,以达到最佳的性能和存储效率。
参数阐明
StoreFile Compaction 过程中波及到的一些相干参数及其含意如下:
- hbase.hstore.compaction.min:指定了进行 Minor Compaction 的最小文件数。当 StoreFile 的数量达到或超过该值时,才会触发 Minor Compaction。默认值为 3。
- hbase.hstore.compaction.max:指定了进行 Major Compaction 的最大文件数。当 StoreFile 的数量超过该值时,将触发 Major Compaction。默认值为 10。
- hbase.hstore.compaction.ratio:指定了触发 Major Compaction 的比率。当一个 Region 中的 StoreFile 的总大小超过其最大文件大小的比率时,将触发 Major Compaction。默认值为 1.2。
- hbase.hstore.compaction.min.size:指定了进行 Compaction 的最小文件大小。当一个 StoreFile 的大小小于该值时,将不会参加 Compaction。默认值为 1 KB。
- hbase.hstore.compaction.max.size:指定了进行 Compaction 的最大文件大小。当一个 StoreFile 的大小超过该值时,将不会参加 Compaction。默认值为 Long.MAX_VALUE,即无限度。
- hbase.hstore.compaction.enabled:指定了是否启用 Compaction。如果设置为 false,则不会触发任何 Compaction 操作。默认值为 true。
- hbase.hstore.compaction.checker.interval.multiplier:指定了进行 Compaction 查看的工夫距离。理论查看的工夫距离为 hbase.hstore.compaction.checker.interval.multiplier 乘以 StoreFile 的均匀大小。默认值为 1.0。
这些参数能够在 HBase 的配置文件(hbase-site.xml)中进行设置。通过调整这些参数的值,能够依据数据量、存储需要和性能要求来优化 Compaction 操作的触发条件和行为。
触发过程
以下是判断是否触发 Compaction 的过程:
-
判断是否满足进行 Minor Compaction 的条件:
- 查看 StoreFile 的数量是否达到或超过 hbase.hstore.compaction.min。如果是,则满足触发 Minor Compaction 的条件。
-
判断是否满足进行 Major Compaction 的条件:
- 查看 StoreFile 的数量是否超过 hbase.hstore.compaction.max。如果是,则满足触发 Major Compaction 的条件。
或者
- 计算 StoreFile 的总大小与最大文件大小之间的比率。如果超过 hbase.hstore.compaction.ratio,即 StoreFile 的总大小超过最大文件大小的比率,那么满足触发 Major Compaction 的条件。
-
对于行将进行 Compaction 的 StoreFile:
- 查看 StoreFile 的大小是否在 hbase.hstore.compaction.min.size 和 hbase.hstore.compaction.max.size 之间。如果不在这个范畴内,则该文件将不会参加 Compaction。
-
查看是否启用 Compaction:
- 查看 hbase.hstore.compaction.enabled 的值是否为 true。如果为 false,则不会触发任何 Compaction 操作。
-
判断触发 Compaction 的工夫距离:
- 依据 hbase.hstore.compaction.checker.interval.multiplier 乘以 StoreFile 的均匀大小,得出理论的查看工夫距离。
依据以上判断过程,HBase 在每个 RegionServer 上的每个 Store(列族)会依据配置参数进行定期的 Compaction 查看。一旦满足触发 Compaction 的条件,相应的 Minor Compaction 或 Major Compaction 将被触发,合并和优化存储的数据文件。这样能够进步读取性能、节俭磁盘空间,并且在某些状况下能够进步写入性能。
Region Split
Region Split(区域分割)是 HBase 中的一个重要操作,它用于在数据增长过程中,将一个较大的 HBase 表的 Region(区域)划分成更小的子区域,以进步读写性能和负载平衡。
当一个 Region 的大小达到了事后配置的阈值时,HBase 将触发 Region Split 操作。Region Split 的根本过程如下:
- Split Policy(宰割策略):HBase 提供了多种宰割策略,用于决定何时触发 Region Split。常见的宰割策略包含按大小宰割(Size-based Split)和按行数宰割(Row-count-based Split)。这些策略能够依据数据特点和利用需要进行抉择。
- Split Selection(抉择宰割点):在触发宰割之前,HBase 首先抉择一个适当的宰割点。宰割点是指一个 RowKey,它将成为宰割后的两个子区域的边界。抉择宰割点的策略能够是依据大小、行数或其余自定义逻辑进行抉择。
- Region Split(区域分割):一旦抉择了宰割点,HBase 将通过创立两个新的子区域来执行宰割操作。原始的 Region 将被拆分成两个子区域,每个子区域负责存储宰割点两侧的数据。同时,HBase 会为新的子区域生成新的 Region ID,并更新元数据信息。
常见的区域分割形式包含:
- 平均宰割(Even Split):将一个 Region 平均地划分为两个子区域。宰割点依据数据大小或行数进行抉择,以放弃两个子区域的大小相近。
- 预分区(Pre-splitting):在创立表时,能够提前定义多个宰割点,将表划分为多个初始的子区域。这样能够在表创立之初就实现数据的平衡散布,防止后续的动静宰割。
- 自定义宰割(Custom Split):依据具体的业务需要和数据特点,能够通过自定义逻辑来抉择宰割点,实现更灵便的宰割形式。
通过正当地应用区域分割,能够充分利用集群资源,进步读写性能和负载平衡能力。不同的宰割策略和宰割形式能够依据数据规模、拜访模式和利用需要进行抉择,以满足不同场景下的需要。
预分区
在 HBase 中进行预分区能够通过 HBase Shell 或 HBase API 进行操作。以下是应用 HBase Shell 进行预分区的示例:
-
关上 HBase Shell:
$ hbase shell
-
创立表并指定分区:
hbase(main):001:0> create 'my_table', 'cf', {SPLITS => ['a', 'b', 'c']}
上述命令创立了一个名为
my_table
的表,并指定了三个分区点:’a’、’b’ 和 ‘c’。这将创立四个初始的子区域。 -
查看表的分区状况:
hbase(main):002:0> describe 'my_table'
这将显示表的详细信息,包含分区信息。
通过上述步骤,你能够在创立表时事后定义分区点,从而实现预分区。每个分区点将成为一个子区域的边界,确保数据在表创立时就能散布在多个子区域中,从而实现负载平衡和性能优化。
请留神,上述示例是应用 HBase Shell 进行预分区的简略示例。如果须要在编程中进行预分区,能够应用 HBase API,例如 Java API,通过在创立表时设置 SPLITS
参数来指定分区点。
以下是应用 HBase Java API 进行预分区的示例代码:
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
public class PreSplitExample {
public static void main(String[] args) throws IOException {
// 创立 HBase 配置
org.apache.hadoop.conf.Configuration config = HBaseConfiguration.create();
// 创立 HBase 连贯
try (Connection connection = ConnectionFactory.createConnection(config)) {
// 创立 HBase 管理器
try (Admin admin = connection.getAdmin()) {
// 定义表名
TableName tableName = TableName.valueOf("my_table");
// 定义分区点
byte[][] splitKeys = {
Bytes.toBytes("a"),
Bytes.toBytes("b"),
Bytes.toBytes("c")
};
// 创立表并指定分区
admin.createTable(TableDescriptorBuilder.newBuilder(tableName)
.addColumnFamily(ColumnFamilyDescriptorBuilder.of("cf"))
.setSplitKeys(splitKeys)
.build());
}
}
}
}
上述代码通过 HBase Java API 创立了一个名为 my_table
的表,并指定了三个分区点:’a’、’b’ 和 ‘c’。这将创立四个初始的子区域。
请留神,在应用 Java API 进行预分区时,须要先建设与 HBase 的连贯,并通过 HBase 管理器(Admin)执行表的创立操作,并设置 setSplitKeys(splitKeys)
办法来指定分区点。
通过上述示例代码,你能够在编程中应用 HBase Java API 实现预分区性能。
HBase优化
查问优化
设置Scan缓存
在HBase中,能够通过设置Scan
对象的setCaching()
办法来调整Scan
缓存的大小。Scan
缓存用于指定每次扫描操作从RegionServer返回给客户端的行数。通过调整缓存大小,能够在肯定水平上控制数据的读取性能和网络传输的开销。
以下是设置Scan
缓存的示例代码:
Scan scan = new Scan();
scan.setCaching(500); // 设置缓存大小为500行
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 解决扫描后果
}
scanner.close();
在上述示例中,setCaching()
办法将缓存大小设置为500行。能够依据理论需要调整这个值,须要依据数据大小、网络带宽和性能要求进行衡量。较大的缓存大小能够缩小客户端与RegionServer之间的通信次数,进步读取性能,但同时也会减少内存耗费。较小的缓存大小能够缩小内存耗费,但可能会减少通信次数和网络传输开销。
须要留神的是,setCaching()
办法设置的是每次扫描的缓存大小,并不是全局的设置。如果须要对整个表的扫描操作失效,须要在每次扫描时都设置缓存大小。
此外,还能够通过调整HBase的配置参数来全局设置缓存大小。在hbase-site.xml
配置文件中增加以下参数能够设置默认的缓存大小:
<property>
<name>hbase.client.scanner.caching</name>
<value>500</value> <!-- 设置默认的缓存大小为500行 -->
</property>
以上是通过代码和配置文件来设置Scan
缓存大小的办法,依据具体的利用场景和需要,能够抉择适当的形式进行设置。
显示指定列
当应用Scan或者GET获取大量的行时,最好指定所须要的列,因为服务端通过网络传输到客户端,数据量太大可能是瓶颈。如果能无效过滤局部数据,能很大水平的缩小网络I/O的破费。
在HBase中,能够应用Scan
或Get
操作来显示指定的列。上面别离介绍两种形式的用法:
- 应用
Scan
操作显示指定列:
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1")); // 指定列族(cf)和列(col1)
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
byte[] value = result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("col1"));
// 解决列(col1)的值
}
scanner.close();
在上述示例中,应用scan.addColumn()
办法来指定要显示的列族和列。在for
循环中,通过result.getValue()
办法获取指定列的值。
- 应用
Get
操作显示指定列:
Get get = new Get(Bytes.toBytes("row1")); // 指定行键(row1)
get.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1")); // 指定列族(cf)和列(col1)
Result result = table.get(get);
byte[] value = result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("col1"));
// 解决列(col1)的值
在上述示例中,应用get.addColumn()
办法来指定要显示的列族和列。通过table.get()
办法获取行数据,并通过result.getValue()
办法获取指定列的值。
无论是应用Scan
还是Get
,都能够通过addColumn()
办法来指定要显示的列族和列。能够依据具体的需要,屡次调用addColumn()
办法来显示多个列。
须要留神的是,HBase中的列是以字节数组(byte[]
)模式示意的,因而在应用addColumn()
和getValue()
办法时,须要将列族和列名转换为字节数组。
禁用块缓存
如果批量进行全表扫描,默认是有缓存的,如果此时有缓存,会升高扫描的效率。
在HBase中,能够通过设置Scan
对象的setCacheBlocks()
办法来禁用块缓存。块缓存是HBase中的一种缓存机制,用于放慢数据的读取操作。然而,在某些状况下,禁用块缓存可能是无益的,例如对于某些热点数据或者须要立刻获取最新数据的场景。
以下是禁用Scan
块缓存的示例代码:
Scan scan = new Scan();
scan.setCacheBlocks(false); // 禁用块缓存
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 解决扫描后果
}
scanner.close();
在上述示例中,setCacheBlocks(false)
办法将禁用Scan
操作的块缓存。
须要留神的是,禁用块缓存可能会减少对HBase存储的理论磁盘读取次数,并且在一些场景下可能导致性能降落。因而,在禁用块缓存之前,倡议认真评估利用需要和场景,确保禁用块缓存的决策是正当的。
对于常常读到的数据,倡议应用默认值,开启块缓存。
写入优化
设置AutoFlush
Htable有一个属性是AutoFlush,该属性用于反对客户端的批量更新,默认是true,当客户端每收到一条数据,立即发送到服务端,如果设置为false,当客户端提交put申请时候,先将该申请在客户端缓存,达到阈值的时候或者执行hbase.flushcommits(),才向RegionServer提交申请。
在HBase中,能够通过设置Table
对象的setAutoFlush()
办法来管制主动刷新(AutoFlush)行为。AutoFlush决定了在何时将数据从客户端发送到RegionServer并写入到存储中。
以下是设置AutoFlush的示例代码:
// 创立HBase配置对象
Configuration conf = HBaseConfiguration.create();
// 创立HBase连贯
Connection connection = ConnectionFactory.createConnection(conf);
// 获取表对象
TableName tableName = TableName.valueOf("your_table_name");
Table table = connection.getTable(tableName);
// 设置AutoFlush
table.setAutoFlush(false); // 敞开AutoFlush
// 执行写入操作
Put put = new Put(Bytes.toBytes("row1"));
put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1"), Bytes.toBytes("value1"));
table.put(put);
// 手动刷新数据
table.flushCommits(); // 手动刷新数据到RegionServer
// 敞开表和连贯
table.close();
connection.close();
在上述示例中,table.setAutoFlush(false)
办法将敞开AutoFlush。这意味着在执行写操作时,数据不会立刻被刷新到RegionServer和存储中,而是先缓存在客户端的内存中。只有当调用table.flushCommits()
办法时,数据才会被手动刷新到RegionServer。
须要留神的是,敞开AutoFlush能够进步写入性能,尤其是在批量写入或者频繁写入的场景中。然而,敞开AutoFlush也会减少数据在客户端内存中的暂存工夫,并减少了数据失落的危险。因而,在敞开AutoFlush时,须要在适当的机会手动调用flushCommits()
办法来确保数据的持久性。
同时,还能够通过设置table.setWriteBufferSize()
办法来指定客户端写缓冲区的大小。这能够帮忙在缓存中存储更多的数据,缩小刷新到RegionServer的次数,进步写入性能。例如:
table.setWriteBufferSize(1024 * 1024); // 设置写缓冲区大小为1MB
在上述示例中,将写缓冲区大小设置为1MB。
总之,通过设置table.setAutoFlush(false)
和table.setWriteBufferSize()
办法,能够管制AutoFlush行为和客户端写缓冲区大小,以优化写入性能和数据刷新的策略。依据具体的利用需要和场景,能够进行适当的配置调整。
参数优化
Zookeeper 会话超时工夫
属性:zookeeper.session.timeout
解释:默认值为 90000 毫秒(90s)。当某个 RegionServer 挂掉,90s 之后 Master 能力察觉到。可适当减小此值,尽可能快地检测 regionserver 故障,可调整至 20-30s。看你能有都能忍受超时,同时能够调整重试工夫和重试次数
hbase.client.pause(默认值 100ms)
hbase.client.retries.number(默认 15 次)
设置 RPC 监听数量
属性:hbase.regionserver.handler.count
解释:默认值为 30,用于指定 RPC 监听的数量,能够依据客户端的申请数进行调整,读写申请较多时,减少此值。
手动管制 Major Compaction
属性:hbase.hregion.majorcompaction
解释:默认值:604800000 秒(7 天), Major Compaction 的周期,若敞开主动 Major Compaction,可将其设为 0。如果敞开肯定记得本人手动合并,因为大合并十分有意义。
优化 HStore 文件大小
属性:hbase.hregion.max.filesize
解释:默认值 10737418240(10GB),如果须要运行 HBase 的 MR 工作,能够减小此值,因为一个 region 对应一个 map 工作,如果单个 region 过大,会导致 map 工作执行工夫。过长。该值的意思就是,如果 HFile 的大小达到这个数值,则这个 region 会被切分为两个 Hfile。
优化 HBase 客户端缓存
属性:hbase.client.write.buffer
解释:默认值 2097152bytes(2M)用于指定 HBase 客户端缓存,增大该值能够缩小 RPC调用次数,然而会耗费更多内存,反之则反之。个别咱们须要设定肯定的缓存大小,以达到缩小 RPC 次数的目标。
指定 scan.next 扫描 HBase 所获取的行数
属性:hbase.client.scanner.caching
解释:用于指定 scan.next 办法获取的默认行数,值越大,耗费内存越大。
SpringBoot中应用HBase
增加 Maven 依赖:
<!-- HBase 2.4.3 依赖 -->
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.4.3</version>
</dependency>
配置 HBase 连贯:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
@Configuration
public class HBaseConfig {
@Bean
public Connection hbaseConnection() throws IOException {
Configuration config = HBaseConfiguration.create();
config.set("hbase.zookeeper.quorum", "localhost"); // HBase ZooKeeper 地址
config.set("hbase.zookeeper.property.clientPort", "2181"); // HBase ZooKeeper 端口
return ConnectionFactory.createConnection(config);
}
}
编写增删改查代码:
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class HBaseService {
@Autowired
private Connection hbaseConnection;
//增加数据
public void putData(String tableName, String rowKey, String columnFamily, String column, String value) throws IOException {
Table table = hbaseConnection.getTable(TableName.valueOf(tableName));
Put put = new Put(Bytes.toBytes(rowKey));
put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value));
table.put(put);
table.close();
}
//删除数据
public void deleteData(String tableName, String rowKey) throws IOException {
Table table = hbaseConnection.getTable(TableName.valueOf(tableName));
Delete delete = new Delete(Bytes.toBytes(rowKey));
table.delete(delete);
table.close();
}
//获取数据
public String getData(String tableName, String rowKey, String columnFamily, String column) throws IOException {
Table table = hbaseConnection.getTable(TableName.valueOf(tableName));
Get get = new Get(Bytes.toBytes(rowKey));
Result result = table.get(get);
byte[] valueBytes = result.getValue(Bytes.toBytes(columnFamily), Bytes.toBytes(column));
table.close();
return Bytes.toString(valueBytes);
}
}
在上述代码中,HBaseConfig
类配置了 HBase 连贯,通过 hbaseConnection()
办法创立 HBase 连贯。HBaseService
类提供了 putData()
、deleteData()
和 getData()
办法,别离用于插入数据、删除数据和获取数据。
Scan
以下是应用Scan 操作的示例代码:
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
public class HBaseScanExample {
public static void main(String[] args) throws IOException {
// 创立 HBase 配置对象
Configuration conf = HBaseConfiguration.create();
// 创立 HBase 连贯
Connection connection = ConnectionFactory.createConnection(conf);
// 获取表对象
TableName tableName = TableName.valueOf("your_table_name");
Table table = connection.getTable(tableName);
// 创立 Scan 对象
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1")); // 指定要查问的列族和列
// 执行 Scan 操作
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 解决每一行数据
byte[] row = result.getRow();
byte[] value = result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("col1"));
System.out.println("Row key: " + Bytes.toString(row) + ", Value: " + Bytes.toString(value));
}
// 敞开资源
scanner.close();
table.close();
connection.close();
}
}
在上述代码中,首先创立 HBase 配置对象 Configuration
,而后通过 ConnectionFactory
创立 HBase 连贯 Connection
。接下来,通过连贯获取表对象 Table
,指定要进行 Scan 操作的表名。而后创立 Scan
对象,并应用 addColumn
办法指定要查问的列族和列。最初,应用 getScanner
办法执行 Scan 操作,并遍历 ResultScanner
获取每一行的数据,并进行解决。
Phoenix
Phoenix是一个开源的基于Apache HBase的关系型数据库引擎,它提供了SQL接口来拜访HBase中存储的数据。它在HBase的根底上增加了SQL查问和事务性能,使得应用HBase的开发者能够应用相熟的SQL语言进行数据操作和查问。
Phoenix在HBase中的主要用途包含:
- SQL查问:Phoenix容许开发者应用规范的SQL语句来查问和操作HBase中的数据,无需编写简单的HBase API代码。这简化了开发过程,升高了应用HBase进行数据拜访的门槛。
- 索引反对:Phoenix提供了对HBase数据的二级索引反对,开发者能够应用SQL语句创立索引,从而放慢查问速度。索引在数据查问和过滤中起到重要的作用,进步了数据的检索效率。
- 事务反对:Phoenix引入了基于MVCC(多版本并发管制)的事务机制,使得在HBase中进行简单的事务操作成为可能。开发者能够通过Phoenix的事务性能来保证数据的一致性和可靠性。
- SQL函数和聚合:Phoenix反对各种内置的SQL函数和聚合函数,如SUM、COUNT、MAX、MIN等,使得在HBase上进行数据统计和剖析变得更加不便。
要在HBase中应用Phoenix,须要先装置并配置好Phoenix。以下是一个在HBase中应用Phoenix的示例代码:
- 增加 Maven 依赖: 在 Maven 我的项目的
pom.xml
文件中增加以下依赖:
<!-- Phoenix 依赖 -->
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-core</artifactId>
<version>4.16.0-HBase-2.4</version>
</dependency>
- 创立 Phoenix 表: 在 HBase 中创立 Phoenix 表。能够应用 Phoenix 提供的 SQL 语法创立表和定义模式。例如,创立一个名为
users
的表:
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR,
age INTEGER
);
- 应用 Phoenix 进行操作: 在 Java 代码中,能够应用 Phoenix 提供的
PhoenixConnection
和PhoenixStatement
来执行 SQL 操作。
import java.sql.*;
public class PhoenixExample {
public static void main(String[] args) throws SQLException {
// 创立 Phoenix 连贯
String url = "jdbc:phoenix:<HBase ZooKeeper Quorum>:<HBase ZooKeeper Port>";
Connection connection = DriverManager.getConnection(url);
// 执行 SQL 查问
String query = "SELECT * FROM users";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
// 解决查问后果
while (resultSet.next()) {
long id = resultSet.getLong("ID");
String name = resultSet.getString("NAME");
int age = resultSet.getInt("AGE");
System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
}
// 敞开资源
resultSet.close();
statement.close();
connection.close();
}
}
在上述代码中,须要将 <HBase ZooKeeper Quorum>
和 <HBase ZooKeeper Port>
替换为你的 HBase ZooKeeper 地址和端口。
通过创立 PhoenixConnection
并传递正确的 JDBC URL,能够取得连贯对象。接下来,能够应用 createStatement()
办法创立 PhoenixStatement
对象,并应用 executeQuery()
办法执行 SQL 查问。
而后,能够应用 ResultSet
对象遍历查问后果,并提取所需的字段。在此示例中,遍历了 users
表的后果,并打印了每行的 ID、Name 和 Age。
本篇文章就到这里,感激浏览,如果本篇博客有任何谬误和倡议,欢送给我留言斧正。文章继续更新,能够关注公众号第一工夫浏览。
发表回复