区域是表的可用性和分布的基本元素,并且由每列存储族组成。对象的层次结构如下:

Table                    (HBase table)
    Region               (Regions for the table)
        Store            (Store per ColumnFamily for each Region for the table)
            MemStore     (MemStore for each Store for each Region for the table)
            StoreFile    (StoreFiles for each Store for each Region for the table)
                Block    (Blocks within a StoreFile within a Store for each Region for the table) 

有关写入 HDFS 时 HBase 文件的描述,请参阅浏览 HBFS 对象的 HDFS

72.1。区域数量的考虑因素

通常,HBase 被设计为每个服务器运行一小部分(20-200)个相对较大(5-20​​Gb)的区域。对此的考虑如下:

72.1.1。我为什么要保持我的地区数量低?

通常,您希望保留您的区域在 HBase 上的数量较少,原因有很多。通常每个 RegionServer 大约 100 个区域产生了最好的结果。以下是保持区域数量低的一些原因:

  1. MSLAB(MemStore 本地分配缓冲区)每个 MemStore 需要 2MB(每个区域每个系列 2MB)。每个拥有 2 个系列的 1000 个区域使用了 3.9GB 的堆,并且它甚至还没有存储数据。注意:2MB 值是可配置的。

  2. 如果以相同的速率填充所有区域,则全局内存使用会使得当您有太多区域而这会产生压缩时会强制进行微小的刷新。几十次重写相同的数据是你想要的最后一件事。一个例子是平均填充 1000 个区域(有一个系列),让我们考虑全局 MemStore 使用 5GB 的下限(区域服务器将有一个大堆)。一旦达到 5GB,它将强制刷新最大区域,此时它们几乎都应该有大约 5MB 的数据,因此它将刷新该数量。稍后插入 5MB,它将刷新另一个区域,现在将有超过 5MB 的数据,依此类推。这是目前区域数量的主要限制因素;参见每个 RS 的区域数 - 上限详细公式。

  3. 主人对大量地区过敏,并且需要花费大量时间分配它们并分批移动它们。原因是它对 ZK 的使用很重,而且目前它并不是非常同步(真的可以改进 - 并且已经在 0.96 HBase 中得到了改进)。

  4. 在旧版本的 HBase(pre-HFile v2,0.90 和之前版本)中,少数 RS 上的大量区域可能导致存储文件索引上升,增加堆使用量并可能在 RS 上产生内存压力或 OOME

另一个问题是 MapReduce 作业的区域数量的影响;每个 HBase 区域通常有一个映射器。因此,每个 RS 仅托管 5 个区域可能不足以为 MapReduce 作业获取足够数量的任务,而 1000 个区域将生成太多任务。

有关配置指南,请参阅确定区域计数和大小

72.2。 Region-RegionServer 分配

本节介绍如何将区域分配给 RegionServers。

72.2.1。启动

当 HBase 启动时,区域分配如下(短版本):

  1. Master 在启动时调用AssignmentManager

  2. AssignmentManager查看hbase:meta中的现有区域分配。

  3. 如果区域分配仍然有效(即,如果 RegionServer 仍在线),则保留分配。

  4. 如果赋值无效,则调用LoadBalancerFactory来分配区域。负载均衡器(HBase 1.0 中默认为StochasticLoadBalancer)将区域分配给 RegionServer。

  5. 在 RegionServer 打开区域时,使用 RegionServer 分配(如果需要)和 RegionServer 启动代码(RegionServer 进程的开始时间)更新hbase:meta

72.2.2。故障转移

RegionServer 失败时:

  1. 由于 RegionServer 已关闭,这些区域立即变为不可用。

  2. Master 将检测到 RegionServer 失败。

  3. 区域分配将被视为无效,并将像启动顺序一样重新分配。

  4. 机上查询会重新尝试,而不会丢失。

  5. 操作在以下时间内切换到新的 RegionServer:

    ZooKeeper session timeout + split time + assignment/replay time 
    

72.2.3。区域负载平衡

可以通过 LoadBalancer 周期性地移动区域。

72.2.4。地区国家转型

HBase 维护每个区域的状态,并在hbase:meta中保持状态。 hbase:meta区域本身的状态在 ZooKeeper 中持久存在。您可以在 Master Web UI 中查看转换中的区域的状态。以下是可能的区域状态列表。

可能的地区国家

  • OFFLINE:该区域处于脱机状态且未打开

  • OPENING:该地区正处于开放状态

  • OPEN:区域已打开且 RegionServer 已通知主服务器

  • FAILED_OPEN:RegionServer 无法打开该区域

  • CLOSING:该地区正处于关闭状态

  • CLOSED:RegionServer 已关闭该区域并通知主站

  • FAILED_CLOSE:RegionServer 无法关闭该区域

  • SPLITTING:RegionServer 通知主站区域正在拆分

  • SPLIT:RegionServer 通知主站区域已完成拆分

  • SPLITTING_NEW:正在通过正在进行的拆分创建此区域

  • MERGING:RegionServer 通知主服务器该区域正在与另一个区域合并

  • MERGED:RegionServer 通知主服务器该区域已合并

  • MERGING_NEW:该区域由两个区域的合并创建

region states图 2. Region State TransitionsGraph Legend

  • 布朗:离线状态,一种特殊状态,可以是瞬态的(在打开之前关闭之后),终端(禁用表的区域)或初始(新创建的表的区域)

  • Palegreen:在线状态,区域可以提供请求

  • Lightblue:瞬态

  • 红色:失败状态需要 OPS 注意

  • 黄金:区域的终端状态分裂/合并

  • 灰色:通过拆分/合并创建的区域的初始状态

过渡状态描述

  1. 主设备将区域从OFFLINE移动到OPENING状态,并尝试将区域分配给 RegionServer。 RegionServer 可能已收到或未收到开放区域请求。主服务器重试将开放区域请求发送到 RegionServer,直到 RPC 通过或主服务器用完为止。 RegionServer 收到开放区域请求后,RegionServer 开始打开该区域。

  2. 如果主服务器没有重试,则主服务器会阻止 RegionServer 通过将区域移动到CLOSING状态并尝试关闭它来打开该区域,即使 RegionServer 开始打开该区域也是如此。

  3. 在 RegionServer 打开区域后,它会继续尝试通知主服务器,直到主服务器将区域移动到OPEN状态并通知 RegionServer。该地区现已开放。

  4. 如果 RegionServer 无法打开该区域,则会通知主服务器。主服务器将区域移动到CLOSED状态并尝试在不同的 RegionServer 上打开该区域。

  5. 如果主服务器无法在某个区域中的任何区域上打开该区域,则会将该区域移动到FAILED_OPEN状态,并且在操作员从 HBase shell 进行干预或服务器已停止之前不会采取进一步操作。

  6. 主设备将区域从OPEN移动到CLOSING状态。持有该区域的 RegionServer 可能已收到或未收到近区域请求。主服务器重试向服务器发送关闭请求,直到 RPC 通过或主服务器用完为止。

  7. 如果 RegionServer 未联机或抛出NotServingRegionException,则主服务器将该区域移至OFFLINE状态并将其重新分配给其他 RegionServer。

  8. 如果 RegionServer 处于联机状态,但在主计算机用完重试后无法访问,则主服务器会将该区域移至FAILED_CLOSE状态,并且在操作员从 HBase shell 进行干预或服务器已停止之前不会采取进一步操作。

  9. 如果 RegionServer 获取关闭区域请求,它将关闭该区域并通知主服务器。主设备将区域移动到CLOSED状态,并将其重新分配给不同的 RegionServer。

  10. 在分配区域之前,如果区域处于CLOSED状态,则主区域会自动将区域移动到OFFLINE状态。

  11. 当 RegionServer 即将拆分区域时,它会通知主服务器。主设备将要分割的区域从OPEN状态移动到SPLITTING状态,并将要创建的两个新区域添加到 RegionServer。这两个区域最初处于SPLITTING_NEW状态。

  12. 通知主服务器后,RegionServer 开始拆分该区域。一旦超过不返回点,RegionServer 就会再次通知主站,以便主站可以更新hbase:meta表。但是,在服务器通知拆分完成之前,主服务器不会更新区域状态。如果分割成功,则分割区域从SPLITTING移动到SPLIT状态,并且两个新区域从SPLITTING_NEW移动到OPEN状态。

  13. 如果分割失败,则分割区域从SPLITTING移回OPEN状态,并且创建的两个新区域从SPLITTING_NEW移动到OFFLINE状态。

  14. 当 RegionServer 即将合并两个区域时,它会首先通知主服务器。主设备将要合并的两个区域从OPEN合并到MERGING状态,并将保存合并区域区域内容的新区域添加到 RegionServer。新区域最初处于MERGING_NEW状态。

  15. 通知主服务器后,RegionServer 开始合并这两个区域。一旦超过不返回点,RegionServer 就会再次通知主服务器,以便主服务器可以更新 META。但是,在 RegionServer 通知合并已完成之前,主服务器不会更新区域状态。如果合并成功,则两个合并区域从MERGING移动到MERGED状态,并且新区域从MERGING_NEW移动到OPEN状态。

  16. 如果合并失败,则两个合并区域从MERGING移回到OPEN状态,并且为保持合并区域的内容而创建的新区域从MERGING_NEW移动到OFFLINE状态。

  17. 对于FAILED_OPENFAILED_CLOSE状态的区域,当操作员通过 HBase Shell 重新分配它们时,主设备会尝试再次关闭它们。

72.3。 Region-RegionServer 的位置

随着时间的推移,Region-RegionServer 的位置是通过 HDFS 块复制实现的。在选择写入副本的位置时,HDFS 客户端默认执行以下操作:

  1. 第一个副本写入本地节点

  2. 第二个副本写入另一个机架上的随机节点

  3. 第三个副本与第二个副本写在同一个机架上,但是在随机选择的不同节点上

  4. 后续副本将写入群集上的随机节点。请参阅此页面上的 _ 副本放置:第一个婴儿步骤 _: HDFS 架构

因此,HBase 最终在冲洗或压实之后实现区域的局部性。在 RegionServer 故障转移情况下,可以为 RegionServer 分配具有非本地 StoreFiles 的区域(因为没有任何副本是本地的),但是当在该区域中写入新数据,或者压缩表并重写 StoreFiles 时,它们将成为 RegionServer 的“本地”。

有关详细信息,请参阅此页面上的 _ 副本放置:第一个婴儿步骤 _: HDFS 架构以及 Lars George 关于 HBase 和 HDFS 位置的博客。

72.4。地区分裂

区域在达到配置的阈值时分割。下面我们简单地讨论这个话题。有关更长时间的展示,请参阅我们的 Enis Soztutar 的 Apache HBase 区域拆分和合并

Splits 在 RegionServer 上独立运行;即师父不参加。 RegionServer 拆分一个区域,对拆分区域进行离线,然后将子区域添加到hbase:meta,打开父级托管 RegionServer 上的女儿,然后将拆分报告给 Master。请参阅 Managed Splitting ,了解如何手动管理拆分(以及为什么要这样做)。

72.4.1。自定义拆分策略

您可以使用自定义 RegionSplitPolicy (HBase 0.94+)覆盖默认拆分策略。通常,自定义拆分策略应该扩展 HBase 的默认拆分策略: IncreaseToUpperBoundRegionSplitPolicy

策略可以通过 HBase 配置或基于每个表进行全局设置。

hbase-site.xml 中全局配置拆分策略

<property>
  <name>hbase.regionserver.region.split.policy</name>
  <value>org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value>
</property> 

使用 Java API 在表上配置拆分策略

HTableDescriptor tableDesc = new HTableDescriptor("test");
tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, ConstantSizeRegionSplitPolicy.class.getName());
tableDesc.addFamily(new HColumnDescriptor(Bytes.toBytes("cf1")));
admin.createTable(tableDesc);
---- 

使用 HBase Shell 在表上配置拆分策略

hbase> create 'test', {METADATA => {'SPLIT_POLICY' => 'org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy'}},{NAME => 'cf1'} 

可以通过使用的 HBaseConfiguration 或基于每个表来全局设置策略:

HTableDescriptor myHtd = ...;
myHtd.setValue(HTableDescriptor.SPLIT_POLICY, MyCustomSplitPolicy.class.getName()); 

DisabledRegionSplitPolicy策略阻止手动区域拆分。

72.5。手动区域拆分

可以在创建表(预分割)时或在稍后的时间手动拆分表作为管理操作。出于以下一个或多个原因,您可以选择拆分您的区域。可能还有其他正当理由,但手动拆分表的需要也可能表明您的架构设计存在问题。

手动拆分表的原因

  • 您的数据按时间序列或其他类似算法排序,该算法在表格末尾对新数据进行排序。这意味着持有最后一个区域的 Region Server 始终处于负载状态,而其他 Region Servers 处于空闲状态或大部分处于空闲状态。另请参见单调递增行键/时间序列数据

  • 您在桌子的一个区域中开发了一个意外的热点。例如,跟踪网络搜索的应用程序可能会因为有关该名人的新闻而对名人进行大量搜索而被淹没。有关此特定方案的更多讨论,请参见 perf.one.region

  • 在群集中 RegionServers 数量大幅增加之后,可以快速分散负载。

  • 在大容量负载之前,这可能会导致跨区域的异常和不均匀负载。

有关完全手动管理拆分的危险和可能的好处的讨论,请参阅管理拆分

The DisabledRegionSplitPolicy policy blocks manual region splitting.

72.5.1。确定分裂点

手动拆分表的目的是为了在单独使用良好的 rowkey 设计无法实现的情况下,提高平衡群集负载的几率。牢记这一点,您划分区域的方式非常依赖于数据的特征。您可能已经知道拆分桌子的最佳方法。如果没有,你拆分表的方式取决于你的键是什么样的。

字母数字 Rowkeys

如果您的 rowkeys 以字母或数字开头,则可以在字母或数字边界处拆分表格。例如,以下命令创建一个表,其中区域在每个元音处分开,因此第一个区域具有 A-D,第二个区域具有 E-H,第三个区域具有 I-N,第四个区域具有 O-V,第五个区域具有 U-Z。

使用自定义算法

RegionSplitter 工具随 HBase 一起提供,并使用 SplitAlgorithm 为您确定分割点。作为参数,您可以为其提供算法,所需的区域数和列族。它包括三种分割算法。第一种是[HexStringSplit](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.HexStringSplit.html)算法,它假设行键是十六进制字符串。第二个是[DecimalStringSplit](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.DecimalStringSplit.html)算法,它假定行键是 00000000 到 99999999 范围内的十进制字符串。第三个[UniformSplit](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.UniformSplit.html)假设行键是随机字节数组。你可能需要开发自己的[SplitAlgorithm](https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/util/RegionSplitter.SplitAlgorithm.html),使用提供的那些作为模型。

72.6。在线区域合并

Master 和 RegionServer 都参与在线区域合并事件。客户端将合并 RPC 发送到主服务器,然后主服务器将这些区域一起移动到负载较重的区域所在的 RegionServer。最后,主服务器将合并请求发送到此 RegionServer,然后运行合并。与区域拆分过程类似,区域合并在 RegionServer 上作为本地事务运行。它勾勒出区域,然后合并文件系统上的两个区域,从hbase:meta原子删除合并区域并将合并区域添加到hbase:meta,打开 RegionServer 上的合并区域并将合并报告给主区域。

HBase shell 中区域合并的示例

$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME'
$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME', true 

这是一个异步操作,调用立即返回而不等待合并完成。将true作为可选的第三个参数传递将强制合并。通常只能合并相邻区域。 force参数会覆盖此行为,仅供专家使用。

72.7。商店

商店拥有一个 MemStore 和 0 个或更多 StoreFiles(HFiles)。商店对应于给定区域的表的列族。

72.7.1。那种 MEMSTORE

MemStore 保存对 Store 的内存修改。修改是 Cells / KeyValues。请求刷新时,当前的 MemStore 将移动到快照并被清除。 HBase 继续提供来自新 MemStore 和后备快照的编辑,直到刷新器报告刷新成功。此时,快照将被丢弃。请注意,当刷新发生时,属于同一区域的 MemStore 都将被刷新。

72.7.2。 MemStore Flush

可以在下面列出的任何条件下触发 MemStore 刷新。最小冲洗单位是每个区域,而不是单个 MemStore 级别。

  1. 当 MemStore 达到hbase.hregion.memstore.flush.size指定的大小时,属于其区域的所有 MemStore 都将刷新到磁盘。

  2. 当整个 MemStore 使用率达到hbase.regionserver.global.memstore.upperLimit指定的值时,来自不同区域的 MemStores 将刷新到磁盘,以减少 RegionServer 中的 MemStore 总体使用量。

    刷新顺序基于区域的 MemStore 用法的降序。

    区域将刷新其 MemStore,直到整个 MemStore 使用率降至或略低于hbase.regionserver.global.memstore.lowerLimit

  3. 当给定区域服务器的 WAL 中的 WAL 日志条目数达到hbase.regionserver.max.logs中指定的值时,来自不同区域的 MemStores 将刷新到磁盘以减少 WAL 中的日志数。

    冲洗订单基于时间。

    具有最早 MemStores 的区域首先被刷新,直到 WAL 计数降至hbase.regionserver.max.logs以下。

72.7.3。扫描

  • 当客户端对表发出扫描时,HBase 会生成RegionScanner对象,每个区域一个,以提供扫描请求。

  • RegionScanner对象包含StoreScanner对象列表,每列一个对象。

  • 每个StoreScanner对象还包含StoreFileScanner对象的列表,对应于相应列族的每个 StoreFile 和 HFile,以及 MemStore 的KeyValueScanner对象列表。

  • 这两个列表合并为一个,按照升序排序,列表末尾的 MemStore 扫描对象。

  • 构造StoreFileScanner对象时,它与MultiVersionConcurrencyControl读取点相关联,该读取点是当前memstoreTS,过滤掉读取点之外的任何新更新。

72.7.4。 StoreFile(HFile)

StoreFiles 是您的数据所在的位置。

HFile 格式

HFile 文件格式基于[BigTable 2006 ]论文和 Hadoop 的 TFile 中描述的 SSTable 文件(单元测​​试套件和压缩线束是直接取自 TFile)。 Schubert Zhang 关于 HFile 的博文:存储分类键值对的块索引文件格式对 HBase 的 HFile 进行了全面介绍。 Matteo Bertozzi 也提出了一个有用的描述, HBase I / O:HFile

有关更多信息,请参阅 HFile 源代码。另请参阅带有内联块(版本 2)的 HBase 文件格式,以获取有关 0.92 中包含的 HFile v2 格式的信息。

HFile 工具

要查看 HFile 内容的文本化版本,您可以使用hbase hfile工具。键入以下内容以查看用法:

$ ${HBASE_HOME}/bin/hbase hfile 

例如,要查看文件 hdfs://10.81.47.41:8020 / hbase / default / TEST / 1418428042 / DSMP / 4759508618286845475 的内容,请键入以下内容:

 $ ${HBASE_HOME}/bin/hbase hfile -v -f hdfs://10.81.47.41:8020/hbase/default/TEST/1418428042/DSMP/4759508618286845475 

如果你不使用选项-v 来查看 HFile 的摘要。有关hfile工具的其他信息,请参阅用法。

在此工具的输出中,您可能会在“Mid-key”/“firstKey”/“lastKey”等位置看到某些键的“seqid = 0”。这些是'KeyOnlyKeyValue'类型实例 - 意味着它们的 seqid 是无关紧要的&amp;我们只需要这些键值实例的键。

HDFS 上的 StoreFile 目录结构

有关目录结构的 HDFS 上 StoreFiles 的详细信息,请参阅浏览 HBase 对象的 HDFS

72.7.5。块

StoreFiles 由块组成。 blocksize 是基于每个 ColumnFamily 配置的。

压缩发生在 StoreFiles 中的块级别。有关压缩的更多信息,请参见 HBase 中的压缩和数据块编码。

有关块的更多信息,请参阅 HFileBlock 源代码。

72.7.6。核心价值

KeyValue 类是 HBase 中数据存储的核心。 KeyValue 包装一个字节数组,并将偏移量和长度转换为传递的数组,该数组指定将内容解释为 KeyValue 的位置。

字节数组中的 KeyValue 格式为:

  • keylength

  • valuelength

密钥进一步分解为:

  • rowlength

  • 行(即 rowkey)

  • columnfamilylength

  • 的 ColumnFamily

  • 列限定符

  • 时间戳

  • keytype(例如,Put,Delete,DeleteColumn,DeleteFamily)

KeyValue 实例是 _ 而不是 _ 跨块分割。例如,如果存在 8 MB KeyValue,即使块大小为 64kb,此 KeyValue 也将作为相干块读入。有关更多信息,请参阅 KeyValue 源代码。

为了强调上述几点,请检查同一行的两个不同列的两个 Puts 会发生什么:

  • 放#1:rowkey=row1, cf:attr1=value1

  • 放#2:rowkey=row1, cf:attr2=value2

即使这些是同一行,也会为每列创建一个 KeyValue:

Put#1 的关键部分:

  • rowlength -----------→ 4

  • row -----------------→ row1

  • columnfamilylength --→ 2

  • columnfamily --------→ cf

  • columnqualifier -----→ attr1

  • timestamp -----------→ server time of Put

  • keytype -------------→ Put

Put#2 的关键部分:

  • rowlength -----------→ 4

  • row -----------------→ row1

  • columnfamilylength --→ 2

  • columnfamily --------→ cf

  • columnqualifier -----→ attr2

  • timestamp -----------→ server time of Put

  • keytype -------------→ Put

了解 rowkey,ColumnFamily 和 column(aka columnqualifier)嵌入在 KeyValue 实例中至关重要。这些标识符越长,KeyValue 就越大。

72.7.7。压实

模棱两可的术语

  • StoreFile 是 HFile 的外观。在压缩方面,StoreFile 的使用似乎在过去一直盛行。

  • _ 商店 _ 与列族相同。商店文件与商店或 ColumnFamily 相关。

  • 如果您想了解更多关于 StoreFiles 与 HFiles 和 Stores 与 ColumnFamilies 的信息,请参阅 HBASE-11316

当 MemStore 达到给定大小(hbase.hregion.memstore.flush.size)时,它会将其内容刷新到 StoreFile。商店中的 StoreFiles 数量会随着时间的推移而增加。 _ 压缩 _ 是一种通过将它们合并在一起来减少 Store 中 StoreFiles 数量的操作,以提高读取操作的性能。压缩可能需要大量资源,并且可能会因许多因素而有助于或阻碍性能。

压缩分为两类:次要和主要。次要和主要压缩在以下方面有所不同。

_ 次要压缩 _ 通常选择少量小的相邻 StoreFiles 并将它们重写为单个 StoreFile。由于潜在的副作用,次要压缩不会删除(过滤掉)删除或过期版本。有关如何处理与压缩相关的删除和版本的信息,请参阅压缩和删除压缩和版本。对于给定的商店,次要压缩的最终结果是更少,更大的 StoreFiles。

_ 主要压缩 _ 的最终结果是每个商店的单个 StoreFile。主要压缩也处理删除标记和最大版本。有关如何处理与压缩相关的删除和版本的信息,请参阅压缩和删除压缩和版本

压缩和删除

在 HBase 中发生显式删除时,实际上不会删除数据。而是编写 _ 墓碑 _ 标记。逻辑删除标记可防止数据与查询一起返回。在主要压缩过程中,实际上会删除数据,并从 StoreFile 中删除逻辑删除标记。如果由于 TTL 过期而发生删除,则不会创建逻辑删除。相反,过期的数据被过滤掉,不会写回到压缩的 StoreFile。

压缩和版本

创建列族时,可以通过指定HColumnDescriptor.setMaxVersions(int versions)指定要保留的最大版本数。默认值为3。如果存在的版本超过指定的最大值,则会过滤掉多余的版本,而不会将其写回到压缩的 StoreFile。

主要压缩可能会影响查询结果

在某些情况下,如果明确删除较新版本,则可能会无意中复活旧版本。请参阅主要压缩更改查询结果以获得更深入的解释。这种情况只有在压缩完成之前才有可能。

从理论上讲,主要压缩可以提高性能。但是,在高负载系统中,主要压缩可能需要不适当数量的资源并对性能产生负面影响。在默认配置中,主要压缩会自动安排在 7 天内运行一次。这有时不适合生产中的系统。您可以手动管理主要压缩。参见管理的压缩

压缩不执行区域合并。有关区域合并的更多信息,请参见 Merge

压实开关

我们可以在区域服务器上打开和关闭压缩。关闭压缩也会中断任何当前正在进行的压缩。它可以使用 hbase shell 中的“compaction_switch”命令动态完成。如果从命令行完成,则在重新启动服务器时此设置将丢失。要在区域服务器之间保留更改,请修改 hbase-site.xml 中的配置 hbase.regionserver .compaction.enabled 并重新启动 HBase。

压缩策略 - HBase 0.96.x 及更新版本

压缩大型 StoreFiles 或一次使用太多 StoreFiles 会导致比集群能够处理的 IO 负载更多,而不会导致性能问题。 HBase 选择哪个 StoreFiles 包含在压缩中的方法(以及压缩是次要压缩还是主要压缩)称为 _ 压缩策略 _。

在 HBase 0.96.x 之前,只有一个压缩策略。原始压缩策略仍可作为RatioBasedCompactionPolicy使用。新的压缩默认策略称为ExploringCompactionPolicy,随后被移植到 HBase 0.94 和 HBase 0.95,并且是 HBase 0.96 及更新版本的默认值。它在 HBASE-7842 中实施。简而言之,ExploringCompactionPolicy尝试选择尽可能最好的 StoreFiles 集合,以最少的工作量压缩,而RatioBasedCompactionPolicy选择符合条件的第一个集合。

无论使用何种压缩策略,文件选择都由几个可配置参数控制,并以多步骤方式发生。这些参数将在上下文中进行解释,然后将在表格中给出,该表格显示了它们的描述,默认值以及更改它们的含义。

被卡住

当 MemStore 变得太大时,它需要将其内容刷新到 StoreFile。但是,Stores 配置了 StoreFiles 数字hbase.hstore.blockingStoreFiles的绑定,如果超过,则 MemStore 刷新必须等到 StoreFile 计数减少一个或多个压缩。如果 MemStore 太大而且 StoreFiles 的数量也太高,则该算法被称为“卡住”。默认情况下,我们将等待hbase.hstore.blockingWaitTime毫秒的压缩。如果这段时间到期,即使我们超过hbase.hstore.blockingStoreFiles计数,我们也会冲洗。

提高hbase.hstore.blockingStoreFiles计数将允许刷新,但具有许多 StoreFiles 的 Store 可能具有更高的读取延迟。试着想一想为什么 Compactions 没跟上。这是一种引发这种情况的写入突发还是经常出现,并且群集的写入量不足?

ExploringCompactionPolicy 算法

在选择压缩最有益的集合之前,ExploringCompactionPolicy 算法会考虑每个可能的相邻 StoreFiles 集合。

ExploringCompactionPolicy 工作得特别好的一种情况是,当您批量加载数据时,批量加载会创建比 StoreFiles 更大的 StoreFiles,而 StoreFiles 的数据保存的数据早于批量加载数据。这可以“欺骗”HBase 在每次需要压缩时选择执行主要压缩,并导致大量额外开销。使用 ExploringCompactionPolicy,主要压缩发生的频率要低得多,因为较小的压缩效率更高。

通常,ExploringCompactionPolicy 是大多数情况下的正确选择,因此是默认的压缩策略。您还可以使用 ExploringCompactionPolicy 和 Experimental:Stripe Compactions

可以在 hbase-server / src / main / java / org / apache / hadoop / hbase / regionserver / compactions / ExploringCompactionPolicy.java 中检查此策略的逻辑。以下是 ExploringCompactionPolicy 逻辑的演练。

  1. 列出商店中所有现有的 StoreFiles。算法的其余部分过滤此列表以提出将被选择用于压缩的 HFile 子集。

  2. 如果这是用户请求的压缩,则尝试执行请求的压缩类型,而不管通常选择什么。请注意,即使用户请求主要压缩,也可能无法执行主要压缩。这可能是因为并非列族中的所有 StoreFiles 都可用于压缩,或者因为列族中的存储太多。

  3. 某些 StoreFiles 会自动排除在考虑之外。这些包括:

    • 大于hbase.hstore.compaction.max.size的 StoreFiles

    • 由明确排除压缩的批量加载操作创建的 StoreFiles。您可以决定从压缩中排除因批量加载而产生的 StoreFiles。为此,请在批量装入操作期间指定hbase.mapreduce.hfileoutputformat.compaction.exclude参数。

  4. 迭代步骤 1 中的列表,并列出所有可能的 StoreFiles 集合以压缩在一起。潜在集合是列表中的hbase.hstore.compaction.min连续 StoreFiles 的分组。对于每个集合,执行一些完整性检查并确定这是否是可以完成的最佳压缩:

    • 如果此集合中的 StoreFiles 数量(不是 StoreFiles 的大小)小于hbase.hstore.compaction.min或大于hbase.hstore.compaction.max,请将其考虑在内。

    • 将这组 StoreFiles 的大小与目前在列表中找到的最小可能压缩的大小进行比较。如果这组 StoreFiles 的大小代表可以完成的最小压缩,则存储它以用作后退,如果算法被“卡住”并且否则将不选择 StoreFiles。见被困

    • 对这组 StoreFiles 中的每个 StoreFile 进行基于大小的健全性检查。

      • 如果此 StoreFile 的大小大于hbase.hstore.compaction.max.size,请将其考虑在内。

      • 如果大小大于或等于hbase.hstore.compaction.min.size,则根据基于文件的比率进行健全性检查,以查看它是否太大而无法考虑。

        如果符合以下条件,则完整性检查成功:

      • 此集中只有一个 StoreFile,或

      • 对于每个 StoreFile,其大小乘以hbase.hstore.compaction.ratio(如果配置非高峰时间,则为hbase.hstore.compaction.ratio.offpeak,并且在非高峰时段)小于该集合中其他 HFile 的大小总和。

  5. 如果仍在考虑这组 StoreFiles,请将其与先前选择的最佳压缩进行比较。如果它更好,用这个替换先前选择的最佳压缩。

  6. 当处理完整个潜在压缩列表后,执行找到的最佳压缩。如果没有选择 StoreFiles 进行压缩,但有多个 StoreFiles,则假设算法被卡住(参见被困),如果是,请执行步骤 3 中找到的最小压缩。

RatioBasedCompactionPolicy 算法

RatioBasedCompactionPolicy 是 HBase 0.96 之前唯一的压缩策略,尽管 ExploringCompactionPolicy 现已被反向移植到 HBase 0.94 和 0.95。要使用 RatioBasedCompactionPolicy 而不是 ExploringCompactionPolicy,请在 hbase-site.xml 文件中将hbase.hstore.defaultengine.compactionpolicy.class设置为RatioBasedCompactionPolicy。要切换回 ExploringCompactionPolicy,请从 hbase-site.xml 中删除该设置。

以下部分将引导您完成用于在 RatioBasedCompactionPolicy 中选择 StoreFiles 进行压缩的算法。

  1. 第一阶段是创建所有压缩候选者的列表。将创建一个列表,该列表不包含在压缩队列中的所有 StoreFiles,以及比当前正在压缩的最新文件更新的所有 StoreFiles。 StoreFiles 列表按序列 ID 排序。将 Put 添加到预写日志(WAL)时生成序列 ID,并将其存储在 HFile 的元数据中。

  2. 检查算法是否卡住(参见被困,如果是,则强制进行主要压缩。这是 ExploringCompactionPolicy 算法通常比选择的更好的关键区域。 RatioBasedCompactionPolicy。

  3. 如果压缩是用户请求的,请尝试执行请求的压缩类型。请注意,如果所有 HFile 都不可用于压缩或存在太多 StoreFiles(超过hbase.hstore.compaction.max),则可能无法进行主要压缩。

  4. Some StoreFiles are automatically excluded from consideration. These include:

    • StoreFiles that are larger than hbase.hstore.compaction.max.size

    • StoreFiles that were created by a bulk-load operation which explicitly excluded compaction. You may decide to exclude StoreFiles resulting from bulk loads, from compaction. To do this, specify the hbase.mapreduce.hfileoutputformat.compaction.exclude parameter during the bulk load operation.

  5. 主要压缩中允许的最大 StoreFiles 数由hbase.hstore.compaction.max参数控制。如果列表包含的数量超过此数量的 StoreFiles,则即使进行了主要压缩,也会执行次要压缩。但是,即使存在多个hbase.hstore.compaction.max StoreFiles 要压缩,仍会发生用户请求的主要压缩。

  6. 如果列表包含少于hbase.hstore.compaction.min StoreFiles 以进行压缩,则会中止轻微压缩。请注意,可以在单个 HFile 上执行主要压缩。它的功能是删除删除和过期版本,并重置 StoreFile 上的位置。

  7. hbase.hstore.compaction.ratio参数的值乘以小于给定文件的 StoreFiles 的总和,以确定是否在次要压缩期间选择了 StoreFile 进行压缩。例如,如果 hbase.hstore.compaction.ratio 为 1.2,则 FileX 为 5MB,FileY 为 2MB,FileZ 为 3MB:

    5 &lt;= 1.2 x (2 + 3)            or            5 &lt;= 6 
    

    在这种情况下,FileX 有资格进行轻微压缩。如果 FileX 为 7MB,则不符合轻微压缩的条件。这个比例有利于较小的 StoreFile。如果还配置了hbase.offpeak.start.hourhbase.offpeak.end.hour,则可以使用参数hbase.hstore.compaction.ratio.offpeak配置在非高峰时段使用的不同比率。

  8. 如果最后一次主要的压缩是很久以前并且要压缩多个 StoreFile,则会运行一个主要的压缩,即使它本来是次要的。默认情况下,主要压缩之间的最长时间为 7 天,加上或减去 4.8 小时,并在这些参数中随机确定。在 HBase 0.96 之前,主要压实期为 24 小时。请参阅下表中的hbase.hregion.majorcompaction以调整或禁用基于时间的主要压缩。

压缩算法使用的参数

该表包含压缩的主要配置参数。这份清单并非详尽无遗。要从默认值中调整这些参数,请编辑 hbase-default.xml 文件。有关所有可用配置参数的完整列表,请参阅 config.files

hbase.hstore.compaction.min

在压缩之前必须符合压缩条件的最小 StoreFiles 数量才能运行。调整hbase.hstore.compaction.min的目的是避免使用太多的小型 StoreFiles 来压缩。将此值设置为 2 会在每次在 Store 中存在两个 StoreFiles 时导致轻微压缩,这可能不合适。如果将此值设置得太高,则需要相应调整所有其他值。对于大多数情况,默认值是合适的。在以前版本的 HBase 中,参数hbase.hstore.compaction.min被称为hbase.hstore.compactionThreshold

默认:3

hbase.hstore.compaction.max

无论符合条件的 StoreFiles 的数量,将为单个次要压缩选择的 StoreFiles 的最大数量。实际上,hbase.hstore.compaction.max的值控制单个压缩完成所需的时间长度。将其设置得更大意味着更多 StoreFiles 包含在压缩中。对于大多数情况,默认值是合适的。

默认:10

hbase.hstore.compaction.min.size

小于此大小的 StoreFile 将始终符合轻微压缩的条件。通过hbase.hstore.compaction.ratio评估此大小或更大的 StoreFiles 以确定它们是否符合条件。由于此限制表示所有小于此值的 StoreFiles 的“自动包含”限制,因此可能需要在写入 1-2 MB 范围内的许多文件的写入繁重环境中减少此值,因为每个 StoreFile 都将成为目标压缩和生成的 StoreFiles 可能仍然在最小尺寸,需要进一步压缩。如果降低此参数,则会更快地触发比率检查。这解决了早期版本的 HBase 中出现的一些问题,但在大多数情况下不再需要更改此参数。

默认值:128 MB

hbase.hstore.compaction.max.size

大于此大小的 StoreFile 将被排除在压缩之外。提高hbase.hstore.compaction.max.size的效果更少,更大的 StoreFiles 不会经常被压缩。如果您觉得压缩过于频繁而没有太多好处,您可以尝试提高此值。

默认Long.MAX_VALUE

hbase.hstore.compaction.ratio

对于轻微压缩,此比率用于确定大于hbase.hstore.compaction.min.size的给定 StoreFile 是否有资格进行压缩。它的作用是限制大型 StoreFile 的压缩。 hbase.hstore.compaction.ratio的值表示为浮点小数。

  • 较大的比例(例如 10)将生成单个巨型 StoreFile。相反,值为.25,将产生类似于 BigTable 压缩算法的行为,产生四个 StoreFiles。

  • 建议使用介于 1.0 和 1.4 之间的中等值。调整此值时,您将平衡写入成本与读取成本。提高值(类似于 1.4)会产生更多的写入成本,因为您将压缩更大的 StoreFiles。但是,在读取过程中,HBase 需要通过更少的 StoreFiles 来完成读取。如果你不能利用布隆过滤器,请考虑这种方法。

  • 或者,您可以将此值降低到 1.0 以降低写入的后台成本,并用于限制读取期间触摸的 StoreFiles 的数量。对于大多数情况,默认值是合适的。

    默认1.2F

hbase.hstore.compaction.ratio.offpeak

非高峰时段使用的压实比例,如果还配置了非高峰时段(见下文)。表示为浮点小数。这允许在设定的时间段内更具侵略性(或者如果将其设置为低于hbase.hstore.compaction.ratio则更不具侵略性)压实。如果禁用非高峰时忽略(默认)。这与hbase.hstore.compaction.ratio的作用相同。

默认5.0F

hbase.offpeak.start.hour

非高峰时段的开始,表示为 0 到 23 之间的整数,包括 0 和 23。设置为-1 可禁用非高峰。

默认-1(禁用)

hbase.offpeak.end.hour

非高峰时段结束,表示为 0 到 23 之间的整数,包括 0 和 23。设置为-1 可禁用非高峰。

Default: -1 (disabled)

hbase.regionserver.thread.compaction.throttle

压缩有两种不同的线程池,一种用于大型压缩,另一种用于小型压缩。这有助于快速压缩精益表(例如hbase:meta)。如果压缩大于此阈值,则会进入大型压缩池。在大多数情况下,默认值是合适的。

默认2 x hbase.hstore.compaction.max x hbase.hregion.memstore.flush.size(默认为128

hbase.hregion.majorcompaction

主要压缩之间的时间,以毫秒表示。设置为 0 可禁用基于时间的自动主要压缩。用户请求的和基于大小的主要压缩仍将运行。该值乘以hbase.hregion.majorcompaction.jitter,以使压缩在给定的时间窗口内以稍微随机的时间开始。

默认:7 天(604800000毫秒)

hbase.hregion.majorcompaction.jitter

应用于 hbase.hregion.majorcompaction 的乘数,以使压缩在hbase.hregion.majorcompaction的任一侧发生给定的时间。数字越小,压缩越接