Apache HBase Logo

Preface

这是其附带的HBase版本的官方参考指南.

在这里,您可以找到有关HBase主题的权威性文档(指当引用的HBase版本交付时的状态),也可以指向JavadocJIRAWiki中可以找到相关信息的位置.

关于本指南

本参考指南正在进行中. 可以在HBase源代码的_src / main / asciidoc目录中找到本指南的源代码. 使用AsciiDoc对本参考指南进行了标记,由此生成的最终指南作为"站点"构建目标的一部分. 跑

mvn site

生成此文档. 欢迎对文档进行修改和改进. 单击此链接可以针对Apache HBase提交新的文档错误,并预先选择一些值.

撰写文档

有关AsciiDoc的概述以及开始对文档进行撰写的建议,请参阅本文档后面相关部分 .

如果这是您首次涉足分布式计算领域,请注意...

如果这是您首次进入分布式计算的美好世界,那么您将处于一段有趣的时期. 首先,分布式系统很难. 使分布式系统嗡嗡声需要跨越系统(硬件和软件)和网络的完全不同的技能.

群集运行可能会因各种原因而打ic,原因包括HBase本身的错误,错误配置(HBase的错误配置以及操作系统的错误配置),以及硬件问题(无论是网卡驱动程序中的错误还是RAM总线不足) (要提到两个最近的硬件问题示例,这些问题表现为" HBase缓慢"). 如果您已将计算结果绑定到单个框,则还需要重新校准. 这是一个很好的起点: 分布式计算的谬误 .

That said, you are welcome.
It’s a fun place to be.
Yours, the HBase Community.

报告错误

请使用JIRA报告与安全无关的错误.

为了保护现有的HBase安装不受新漏洞的影响,请不要使用JIRA报告与安全性有关的错误. 而是将您的报告发送到邮件列表private@apache.org ,该列表允许任何人发送消息,但限制了可以读取消息的人. 该列表中的某人将与您联系以跟进您的报告.

Getting Started

1. Introduction

快速入门将使您在HBase的单节点独立实例上运行并运行,然后是伪分布式单机实例,最后是完全分布式集群.

2. Quick Start - Standalone HBase

本指南描述了针对本地文件系统运行的独立HBase实例的设置. 对于HBase的生产实例,这不是适当的配置,但是可以让您尝试使用HBase. 本节说明如何使用hbase shell CLI在HBase中创建表,如何在表中插入行,对表执行放置和扫描操作,启用或禁用表以及启动和停止HBase. 除了下载HBase之外,此过程还需要不到10分钟的时间.

本地文件系统和持久性
HBase 0.98.3及更高版本中修复了以下问题. 请参阅HBASE-11272HBASE-11218 .

将HBase与本地文件系统一起使用不能保证持久性. 如果未正确关闭文件,HDFS本地文件系统实现将丢失编辑. 当您尝试使用新软件,经常且不总是干净地启动和停止守护程序时,很可能会发生这种情况. 您需要在HDFS上运行HBase以确保保留所有写入. 针对本地文件系统运行是作为评估的第一阶段,它是使您熟悉通用系统如何工作的捷径. 有关在本地文件系统上运行的问题的更多详细信息,请参见HBASE-3696及其相关问题.

回送IP-HBase 0.94.x和更早版本
以下建议仅适用于hbase-0.94.x和更早版本. 此问题已在hbase-0.96.0及更高版本中修复.

在HBase 0.94.x之前,HBase希望环回IP地址为127.0.0.1. Ubuntu和其他一些发行版默认为127.0.1.1,这会给您带来问题. 请参阅为什么HBase关心/ etc / hosts? 详细

例子1. Ubuntu的例子/ etc / hosts文件

以下/ etc / hosts文件可在Ubuntu上针对HBase 0.94.x及更早版本正常运行. 如果遇到麻烦,可以使用它作为模板.

127.0.0.1 localhost
127.0.0.1 ubuntu.ubuntu-domain ubuntu

2.1. JDK Version Requirements

HBase要求安装JDK. 有关受支持的JDK版本的信息,请参见Java .

2.2. Get Started with HBase

过程:下载,配置和启动HBase
  1. Apache下载镜像列表中选择一个下载站点. 单击建议的顶部链接. 这将带您了解HBase版本 . 单击名为稳定的文件夹,然后将以.tar.gz结尾的二进制文件下载到本地文件系统. 确保选择与以后可能使用的Hadoop版本相对应的版本. 在大多数情况下,您应该为Hadoop 2选择文件,该文件的名称将类似于hbase-0.98.3-hadoop2-bin.tar.gz . 现在不要下载以src.tar.gz结尾的文件.

  2. 解压缩下载的文件,然后转到新创建的目录.

    $ tar xzvf hbase-<?eval ${project.version}?>-hadoop2-bin.tar.gz
    $ cd hbase-<?eval ${project.version}?>-hadoop2/
  3. 对于HBase 0.98.5和更高版本,需要在启动HBase之前设置JAVA_HOME环境变量. 在0.98.5之前,如果未设置变量,则HBase尝试检测Java的位置. 您可以通过操作系统的常用机制来设置变量,但是HBase提供了一个中心机制conf / hbase-env.sh . 编辑此文件,取消注释以JAVA_HOME开头的行,并将其设置为适合您的操作系统的位置. JAVA_HOME变量应设置为包含可执行文件bin / java的目录 . 大多数现代Linux操作系统都提供了一种机制,例如RHEL或CentOS上的/ usr / bin / alternatives,用于在诸如Java之类的可执行文件版本之间透明地进行切换. 在这种情况下,可以将JAVA_HOME为包含指向bin / java的符号链接的目录,该目录通常是/ usr .

    JAVA_HOME=/usr
    这些说明假定群集的每个节点使用相同的配置. 如果不是这种情况,则可能需要为每个节点分别设置JAVA_HOME .
  4. Edit conf/hbase-site.xml, which is the main HBase configuration file. At this time, you only need to specify the directory on the local filesystem where HBase and ZooKeeper write data. By default, a new directory is created under /tmp. Many servers are configured to delete the contents of /tmp upon reboot, so you should store the data elsewhere. The following configuration will store HBase’s data in the hbase directory, in the home directory of the user called testuser. Paste the <property> tags beneath the <configuration> tags, which should be empty in a new HBase install.

    例子2.独立HBase的例子hbase-site.xml
    <configuration>
      <property>
        <name>hbase.rootdir</name>
        <value>file:///home/testuser/hbase</value>
      </property>
      <property>
        <name>hbase.zookeeper.property.dataDir</name>
        <value>/home/testuser/zookeeper</value>
      </property>
    </configuration>

    您不需要创建HBase数据目录. HBase将为您完成此任务. 如果创建目录,则HBase将尝试进行迁移,这不是您想要的.

  5. 提供bin / start-hbase.sh脚本是启动HBase的便捷方法. 发出命令,如果一切顺利,则会在标准输出中记录一条消息,表明HBase已成功启动. 您可以使用jps命令来验证您是否正在运行一个名为HMaster进程. 在独立模式下,HBase在此单个JVM中运行所有守护程序,即HMaster,单个HRegionServer和ZooKeeper守护程序.

    Java需要安装并可用. 如果收到指示未安装Java的错误,但该错误在系统上(可能位于非标准位置),请编辑conf / hbase-env.sh文件并修改JAVA_HOME设置以指向包含bin的目录/ java您的系统.
过程:首次使用HBase
  1. 连接到HBase.

    使用hbase shell命令连接到正在运行的HBase实例,该命令位于HBase安装目录的bin /目录中. 在此示例中,省略了启动HBase Shell时打印的一些用法和版本信息. HBase Shell提示符以>字符结束.

    $ ./bin/hbase shell
    hbase(main):001:0>
  2. 显示HBase Shell帮助文本.

    键入help并按Enter,以显示HBase Shell的一些基本用法信息以及一些示例命令. 注意,表名,行,列都必须用引号引起来.

  3. 创建一个表.

    使用create命令创建一个新表. 您必须指定表名称和ColumnFamily名称.

    hbase(main):001:0> create 'test', 'cf'
    0 row(s) in 0.4170 seconds
    
    => Hbase::Table - test
  4. 列出有关表的信息

    使用list命令来

    hbase(main):002:0> list 'test'
    TABLE
    test
    1 row(s) in 0.0180 seconds
    
    => ["test"]
  5. 将数据放入表中.

    要将数据放入表中,请使用put命令.

    hbase(main):003:0> put 'test', 'row1', 'cf:a', 'value1'
    0 row(s) in 0.0850 seconds
    
    hbase(main):004:0> put 'test', 'row2', 'cf:b', 'value2'
    0 row(s) in 0.0110 seconds
    
    hbase(main):005:0> put 'test', 'row3', 'cf:c', 'value3'
    0 row(s) in 0.0100 seconds

    在这里,我们插入三个值,一次插入一个. 第一次插入是在row1 cf:a列,其值为value1 . 在HBase的列由列族前缀的cf在本例中,后面跟着冒号,然后列限定符后缀, a在此情况下.

  6. 一次扫描表中的所有数据.

    从HBase获取数据的一种方法是扫描. 使用scan命令扫描表中的数据. 您可以限制扫描,但目前已获取所有数据.

    hbase(main):006:0> scan 'test'
    ROW                                      COLUMN+CELL
     row1                                    column=cf:a, timestamp=1421762485768, value=value1
     row2                                    column=cf:b, timestamp=1421762491785, value=value2
     row3                                    column=cf:c, timestamp=1421762496210, value=value3
    3 row(s) in 0.0230 seconds
  7. 获取单行数据.

    要一次获取一行数据,请使用get命令.

    hbase(main):007:0> get 'test', 'row1'
    COLUMN                                   CELL
     cf:a                                    timestamp=1421762485768, value=value1
    1 row(s) in 0.0350 seconds
  8. 禁用表格.

    如果要删除表或更改其设置,以及在某些其他情况下,则需要先使用disable命令禁用该表. 您可以使用enable命令重新启用它.

    hbase(main):008:0> disable 'test'
    0 row(s) in 1.1820 seconds
    
    hbase(main):009:0> enable 'test'
    0 row(s) in 0.1770 seconds

    如果您测试了上面的enable命令,请再次禁用该表:

    hbase(main):010:0> disable 'test'
    0 row(s) in 1.1820 seconds
  9. 放下桌子.

    要删除(删除)表,请使用drop命令.

    hbase(main):011:0> drop 'test'
    0 row(s) in 0.1370 seconds
  10. 退出HBase Shell.

    要退出HBase Shell并从群集断开连接,请使用quit命令. HBase仍在后台运行.

过程:停止HBase
  1. 与提供bin / start-hbase.sh脚本以方便地启动所有HBase守护程序相同, bin / stop-hbase.sh脚本将停止它们.

    $ ./bin/stop-hbase.sh
    stopping hbase....................
    $
  2. 发出命令后,关闭进程可能需要几分钟. 使用jps确保HMaster和HRegionServer进程已关闭.

2.3. Intermediate - Pseudo-Distributed Local Install

在完成快速入门之后 ,您可以将HBase重新配置为以伪分布式模式运行. 伪分布式模式意味着HBase仍完全在单个主机上运行,​​但是每个HBase守护程序(HMaster,HRegionServer和Zookeeper)作为单独的进程运行. 默认情况下,除非您按照quickstart中的说明配置hbase.rootdir属性,否则数据仍存储在/ tmp /中 . 在本演练中,假设您有可用的HDFS,我们将您的数据存储在HDFS中. 您可以跳过HDFS配置,以继续将数据存储在本地文件系统中.

Hadoop配置

此过程假定您已在本地系统和/或远程系统上配置了Hadoop和HDFS,并且它们正在运行并且可用. 它还假设您使用的是Hadoop2.当前,Hadoop网站上的文档并未包括Hadoop 2的快速入门,而是该指南的链接:http://www.alexjf.net/blog/distributed-systems/hadoop -yarn-installation-definitive-guide是一个很好的起点.

  1. 如果HBase正在运行,请停止它.

    如果您刚刚完成快速入门而HBase仍在运行,请停止它. 此过程将创建一个全新的目录,HBase将在该目录中存储其数据,因此您之前创建的所有数据库都将丢失.

  2. 配置HBase.

    编辑hbase-site.xml配置. 首先,添加以下属性. 它指示HBase在分布式模式下运行,每个守护程序一个JVM实例.

    <property>
      <name>hbase.cluster.distributed</name>
      <value>true</value>
    </property>

    接下来,使用hdfs://// URI语法将hbase.rootdir从本地文件系统更改为HDFS实例的地址. 在此示例中,HDFS在本地主机上的端口8020上运行.

    <property>
      <name>hbase.rootdir</name>
      <value>hdfs://localhost:8020/hbase</value>
    </property>

    您无需在HDFS中创建目录. HBase将为您完成此任务. 如果创建目录,则HBase将尝试进行迁移,这不是您想要的.

  3. 启动HBase.

    使用bin / start-hbase.sh命令启动HBase. 如果系统配置正确,则jps命令应显示正在运行的HMaster和HRegionServer进程.

  4. 检查HDFS中的HBase目录.

    如果一切正常,HBase将在HDFS中创建其目录. 在上面的配置中,它存储在HDFS的/ hbase /中. 您可以在Hadoop的bin /目录中使用hadoop fs命令列出该目录.

    $ ./bin/hadoop fs -ls /hbase
    Found 7 items
    drwxr-xr-x   - hbase users          0 2014-06-25 18:58 /hbase/.tmp
    drwxr-xr-x   - hbase users          0 2014-06-25 21:49 /hbase/WALs
    drwxr-xr-x   - hbase users          0 2014-06-25 18:48 /hbase/corrupt
    drwxr-xr-x   - hbase users          0 2014-06-25 18:58 /hbase/data
    -rw-r--r--   3 hbase users         42 2014-06-25 18:41 /hbase/hbase.id
    -rw-r--r--   3 hbase users          7 2014-06-25 18:41 /hbase/hbase.version
    drwxr-xr-x   - hbase users          0 2014-06-25 21:49 /hbase/oldWALs
  5. 创建一个表并用数据填充它.

    您可以使用HBase Shell创建一个表,使用数据填充该表,扫描并从中获取值,方法与Shell练习中相同.

  6. 启动和停止备用HBase主服务器(HMaster)服务器.

    在生产环境中,在同一硬件上运行多个HMaster实例没有意义,就像在生产环境中运行伪分布式集群没有意义. 此步骤仅用于测试和学习目的.

    HMaster服务器控制HBase群集. 您最多可以启动9台备用HMaster服务器,这使总数为10台HMaster成为主要服务器. 要启动备份HMaster,请使用local-master-backup.sh . 对于要启动的每个备份主服务器,添加一个代表该主服务器的端口偏移量的参数. 每个HMaster使用三个端口(默认情况下为16010、16020和16030). 端口偏移量将添加到这些端口,因此,使用偏移量2时,备份HMaster将使用端口16012、16022和16032.以下命令使用端口16012/16022 / 16032、16013 / 16023/16033启动3个备份服务器,和16015/16025/16035.

    $ ./bin/local-master-backup.sh 2 3 5

    要杀死备份主服务器而不杀死整个集群,您需要找到其进程ID(PID). PID以类似/tmp/hbase-USER-X-master.pid的名称存储在文件中. 该文件的唯一内容是PID. 您可以使用kill -9命令杀死该PID. 以下命令将杀死端口偏移为1的主服务器,但使集群保持运行状态:

    $ cat /tmp/hbase-testuser-1-master.pid |xargs kill -9
  7. 启动和停止其他RegionServer

    HRegionServer按照HMaster的指示管理其StoreFiles中的数据. 通常,群集中的每个节点都运行一个HRegionServer. 在同一系统上运行多个HRegionServer对于在伪分布式模式下进行测试非常有用. local-regionservers.sh命令允许您运行多个RegionServer. 它的工作方式与local-master-backup.sh命令类似,因为您提供的每个参数都代表实例的端口偏移量. 每个RegionServer需要两个端口,默认端口为16020和16030.但是,其他RegionServer的基本端口不是默认端口,因为默认端口由HMaster使用,从HBase 1.0.0开始,它也是RegionServer. 基本端口改为16200和16300. 您可以在服务器上运行99个不是HMaster或备份HMaster的其他RegionServer. 以下命令启动四个附加的RegionServer,它们在从16202/16302开始的顺序端口(基本端口16200/16300加2)上运行.

    $ .bin/local-regionservers.sh start 2 3 4 5

    要手动停止RegionServer,请使用带有stop参数的local-regionservers.sh命令和要stop的服务器偏移量.

    $ .bin/local-regionservers.sh stop 3
  8. 停止HBase.

    您可以使用bin / stop-hbase.sh命令以与快速入门过程中相同的方式停止HBase.

2.4. Advanced - Fully Distributed

实际上,您需要一个完全分布式的配置来全面测试HBase并在实际场景中使用它. 在分布式配置中,集群包含多个节点,每个节点运行一个或多个HBase守护程序. 其中包括主实例和备份Master实例,多个Zookeeper节点和多个RegionServer节点.

此高级快速入门为集群添加了两个以上的节点. 架构如下:

表1.分布式集群演示架构
节点名称 Master ZooKeeper RegionServer

node-a.example.com

yes

yes

no

node-b.example.com

backup

yes

yes

node-c.example.com

no

yes

yes

本快速入门假定每个节点都是虚拟机,并且它们都在同一网络上. 假设您在该过程中配置的系统现在为node-a ,则它以先前的快速入门" 中级-伪分布式本地安装" node-a . 在继续之前,在node-a上停止HBase.

确保所有节点都具有完全的通信访问权限,并且没有适当的防火墙规则可能阻止它们相互通信. 如果看到任何错误,例如no route to host ,请检查防火墙.
过程:配置无密码的SSH访问

node-a需要能够登录到node-bnode-c (以及自身)才能启动守护程序. 完成此操作的最简单方法是在所有主机上使用相同的用户名,并配置从node-a到其他每个node-a密码SSH登录.

  1. node-a ,生成一个密钥对.

    以将要运行HBase的用户身份登录后,使用以下命令生成SSH密钥对:

    $ ssh-keygen -t rsa

    如果命令成功执行,则将密钥对的位置打印到标准输出. 公钥的默认名称是id_rsa.pub .

  2. 创建将在其他节点上保存共享密钥的目录.

    node-bnode-c ,以HBase用户身份登录,并在用户的主目录中创建.ssh /目录(如果尚不存在). 如果已经存在,请注意它可能已经包含其他密钥.

  3. 将公钥复制到其他节点.

    通过使用scp或其他某种安全方式,将公钥从node-a安全地复制到每个节点. 在其他每个节点上,创建一个名为.ssh / authorized_keys的新文件( 如果尚不存在) ,并将id_rsa.pub文件的内容附加到文件末尾. 请注意,您还需要对node-a本身执行此操作.

    $ cat id_rsa.pub >> ~/.ssh/authorized_keys
  4. 测试无密码登录.

    如果正确执行了该过程,并且您使用相同的用户名从node-a SSH到其他节点中的任何一个,则不会提示您输入密码.

  5. 由于node-b将运行备份主服务器,因此重复上述过程,在看到node-a node-b任何地方都替换为node-b . 确保不要覆盖现有的.ssh / authorized_keys文件,而是使用>>运算符而不是>运算符将新密钥连接到现有文件上.

Procedure: Prepare node-a

node-a将运行您的主要主进程和ZooKeeper进程,但不会运行RegionServer. . 停止RegionServer在node-a上启动.

  1. 编辑conf / regionservers并删除包含localhost的行. 添加带有node-bnode-c的主机名或IP地址的行.

    即使您确实想在node-a上运行RegionServer,也应使用其他服务器用来与其通信的主机名来引用它. 在这种情况下,它将是node-a.example.com . 这使您可以将任何主机名冲突将配置分发到群集的每个节点. 保存文件.

  2. 配置HBase以将node-b用作备份主服务器.

    conf /中创建一个名为backup-masters的新文件,并使用node-b的主机名在其中添加新行. 在此演示中,主机名是node-b.example.com .

  3. 配置ZooKeeper

    实际上,您应该仔细考虑您的ZooKeeper配置. 您可以找到有关在zookeeper中配置ZooKeeper的更多信息. 此配置将指导HBase在群集的每个节点上启动和管理ZooKeeper实例.

    node-a ,编辑conf / hbase-site.xml并添加以下属性.

    <property>
      <name>hbase.zookeeper.quorum</name>
      <value>node-a.example.com,node-b.example.com,node-c.example.com</value>
    </property>
    <property>
      <name>hbase.zookeeper.property.dataDir</name>
      <value>/usr/local/zookeeper</value>
    </property>
  4. 在配置中您已将node-a称为localhost ,更改引用以指向其他节点将用来引用node-a的主机名. 在这些示例中,主机名是node-a.example.com .

过程:准备node-bnode-c

node-b将运行一个备份主服务器和一个ZooKeeper实例.

  1. 下载并解压缩HBase.

    将HBase下载并解压缩到node-b ,就像对独立和伪分布式快速入门所做的那样.

  2. 将配置文件从node-a复制到node-bnode-c .

    群集的每个节点都需要具有相同的配置信息. 将conf /目录的内容复制到node-bnode-c上的conf /目录.

过程:启动和测试集群
  1. 确保HBase不在任何节点上运行.

    如果您忘记从先前的测试中停止HBase,则将出现错误. 使用jps命令检查HBase是否在您的任何节点上运行. 查找进程HMasterHRegionServerHQuorumPeer . 如果它们存在,杀死它们.

  2. 启动集群.

    node-a ,发出start-hbase.sh命令. 您的输出将类似于以下内容.

    $ bin/start-hbase.sh
    node-c.example.com: starting zookeeper, logging to /home/hbuser/hbase-0.98.3-hadoop2/bin/../logs/hbase-hbuser-zookeeper-node-c.example.com.out
    node-a.example.com: starting zookeeper, logging to /home/hbuser/hbase-0.98.3-hadoop2/bin/../logs/hbase-hbuser-zookeeper-node-a.example.com.out
    node-b.example.com: starting zookeeper, logging to /home/hbuser/hbase-0.98.3-hadoop2/bin/../logs/hbase-hbuser-zookeeper-node-b.example.com.out
    starting master, logging to /home/hbuser/hbase-0.98.3-hadoop2/bin/../logs/hbase-hbuser-master-node-a.example.com.out
    node-c.example.com: starting regionserver, logging to /home/hbuser/hbase-0.98.3-hadoop2/bin/../logs/hbase-hbuser-regionserver-node-c.example.com.out
    node-b.example.com: starting regionserver, logging to /home/hbuser/hbase-0.98.3-hadoop2/bin/../logs/hbase-hbuser-regionserver-node-b.example.com.out
    node-b.example.com: starting master, logging to /home/hbuser/hbase-0.98.3-hadoop2/bin/../logs/hbase-hbuser-master-nodeb.example.com.out

    ZooKeeper首先启动,然后是主机,然后是RegionServers,最后是备份主机.

  3. 验证进程正在运行.

    On each node of the cluster, run the jps command and verify that the correct processes are running on each server. You may see additional Java processes running on your servers as well, if they are used for other purposes.

    例子3. node-a jps输出
    $ jps
    20355 Jps
    20071 HQuorumPeer
    20137 HMaster
    例子4. node-b jps输出
    $ jps
    15930 HRegionServer
    16194 Jps
    15838 HQuorumPeer
    16010 HMaster
    例子5. node-a jps输出
    $ jps
    13901 Jps
    13639 HQuorumPeer
    13737 HRegionServer
    ZooKeeper进程名称

    HQuorumPeer进程是一个由HBase控制和启动的ZooKeeper实例. 如果以这种方式使用ZooKeeper,则每个群集节点仅限一个实例,并且仅适用于测试. 如果ZooKeeper在HBase外部运行,则该过程称为QuorumPeer . 有关ZooKeeper配置的更多信息,包括将外部ZooKeeper实例与HBase一起使用,请参阅zookeeper .

  4. 浏览到Web UI.

    Web UI端口更改
    Web UI端口更改

    在HBase高于0.98.x的版本中,HBase Web UI使用的HTTP端口从Master的60010和每个RegionServer的60030变为Master的16010和RegionServer的16030.

    如果一切设置正确,则应该能够连接到主服务器http://node-a.example.com:16010/或辅助主服务器的UI,位于http://node-b.example.com:16010/用于辅助主服务器),使用网络浏览器. 如果可以通过localhost主机连接,但不能通过其他主机连接,请检查防火墙规则. 您可以在其IP地址的端口16030上单击每个RegionServer的Web UI,也可以单击主服务器的Web UI中的链接.

  5. 测试当节点或服务消失时会发生什么.

    使用您已配置的三节点群集,事情将不会非常灵活. 不过,您可以通过杀死进程并查看日志来测试当主Master或RegionServer消失时发生的情况.

2.5. Where to go next

下一章configuration提供了有关不同HBase运行模式,运行HBase的系统要求以及用于设置分布式HBase群集的关键配置区域的更多信息.

Apache HBase Configuration

本章在[getting_started]章的基础上进行了扩展,以进一步说明Apache HBase的配置. 请仔细阅读本章,尤其是基本先决条件,以确保您的HBase测试和部署顺利进行并防止数据丢失.

3. Configuration Files

Apache HBase使用与Apache Hadoop相同的配置系统. 所有配置文件都位于conf /目录中,该文件需要与集群中的每个节点保持同步.

HBase配置文件说明
backup-masters

默认情况下不存在. 一个纯文本文件,其中列出了主机应在其上启动备份主机进程的主机,每行一个主机.

hadoop-metrics2-hbase.properties

用于连接HBase Hadoop的Metrics2框架. 有关Metrics2的更多信息,请参见Hadoop Wiki条目 . 默认情况下仅包含注释掉的示例.

hbase-env.cmd and hbase-env.sh

用于Windows和Linux / Unix环境的脚本,用于设置HBase的工作环境,包括Java的位置,Java选项和其他环境变量. 该文件包含许多注释掉的示例以提供指导.

hbase-policy.xml

RPC服务器用于对客户端请求做出授权决策的默认策略配置文件. 仅在启用HBase 安全性时使用.

hbase-site.xml

HBase的主要配置文件. 该文件指定了覆盖HBase默认配置的配置选项. 您可以在docs / hbase-default.xml上查看(但不能编辑)默认配置文件. 您还可以在HBase Web UI的" HBase配置"选项卡中查看集群的整个有效配置(默认值和替代值).

log4j.properties

通过log4j进行HBase日志记录的配置文件.

regionservers

一个纯文本文件,其中包含应在HBase群集中运行RegionServer的主机列表. 默认情况下,此文件包含单个条目localhost . 它应该包含一个主机名或IP地址列表,每行一个,并且仅当群集中的每个节点都将在其localhost接口上运行RegionServer时才包含localhost .

Checking XML Validity

在编辑XML时,最好使用支持XML的编辑器,以确保语法正确且XML格式正确. 您还可以使用xmllint实用程序来检查XML格式是否正确. 默认情况下, xmllint重排并将XML打印到标准输出. 要检查格式是否正确并仅在存在错误的情况下才打印输出,请使用命令xmllint -noout filename.xml .

使配置在整个群集中保持同步

在分布式模式下运行时,对HBase配置进行编辑后,请确保将conf /目录的内容复制到群集的所有节点. HBase不会为您这样做. 使用rsyncscp或其他安全机制将配置文件复制到您的节点. 对于大多数配置,服务器需要重新启动才能获取更改.动态配置是一个例外. 稍后将描述.

4. Basic Prerequisites

本节列出了必需的服务和一些必需的系统配置.

表2. Java
HBase版本 JDK 6 JDK 7 JDK 8

1.1

Not Supported

yes

使用JDK 8可以运行,但未经过良好测试.

1.0

Not Supported

yes

使用JDK 8可以运行,但未经过良好测试.

0.98

yes

yes

使用JDK 8可以运行,但未经过良好测试. 使用JDK 8进行构建时,需要删除PoolMap类中不推荐使用的remove()方法,并且正在考虑中. 有关JDK 8支持的更多信息,请参见HBASE-7608 .

0.96

yes

yes

N/A

0.94

yes

yes

N/A

在HBase 0.98.5及更高版本中,必须在群集的每个节点上设置JAVA_HOME . hbase-env.sh提供了一种方便的机制来执行此操作.
操作系统实用程序
ssh

HBase广泛使用Secure Shell(ssh)命令和实用程序在群集节点之间进行通信. 集群中的每个服务器都必须运行ssh以便可以管理Hadoop和HBase守护程序. 您必须能够使用共享密钥而不是密码通过SSH通过SSH从Master以及任何备份Master连接到所有节点,包括本地节点. 您可以在" 过程:配置无密码SSH访问 "中查看在Linux或Unix系统中进行此类设置的基本方法. 如果您的群集节点使用OS X,请参阅Hadoop Wiki上的SSH:设置远程桌面和启用自登录部分 .

DNS

HBase使用本地主机名自报告其IP地址. 正向和反向DNS解析都必须在0.92.0之前的HBase版本中工作. hadoop-dns-checker工具可用于验证DNS在群集上是否正常运行. 项目README文件提供了有关用法的详细说明.

Loopback IP

在hbase-0.96.0之前,HBase仅使用IP地址127.0.0.1来引用localhost ,并且无法进行配置. 有关更多详细信息,请参见回送IP .

NTP

群集节点上的时钟应同步. 少量的变化是可以接受的,但是较大的偏斜会导致不稳定和意外的行为. 时间同步是检查集群中是否出现无法解释的问题的首要检查之一. 建议您在群集上运行网络时间协议(NTP)服务或其他时间同步机制,并且所有节点都希望使用同一服务进行时间同步. 请参阅Linux文档项目(TLDP)上的" 基本NTP配置 "以设置NTP.

Limits on Number of Files and Processes (ulimit)

Apache HBase是一个数据库. 它要求能够一次打开大量文件. 许多Linux发行版将允许单个用户打开的文件数限制为1024 (在旧版本的OS X中为256 ). 您可以通过以运行HBase的用户身份登录时运行命令ulimit -n来检查服务器上的此限制. 如果限制太低,可能会遇到一些问题,请参阅"故障排除"部分 . 您可能还会注意到以下错误:

2010-04-06 03:04:37,542 INFO org.apache.hadoop.hdfs.DFSClient: Exception increateBlockOutputStream java.io.EOFException
2010-04-06 03:04:37,542 INFO org.apache.hadoop.hdfs.DFSClient: Abandoning block blk_-6935524980745310745_1391901

建议将ulimit至少增加到10,000,但更可能是10,240,因为该值通常以1024的倍数表示.每个ColumnFamily至少具有一个StoreFile,如果该区域处于负载状态,则可能有六个以上的StoreFile. 所需打开文件的数量取决于ColumnFamilies的数量和区域的数量. 以下是用于计算RegionServer上打开文件的潜在数量的粗略公式.

计算打开文件的潜在数量
(StoreFiles per ColumnFamily) x (regions per RegionServer)

例如,假设一个模式每个区域有3个ColumnFamily,每个ColumnFamily平均有3个StoreFiles,并且每个RegionServer有100个区域,那么JVM将打开3 * 3 * 100 = 900文件描述符,不计算打开的JAR文件,配置文件等. 打开文件不会占用太多资源,并且允许用户打开太多文件的风险很小.

另一个相关的设置是允许用户一次运​​行的进程数. 在Linux和Unix中,使用ulimit -u命令设置进程数. 这不应与nproc命令混淆,后者控制给定用户可用的CPU数量. 在负载下, ulimit -u太低会导致OutOfMemoryError异常. 从2011年开始,请参见hbase-users邮件列表中Jack Levin的主要HDFS问题线程.

为运行HBase进程的用户配置文件描述符和进程的最大数量是操作系统配置,而不是HBase配置. 确保为实际运行HBase的用户更改设置也很重要. 要查看哪个用户启动了HBase,以及该用户的ulimit配置,请查看该实例的HBase日志的第一行. hadoop集群上一个有用的读取设置配置是Aaron Kimballs的配置参数:您可以忽略什么?

例子6. Ubuntu上的ulimit设置

要在Ubuntu上配置ulimit设置,请编辑/etc/security/limits.conf ,它是一个由空格分隔的四列文件. 有关此文件格式的详细信息,请参见limits.conf的手册页. 在以下示例中,第一行将具有用户名hadoop的操作系统用户的打开文件(nofile)数量的软限制和硬限制都设置为32768. 第二行将同一用户的进程数设置为32000.

hadoop  -       nofile  32768
hadoop  -       nproc   32000

仅在指示可插拔身份验证模块(PAM)环境使用它们时才应用设置. 要将PAM配置为使用这些限制,请确保/etc/pam.d/common-session文件包含以下行:

session required  pam_limits.so
Linux Shell

HBase附带的所有shell脚本都依赖于GNU Bash shell.

Windows

在HBase 0.96之前,在Microsoft Windows上运行HBase的测试受到限制. 不建议在生产系统上在Windows节点上运行.

4.1. Hadoop

下表总结了每个HBase版本支持的Hadoop版本. 基于HBase的版本,您应该选择最合适的Hadoop版本. 您可以使用Apache Hadoop或供应商的Hadoop发行版. 这里没有区别. 有关Hadoop供应商的信息,请参见Hadoop Wiki .

推荐使用Hadoop2.x.

Hadoop 2.x速度更快,并且具有短路读取等功能,这些功能将有助于改善HBase随机读取配置文件. Hadoop 2.x还包括重要的错误修复,这些错误修复将改善您的整体HBase体验. HBase 0.98放弃了对Hadoop 1.0的支持,不赞成使用Hadoop 1.1+,并且HBase 1.0将不支持Hadoop1.x.

使用以下图例解释此表:

Hadoop版本支持表
  • " S" =支持

  • " X" =不支持

  • " NT" =未测试

HBase-0.92.x HBase-0.94.x HBase-0.96.x HBase-0.98.x(不建议使用Hadoop 1.1+.) HBase-1.0.x(不支持Hadoop 1.x) HBase-1.1.x

Hadoop-0.20.205

S

X

X

X

X

X

Hadoop-0.22.x

S

X

X

X

X

X

Hadoop-1.0.x

X

X

X

X

X

X

Hadoop-1.1.x

NT

S

S

NT

X

X

Hadoop-0.23.x

X

S

NT

X

X

X

Hadoop-2.0.x-alpha

X

NT

X

X

X

X

Hadoop-2.1.0-beta

X

NT

S

X

X

X

Hadoop-2.2.0

X

NT

S

S

NT

NT

Hadoop-2.3.x

X

NT

S

S

NT

NT

Hadoop-2.4.x

X

NT

S

S

S

S

Hadoop-2.5.x

X

NT

S

S

S

S

Hadoop-2.6.x

X

NT

NT

NT

S

S

Hadoop-2.7.x

X

NT

NT

NT

NT

NT

用HBase替换捆绑的Hadoop!

因为HBase依赖于Hadoop,所以它将Hadoop jar的实例捆绑在其lib目录下. 捆绑的jar只能在独立模式下使用. 在分布式模式下,群集上的Hadoop版本与HBase下的Hadoop版本相匹配至关重要 . 将HBase lib目录中找到的hadoop jar替换为您在集群上运行的hadoop jar,以避免版本不匹配的问题. 确保在群集的所有位置都替换HBase中的jar. Hadoop版本不匹配问题有多种表现形式,但通常都看起来像挂了一样.

4.1.1. Apache HBase 0.94 with Hadoop 2

To get 0.94.x to run on Hadoop 2.2.0, you need to change the hadoop 2 and protobuf versions in the pom.xml: Here is a diff with pom.xml changes:

$ svn diff pom.xml
Index: pom.xml
===================================================================
--- pom.xml     (revision 1545157)
+++ pom.xml     (working copy)
@@ -1034,7 +1034,7 @@
     <slf4j.version>1.4.3</slf4j.version>
     <log4j.version>1.2.16</log4j.version>
     <mockito-all.version>1.8.5</mockito-all.version>
-    <protobuf.version>2.4.0a</protobuf.version>
+    <protobuf.version>2.5.0</protobuf.version>
     <stax-api.version>1.0.1</stax-api.version>
     <thrift.version>0.8.0</thrift.version>
     <zookeeper.version>3.4.5</zookeeper.version>
@@ -2241,7 +2241,7 @@
         </property>
       </activation>
       <properties>
-        <hadoop.version>2.0.0-alpha</hadoop.version>
+        <hadoop.version>2.2.0</hadoop.version>
         <slf4j.version>1.6.1</slf4j.version>
       </properties>
       <dependencies>

下一步是重新生成Protobuf文件,并假定已安装Protobuf:

  • 使用命令行转到HBase根文件夹;

  • 键入以下命令:

    $ protoc -Isrc/main/protobuf --java_out=src/main/java src/main/protobuf/hbase.proto
    $ protoc -Isrc/main/protobuf --java_out=src/main/java src/main/protobuf/ErrorHandling.proto

通过运行类似于以下命令的内容,针对hadoop 2配置文件进行构建:

$  mvn clean install assembly:single -Dhadoop.profile=2.0 -DskipTests

4.1.2. Apache HBase 0.92 and 0.94

HBase 0.92和0.94版本可以与Hadoop版本0.20.205、0.22.x,1.0.x和1.1.x一起使用. HBase-0.94还可以与Hadoop-0.23.x和2.x一起使用,但是您可能必须使用特定的maven配置文件重新编译代码(请参阅顶级pom.xml).

4.1.3. Apache HBase 0.96

从Apache HBase 0.96.x开始,至少需要Apache Hadoop1.0.x. 强烈建议使用Hadoop 2(速度更快,但也提供有助于MTTR的修复程序). 我们将无法在0.20.205或branch-0.20-append等较旧的Hadoop上正常运行. 如果无法升级Hadoop,请不要使用Apache HBase0.96.x. 参见HBase,邮件#dev-讨论:hbase是否至少在hbase 0.96.0中要求hadoop 1.0.0?

4.1.4. Hadoop versions 0.20.x - 1.x

除非HBase在具有持久sync实现的HDFS上运行,否则它将丢失数据. 请勿使用不具有此属性的Hadoop 0.20.2,Hadoop 0.20.203.0和Hadoop 0.20.204.0. 当前,只有Hadoop版本0.20.205.x或此版本以外的任何版本(包括hadoop-1.0.0)具有持久的正常工作. Charles Zedlweski撰写的Cloudera博客文章Apache Hadoop 1.0的更新对所有Hadoop版本之间的关系进行了很好的阐述. 值得一试的是,您是否无法理解Hadoop版本的问题.

同步必须通过设置明确启用dfs.support.append等于true同时在客户端-在HBase的-site.xml中 -以及在HDFS-site.xml中的服务器端(同步设施HBase的需要是的一个子集附加代码路径).

<property>
  <name>dfs.support.append</name>
  <value>true</value>
</property>

进行此编辑后,您将必须重新启动集群. 忽略您在dfs.support.append配置的描述中的hdfs-default.xml中会发现的鸡肋注释.

4.1.5. Apache HBase on Secure Hadoop

只要您按照上面的建议进行操作,Apache HBase就可以在任何包含Hadoop安全功能的Hadoop 0.20.x上运行,并用安全版本替换HBase附带的Hadoop jar. 如果您想了解有关如何设置安全HBase的更多信息,请参见hbase.secure.configuration .

4.1.6. dfs.datanode.max.transfer.threads

HDFS DataNode可以随时提供服务的文件数量上限. 在执行任何加载之前,请确保已配置Hadoop的conf / hdfs-site.xml ,并将dfs.datanode.max.transfer.threads值至少设置为以下值:

<property>
  <name>dfs.datanode.max.transfer.threads</name>
  <value>4096</value>
</property>

完成上述配置后,请务必重新启动HDFS.

如果没有适当的配置,则会导致外观异常. 一种表现是抱怨缺少积木. 例如:

10/12/08 20:10:31 INFO hdfs.DFSClient: Could not obtain block
          blk_XXXXXXXXXXXXXXXXXXXXXX_YYYYYYYY from any node: java.io.IOException: No live nodes
          contain current block. Will get new block locations from namenode and retry...

另请参阅casestudies.max.transfer.threads,并注意此属性以前称为dfs.datanode.max.xcievers (例如Hadoop HDFS:由Xciever欺骗 ).

4.2. ZooKeeper Requirements

从HBase 1.0.0开始,ZooKeeper 3.4.x是必需的. HBase利用了仅从3.4.0开始可用的multi功能(在HBase 1.0.0中, useMulti配置选项默认为true ). 有关背景信息,请参见HBASE-12241(在使用Deadserver的复制队列时regionServer崩溃导致复制中断)HBASE-6775(在可用于HBASE-6710 0.92 / 0.94兼容性修补程序时使用ZK.multi)作为背景.

5. HBase run modes: Standalone and Distributed

HBase有两种运行模式: 独立运行和分布式运行. 开箱即用,HBase以独立模式运行. 无论使用哪种模式,都需要通过编辑HBase conf目录中的文件来配置HBase. 至少,您必须编辑conf / hbase-env.sh以告知HBase使用哪个Java. 在此文件中,您设置HBase环境变量,例如JVM的堆大小和其他选项,日志文件的首选位置等.将JAVA_HOME设置为指向Java安装的根目录.

5.1. Standalone HBase

这是默认模式. 快速入门部分介绍了独立模式. 在独立模式下,HBase不使用HDFS(而是使用本地文件系统),并且在同一JVM中运行所有HBase守护程序和本地ZooKeeper. Zookeeper绑定到一个知名端口,因此客户端可以与HBase进行通信.

5.2. Distributed

可以将分布式模式细分为分布式模式,但是所有守护程序都在单个节点上运行(也称为伪分布式) ,并且可以完全分布式 ,其中,守护程序分布在群集中的所有节点上. 伪分布式全分布式术语来自Hadoop.

伪分布式模式可以针对本地文件系统运行,也可以针对Hadoop分布式文件系统 (HDFS)实例运行. 全分布式模式只能在HDFS上运行. 有关如何设置HDFS的信息 ,请参阅Hadoop 文档 . 可在http://www.alexjf.net/blog/distributed-systems/hadoop-yarn-installation-definitive-guide中找到有关在Hadoop 2上设置HDFS的良好演练.

5.2.1. Pseudo-distributed

伪分布式快速入门

快速入门已添加到快速入门一章. 请参阅quickstart-pseudo . 本节中最初的某些信息已移至此处.

伪分布式模式只是在单个主机上运行的完全分布式模式. 在HBase上使用此配置测试和原型. 请勿将此配置用于生产或评估HBase性能.

5.3. Fully-distributed

默认情况下,HBase在独立模式下运行. 提供了独立模式和伪分布式模式都是为了进行小型测试. 对于生产环境,分布式模式是合适的. 在分布式模式下,HBase守护程序的多个实例在群集中的多个服务器上运行.

与伪分布式模式一样,完全分布式配置要求将hbase-cluster.distributed属性设置为true . 通常,将hbase.rootdir配置为指向高可用性HDFS文件系统.

此外,还配置了群集,以便多个群集节点可以注册为RegionServers,ZooKeeper QuorumPeers和备份HMaster服务器. 这些配置基础都在quickstart-full-distributed中进行了演示.

分布式RegionServer

通常,您的群集将包含运行在不同服务器上的多个RegionServer,以及主要和备份的Master和Zookeeper守护程序. 主服务器上的conf / regionservers文件包含其RegionServer与该群集关联的主机列表. 每个主机位于单独的行上. 当主服务器启动或停止时,此文件中列出的所有主机都将启动和停止其RegionServer进程.

ZooKeeper和HBase

有关HBase的ZooKeeper设置说明,请参见ZooKeeper部分.

例子7.例子分布式HBase集群

这是分布式HBase群集的conf / hbase-site.xml . 用于实际工作的群集将包含更多自定义配置参数. 大多数HBase配置指令都有默认值,除非在hbase-site.xml中覆盖该值,否则将使用默认值. 有关更多信息,请参见" 配置文件 ".

<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://namenode.example.org:8020/hbase</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>node-a.example.com,node-b.example.com,node-c.example.com</value>
  </property>
</configuration>

这是示例conf / regionservers文件,其中包含应在集群中运行RegionServer的节点的列表. 这些节点需要安装HBase,并且需要使用与主服务器相同的conf /目录内容

node-a.example.com
node-b.example.com
node-c.example.com

这是示例conf / backup-masters文件,其中包含应运行备份Master实例的每个节点的列表. 除非主主实例不可用,否则备份主实例将处于空闲状态.

node-b.example.com
node-c.example.com
分布式HBase快速入门

有关具有多个ZooKeeper,备份HMaster和RegionServer实例的简单三节点群集配置的演练,请参阅快速分发 .

过程:HDFS客户端配置
  1. 值得注意的是,如果您在Hadoop集群上进行了HDFS客户端配置更改(例如HDFS客户端的配置指令),而不是服务器端配置,则必须使用以下方法之一使HBase能够查看和使用这些配置更改:

    1. hbase-env.sh中 ,将指向HADOOP_CONF_DIR的指针添加到HBASE_CLASSPATH环境变量.

    2. $ {HBASE_HOME} / conf下添加hdfs-site.xml (或hadoop-site.xml )或更佳的符号链接的副本 ,或

    3. 如果只有一小部分HDFS客户端配置,请将其添加到hbase-site.xml .

此类HDFS客户端配置的示例是dfs.replication . 例如,如果要以5的复制因子运行,除非您执行上述操作以使配置可用于HBase,否则HBase将创建默认值为3的文件.

6. Running and Confirming Your Installation

确保HDFS首先运行. 通过在HADOOP_HOME目录中运行bin / start-hdfs.sh来启动和停止Hadoop HDFS守护程序. 您可以通过测试put文件放置到Hadoop文件系统中的putget来确保它正确启动. HBase通常不使用MapReduce或YARN守护程序. 这些不需要启动.

如果您正在管理自己的ZooKeeper,请启动它并确认它正在运行,否则HBase将在启动过程中为您启动ZooKeeper.

使用以下命令启动HBase:

bin/start-hbase.sh

HBASE_HOME目录运行以上HBASE_HOME .

您现在应该有一个正在运行的HBase实例. HBase日志可在logs子目录中找到. 检查它们,特别是如果HBase无法启动.

HBase还建立了一个列出重要属性的UI. 默认情况下,它部署在主主机上的端口16010上(HBase RegionServers默认在端口16020上侦听,并在端口16030上建立一个信息性HTTP服务器). 如果主master.example.org在默认端口上的名为master.example.org的主机上运行,​​请将浏览器指向http://master.example.org:16010以查看Web界面.

在HBase 0.98之前,主UI部署在端口60010上,HBase RegionServers UI部署在端口60030上.

HBase启动后,请参阅外壳练习部分,以了解如何创建表,添加数据,扫描插入以及最后禁用和删除表.

要在退出HBase Shell之后停止HBase,请输入

$ ./bin/stop-hbase.sh
stopping hbase...............

关机可能需要一些时间才能完成. 如果群集由多台计算机组成,则可能需要更长的时间. 如果您正在运行分布式操作,请确保等到HBase完全关闭后再停止Hadoop守护程序.

7. Default Configuration

7.1. hbase-site.xml and hbase-default.xml

就像在Hadoop中将特定于站点的HDFS配置添加到hdfs-site.xml文件中一样,对于HBase,特定于站点的自定义项也放入conf / hbase-site.xml文件中. 有关可配置属性的列表,请参见下面的hbase默认配置 ,或在src / main / resources的HBase源代码中查看原始的hbase-default.xml源文件.

并非所有配置选项都将其显示在hbase-default.xml中 . 人们认为很少有人会改变的配置只能存在于代码中. 进行此类配置的唯一方法是通过读取源代码本身.

当前,此处的更改将要求HBase重新启动群集以注意到更改.

7.2. HBase Default Configuration

以下文档是使用默认的hbase配置文件hbase-default.xml作为源生成的.

hbase.tmp.dir
Description

本地文件系统上的临时目录. 更改此设置以指向比" / tmp"更永久的位置(java.io.tmpdir的通常解析方法),因为在重新启动计算机时会清除" / tmp"目录.

Default

${java.io.tmpdir}/hbase-${user.name}

hbase.rootdir
Description

区域服务器共享的目录,HBase保留在该目录中. URL应该是"完全限定"的,以包括文件系统方案. 例如,要指定HDFS实例的namenode在端口9000上的namenode.example.org上运行的HDFS目录" / hbase",请将此值设置为:hdfs://namenode.example.org:9000 / hbase. 默认情况下,我们也会写入也设置了$ {hbase.tmp.dir}的内容(通常是/ tmp),因此请更改此配置,否则所有数据都会在计算机重新启动时丢失.

Default

${hbase.tmp.dir}/hbase

hbase.fs.tmp.dir
Description

默认文件系统(HDFS)中的暂存目录,用于保留临时数据.

Default

/user/${user.name}/hbase-staging

hbase.bulkload.staging.dir
Description

A staging directory in default file system (HDFS) for bulk loading.

Default

${hbase.fs.tmp.dir}

hbase.cluster.distributed
Description

群集将处于的模式.对于独立模式,可能的值为false;对于分布式模式,可能的值为true. 如果为false,则启动将在一个JVM中同时运行所有HBase和ZooKeeper守护程序.

Default

false

hbase.zookeeper.quorum
Description

ZooKeeper集合中服务器的逗号分隔列表(此配置应已命名为hbase.zookeeper.ensemble). 例如," host1.mydomain.com,host2.mydomain.com,host3.mydomain.com". 默认情况下,对于本地和伪分布式操作模式,此选项设置为localhost. 对于完全分布式的设置,应将其设置为ZooKeeper集成服务器的完整列表. 如果在hbase-env.sh中设置了HBASE_MANAGES_ZK,这是hbase在集群启动/停止过程中将启动/停止ZooKeeper的服务器列表. 在客户端,我们将使用此集合成员列表,并将其与hbase.zookeeper.clientPort配置放在一起. 并将其作为connectString参数传递到zookeeper构造函数中.

Default

localhost

zookeeper.recovery.retry.maxsleeptime
Description

重试动物园管理员操作之前的最大睡眠时间(以毫秒为单位),此处需要一个最大时间,以使睡眠时间不会无限制地增长

Default

60000

hbase.local.dir
Description

本地文件系统上用作本地存储的目录.

Default

${hbase.tmp.dir}/local/

hbase.master.port
Description

HBase主站应绑定的端口.

Default

16000

hbase.master.info.port
Description

HBase Master Web UI的端口. 如果您不希望运行UI实例,请设置为-1.

Default

16010

hbase.master.info.bindAddress
Description

HBase Master Web UI的绑定地址

Default

0.0.0.0

hbase.master.logcleaner.plugins
Description

A comma-separated list of BaseLogCleanerDelegate invoked by the LogsCleaner service. These WAL cleaners are called in order, so put the cleaner that prunes the most files in front. To implement your own BaseLogCleanerDelegate, just put it in HBase’s classpath and add the fully qualified class name here. Always add the above default log cleaners in the list.

Default

org.apache.hadoop.hbase.master.cleaner.TimeToLiveLogCleaner

hbase.master.logcleaner.ttl
Description

WAL可以保留在.oldlogdir目录中的最长时间,之后它将由主线程清除.

Default

600000

hbase.master.hfilecleaner.plugins
Description

由HFileCleaner服务调用的BaseHFileCleanerDelegate的逗号分隔列表. 这些HFiles清理程序是按顺序调用的,因此将修剪大多数文件的清理程序放在前面. 要实现自己的BaseHFileCleanerDelegate,只需将其放在HBase的类路径中,然后在此处添加完全限定的类名. 请始终在列表中添加上述默认日志清除器,因为它们将在hbase-site.xml中被覆盖.

Default

org.apache.hadoop.hbase.master.cleaner.TimeToLiveHFileCleaner

hbase.master.infoserver.redirect
Description

主服务器是否侦听主服务器Web UI端口(hbase.master.info.port)并将请求重定向到由主服务器和RegionServer共享的Web UI服务器.

Default

true

hbase.regionserver.port
Description

The port the HBase RegionServer binds to.

Default

16020

hbase.regionserver.info.port
Description

如果您不希望运行RegionServer UI,则将HBase RegionServer Web UI的端口设置为-1.

Default

16030

hbase.regionserver.info.bindAddress
Description

HBase RegionServer Web UI的地址

Default

0.0.0.0

hbase.regionserver.info.port.auto
Description

Master或RegionServer UI是否应搜索要绑定的端口. 如果hbase.regionserver.info.port已在使用中,则启用自动端口搜索. 对于测试很有用,默认情况下处于关闭状态.

Default

false

hbase.regionserver.handler.count
Description

在RegionServer上旋转的RPC侦听器实例数. 主机将相同的属性用于主机处理程序的计数.

Default

30

hbase.ipc.server.callqueue.handler.factor
Description

确定呼叫队列数量的因素. 值为0表示在所有处理程序之间共享一个队列. 值为1表示每个处理程序都有自己的队列.

Default

0.1

hbase.ipc.server.callqueue.read.ratio
Description

将呼叫队列划分为读写队列. 指定的间隔(应在0.0到1.0之间)将乘以呼叫队列的数量. 值为0表示不拆分呼叫队列,这意味着读取和写入请求都将被推送到同一组队列中. 小于0.5的值表示读队列少于写队列. 值为0.5表示将有相同数量的读取和写入队列. 大于0.5的值表示将有比写队列更多的读队列. 值1.0表示除一个队列外的所有队列均用于调度读取请求. 示例:给定呼叫队列的总数为10,则read.ratio为0表示:10个队列将包含两个读/写请求. read.ratio为0.3表示:3个队列仅包含读取请求,而7个队列仅包含写入请求. read.ratio为0.5表示:5个队列仅包含读取请求,而5个队列仅包含写入请求. read.ratio为0.8表示:8个队列仅包含读取请求,而2个队列仅包含写入请求. read.ratio为1表示:9个队列将仅包含读取请求,而1个队列将仅包含写入请求.

Default

0

hbase.ipc.server.callqueue.scan.ratio
Description

给定读取呼叫队列的数量(根据呼叫队列总数乘以callqueue.read.ratio计算得出),scan.ratio属性会将读取呼叫队列分为小读取队列和长读取队列. 小于0.5的值表示长读队列少于短读队列. 值为0.5表示将有相同数量的短读和长读队列. 大于0.5的值表示长读取队列比短读取队列多.值为0或1表示使用相同的队列进行获取和扫描. 示例:假设读取呼叫队列的总数为8,则scan.ratio为0或1表示:8个队列将同时包含长读取请求和短读取请求. scan.ratio为0.3表示:2个队列将仅包含长读请求,而6个队列将仅包含短读请求. scan.ratio为0.5意味着:4个队列将仅包含长读请求,而4个队列将仅包含短读请求. scan.ratio为0.8表示:6个队列将仅包含长读请求,而2个队列将仅包含短读请求.

Default

0

hbase.regionserver.msginterval
Description

从RegionServer到Master的消息之间的时间间隔(以毫秒为单位).

Default

3000

hbase.regionserver.logroll.period
Description

无论提交多少编辑,我们都会滚动提交日志的时间段.

Default

3600000

hbase.regionserver.logroll.errors.tolerated
Description

在触发服务器中止之前,我们将允许的连续WAL关闭错误数. 如果在日志滚动过程中关闭当前WAL写入器失败,则设置为0将导致区域服务器中止. 即使是很小的值(2或3)也将使区域服务器能够克服瞬态HDFS错误.

Default

2

hbase.regionserver.hlog.reader.impl
Description

WAL文件阅读器实现.

Default

org.apache.hadoop.hbase.regionserver.wal.ProtobufLogReader

hbase.regionserver.hlog.writer.impl
Description

WAL文件编写器实现.

Default

org.apache.hadoop.hbase.regionserver.wal.ProtobufLogWriter

hbase.regionserver.global.memstore.size
Description

在阻止新更新并强制进行刷新之前,区域服务器中所有内存存储区的最大大小. 默认为堆的40%(0.4). 阻止更新并强制执行刷新,直到区域服务器中所有内存存储的大小达到hbase.regionserver.global.memstore.size.lower.limit. 为了尊重旧的hbase.regionserver.global.memstore.upperLimit属性(如果存在),有意将此配置中的默认值保留为空.

Default

none

hbase.regionserver.global.memstore.size.lower.limit
Description

强制刷新之前,区域服务器中所有内存存储区的最大大小. 默认为hbase.regionserver.global.memstore.size(0.95)的95%. 如果由于内存存储限制而阻止更新,则此值的100%值将导致最小的刷新发生. 此配置中的默认值有意保留为空,以便使用旧的hbase.regionserver.global.memstore.lowerLimit属性(如果存在).

Default

none

hbase.regionserver.optionalcacheflushinterval
Description

编辑内容在自动刷新之前保留在内存中的最长时间. 默认值1小时. 将其设置为0以禁用自动刷新.

Default

3600000

hbase.regionserver.dns.interface
Description

区域服务器应从中报告其IP地址的网络接口的名称.

Default

default

hbase.regionserver.dns.nameserver
Description

区域服务器应使用该名称服务器(DNS)的主机名或IP地址来确定主机用于通讯和显示目的的主机名.

Default

default

hbase.regionserver.region.split.policy
Description

拆分策略确定何时应拆分区域. 当前可用的其他各种拆分策略为BusyRegionSplitPolicy,ConstantSizeRegionSplitPolicy,DisabledRegionSplitPolicy,DelimitedKeyPrefixRegionSplitPolicy,KeyPrefixRegionSplitPolicy等.

Default

org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy

hbase.regionserver.regionSplitLimit
Description

区域数量的限制,之后将不再进行区域划分. 这不是对区域数量的硬限制,但可作为区域服务器在特定限制后停止拆分的准则. 默认设置为1000.

Default

1000

zookeeper.session.timeout
Description

ZooKeeper会话超时(以毫秒为单位). 它以两种不同的方式使用. 首先,此值在HBase用于连接到集成体的ZK客户端中使用. HBase在启动ZK服务器时也使用它,并将其作为" maxSessionTimeout"传递. 请参阅http://hadoop.apache.org/zookeeper/docs/current/zookeeperProgrammers.html#ch_zkSessions . 例如,如果HBase区域服务器连接到也由HBase管理的ZK集成,则会话超时将是此配置指定的会话超时. 但是,连接到使用不同配置管理的集成服务器的区域服务器将受到该集成服务器的maxSessionTimeout的影响. 因此,即使HBase可能建议使用90秒,该集合的最大超时值也可以低于此值,并且它将具有优先权. ZK附带的当前默认值为40秒,比HBase的默认值低.

Default

90000

zookeeper.znode.parent
Description

ZooKeeper中用于HBase的根ZNode. 配置有相对路径的所有HBase的ZooKeeper文件都将位于此节点下. 默认情况下,所有HBase的ZooKeeper文件路径都配置有相对路径,因此除非更改,否则它们都将位于此目录下.

Default

/hbase

zookeeper.znode.acl.parent
Description

根ZNode用于访问控制列表.

Default

acl

hbase.zookeeper.dns.interface
Description

ZooKeeper服务器应从其报告其IP地址的网络接口的名称.

Default

default

hbase.zookeeper.dns.nameserver
Description

ZooKeeper服务器应使用其名称服务器(DNS)的主机名或IP地址来确定主服务器用于通信和显示目的的主机名.

Default

default

hbase.zookeeper.peerport
Description

ZooKeeper对等方用来互相通信的端口. 有关更多信息,请参见http://hadoop.apache.org/zookeeper/docs/r3.1.1/zookeeperStarted.html#sc_RunningReplicatedZooKeeper .

Default

2888

hbase.zookeeper.leaderport
Description

ZooKeeper用于领导者选举的端口. 有关更多信息,请参见http://hadoop.apache.org/zookeeper/docs/r3.1.1/zookeeperStarted.html#sc_RunningReplicatedZooKeeper .

Default

3888

hbase.zookeeper.useMulti
Description

指示HBase使用ZooKeeper的多重更新功能. 这样可以使某些ZooKeeper操作更快地完成,并避免因罕见的复制失败情况而引起的某些问题(有关示例,请参阅HBASE-2611的发行说明). 重要说明:仅当群集中的所有ZooKeeper服务器都在3.4+版且不会降级时,才将其设置为true. 3.4之前的ZooKeeper版本不支持多重更新,并且如果调用多重更新,也不会正常失败(请参阅ZOOKEEPER-1495).

Default

true

hbase.config.read.zookeeper.config
Description

设置为true允许HBaseConfiguration读取ZooKeeper属性的zoo.cfg文件. 不建议将其切换为true,因为不建议使用zoo.cfg文件读取ZK属性的功能.

Default

false

hbase.zookeeper.property.initLimit
Description

ZooKeeper的配置zoo.cfg中的属性. 初始同步阶段可以进行的滴答声数量.

Default

10

hbase.zookeeper.property.syncLimit
Description

ZooKeeper的配置zoo.cfg中的属性. 发送请求和获得确认之间可以经过的滴答声数量.

Default

5

hbase.zookeeper.property.dataDir
Description

ZooKeeper的配置zoo.cfg中的属性. 快照存储的目录.

Default

${hbase.tmp.dir}/zookeeper

hbase.zookeeper.property.clientPort
Description

ZooKeeper的配置zoo.cfg中的属性. 客户端将连接的端口.

Default

2181

hbase.zookeeper.property.maxClientCnxns
Description

ZooKeeper的配置zoo.cfg中的属性. 限制单个客户端通过IP地址标识到ZooKeeper集成的单个成员的并发连接数(在套接字级别). 设置为高值可以避免独立运行和伪分布式运行的zk连接问题.

Default

300

hbase.client.write.buffer
Description

HTable客户端写缓冲区的默认大小(以字节为单位). 较大的缓冲区会占用更多内存(在客户端和服务器端都需要,因为服务器会实例化传递的写缓冲区以对其进行处理),但是较大的缓冲区大小会减少制作的RPC的数量. 要估算服务器端使用的内存,请评估hbase.client.write.buffer * hbase.regionserver.handler.count

Default

2097152

hbase.client.pause
Description

常规客户端暂停值. 在运行重试失败的获取,区域查找等之前,主要用作等待值.请参见hbase.client.retries.number,以获取有关我们如何从此初始暂停量回退以及此暂停如何进行重试的描述.

Default

100

hbase.client.pause.cqtbe
Description

是否对CallQueueTooBigException(cqtbe)使用特殊的客户端暂停. 如果您观察到来自同一RegionServer的频繁CQTBE,并且此呼叫队列保持满状态,则将此属性设置为比hbase.client.pause高的值.

Default

none

hbase.client.retries.number
Description

最大重试次数. 用作所有可重试操作的最大值,例如获取单元格的值,开始行更新等.重试间隔是基于hbase.client.pause的粗略函数. 首先,我们以该间隔重试,但随后随着退避,我们很快就达到了每十秒钟重试一次的目的. 有关备份如何增加的信息,请参见HConstants#RETRY_BACKOFF. 更改此设置和hbase.client.pause以适合您的工作量.

Default

35

hbase.client.max.total.tasks
Description

一个HTable实例将发送到群集的最大并发变异任务数.

Default

100

hbase.client.max.perserver.tasks
Description

The maximum number of concurrent mutation tasks a single HTable instance will send to a single region server.

Default

5

hbase.client.max.perregion.tasks
Description

客户将维护到一个区域的最大并发突变任务数. 也就是说,如果已经对该区域进行了hbase.client.max.perregion.tasks写入,则在完成某些写入之前,不会将新的put发送到该区域.

Default

1

hbase.client.perserver.requests.threshold
Description

所有客户端线程(进程级别)中一台服务器的并发暂挂请求的最大数量. 超出的请求将立即引发ServerTooBusyException,以防止仅一台慢速区域服务器占用和阻止用户的线程. 如果您使用固定数量的线程以同步方式访问HBase,请将其设置为与线程数量相关的合适值将对您有所帮助. 有关详细信息,请参见https://issues.apache.org/jira/browse/HBASE-16388 .

Default

2147483647

hbase.client.scanner.caching
Description

如果未从(本地,客户端)内存提供服务,则在扫描器上调用next时尝试获取的行数. 此配置与hbase.client.scanner.max.result.size一起使用,以尝试有效地使用网络. 默认情况下,默认值为Integer.MAX_VALUE,以便网络将填充hbase.client.scanner.max.result.size定义的块大小,而不是受特定的行数限制,因为行的大小因表而异. 如果您提前知道一次扫描不需要多于一定数量的行,则应通过Scan#setCaching将此配置设置为该行限制. 较高的缓存值将启用更快的扫描程序,但会占用更多的内存,并且当缓存为空时,对next的某些调用可能会花费越来越长时间. 请勿将该值设置为两次调用之间的时间大于扫描程序的超时时间; 即hbase.client.scanner.timeout.period

Default

2147483647

hbase.client.keyvalue.maxsize
Description

指定KeyValue实例的组合最大允许大小. 这是为保存在存储文件中的单个条目设置上限. 由于无法拆分它们,因此有助于避免由于数据太大而无法进一步拆分区域. 将其设置为最大区域大小的一小部分似乎是明智的. 将其设置为零或更少将禁用检查.

Default

10485760

hbase.server.keyvalue.maxsize
Description

单个单元格的最大允许大小,包括值和所有关键组件. 小于或等于0的值将禁用该检查. 默认值为10MB. 这是一项安全设置,可防止服务器受到OOM的影响.

Default

10485760

hbase.client.scanner.timeout.period
Description

客户端扫描程序的租用期限(以毫秒为单位).

Default

60000

hbase.client.localityCheck.threadPoolSize
Default

2

hbase.bulkload.retries.number
Description

最大重试次数. 这是面对分裂操作时尝试进行的原子批量加载的最大迭代次数0表示永不放弃.

Default

10

hbase.master.balancer.maxRitPercent
Description

平衡时过渡区域的最大百分比. 默认值为1.0. 因此,没有平衡器节流. 如果将此配置设置为0.01,则表示平衡时最多有1%的过渡区域. 然后,平衡时群集的可用性至少为99%.

Default

1.0

hbase.balancer.period
Description

区域平衡器在主服务器中运行的时间段.

Default

300000

hbase.normalizer.period
Description

区域规范化器在主服务器中运行的时间段.

Default

1800000

hbase.regions.slop
Description

如果任何区域服务器具有平均+(平均*斜率)区域,则重新平衡. 在StochasticLoadBalancer(默认的负载均衡器)中,此参数的默认值为0.001,而在其他负载均衡器(即SimpleLoadBalancer)中,默认值为0.2.

Default

0.001

hbase.server.thread.wakefrequency
Description

两次搜索工作之间的睡眠时间(以毫秒为单位). 由服务线程(例如对数辊)用作睡眠间隔.

Default

10000

hbase.server.versionfile.writeattempts
Description

在中止之前有多少时间重试尝试写入版本文件. 每次尝试都由hbase.server.thread.wakefrequency毫秒分隔.

Default

3

hbase.hregion.memstore.flush.size
Description

如果内存大小超过此字节数,则将内存存储刷新到磁盘. 值由运行每个hbase.server.thread.wakefrequency的线程检查.

Default

134217728

hbase.hregion.percolumnfamilyflush.size.lower.bound
Description

如果使用FlushLargeStoresPolicy,则每当我们达到总内存存储限制时,我们都会找出其内存存储超过此值的所有列族,并仅对其进行刷新,同时保留其内存存储低于此限制的其他列族. 如果没有一个家庭的内存大小超过此大小,则将刷新所有内存(就像往常一样). 此值应小于总内存存储阈值(hbase.hregion.memstore.flush.size)的一半.

Default

16777216

hbase.hregion.preclose.flush.size
Description

如果在关闭时某个区域中的存储器大小等于或大于此大小,则在设置区域关闭标志并使该区域脱机之前,运行"预冲洗"以清除存储器. 关闭时,在关闭标志下运行刷新以清空内存. 在这段时间内,该地区处于离线状态,我们没有进行任何写操作. 如果内存存储区内容很大,则刷新可能需要很长时间才能完成. 预刷新的目的是在放置关闭标志并使区域脱机之前清理掉大部分的内存存储,因此在关闭标志下运行的刷新几乎没有作用.

Default

5242880

hbase.hregion.memstore.block.multiplier
Description

如果memstore具有hbase.hregion.memstore.block.multiplier乘以hbase.hregion.memstore.flush.size字节,则阻止更新. 防止更新流量激增期间失控的存储器. 如果没有上限,则内存存储将进行填充,以便在刷新结果刷新文件时需要花费很长时间来压缩或拆分,或更糟糕的是,我们OOME.

Default

4

hbase.hregion.memstore.mslab.enabled
Description

启用MemStore-Local Allocation Buffer,该功能可防止在重写入负载下发生堆碎片. 这可以减少大堆上停止世界GC暂停的频率.

Default

true

hbase.hregion.max.filesize
Description

HStoreFile的最大大小. 如果列族的HStoreFiles中的任何一个增长到超过该值,则托管HRegion都会分为两部分.

Default

10737418240

hbase.hregion.majorcompaction
Description

区域中所有HStoreFiles的"主要"压缩之间的时间(以毫秒为单位). 默认值:设置为7天. 大型压缩通常恰好在您最不需要它们时发生,因此请启用它们以使其在非高峰期运行以进行部署; 或者,由于此设置的周期不太可能与您的负载相匹配,因此可以通过cron作业或类似方法进行外部调用来运行压缩.

Default

604800000

hbase.hregion.majorcompaction.jitter
Description

抖动外边界,用于大型压实. 在每个区域服务器上,我们将hbase.region.majorcompaction间隔乘以该最大值范围内的某个随机分数. 然后,当下一次大型压缩将要运行时,我们将此+或-产品添加到. 这个想法是,在每个区域服务器上确实会同时进行重大压缩. 该数字越小,压实作用越紧密.

Default

0.50

hbase.hstore.compactionThreshold
Description

如果任何一个HStore中的HStoreFiles数量超过此数目(每次刷新memstore写入一个HStoreFile),则运行压缩以将所有HStoreFiles文件重写为一个. 较大的数量会推迟压缩,但是当压缩运行时,需要更长的时间才能完成.

Default

3

hbase.hstore.flusher.count
Description

刷新线程数. 如果线程较少,则将对存储区刷新进行排队. 如果线程更多,则刷新将并行执行,从而增加了hdfs负载. 这也可能导致更多的压缩.

Default

2

hbase.hstore.blockingStoreFiles
Description

如果任何一个存储中的存储文件数量都超过此数目(每次刷新MemStore写入一个StoreFile),则此HRegion的更新将被阻止,直到压缩完成或超过hbase.hstore.blockingWaitTime.

Default

10

hbase.hstore.blockingWaitTime
Description

HRegion达到hbase.hstore.blockingStoreFiles定义的StoreFile限制后将阻止更新的时间. 此时间过后,即使压缩尚未完成,HRegion也会停止阻止更新.

Default

90000

hbase.hstore.compaction.max
Description

每"次要"压缩要压缩的HStoreFiles的最大数目.

Default

10

hbase.hstore.compaction.kv.max
Description

刷新或压缩时,批量读取和写入多少个KeyValue. 如果有较大的KeyValue和OOME问题,请减少处理. 如果行宽较小,则执行更多操作.

Default

10

hbase.hstore.time.to.purge.deletes
Description

延迟清除带有未来时间戳记的删除标记的时间. 如果未设置或设置为0,则所有删除标记(包括带有未来时间戳记的标记)将在下一次主要压缩期间清除. 否则,将保留删除标记,直到在标记的时间戳加此设置的值之后发生的主要压缩为止(以毫秒为单位).

Default

0

hbase.regionserver.majorcompaction.pagecache.drop
Description

指定是否通过主要压缩将读取/写入的页面丢弃到系统页面缓存中. 将其设置为true有助于防止大型压缩污染页面缓存,这几乎总是需要的,尤其是对于内存/存储比率低/中等的群集.

Default

true

hbase.regionserver.minorcompaction.pagecache.drop
Description

指定是否通过较小的压缩将读取/写入的页面丢弃到系统页面缓存中. 将其设置为true有助于防止较小的压缩污染页面缓存,这在内存与存储比率低或写入量很大的群集中最有用. 当大量读取都在最近写入的数据上时,您可能希望在中等到较低的写入工作量下将其设置为false.

Default

true

hbase.storescanner.parallel.seek.enable
Description

在StoreScanner中启用StoreFileScanner并行搜索功能,该功能可以减少特殊情况下的响应延迟.

Default

false

hbase.storescanner.parallel.seek.threads
Description

如果启用了并行查找功能,则为默认线程池大小.

Default

10

hfile.block.cache.size
Description

分配给HFile / StoreFile使用的块缓存的最大堆的百分比(-Xmx设置). 默认值为0.4表示分配40%. 设置为0禁用,但不建议使用; 您至少需要足够的缓存来保存存储文件索引.

Default

0.4

hfile.block.index.cacheonwrite
Description

这允许在写入索引时将非根多级索引块放入块高速缓存中.

Default

false

hfile.index.block.max.size
Description

当多级块索引中的叶级,中间级或根级索引块的大小增长到该大小时,将写出该块并开始一个新块.

Default

131072

hbase.bucketcache.ioengine
Description

存储桶式缓存内容的位置. 其中之一:堆,堆或文件. 如果是文件,请将其设置为file:PATH_TO_FILE. 有关更多信息,请参见http://hbase.apache.org/book.html#offheap.blockcache .

Default

none

hbase.bucketcache.combinedcache.enabled
Description

桶式缓存是否与LRU堆式块缓存一起使用. 在这种模式下,索引和bloom保留在LRU块缓存中,数据块保留在存储桶中.

Default

true

hbase.bucketcache.size
Description

EITHER表示要提供给缓存的总堆内存大小的百分比的浮点数(如果<1.0),或者,它是BucketCache的总容量(以兆字节为单位). 默认值:0.0

Default

none

hbase.bucketcache.bucket.sizes
Description

以逗号分隔的存储区存储区大小列表. 可以是多种尺寸. 按从小到大的顺序列出块大小. 您使用的大小将取决于您的数据访问模式. 必须是256的倍数,否则当您从缓存中读取数据时,将遇到" java.io.IOException:无效的HFile块魔术". 如果在此处未指定任何值,则将选择代码中设置的默认存储桶大小(请参见BucketAllocator#DEFAULT_BUCKET_SIZES).

Default

none

hfile.format.version
Description

用于新文件的HFile格式版本. 第3版增加了对hfiles中标签的支持(请参阅http://hbase.apache.org/book.html#hbase.tags ). 分布式日志重播要求启用标签. 另请参阅配置" hbase.replication.rpc.codec".

Default

3

hfile.block.bloom.cacheonwrite
Description

为复合Bloom筛选器的内联块启用写时缓存.

Default

false

io.storefile.bloom.block.size
Description

复合布隆过滤器的单个块("块")的大小(以字节为单位). 此大小是近似值,因为Bloom块只能插入数据块边界,并且每个数据块的键数有所不同.

Default

131072

hbase.rs.cacheblocksonwrite
Description

块完成后是否应将HFile块添加到块缓存中.

Default

false

hbase.rpc.timeout
Description

这是为RPC层定义的,HBase客户端应用程序需要花费多长时间(毫秒)来进行远程调用以使超时. 它使用ping来检查连接,但最终将抛出TimeoutException.

Default

60000

hbase.client.operation.timeout
Description

操作超时是一个顶级限制(毫秒),可确保Table中的阻止操作不会超过此限制. 在每个操作中,如果rpc请求由于超时或其他原因而失败,它将重试直到成功或抛出RetriesExhaustedException. 但是,如果阻塞的总时间在重试用尽之前达到了操作超时,它将提前中断并抛出SocketTimeoutException.

Default

1200000

hbase.cells.scanned.per.heartbeat.check
Description

在两次心跳检查之间扫描的细胞数. 心跳检查在扫描处理期间进行,以确定服务器是否应停止扫描以将心跳消息发送回客户端. 心跳消息用于在长时间运行的扫描期间保持客户端-服务器连接保持活动状态. 较小的值表示心跳检查将更频繁地发生,因此将对扫描的执行时间提供更严格的限制. 较大的值表示心跳检查发生的频率较低

Default

10000

hbase.rpc.shortoperation.timeout
Description

这是" hbase.rpc.timeout"的另一个版本. 对于群集内的那些RPC操作,我们依靠此配置为短操作设置短超时限制. 例如,区域服务器尝试向活动主服务器报告的短rpc超时可以使主服务器故障转移过程更快.

Default

10000

hbase.ipc.client.tcpnodelay
Description

设置rpc套接字连接没有延迟. 参见http://docs.oracle.com/javase/1.5.0/docs/api/java/net/Socket.html#getTcpNoDelay(

Default

true

hbase.regionserver.hostname
Description

此配置适用于专家:除非您真的知道自己在做什么,否则请不要设置其值. 设置为非空值时,它表示基础服务器的(外部)主机名. 有关详细信息,请参见https://issues.apache.org/jira/browse/HBASE-12954 .

Default

none

hbase.regionserver.hostname.disable.master.reversedns
Description

此配置适用于专家:除非您真的知道自己在做什么,否则请不要设置其值. 设置为true时,regionserver将使用当前节点的主机名作为服务器名,HMaster将跳过反向DNS查找,而是使用regionserver发送的主机名. 请注意,此配置和hbase.regionserver.hostname是互斥的. 有关更多详细信息,请参见https://issues.apache.org/jira/browse/HBASE-18226 .

Default

false

hbase.master.keytab.file
Description

kerberos keytab文件的完整路径,用于登录配置的HMaster服务器主体.

Default

none

hbase.master.kerberos.principal
Description

例如 " hbase/_HOST@EXAMPLE.COM". 用来运行HMaster进程的Kerberos主体名称. 主体名称应采用以下格式:user / hostname @ DOMAIN. 如果将" _HOST"用作主机名部分,它将被正在运行的实例的实际主机名替换.

Default

none

hbase.regionserver.keytab.file
Description

kerberos keytab文件的完整路径,用于登录配置的HRegionServer服务器主体.

Default

none

hbase.regionserver.kerberos.principal
Description

Ex. "hbase/_HOST@EXAMPLE.COM". The kerberos principal name that should be used to run the HRegionServer process. The principal name should be in the form: user/hostname@DOMAIN. If "_HOST" is used as the hostname portion, it will be replaced with the actual hostname of the running instance. An entry for this principal must exist in the file specified in hbase.regionserver.keytab.file

Default

none

hadoop.policy.file
Description

RPC服务器用来对客户端请求做出授权决策的策略配置文件. 仅在启用HBase安全性时使用.

Default

hbase-policy.xml

hbase.superuser
Description

List of users or groups (comma-separated), who are allowed full privileges, regardless of stored ACLs, across the cluster. Only used when HBase security is enabled.

Default

none

hbase.auth.key.update.interval
Description

服务器中认证令牌的主密钥的更新间隔(以毫秒为单位). 仅在启用HBase安全性时使用.

Default

86400000

hbase.auth.token.max.lifetime
Description

认证令牌到期的最大生存时间(以毫秒为单位). 仅在启用HBase安全性时使用.

Default

604800000

hbase.ipc.client.fallback-to-simple-auth-allowed
Description

当客户端配置为尝试安全连接,但尝试连接到不安全的服务器时,该服务器可能会指示客户端切换到SASL SIMPLE(不安全)身份验证. 此设置控制客户端是否将接受来自服务器的此指令. 如果为false(默认值),则客户端将不允许回退到SIMPLE身份验证,并将中止连接.

Default

false

hbase.ipc.server.fallback-to-simple-auth-allowed
Description

当服务器配置为要求安全连接时,它将使用SASL SIMPLE(不安全)身份验证拒绝来自客户端的连接尝试. 此设置允许安全服务器在客户端请求时接受来自客户端的SASL SIMPLE连接. 如果为false(默认值),则服务器将不允许回退到SIMPLE身份验证,并且将拒绝连接. 警告:在将客户端转换为安全身份验证时,仅应将此设置用作临时措施. 为了安全操作,必须禁用它.

Default

false

hbase.coprocessor.enabled
Description

启用或禁用协处理器加载. 如果为" false"(禁用),则将忽略任何其他与协处理器相关的配置.

Default

true

hbase.coprocessor.user.enabled
Description

启用或禁用用户(aka表)协处理器加载. 如果为" false"(禁用),则将忽略表描述符中的任何表协处理器属性. 如果" hbase.coprocessor.enabled"为" false",则此设置无效.

Default

true

hbase.coprocessor.region.classes
Description

默认情况下,在所有表上加载的以逗号分隔的协处理器列表. 对于任何重写协处理器方法,将按顺序调用这些类. 在实现自己的协处理器之后,只需将其放在HBase的类路径中,然后在此处添加完全限定的类名即可. 也可以通过设置HTableDescriptor来按需加载协处理器.

Default

none

hbase.rest.port
Description

HBase REST服务器的端口.

Default

8080

hbase.rest.readonly
Description

定义启动REST服务器的模式.可能的值是:false:允许所有HTTP方法-GET / PUT / POST / DELETE. true:仅允许GET方法.

Default

false

hbase.rest.threads.max
Description

REST服务器线程池的最大线程数. 池中的线程被重用以处理REST请求. 这控制了并发处理的最大请求数. 这可能有助于控制REST服务器使用的内存,以避免OOM问题. 如果线程池已满,则传入的请求将排队,并等待一些空闲线程.

Default

100

hbase.rest.threads.min
Description

REST服务器线程池的最小线程数. 线程池始终至少具有这些线程数,因此REST服务器已准备就绪,可以处理传入的请求.

Default

2

hbase.rest.support.proxyuser
Description

允许运行REST服务器以支持代理用户模式.

Default

false

hbase.defaults.for.version.skip
Description

设置为true可跳过" hbase.defaults.for.version"检查. 将其设置为true可以在Maven生成的另一端以外的环境中使用. 即在思想上运行. 您需要将此布尔值设置为true以避免看到RuntimException投诉:" hbase-default.xml文件似乎适用于旧版本的HBase(\ $ {hbase.version}),此版本为XXX-SNAPSHOT"

Default

false

hbase.coprocessor.master.classes
Description

逗号分隔的org.apache.hadoop.hbase.coprocessor.MasterObserver协处理器列表,默认情况下在活动HMaster进程中加载​​. 对于任何已实现的协处理器方法,将按顺序调用列出的类. 在实现自己的MasterObserver之后,只需将其放入HBase的类路径中,并在此处添加完全限定的类名.

Default

none

hbase.coprocessor.abortonerror
Description

设置为true会导致如果协处理器无法加载,初始化失败或引发意外的Throwable对象,则导致托管服务器(主服务器或区域服务器)中止. 将其设置为false将允许服务器继续执行,但是相关协处理器的系统范围状态将变得不一致,因为它将仅在一部分服务器中正确执行,因此这仅对调试最有用.

Default

true

hbase.online.schema.update.enable
Description

设置为true启用联机模式更改.

Default

true

hbase.table.lock.enable
Description

设置为true以启用将锁锁定在zookeeper中以进行模式更改操作. 来自主服务器的表锁定可防止将并行模式修改为损坏的表状态.

Default

true

hbase.table.max.rowsize
Description

未设置行内扫描标志的"获取"或"扫描"单行的最大大小(以字节为单位)(默认为1 Gb). 如果行大小超过此限制,则将RowTooBigException抛出给客户端.

Default

1073741824

hbase.thrift.minWorkerThreads
Description

线程池的"核心大小". 在每个连接上都会创建新线程,直到创建了这么多线程.

Default

16

hbase.thrift.maxWorkerThreads
Description

线程池的最大大小. 当挂起的请求队列溢出时,将创建新线程,直到它们的数量达到该数量为止. 此后,服务器开始断开连接.

Default

1000

hbase.thrift.maxQueuedRequests
Description

在队列中等待的未决Thrift连接的最大数量. 如果池中没有空闲线程,则服务器会将请求排队. 仅当队列溢出时,才添加新线程,直到hbase.thrift.maxQueuedRequests线程.

Default

1000

hbase.regionserver.thrift.framed
Description

在服务器端使用Thrift TFramedTransport. 这是旧服务器推荐的传输方式,并且在客户端需要类似的设置. 将其更改为false将选择默认传输方式,当由于THRIFT-601发出格式错误的请求时,该传输方式容易受到DoS攻击.

Default

false

hbase.regionserver.thrift.framed.max_frame_size_in_mb
Description

使用成帧传输时的默认帧大小

Default

2

hbase.regionserver.thrift.compact
Description

使用Thrift TCompactProtocol二进制序列化协议.

Default

false

hbase.rootdir.perms
Description

安全(kerberos)设置中根目录的FS权限. 当master启动时,它将使用此权限创建rootdir或在权限不匹配时设置权限.

Default

700

hbase.wal.dir.perms
Description

安全(kerberos)设置中的根WAL目录的FS权限. 当master启动时,它将使用此权限创建WAL目录,或者在不匹配时设置权限.

Default

700

hbase.data.umask.enable
Description

启用(如果为true),应将文件权限分配给由regionserver写入的文件

Default

false

hbase.data.umask
Description

hbase.data.umask.enable为true时应用于写入数据文件的文件权限

Default

000

hbase.snapshot.enabled
Description

设置为true以允许拍摄/还原/克隆快照.

Default

true

hbase.snapshot.restore.take.failsafe.snapshot
Description

设置为true以在还原操作之前进行快照. 发生故障时将使用拍摄的快照来还原以前的状态. 在还原操作结束时,此快照将被删除

Default

true

hbase.snapshot.restore.failsafe.name
Description

还原操作获取的故障安全快照的名称. 您可以使用{snapshot.name},{table.name}和{restore.timestamp}变量根据要还原的内容创建名称.

Default

hbase-failsafe-{snapshot.name}-{restore.timestamp}

hbase.snapshot.working.dir
Description

快照过程将发生的位置. 完成的快照的位置不会更改,但是快照过程发生的临时目录将设置为此位置. 为了提高性能,这可以是与根目录不同的文件系统. 有关更多信息,请参见HBASE-21098

Default

none

hbase.server.compactchecker.interval.multiplier
Description

该数字确定我们进行扫描以查看是否有必要进行压缩的频率. 通常,压缩是在某些事件(例如memstore刷新)之后完成的,但是如果一段时间未收到区域的大量写入,或者由于不同的压缩策略,可能有必要定期对其进行检查. 检查之间的间隔是hbase.server.compactchecker.interval.multiplier乘以hbase.server.thread.wakefrequency.

Default

1000

hbase.lease.recovery.timeout
Description

在放弃之前,我们等待dfs租赁恢复的总时间为多长时间.

Default

900000

hbase.lease.recovery.dfs.timeout
Description

dfs之间恢复租约调用的时间. 应该大于namenode作为datanode的一部分发出块恢复命令所花费的时间的总和; dfs.heartbeat.interval以及主数据节点所花费的时间,在死数据节点上执行块恢复到超时; 通常是dfs.client.socket-timeout. 有关更多信息,请参见HBASE-8389的末尾.

Default

64000

hbase.column.max.version
Description

新的列族描述符将使用此值作为要保留的默认版本数.

Default

1

hbase.dfs.client.read.shortcircuit.buffer.size
Description

如果未设置DFSClient配置dfs.client.read.shortcircuit.buffer.size,我们将使用此处配置的短路读取默认直接字节缓冲区大小. DFSClient本机默认值为1MB; HBase保持其HDFS文件处于打开状态,因此文件块数* 1MB很快就开始增加,并由于直接内存不足而威胁了OOME. 因此,我们将其设置为默认值. 使其>在HColumnDescriptor中设置的默认hbase块大小,通常为64k.

Default

131072

hbase.regionserver.checksum.verify
Description

如果设置为true(默认值),则HBase会验证hfile块的校验和. HBase在写出hfile时会与数据内联地写校验和. HDFS(在撰写本文时)将校验和写入数据文件之外的单独文件,这需要额外的查找. 设置该标志可节省一些I / O. 设置此标志时,将在hfile流上内部禁用HDFS的校验和验证. 如果hbase-checksum验证失败,我们将切换回使用HDFS校验和(因此请不要禁用HDFS校验和!此外,此功能仅适用于hfile,不适用于WAL). 如果将此参数设置为false,则hbase将不会验证任何校验和,而是取决于HDFS客户端中进行的校验和验证.

Default

true

hbase.hstore.bytes.per.checksum
Description

hfile块中HBase级别校验和的新创建校验和块中的字节数.

Default

16384

hbase.hstore.checksum.algorithm
Description

用于计算校验和的算法的名称. 可能的值为NULL,CRC32,CRC32C.

Default

CRC32C

hbase.client.scanner.max.result.size
Description

调用扫描仪的下一个方法时返回的最大字节数. 请注意,当单行大于此限制时,该行仍将完全返回. 默认值为2MB,适合1ge网络. 对于更快和/或更高延迟的网络,应该增加该值.

Default

2097152

hbase.server.scanner.max.result.size
Description

调用扫描仪的下一个方法时返回的最大字节数. 请注意,当单行大于此限制时,该行仍将完全返回. 默认值为100MB. 这是一项安全设置,可防止服务器受到OOM的影响.

Default

104857600

hbase.status.published
Description

此设置激活主服务器发布区域服务器状态. 当区域服务器停止运行并开始恢复时,主服务器会将这些信息推送到客户端应用程序,以使它们立即断开连接,而不必等待超时.

Default

false

hbase.status.publisher.class
Description

使用多播消息实现状态发布.

Default

org.apache.hadoop.hbase.master.ClusterStatusPublisher$MulticastPublisher

hbase.status.listener.class
Description

使用多播消息实现状态侦听器.

Default

org.apache.hadoop.hbase.client.ClusterStatusListener$MulticastListener

hbase.status.multicast.address.ip
Description

用于通过多播发布状态的多播地址.

Default

226.1.1.3

hbase.status.multicast.address.port
Description

组播端口,用于通过组播发布状态.

Default

16100

hbase.dynamic.jars.dir
Description

区域服务器无需重新启动就可以动态加载自定义过滤器/协处理器jar的目录. 但是,已经加载的过滤器/协处理器类不会被卸载. 有关更多详细信息,请参见HBASE-1936.

Default

${hbase.rootdir}/lib

hbase.security.authentication
Description

控制是否为HBase启用安全身份验证. 可能的值为"简单"(不进行身份验证)和" kerberos".

Default

simple

hbase.rest.filter.classes
Description

REST服务的Servlet过滤器.

Default

org.apache.hadoop.hbase.rest.filter.GzipFilter

hbase.master.loadbalancer.class
Description

Class used to execute the regions balancing when the period occurs. See the class comment for more on how it works http://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/master/balancer/StochasticLoadBalancer.html It replaces the DefaultLoadBalancer as the default (since renamed as the SimpleLoadBalancer).

Default

org.apache.hadoop.hbase.master.balancer.StochasticLoadBalancer

hbase.rest.csrf.enabled
Description

设置为true以启用针对跨站点请求伪造(CSRF)的保护

Default

false

hbase.rest-csrf.browser-useragents-regex
Description

通过将hbase.rest.csrf.enabled设置为true为REST服务器启用跨站点请求伪造(CSRF)保护时,用逗号分隔的正则表达式列表,用于与HTTP请求的User-Agent标头匹配. 如果传入的User-Agent与这些正则表达式中的任何一个匹配,则该请求被视为由浏览器发送,因此强制执行CSRF. 如果请求的User-Agent与这些正则表达式都不匹配,则认为该请求是由浏览器以外的其他设备(例如脚本化自动化)发送的. 在这种情况下,CSRF并不是潜在的攻击媒介,因此无法执行预防措施. 这有助于实现与尚未更新为发送CSRF预防标头的现有自动化的向后兼容性.

Default

Mozilla.,Opera.

hbase.security.exec.permission.checks
Description

如果启用此设置并且基于ACL的访问控制处于活动状态(AccessController协处理器既可以作为系统协处理器安装,也可以作为表协处理器安装在表上),那么如果所有相关用户需要执行协处理器终结点的能力,则必须授予他们EXEC特权电话. 像任何其他权限一样,EXEC特权可以全局授予用户,也可以基于每个表或每个命名空间授予用户. 有关协处理器端点的更多信息,请参见HBase在线手册的协处理器部分. 有关使用AccessController授予或撤消权限的更多信息,请参见HBase在线手册的安全性部分.

Default

false

hbase.procedure.regionserver.classes
Description

逗号分隔的org.apache.hadoop.hbase.procedure.RegionServerProcedureManager过程管理器列表,默认情况下在活动的HRegionServer进程中加载​​. 生命周期方法(init / start / stop)将由活动的HRegionServer进程调用,以执行特定的全局受阻过程​​. 在实现自己的RegionServerProcedureManager之后,只需将其放在HBase的类路径中,然后在此处添加完全限定的类名即可.

Default

none

hbase.procedure.master.classes
Description

逗号分隔的org.apache.hadoop.hbase.procedure.MasterProcedureManager过程管理器列表,默认情况下在活动HMaster进程上加载. 过程由其签名标识,用户可以使用签名和即时名称来触发全局障碍过程的执行. 在实现您自己的MasterProcedureManager之后,只需将其放在HBase的类路径中,然后在此处添加完全限定的类名即可.

Default

none

hbase.coordinated.state.manager.class
Description

实现协调状态管理器的类的全限定名称.

Default

org.apache.hadoop.hbase.coordination.ZkCoordinatedStateManager

hbase.regionserver.storefile.refresh.period
Description

刷新辅助区域的存储文件的时间段(以毫秒为单位). 0表示此功能被禁用. 一旦二级区域刷新了该区域中的文件列表(没有通知机制),二级区域就会从主区域看到新文件(通过刷新和压缩). 但是过于频繁的刷新可能会导致额外的Namenode压力. 如果文件刷新的时间不能超过HFile TTL(hbase.master.hfilecleaner.ttl),则拒绝请求. 还建议通过此设置将HFile TTL配置为更大的值.

Default

0

hbase.region.replica.replication.enabled
Description

是否启用了到辅助区域副本的异步WAL复制. 如果启用此功能,将创建一个名为" region_replica_replication"的复制对等方,它将复制日志尾部并将突变复制到具有区域复制> 1的表的区域副本中.如果启用一次,则禁用此复制还需要禁用复制使用shell或ReplicationAdmin java类进行对等. 到辅助区域副本的复制通过标准的群集间复制进行. 因此,如果显式禁用了复制,则还必须通过将" hbase.replication"设置为true来启用此功能.

Default

false

hbase.http.filter.initializers
Description

用逗号分隔的类名称列表. 列表中的每个类都必须扩展org.apache.hadoop.hbase.http.FilterInitializer. 相应的过滤器将被初始化. 然后,该筛选器将应用于所有面向用户的jsp和servlet网页. 列表的顺序定义了过滤器的顺序. 默认的StaticUserWebFilter添加一个由hbase.http.staticuser.user属性定义的用户主体.

Default

org.apache.hadoop.hbase.http.lib.StaticUserWebFilter

hbase.security.visibility.mutations.checkauths
Description

如果启用此属性,将检查可见性表达式中的标签是否与发出突变的用户相关联

Default

false

hbase.http.max.threads
Description

HTTP Server将在其ThreadPool中创建的最大线程数.

Default

10

hbase.replication.rpc.codec
Description

启用复制时要使用的编解码器,以便同时复制标签. 与HFileV3一起使用,后者支持其中的标签. 如果不使用标记,或者使用的hfile版本是HFileV2,则可以将KeyValueCodec用作复制编解码器. 请注意,在没有标签的情况下使用KeyValueCodecWithTags进行复制不会造成任何危害.

Default

org.apache.hadoop.hbase.codec.KeyValueCodecWithTags

hbase.replication.source.maxthreads
Description

任何复制源用于将编辑并行传送到接收器的最大线程数. 这也限制了每个复制批处理分成的块数. 较大的值可以提高主群集和从群集之间的复制吞吐量. 默认值10几乎不需要更改.

Default

10

hbase.http.staticuser.user
Description

呈现内容时在静态Web筛选器上作为筛选条件的用户名. HDFS Web UI(用于浏览文件的用户)是一个示例用法.

Default

dr.stack

hbase.master.normalizer.class
Description

发生周期时用于执行区域规范化的类. 有关其工作原理的更多信息,请参见类注释.http://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.html

Default

org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer

hbase.regionserver.handler.abort.on.error.percent
Description

区域服务器RPC线程无法中止RS的百分比. -1禁用中止; 0即使有一个处理程序死亡,也中止; 0.x仅在此百分比的处理程序已死亡时才中止; 1只有中止所有处理程序的人都死了.

Default

0.5

hbase.snapshot.master.timeout.millis
Description

快照过程执行的主服务器超时

Default

300000

hbase.snapshot.region.timeout
Description

区域服务器将线程保留在快照请求池中的等待时间

Default

300000

hbase.rpc.rows.warning.threshold
Description

批处理操作中的行数,超过该行数将记录警告.

Default

5000

7.3. hbase-env.sh

在此文件中设置HBase环境变量. 示例包括在HBase守护程序启动时传递JVM的选项,例如堆大小和垃圾收集器配置. 您还可以设置HBase配置的配置,日志目录,niceness,ssh选项,在何处查找进程pid文件等.在conf / hbase-env.sh中打开文件并仔细阅读其内容. 每个选项都有充分的文档记录. 如果希望在启动时由HBase守护程序读取它们,请在此处添加您自己的环境变量.

此处的更改将要求群集重新启动,以便HBase注意到更改.

7.4. log4j.properties

编辑此文件以更改HBase文件的滚动速率并更改HBase记录消息的级别.

尽管可以通过HBase UI更改特定守护程序的日志级别,但此处的更改将要求HBase重新启动群集以注意到更改.

7.5. Client configuration and dependencies connecting to an HBase cluster

如果您以独立模式运行HBase,则无需配置任何内容即可让客户端正常工作,只要它们都在同一台计算机上即可.

由于HBase Master可能会四处移动,因此客户端可以通过向ZooKeeper查找当前的关键位置来进行引导. ZooKeeper是保留所有这些值的位置. 因此,客户在执行其他任何操作之前,需要先确定ZooKeeper合奏的位置. 通常,此合奏位置保留在hbase-site.xml中 ,并由客户端从CLASSPATH拾取.

如果正在配置要运行HBase客户端的IDE,则应在类路径中包含conf /目录,以便可以找到hbase-site.xml设置(或添加src / test / resources来选择使用的hbase-site.xml通过测试).

连接到集群时,HBase的客户端至少需要在其CLASSPATH包含多个库,包括:

commons-configuration (commons-configuration-1.6.jar)
commons-lang (commons-lang-2.5.jar)
commons-logging (commons-logging-1.1.1.jar)
hadoop-core (hadoop-core-1.0.0.jar)
hbase (hbase-0.92.0.jar)
log4j (log4j-1.2.16.jar)
slf4j-api (slf4j-api-1.5.8.jar)
slf4j-log4j (slf4j-log4j12-1.5.8.jar)
zookeeper (zookeeper-3.4.2.jar)

仅用于客户端的示例基本hbase-site.xml可能如下所示:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>example1,example2,example3</value>
    <description>The directory shared by region servers.
    </description>
  </property>
</configuration>

7.5.1. Java client configuration

Java客户端使用的配置保留在HBaseConfiguration实例中.

HBaseConfiguration的工厂方法, HBaseConfiguration.create(); 调用时,将读取在客户端的CLASSPATH上找到的第一个hbase-site.xml的内容(如果存在)(调用还将包括找到的任何hbase-default.xmlhbase-default.xml随附在hbase.XXXjar ). 还可以直接指定配置,而不必从hbase-site.xml中读取. 例如,以编程方式为集群设置ZooKeeper集成,请执行以下操作:

Configuration config = HBaseConfiguration.create();
config.set("hbase.zookeeper.quorum", "localhost");  // Here we are running zookeeper locally

如果多个ZooKeeper实例组成了ZooKeeper集合,则可以在用逗号分隔的列表中指定它们(就像在hbase-site.xml文件中一样). 然后可以将此填充的Configuration实例传递给Table ,依此类推.

8. Example Configurations

8.1. Basic Distributed HBase Install

这是分布式十节点群集的示例基本配置:*在此示例中,通过节点example9将节点命名为example0example1等. * HBase主节点和HDFS NameNode在节点example0上运行. * RegionServer在节点example1 - example9上运行. * 3节点ZooKeeper集合在默认端口上的example1example2example3上运行. * ZooKeeper数据保留在目录/ export / zookeeper中 .

下面,我们显示在HBase conf目录中找到的主要配置文件-hbase-site.xmlregionservershbase-env.sh可能是什么样子.

8.1.1. hbase-site.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>example1,example2,example3</value>
    <description>The directory shared by RegionServers.
    </description>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/export/zookeeper</value>
    <description>Property from ZooKeeper config zoo.cfg.
    The directory where the snapshot is stored.
    </description>
  </property>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://example0:8020/hbase</value>
    <description>The directory shared by RegionServers.
    </description>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
    <description>The mode the cluster will be in. Possible values are
      false: standalone and pseudo-distributed setups with managed Zookeeper
      true: fully-distributed with unmanaged Zookeeper Quorum (see hbase-env.sh)
    </description>
  </property>
</configuration>

8.1.2. regionservers

在此文件中,列出将运行RegionServers的节点. 在我们的例子中,这些节点是example1 - example9 .

example1
example2
example3
example4
example5
example6
example7
example8
example9

8.1.3. hbase-env.sh

hbase-env.sh文件中的以下几行显示了如何设置JAVA_HOME环境变量(对于HBase 0.98.5和更高版本是必需的)以及如何将堆设置为4 GB(而不是默认值1 GB). 如果复制并粘贴此示例,请确保调整JAVA_HOME以适合您的环境.

# The java implementation to use.
export JAVA_HOME=/usr/java/jdk1.7.0/

# The maximum amount of heap to use. Default is left to JVM default.
export HBASE_HEAPSIZE=4G

使用rsync将conf目录的内容复制到群集的所有节点.

9. The Important Configurations

下面我们列出了一些重要的配置. 我们将本节分为所需的配置和值得一看的推荐配置.

9.1. Required Configurations

查看oshadoop部分.

9.1.1. Big Cluster Configurations

如果您的群集具有很多区域,则在主服务器启动后,Regionserver可能会短暂签入,而所有其他RegionServer都将滞后. 该第一台要签入的服务器将被分配所有非最佳区域. 为防止发生上述情况,请将hbase.master.wait.on.regionservers.mintostart属性从其默认值1开始.请参见HBASE-6389修改条件,以确保主服务器在启动区域之前等待足够数量的Region Server.作业以获取更多详细信息.

9.1.2. If a backup Master exists, make the primary Master fail fast

如果主要的Master失去了与ZooKeeper的连接,它将陷入一个循环,不断尝试重新连接. 如果您运行多个Master(即备用Master),请禁用此功能. 失败的话,垂死的Master可能会继续接收RPC,尽管另一个Master已经承担了Primary的角色. 请参阅配置fail.fast.expired.active.master .

zookeeper.session.timeout

默认超时为三分钟(以毫秒为单位). 这意味着,如果服务器崩溃,则主服务器将在三分钟后通知崩溃并开始恢复. 您可能希望将超时时间缩短至一分钟或更短,以便主服务器能够更快地注意到故障. 在更改此值之前,请确保已控制JVM垃圾收集配置,否则,持续超过ZooKeeper会话超时的长垃圾收集将占用RegionServer(您可能会满意,您可能会满意的-您可能希望在服务器上开始恢复服务器(如果RegionServer长时间处于GC中).

要更改此配置,请编辑hbase-site.xml ,将更改后的文件复制到群集中,然后重新启动.

我们将此值设置得很高,以免我们不得不在邮件列表中提出问题,询问在大规模导入期间为什么RegionServer出现故障. 通常的原因是未调整其JVM,并且它们正在运行很长时间的GC暂停. 我们的想法是,当用户熟悉HBase时,我们不必为他们省去了解其所有复杂性. 稍后,当他们建立起一定的信心时,他们便可以使用这样的配置.

Number of ZooKeeper Instances

See zookeeper.

9.2.2. HDFS Configurations

dfs.datanode.failed.volumes.tolerated

这是hdfs-default.xml描述中的`` ...在DataNode停止提供服务之前允许失败的卷数.默认情况下,任何卷故障都会导致数据节点关闭''. 您可能希望将其设置为可用磁盘数量的一半.

9.2.3. hbase.regionserver.handler.count

此设置定义保持打开状态以响应对用户表的传入请求的线程数. 经验法则是,当每个请求的有效负载接近MB(大笔数,使用大缓存进行扫描)时,此数字应保持较低;而当有效负载较小时(获取,小放置,ICV,删除),则应保持较高的数字. 正在进行的查询的总大小受设置hbase.ipc.server.max.callqueue.size限制.

如果有效负载很小,则可以安全地将该数目设置为最大传入客户端数,典型示例是为网站提供服务的群集,因为通常不对put进行缓冲,并且大多数操作都可以得到.

将该设置保持在较高状态是危险的,原因是区域服务器中当前正在发生的所有put的总大小可能会对其内存施加过多压力,甚至触发OutOfMemoryError. 在内存不足的情况下运行的RegionServer会触发其JVM的垃圾收集器更频繁地运行,直到明显的GC暂停为止(原因是,用于保留所有请求有效负载的所有内存都不能被废弃,垃圾收集器尝试). 一段时间之后,整个群集的吞吐量会受到影响,因为命中该RegionServer的每个请求都将花费更长的时间,从而使问题更加严重.

通过在单个RegionServer上rpc.logging然后拖尾其日志(排队的请求会消耗内存),您可以了解到您是否拥有过多的处理程序.

9.2.4. Configuration for large memory machines

HBase带有合理,保守的配置,几乎可以在人们可能要测试的所有计算机类型上使用. 如果您拥有更大的计算机(HBase具有8G和更大的堆),那么以下配置选项可能会有所帮助. 去做.

9.2.5. Compression

您应该考虑启用ColumnFamily压缩. 有几个选项几乎是无摩擦的,并且在大多数情况下,它们通过减小StoreFiles的大小从而减少I / O来提高性能.

有关更多信息,请参见压缩 .

9.2.6. Configuring the size and number of WAL files

如果RS发生故障,HBase使用wal来恢复尚未刷新到磁盘的内存存储数据. 这些WAL文件应配置为略小于HDFS块(默认情况下,HDFS块为64Mb,WAL文件为〜60Mb).

HBase对WAL文件的数量也有限制,旨在确保在恢复过程中永远不会重放太多数据. 需要根据memstore配置设置此限制,以便所有必需的数据都适合. 建议分配足够的WAL文件以至少存储那么多的数据(当所有内存存储都快用完时). 例如,对于16Gb RS堆,默认内存存储设置(0.4)和默认WAL文件大小(〜60Mb),16Gb * 0.4 / 60,WAL文件计数的起点是〜109. 但是,由于并非所有存储器都一直都在装满,因此可以分配较少的WAL文件.

9.2.7. Managed Splitting

HBase通常根据hbase-default.xmlhbase-site.xml配置文件中的设置来处理区域划分 . 重要设置包括hbase.regionserver.region.split.policyhbase.hregion.max.filesizehbase.regionserver.regionSplitLimit . 拆分的一种简化视图是,当区域增长到hbase.hregion.max.filesize ,将对其进行拆分. 对于大多数使用模式,大多数时候,应该使用自动拆分. 有关手动区域分割的更多信息,请参阅手动区域分割决策 .

您可以选择自己管理拆分,而不是让HBase自动拆分区域. HBase 0.90.0中添加了此功能. 如果您非常了解密钥空间,则可以手动管理拆分,否则让HBase为您确定拆分位置. 手动拆分可以减轻区域创建和负载下的移动. 它还使区域边界是已知且不变的(如果禁用区域分割). 如果使用手动拆分,则更容易进行基于时间的交错压缩,以分散网络IO负载.

禁用自动拆分

要禁用自动拆分,请将hbase.hregion.max.filesize设置为非常大的值,例如100 GB .不建议将其设置为Long.MAX_VALUE绝对最大值.

推荐自动分割

如果禁用自动拆分以诊断问题或在数据快速增长期间,建议在情况变得更稳定时重新启用它们. 管理区域分裂自己的潜在好处并非没有争议.

确定预分割区域的最佳数量

预分割区域的最佳数量取决于您的应用程序和环境. 一个好的经验法则是从每个服务器10个预分割区域开始,并观察数据随时间增长的情况. 最好在区域太少的一侧犯错误,然后再进行滚动拆分. 最佳区域数取决于您所在区域中最大的StoreFile. 如果数据量增加,则最大的StoreFile的大小将随时间增加. 目的是使最大区域足够大,以使压缩选择算法仅在定时大压缩期间对其进行压缩. 否则,群集可能容易遭受压缩风暴,其中大量区域同时受到压缩. 重要的是要了解数据增长会导致压缩风暴,而不是手动拆分决定.

如果将区域分成太多大区域,则可以通过配置HConstants.MAJOR_COMPACTION_PERIOD来增加主要压缩间隔. HBase 0.90引入了org.apache.hadoop.hbase.util.RegionSplitter ,它提供了所有区域的网络IO安全滚动拆分.

9.2.8. Managed Compactions

默认情况下,大型压缩计划为每7天运行一次. 在HBase 0.96.x之前,默认情况下计划每天进行一次大型压缩.

如果您需要精确控制大型压缩的时间和频率,可以禁用托管大型压缩. 有关详细信息,请参见compaction.parameters表中的hbase.hregion.majorcompaction条目.

不要禁用重大压实

对于StoreFile清理,绝对必需进行大压缩. 请勿完全禁用它们. 您可以通过HBase Shell或Admin API手动运行主要压缩.

有关压缩和压缩文件选择过程的更多信息,请参见压缩.

9.2.9. Speculative Execution

MapReduce任务的推测执行默认情况下处于打开状态,对于HBase群集,通常建议在系统级关闭推测执行,除非在特定情况下需要它,可以在每个作业中对其进行配置. 将属性mapreduce.map.speculativemapreduce.reduce.speculative为false.

9.3. Other Configurations

9.3.1. Balancer

平衡器是一种定期操作,在主服务器上运行,以重新分配集群上的区域. 它是通过hbase.balancer.period配置的,默认值为300000(5分钟).

有关LoadBalancer的更多信息,请参见master.processes.loadbalancer .

9.3.2. Disabling Blockcache

不要关闭块缓存(您可以通过将hbase.block.cache.size设置hbase.block.cache.size来关闭它). 目前,如果您这样做的话,我们做得并不好,因为RegionServer将花费所有的时间一遍又一遍地加载HFile索引. 如果您的工作设置使块缓存不适合您,请至少调整块缓存的大小,以使HFile索引保持在缓存中(您可以通过调查RegionServer UI来大致了解所需的大小;您将请参阅网页顶部附近的索引块大小).

9.3.3. Nagle’s or the small package problem

如果在针对HBase的操作中偶尔会出现40ms左右的延迟,请尝试Nagles的设置. 例如,请参阅用户邮件列表线程," 缓存设置为1时的扫描性能不一致"以及其中引用的问题,其中设置notcpdelay提高扫描速度. 您可能还会在HBASE-7008的尾部看到这些图, 将扫描仪缓存设置为更好的默认值 ,其中我们的Lars Hofhansl尝试打开和关闭Nagle来测量效果的各种数据大小.

9.3.4. Better Mean Time to Recover (MTTR)

本节介绍的配置将使服务器在出现故障后更快地恢复. 请参阅Deveraj Das和Nicolas Liochon博客文章HBase简介平均恢复时间(MTTR) ,以获取简要介绍.

HBASE-8354强制Namenode进入具有租约恢复请求的循环的过程很麻烦,但在低超时以及如何实现更快的恢复(包括引用添加到HDFS的修复程序)的末尾进行了大量的讨论. 阅读Varun Sharma的评论. 以下建议的配置是Varun的建议经过提炼和测试的. 确保您在最新版本的HDFS上运行,因此您也获得了他所引用的修复程序,并且他自己添加了有助于HBase MTTR的HDFS(例如,HDFS-3703,HDFS-3712和HDFS-4791-Hadoop 2肯定具有它们,并且Hadoop 1后期有一些). 在RegionServer中设置以下内容.

<property>
  <name>hbase.lease.recovery.dfs.timeout</name>
  <value>23000</value>
  <description>How much time we allow elapse between calls to recover lease.
  Should be larger than the dfs timeout.</description>
</property>
<property>
  <name>dfs.client.socket-timeout</name>
  <value>10000</value>
  <description>Down the DFS timeout from 60 to 10 seconds.</description>
</property>

在NameNode / DataNode端,设置以下内容以启用HDFS-3703,HDFS-3912中引入的"陈旧性".

<property>
  <name>dfs.client.socket-timeout</name>
  <value>10000</value>
  <description>Down the DFS timeout from 60 to 10 seconds.</description>
</property>
<property>
  <name>dfs.datanode.socket.write.timeout</name>
  <value>10000</value>
  <description>Down the DFS timeout from 8 * 60 to 10 seconds.</description>
</property>
<property>
  <name>ipc.client.connect.timeout</name>
  <value>3000</value>
  <description>Down from 60 seconds to 3.</description>
</property>
<property>
  <name>ipc.client.connect.max.retries.on.timeouts</name>
  <value>2</value>
  <description>Down from 45 seconds to 3 (2 == 3 retries).</description>
</property>
<property>
  <name>dfs.namenode.avoid.read.stale.datanode</name>
  <value>true</value>
  <description>Enable stale state in hdfs</description>
</property>
<property>
  <name>dfs.namenode.stale.datanode.interval</name>
  <value>20000</value>
  <description>Down from default 30 seconds</description>
</property>
<property>
  <name>dfs.namenode.avoid.write.stale.datanode</name>
  <value>true</value>
  <description>Enable stale state in hdfs</description>
</property>

9.3.5. JMX

JMX(Java管理扩展)提供了内置的工具,使您可以监视和管理Java VM. 要从远程系统启用监视和管理,在启动Java VM时,需要设置系统属性com.sun.management.jmxremote.port (要启用JMX RMI连接的端口号). 有关更多信息,请参见官方文档 . 从历史上看,除了上述端口之外,JMX还打开了两个附加的随机TCP侦听端口,这可能会导致端口冲突问题. (有关详细信息,请参见HBASE-10289

或者,您可以使用HBase提供的基于协处理器的JMX实现. 要在0.99或更高版本中启用它,请在hbase-site.xml中添加以下属性:

<property>
  <name>hbase.coprocessor.regionserver.classes</name>
  <value>org.apache.hadoop.hbase.JMXListener</value>
</property>
请勿同时为Java VM设置com.sun.management.jmxremote.port .

当前,它支持Master和RegionServer Java VM. 默认情况下,JMX侦听TCP端口10102,您可以使用以下属性进一步配置端口:

<property>
  <name>regionserver.rmi.registry.port</name>
  <value>61130</value>
</property>
<property>
  <name>regionserver.rmi.connector.port</name>
  <value>61140</value>
</property>

在大多数情况下,注册表端口可以与连接器端口共享,因此您只需要配置regionserver.rmi.registry.port. 但是,如果要使用SSL通信,则必须将2个端口配置为不同的值.

默认情况下,密码验证和SSL通信是禁用的. 要启用密码身份验证,您需要像下面这样更新hbase-env.sh

export HBASE_JMX_BASE="-Dcom.sun.management.jmxremote.authenticate=true                  \
                       -Dcom.sun.management.jmxremote.password.file=your_password_file   \
                       -Dcom.sun.management.jmxremote.access.file=your_access_file"

export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS $HBASE_JMX_BASE "
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS $HBASE_JMX_BASE "

请参阅$ JRE_HOME / lib / management下的示例密码/访问文件.

要通过密码验证启用SSL通信,请执行以下步骤:

#1. generate a key pair, stored in myKeyStore
keytool -genkey -alias jconsole -keystore myKeyStore

#2. export it to file jconsole.cert
keytool -export -alias jconsole -keystore myKeyStore -file jconsole.cert

#3. copy jconsole.cert to jconsole client machine, import it to jconsoleKeyStore
keytool -import -alias jconsole -keystore jconsoleKeyStore -file jconsole.cert

然后像下面这样更新hbase-env.sh

export HBASE_JMX_BASE="-Dcom.sun.management.jmxremote.ssl=true                         \
                       -Djavax.net.ssl.keyStore=/home/tianq/myKeyStore                 \
                       -Djavax.net.ssl.keyStorePassword=your_password_in_step_1       \
                       -Dcom.sun.management.jmxremote.authenticate=true                \
                       -Dcom.sun.management.jmxremote.password.file=your_password file \
                       -Dcom.sun.management.jmxremote.access.file=your_access_file"

export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS $HBASE_JMX_BASE "
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS $HBASE_JMX_BASE "

最后,使用密钥库在客户端上启动jconsole

jconsole -J-Djavax.net.ssl.trustStore=/home/tianq/jconsoleKeyStore
要在Master上启用HBase JMX实现,还需要在hbase-site.xml中添加以下属性:
<property>
  <ame>hbase.coprocessor.master.classes</name>
  <value>org.apache.hadoop.hbase.JMXListener</value>
</property>

端口配置的相应属性是master.rmi.registry.port (默认为10101)和master.rmi.connector.port (默认与master.rmi.connector.port相同)

10. Dynamic Configuration

从HBase 1.0.0开始,可以更改配置的子集而无需重新启动服务器. 在HBase Shell中,有新的运算符update_configupdate_all_config会提示服务器或所有服务器重新加载配置.

当前,正在运行的服务器中只能更改所有配置的一部分. 这是不完整的列表: hbase.regionserver.thread.compaction.largehbase.regionserver.thread.compaction.smallhbase.regionserver.thread.splithbase.regionserver.thread.merge以及压缩策略和配置以及调整非高峰时间. 有关完整列表,请参阅从89-fbHBASE-12147 Porting Online Config Change随附的修补程序.

Upgrading

升级时不能跳过主要版本. 如果要从0.90.x升级到0.94.x,则必须先从0.90.x升级到0.92.x,然后再从0.92.x升级到0.94.x.

可能会跳过各个版本-例如,仅遵循0.96.x升级说明,从0.92.2直接跳到0.98.0-但这些情况未经测试.

查看Apache HBase配置 ,尤其是 Hadoop的 .

11. HBase version number and compatibility

HBase有两个版本控制方案,1.0之前的版本和1.0以后的版本. 两者都在下面详细说明.

11.1. Post 1.0 versions

从1.0.0版本开始,HBase正在为其版本版本进行语义版本控制. 综上所述:

给定版本号MAJOR.MINOR.PATCH,增加:
  • 当您进行不兼容的API更改时的主要版本,

  • 以向后兼容的方式添加功能时的MINOR版本,并且

  • 进行向后兼容的错误修复时的PATCH版本.

  • 预发布和构建元数据的其他标签可作为MAJOR.MINOR.PATCH格式的扩展名使用.

相容尺寸

除了通常的API版本控制注意事项之外,HBase还具有我们需要考虑的其他兼容性维度.

客户端-服务器有线协议兼容性
  • 允许更新客户端和服务器不同步.

  • 我们只能先升级服务器. 也就是说,服务器将与旧客户端向后兼容,这样新的API就可以了.

  • 示例:用户应该能够使用旧客户端连接到升级的群集.

服务器-服务器协议兼容性
  • 不同版本的服务器可以共存于同一群集中.

  • 服务器之间的有线协议兼容.

  • 复制和日志拆分等分布式任务的工作程序可以共存于同一群集中.

  • 相关协议(例如使用ZK进行协调)也不会更改.

  • 示例:用户可以执行滚动升级.

文件格式兼容性
  • 支持文件格式向后和向前兼容

  • 示例:作为HBase升级的一部分,文件,ZK编码,目录布局会自动升级. 用户可以回滚到旧版本,一切将继续进行.

客户端API兼容性
  • 允许更改或删除现有的客户端API.

  • 我们需要在整个主要版本中弃用API,然后再进行更改/删除.

    • 例如:API在2.0.1中已弃用,并在4.0.0中被标记为删除. 另一方面,可以在3.0.0中删除在2.0.0中弃用的API.

  • 修补程序版本中提供的API将在所有更高版本的修补程序版本中提供. 但是,可能会添加新的API,这些API在较早的修补程序版本中将不可用.

  • 示例:使用新弃用的api的用户无需使用hbase api调用即可修改应用程序代码,直到下一个主要版本.

客户端二进制兼容性
  • 写入给定补丁程序版本中可用的API的客户端代码可以针对更高版本的补丁程序的新jar保持不变(无需重新编译).

  • 写入给定补丁程序版本中可用的API的客户端代码可能无法与早期补丁程序版本中的旧jar一起运行.

  • 示例:旧的已编译客户端代码将与新的jar一起使用.

服务器端受限API兼容性(取自Hadoop)
  • 内部API被标记为稳定,不断发展或不稳定

  • 这意味着协处理器和插件(可插拔的类,包括复制)的二进制兼容性,只要它们仅使用标记的接口/类即可.

  • 示例:旧的编译的协处理器,过滤器或插件代码将与新的jar一起使用.

依赖相容性
  • HBase的升级将不需要对依赖项目(包括Java运行时)进行不兼容的升级.

  • 示例:Hadoop的升级不会使我们所作的任何兼容性保证无效.

操作兼容性
  • 指标变化

  • 服务的行为变化

  • 网页API

Summary
  • 修补程序升级是一种替代产品. 与Java二进制不兼容的任何更改都将不允许. [ 1 ] . 修补程序版本中的降级版本可能不兼容.

  • 较小的升级不需要修改应用程序/客户端代码. 理想情况下,这将是直接替换,但如果使用新的jar,则可能必须重新编译客户端代码,协处理器,过滤器等.

  • 重大升级使HBase社区可以进行重大更改.

表3.兼容性列表[ 2 ]

Major

Minor

Patch

客户端-服务器线兼容性

N

Y

Y

服务器-服务器兼容性

N

Y

Y

文件格式兼容性

N [3]

Y

Y

客户端API兼容性

N

Y

Y

客户二进制兼容性

N

N

Y

服务器端受限API兼容性

Stable

N

Y

Y

Evolving

N

N

Y

Unstable

N

N

N

依赖相容性

N

Y

Y

操作兼容性

N

N

Y

11.1.1. HBase API Surface

HBase有很多API要点,但是对于上面的兼容性列表,我们区分了Client API,Limited Private API和Private API. HBase使用Hadoop接口分类的版本. HBase的接口分类类可以在这里找到.

  • InterfaceAudience:捕获目标受众,可能的值为Public(对于最终用户和外部项目),LimitedPrivate(对于其他项目,协处理器或其他插件点)和Private(对于内部使用).

  • InterfaceStability:描述允许哪些类型的接口更改. 可能的值是"稳定","正在演变","不稳定"和"已弃用".

HBase Client API

HBase Client API consists of all the classes or methods that are marked with InterfaceAudience.Public interface. All main classes in hbase-client and dependent modules have either InterfaceAudience.Public, InterfaceAudience.LimitedPrivate, or InterfaceAudience.Private marker. Not all classes in other modules (hbase-server, etc) have the marker. If a class is not annotated with one of these, it is assumed to be a InterfaceAudience.Private class.

HBase LimitedPrivate API

LimitedPrivate批注随附了一组接口的目标使用者. 这些使用者是协处理器,菲尼克斯,复制端点的象征或类似的东西. 此时,HBase仅保证补丁程序版本之间的这些接口的源和二进制兼容性.

HBase Private API

所有使用InterfaceAudience进行注释的类.私有或不具有注释的所有类仅供HBase内部使用. 接口和方法签名可以随时更改. 如果您依赖于标记为"专用"的特定接口,则应打开" jira"以建议将接口更改为"公共"或"有限私有",或为此目的公开的接口.

11.2. Pre 1.0 versions

在1.0之前的语义版本控制方案之前,HBase会跟踪Hadoop的版本(0.2x)或0.9x版本. 如果您喜欢奥秘,请查看我们有关HBase版本控制的旧Wiki页面,该页面尝试连接HBase版本点. 以下各节仅涵盖1.0之前的版本.

奇/偶版本控制或"开发"系列发行

在发布重要版本之前,我们一直在提供预览版本以更早开始反馈周期. 这些"开发"系列发行版始终为奇数,没有任何保证,甚至不考虑能够在两个连续发行版之间进行升级(我们保留打破"开发"系列发行版兼容性的权利). 不用说,这些发行版不适合生产部署. 它们是即将发生的事情的预览,希望有兴趣的各方将发布该版本进行试驾,如果我们在发布有价值的版本之前错过了一些问题,请及早给我们举报.

我们的第一个"开发"系列是在HBase 0.90.0之前推出的0.89集. HBase 0.95是另一个预示HBase 0.96.0的"开发"系列. 0.99.x是1.0之前的"开发人员预览"模式下的最后一个系列. 之后,我们将使用语义版本命名方案(请参见上文).

二进制兼容性

当我们说两个HBase版本兼容时,是指这些版本是有线和二进制兼容的. 兼容的HBase版本意味着客户端可以与兼容但版本不同的服务器通信. 这也意味着您可以换掉一个版本的jar,然后用另一个兼容版本的jar替换它们,所有这些都可以使用. 除非另有说明,否则HBase点版本(主要)是二进制兼容的. 您可以安全地在二进制兼容版本之间进行滚动升级. 即跨点版本:例如从0.94.5到0.94.6. 请参阅HBase开发邮件列表上的链接:[版本之间的兼容性是否还意味着二进制兼容性?].

11.3. Rolling Upgrades

滚动升级是一次更新群集中的服务器的过程. 如果HBase版本是二进制或有线兼容的,则可以跨HBase版本滚动升级. 有关这意味着什么的更多信息,请参见在二进制/有线兼容版本之间滚动升级 . 粗略地讲,滚动升级是每个服务器的正常停止,更新软件然后重新启动的操作. 您为集群中的每个服务器执行此操作. 通常,先升级主服务器,然后再升级RegionServers. 请参阅滚动重启,以获取有助于使用滚动升级过程的工具.

例如,在下面的内容中,HBase被符号链接到实际的HBase安装. 升级时,在通过cluser运行滚动重启之前,我们将符号链接更改为指向新的HBase软件版本,然后运行

$ HADOOP_HOME=~/hadoop-2.6.0-CRC-SNAPSHOT ~/hbase/bin/rolling-restart.sh --config ~/conf_hbase

滚动重新启动脚本将首先正常停止并重新启动主服务器,然后依次停止每个RegionServer. 由于符号链接已更改,因此重启后,服务器将使用新的HBase版本. 随着滚动升级的进行,请检查日志中是否有错误.

二进制/有线兼容版本之间的滚动升级

除非另有说明,否则HBase点版本是二进制兼容的. 您可以在HBase点版本之间进行滚动升级 . 例如,您可以通过在整个群集中进行滚动升级来从0.94.5升级到0.94.6,将0.94.5二进制文件替换为0.94.6二进制文件.

在下面的次要版本特别部分中,我们指出了那些版本与线路/协议兼容的地方,在这种情况下,还可以进行滚动升级 . 例如,在从0.98.x到HBase 1.0.0的滚动升级中 ,我们声明可以在hbase-0.98.x和hbase-1.0.0之间进行滚动升级.

12. Upgrade Paths

12.1. Upgrading to 1.4+

12.1.1. Replication peer’s TableCFs config

在1.4之前,表名称不能包含复制对等方的TableCFs配置的名称空间. 通过将TableCF添加到存储在Zookeeper中的ReplicationPeerConfig中,可以修复该问题. 因此,升级到1.4时,必须首先更新Zookeeper上的原始ReplicationPeerConfig数据. 当群集具有带有TableCFs配置的复制对等方时,有四个升级步骤.

  • 禁用复制对等体.

  • 如果master具有写复制对等znode的权限,则直接滚动更新master. 如果不是,请使用TableCFsUpdater工具更新复制对等方的配置.

$ bin/hbase org.apache.hadoop.hbase.replication.master.TableCFsUpdater update
  • 滚动更新区域服务器.

  • 启用复制对等方.

Notes:

  • 无法使用旧客户端(1.4之前的版本)更改复制对等方的配置. 因为客户端将配置直接写入Zookeeper,所以旧客户端将丢失TableCFs的配置. 并且旧客户端将TableCFs配置写入旧tablecfs znode,它将不适用于新版本的regionserver.

12.2. Upgrading from 0.98.x to 1.x

在本节中,我们首先注意到1.0.0+ HBase附带的重大更改,然后介绍升级过程. 请务必仔细阅读重要更改部分,以免引起意外.

12.2.1. Changes of Note!

在这里,我们列出了自0.98.x起1.0.0+版本中的重要更改,您应该意识到这些更改一旦升级就将生效.

HBase 1.0.0+中需要ZooKeeper 3.4

See ZooKeeper Requirements.

HBase默认端口已更改

HBase使用的端口已更改. 它们曾经在600XX范围内. 在HBase 1.0.0中,它们已移出临时端口范围,而改为160XX(主Web UI为60010,现在为16010; RegionServer Web UI为60030,现在为16030,依此类推). 如果要保留旧的端口位置,请将端口设置配置从hbase-default.xml复制到hbase-site.xml ,将其更改回HBase 0.98.x时代的旧值,并确保已分发重新启动之前进行配置.

hbase.bucketcache.percentage.in.combinedcache配置已被删除

如果您正在使用BucketCache,则可能已使用此配置. 如果不使用BucketCache,则此更改不会影响您. 将其删除意味着您现在可以使用hfile.block.cache.sizehfile.block.cache.size L1 LruBlockCache的大小,即,如果您不进行BucketCache的话,您可以调整堆上L1 LruBlockCache的大小,而BucketCache的大小与hbase的设置hbase.bucketcache.size是. 您可能需要调整配置,以将LruBlockCache和BucketCache的大小设置为0.98.x及之前版本中的大小. 如果您未设置此配置,则其默认值为0.9. 如果您什么也不做,那么BucketCache的大小将增加10%. 您的L1 LruBlockCache将变为hfile.block.cache.size乘以您的Java堆大小( hfile.block.cache.size为0.0到1.0之间的浮点数). 要了解更多信息,请参阅HBASE-11520,通过删除令人困惑的" hbase.bucketcache.percentage.in.combinedcache"来简化offheap缓存配置 .

如果您有自己的客户过滤器.

请参阅关于此问题的发行说明HBASE-12068 [Branch-1]避免始终为Filter transformCell做KeyValueUtil#ensureKeyValue ; 确保遵循其中的建议.

分布式日志重播

默认情况下,HBase 1.0.0中的" 分布式日志重播"处于关闭状态. 启用它可以大大改善HBase MTTR. 如果要在升级时进行干净的停止/启动,请启用此功能. 您无法滚动升级到此功能(如果您在超过HBase 0.98.4的HBase版本上运行,请注意,有关更多信息,请参见HBASE-12577默认情况下禁用分布式日志重放 ).

日期分层压缩的可用性.

从1.3.0版开始的1.y发布行中提供了从0.98.19开始可用的日期分层压缩功能. 如果为所有表启用了此功能,则必须升级到1.3.0或更高版本. 如果您尝试使用早期的1.y版本,则任何配置为使用日期分层压缩的表都将无法打开其区域.

12.2.2. Rolling upgrade from 0.98.x to HBase 1.0.0

从0.96.x到1.0.0
你不能做一个滚动升级从0.96.x到1.0.0不首先做滚动升级到0.98.x. 有关原因,请参见HBASE-11164文档中的注释, 以及从0.98→1.0开始的测试滚动更新 . 同样,因为HBase 1.0.0默认启用了HFile v3,所以HBASE-9801将默认的HFile版本更改为V3 ,并且仅在0.98中支持HFile v3,这是不能从HBase 0.96.x进行升级的另一个原因;这是因为不能使用HFile v3. 如果滚动升级停止,则0.96.x服务器将无法打开由运行版本3的HFile较新的HBase 1.0.0的服务器写入的文件.

从HBase 0.98.x到HBase 1.0.0进行滚动升级时 ,没有已知问题.

12.2.3. Upgrading to 1.0 from 0.94

您不能从0.94.x升级到1.xx,您必须停止集群,安装1.xx软件,运行执行0.96升级 (用1.xx代替在本节中提到0.96.x的地方描述)中描述的迁移.下面),然后重新启动. 如果版本低于要求的3.4.x,请确保升级ZooKeeper.

12.3. Upgrading from 0.96.x to 0.98.x

从0.96.x到0.98.x的滚动升级是可行的. 这两个版本不是二进制兼容的.

要利用0.98.x的某些新功能,还需要采取其他步骤,包括单元可见性标签,单元ACL和透明服务器端加密. 有关更多信息,请参见保护Apache HBase . 性能上的重大改进包括更改了预写日志线程模型,该模型在高负载下提供了更高的事务吞吐量,反向扫描程序,快照文件上的MapReduce以及条带化压缩.

客户端和服务器可以运行0.98.x和0.96.x版本. 但是,由于Java API的更改,可能需要重新编译应用程序.

12.4. Upgrading from 0.94.x to 0.98.x

从0.94.x直接滚动升级到0.98.x不起作用. 升级路径遵循与从0.94.x升级到0.96.x相同的过程. 若要使用0.98.x的某些新功能,需要执行其他步骤. 有关这些功能的简短列表,请参见从0.96.x升级到0.98.x.

12.5. Upgrading from 0.94.x to 0.96.x

12.5.1. The "Singularity"

HBase 0.96.x已于2014年9月1日停产
不要部署0.96.x至少部署0.98.x. 参见EOL 0.96 .

您将不得不完全停止旧的0.94.x群集进行升级. 如果要在群集之间复制,则两个群集都必须关闭才能升级. 确保干净关闭. WAL文件越少,升级将运行得越快(升级会将在文件系统中找到的所有日志文件作为升级过程的一部分进行拆分). 所有客户端也必须升级到0.96.

API已更改. 您将需要根据0.96重新编译代码,并且可能需要调整应用程序以使其与新API相对(TODO:更改列表).

12.5.2. Executing the 0.96 Upgrade

HDFS和ZooKeeper必须启动!
HDFS和ZooKeeper应该在升级过程中启动并运行.

HBase 0.96.0带有升级脚本. 跑

$ bin/hbase upgrade

看看它的用法. 该脚本有两种主要模式: -check-execute .

check

检查步骤针对正在运行的0.94集群运行. 从下载的0.96.x二进制文件运行它. 检查步骤正在寻找是否存在HFile v1文件. HBase 0.96.0不支持这些功能. 要将它们重写为HFile v2,必须运行压缩.

检查步骤在运行结束时打印统计信息(日志中"Result:" grep)打印其扫描表的绝对路径,找到的任何HFile v1文件,包含所述文件的区域(这些区域将需要进行重大压缩) ),以及所有损坏的文件(如果找到). 损坏的文件是不可读的,因此也是未定义的(HFile v1和HFile v2均不).

要运行检查步骤,请运行

$ bin/hbase upgrade -check

这是示例输出:

Tables Processed:
hdfs://localhost:41020/myHBase/.META.
hdfs://localhost:41020/myHBase/usertable
hdfs://localhost:41020/myHBase/TestTable
hdfs://localhost:41020/myHBase/t

Count of HFileV1: 2
HFileV1:
hdfs://localhost:41020/myHBase/usertable    /fa02dac1f38d03577bd0f7e666f12812/family/249450144068442524
hdfs://localhost:41020/myHBase/usertable    /ecdd3eaee2d2fcf8184ac025555bb2af/family/249450144068442512

Count of corrupted files: 1
Corrupted Files:
hdfs://localhost:41020/myHBase/usertable/fa02dac1f38d03577bd0f7e666f12812/family/1
Count of Regions with HFileV1: 2
Regions to Major Compact:
hdfs://localhost:41020/myHBase/usertable/fa02dac1f38d03577bd0f7e666f12812
hdfs://localhost:41020/myHBase/usertable/ecdd3eaee2d2fcf8184ac025555bb2af

There are some HFileV1, or corrupt files (files with incorrect major version)

在上面的示例输出中,在两个区域中有两个HFile v1文件,一个是损坏的文件. 损坏的文件可能应该删除. 具有HFile v1的区域需要进行重大压缩. 要进行大型压缩,请启动hbase shell并查看如何压缩单个区域. 完成主要压缩后,请重新运行检查步骤,并且应删除HFile v1文件,并替换为HFile v2实例.

默认情况下,检查步骤将扫描HBase根目录(在配置中定义为hbase.rootdir ). 要仅扫描特定目录,请传递-dir选项.

$ bin/hbase upgrade -check -dir /myHBase/testTable

上面的命令将检测/ myHBase / testTable目录中的HFile v1文件.

一旦检查步骤报告所有HFile v1文件都已被重写,则可以安全地进行升级.

execute

检查步骤显示群集没有HFile v1之后,可以安全地进行升级. 接下来是执行步骤. 您必须先关闭0.94.x群集,然后才能运行执行步骤. 如果检测到正在运行的HBase主服务器或RegionServer,则执行步骤将不会运行.

HDFS和ZooKeeper应该在升级过程中启动并运行. 如果zookeeper是由HBase管理的,则可以启动zookeeper,以便可以通过运行以下命令进行升级

$ ./hbase/bin/hbase-daemon.sh start zookeeper

执行升级步骤由三个子步骤组成.

  • 命名空间:HBase 0.96.0支持命名空间. 升级需要重新排序文件系统中的目录,以使命名空间正常工作.

  • ZNode:清除所有znode,以便可以使用新的protobuf'd格式将新的znode写入其位置,并迁移到原位置:例如复制和表状态znodes

  • WAL日志拆分:如果0.94.x集群关闭不干净,我们将在迁移到0.96.0之前将WAL日志作为迁移的一部分进行拆分. 此WAL拆分的运行速度比本机分布式WAL拆分慢,因为它都在单个升级过程中(因此,如果可以,请尝试完全关闭0.94.0群集).

要运行执行步骤,请确保首先在服务器和客户端下的所有位置复制HBase 0.96.0二进制文件. 确保0.94.0群集已关闭. 然后执行以下操作:

$ bin/hbase upgrade -execute

这是一些示例输出.

Starting Namespace upgrade
Created version file at hdfs://localhost:41020/myHBase with version=7
Migrating table testTable to hdfs://localhost:41020/myHBase/.data/default/testTable
.....
Created version file at hdfs://localhost:41020/myHBase with version=8
Successfully completed NameSpace upgrade.
Starting Znode upgrade
.....
Successfully completed Znode upgrade

Starting Log splitting
...
Successfully completed Log splitting

如果执行步骤的输出看起来不错,请停止您开始进行升级的Zookeeper实例:

$ ./hbase/bin/hbase-daemon.sh stop zookeeper

现在启动hbase-0.96.0.

12.6. Troubleshooting

旧客户端连接到0.96群集

它将失败,并出现以下类似异常. 升级.

17:22:15  Exception in thread "main" java.lang.IllegalArgumentException: Not a host:port pair: PBUF
17:22:15  *
17:22:15   api-compat-8.ent.cloudera.com ��  ���(
17:22:15    at org.apache.hadoop.hbase.util.Addressing.parseHostname(Addressing.java:60)
17:22:15    at org.apache.hadoop.hbase.ServerName.&init>(ServerName.java:101)
17:22:15    at org.apache.hadoop.hbase.ServerName.parseVersionedServerName(ServerName.java:283)
17:22:15    at org.apache.hadoop.hbase.MasterAddressTracker.bytesToServerName(MasterAddressTracker.java:77)
17:22:15    at org.apache.hadoop.hbase.MasterAddressTracker.getMasterAddress(MasterAddressTracker.java:61)
17:22:15    at org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation.getMaster(HConnectionManager.java:703)
17:22:15    at org.apache.hadoop.hbase.client.HBaseAdmin.&init>(HBaseAdmin.java:126)
17:22:15    at Client_4_3_0.setup(Client_4_3_0.java:716)
17:22:15    at Client_4_3_0.main(Client_4_3_0.java:63)

12.6.1. Upgrading META to use Protocol Buffers (Protobuf)

从0.96之前的版本升级时,需要将META转换为使用协议缓冲区. 这由配置选项hbase.MetaMigrationConvertingToPB控制,默认情况下设置为true . 因此,默认情况下,您无需采取任何措施.

迁移是一次性事件. 但是,每次启动群集时,都会对META进行扫描以确保不需要对其进行转换. 如果您有很多区域,则此扫描可能需要很长时间. 在0.98.5开始,你可以设置hbase.MetaMigrationConvertingToPBfalseHBase的-site.xml中 ,禁用此启动扫描. 这应该被认为是专家级别的设置.

12.7. Upgrading from 0.92.x to 0.94.x

We used to think that 0.92 and 0.94 were interface compatible and that you can do a rolling upgrade between these versions but then we figured that HBASE-5357 Use builder pattern in HColumnDescriptor changed method signatures so rather than return void they instead return HColumnDescriptor. This will throw`java.lang.NoSuchMethodError: org.apache.hadoop.hbase.HColumnDescriptor.setMaxVersions(I)V` so 0.92 and 0.94 are NOT compatible. You cannot do a rolling upgrade between them.

12.8. Upgrading from 0.90.x to 0.92.x

12.8.1. Upgrade Guide

您会发现0.92.0与0.90.x版本的运行有所不同. 从0.90.x升级到0.92.0时需要注意以下几点.

tl:dr

These are the important things to know before upgrading. . Once you upgrade, you can’t go back.

  1. 默认情况下,MSLAB是打开的. 如果您有很多区域,请注意该堆的使用情况.

  2. 默认情况下,分布式日志拆分处于启用状态. 它应该使RegionServer故障转移更快.

  3. 有一个单独的安全性压缩包.

  4. 如果-XX:MaxDirectMemorySize在你hbase-env.sh设置,这将使得实验堆外缓存(您可能不希望这样).

你不能回去!

要移至0.92.0,您需要做的就是关闭群集,用HBase 0.92.0二进制文件替换HBase 0.90.x(确保清除了所有0.90.x实例)并重新启动(您不能进行滚动重新启动)从0.90.x到0.92.x-您必须重新启动). 启动时, .META. 表内容被重写,从info:regioninfo列中删除了表架构. 另外,首次启动后进行的所有刷新操作都将以新的0.92.0文件格式(带有内联块(版本2)的HBase文件格式)写出数据. 这意味着一旦在HBase数据目录上启动HBase 0.92.0,就无法返回到0.90.x.

MSLAB默认为打开

在0.92.0中, hbase.hregion.memstore.mslab.enabled标志设置为true (请参阅长时间GC暂停 ). 在0.90.x中,它是错误的. 启用该功能后,即使存储区中的内存为零或只有几个小元素,存储区也会以MSLAB 2MB块的形式逐步分配内存. 通常这很好,但是如果您在0.90.x群集中每个RegionServer有很多区域(并且MSLAB已关闭),您可能会发现OOME正在升级,因为thousands of regions * number of column families * 2MB MSLAB (在最低)将您的堆放在顶部. 通过将hbase.hregion.memstore.mslab.enabled设置为hbase.hregion.memstore.mslab.enabled ,将hbase.hregion.memstore.mslab.enabled设置为false或将MSLAB大小从2MB hbase.hregion.memstore.mslab.chunksize .

默认情况下,分布式日志拆分处于启用状态

以前,WAL崩溃日志仅由Master拆分. 在0.92.0中,日志拆分由集群完成(请参阅HBASE-1364 [performance] regionserver提交日志的分布式拆分,或参阅博客文章Apache HBase Log Splitting ). 这样可以大大减少拆分日志并使区域重新联机所需的时间.

内存记帐现在不同了

在0.92.0中, 带有内联块(版本2)索引和Bloom过滤器的HBase文件格式位于来自文件系统的LRU使用的相同缓存块中. 在0.90.x中,HFile v1索引位于LRU之外,因此即使索引位于"冷"文件中(该文件并未被积极使用),它们也占用了空间. 通过现在在LRU中的索引,您可能会发现块缓存的空间较小. 相应地调整块缓存. 有关更多详细信息,请参见块缓存 . 块大小的默认大小已在0.92.0中从0.2(占堆的20%)更改为0.25.

在要使用的Hadoop版本上

在Hadoop 1.0.x(或CDH3u3)上运行0.92.0. 性能上的好处值得采取行动. 否则,我们的Hadoop处方将保持不变. 您需要一个支持工作同步的Hadoop. 看到 Hadoop的 .

如果在Hadoop 1.0.x(或CDH3u3)上运行,请启用本地读取. 有关"转到本地"对性能的好处(以及如何启用本地读取)的反思,请参见" 实用缓存"演示.

HBase 0.92.0随附ZooKeeper 3.4.2

If you can, upgrade your ZooKeeper. If you can’t, 3.4.2 clients should work against 3.3.X ensembles (HBase makes use of 3.4.2 API).

默认情况下,在线更改是关闭的

在0.92.0中,我们添加了一个实验性的在线模式更改工具(请参见hbase.online.schema.update.enable ). 默认情况下处于关闭状态. 启用它需要您自担风险. 联机更改表和拆分表不能很好地配合使用,因此请确保使用此功能使群集处于静态状态(目前).

WebUI

Web UI在0.92.0中进行了一些添加. 现在,它显示了当前正在转换的区域的列表,最近的压缩/刷新以及正在运行的进程的进程列表(如果一切正常,并且请求得到及时处理,通常为空). 其他增加内容包括按区域的请求,调试servlet转储等.

安全压缩包

现在,我们附带了两个压缩包. 安全和不安全的HBase. 有关如何设置安全HBase的文档正在开发中.

HBase复制中的更改

0.92.0添加了两个新功能:多从复制和多主复制. 启用此方法的方式与添加新的对等方相同,因此,要拥有多主节点,您只需为充当其他从属群集的主节点的每个群集运行add_peer. 冲突是在时间戳级别处理的,时间戳级别可能是您想要的,也可能不是您想要的,这需要在每个用例的基础上进行评估. 在0.92中,复制仍处于试验阶段,默认情况下处于禁用状态,运行后果自负.

如果OOME,RegionServer现在中止

如果是OOME,则现在我们的JVM杀死了RegionServer进程的-9,因此它的运行速度很快. 以前,RegionServer可能会在某些受伤状态下发生OOME瘫痪后停滞不前. 要禁用此功能,并建议您将其保留在原位,您需要编辑bin / hbase文件. 寻找附加的-XX:OnOutOfMemoryError =" kill -9%p"参数(请参见HBASE-4769-'立即在OOME中终止RegionServer' ).

HFile v2和"更大,更少"的趋势

0.92.0以新格式存储数据,该格式是带有内联块的HBase文件格式(版本2) . 当HBase运行时,它将所有数据从HFile v1迁移到HFile v2格式. 当进行刷新和压缩时,此自动迁移将在后台运行. HFile v2允许HBase在较大的区域/文件中运行. 实际上,我们鼓励所有HBasers都倾向于使用更大,更少区域的Facebook公理#1. 如果现在有很多区域(每台主机超过100个),则应考虑将区域大小设置为0.92.0(在0.92.0中,默认大小现在为1G,从256M增大),然后再运行联机合并工具(请参阅HBASE-1621合并工具应在联机群集上工作,但禁用表 ).

12.9. Upgrading to HBase 0.90.x from 0.20.x or 0.89.x

可以在由HBase 0.20.x或HBase 0.89.x写入的数据上启动此版本的0.90.x HBase. 不需要迁移步骤. HBase 0.89.x和0.90.x确实以不同的方式写出了区域目录的名称-它使用区域名称的md5哈希而不是jenkins哈希来命名它们-因此,这意味着一旦启动,就不会再回到HBase 0.20了.X.

确保在升级时从conf目录中删除hbase-default.xml . 此文件的0.20.x版本将具有0.90.x HBase的次优配置. 现在,将hbase-default.xml文件捆绑到HBase jar中并从那里读取. 如果要查看此文件的内容,请在src树中的src / main / resources / hbase-default.xml上查看它,或参阅HBase Default Configuration .

最后,如果从0.20.x升级,请检查您的.META. 外壳中的架构. 过去,我们建议用户使用16kb MEMSTORE_FLUSHSIZE运行. 跑

hbase> scan '-ROOT-'

在外壳中. 这将输出当前的.META. 模式. 检查MEMSTORE_FLUSHSIZE大小. 是16kb(16384)吗? 如果是这样,则需要对此进行更改("正常" /默认值为64MB(67108864)). 运行脚本bin/set_meta_memstore_size.rb . 这将对您的.META.进行必要的编辑.META. 模式. 无法运行此更改将导致群集变慢. 请参阅HBASE-3499.升级到0.90.0的用户需要其.META. 该表已使用正确的MEMSTORE_SIZE更新 .

The Apache HBase Shell

Apache HBase Shell是(J)Ruby的IRB,其中添加了一些HBase特定命令. 在IRB中可以执行的任何操作,都应该可以在HBase Shell中执行.

要运行HBase Shell,请执行以下操作:

$ ./bin/hbase shell

键入help ,然后输入<RETURN>以查看Shell命令和选项的列表. 至少浏览帮助输出末尾的段落,以了解如何将变量和命令参数输入HBase shell; 特别要注意表名,行和列等必须如何被引用.

有关基本的shell操作,请参见shell练习 .

这是Rajeshbabu Chintaguntla编写的所有shell命令的格式良好的清单.

13. Scripting with Ruby

有关编写Apache HBase脚本的示例,请查看HBase bin目录. 查看以* .rb结尾的文件. 要运行这些文件之一,请执行以下操作:

$ ./bin/hbase org.jruby.Main PATH_TO_SCRIPT

14. Running the Shell in Non-Interactive Mode

新的非交互模式已添加到HBase Shell( HBASE-11658) . 非交互模式捕获HBase Shell命令的退出状态(成功或失败),并将该状态传递回命令解释器. 如果您使用普通交互模式,则HBase Shell将仅返回其自己的退出状态,为成功,该退出状态几乎始终为0 .

要调用非交互模式,请将-n--non-interactive选项传递给HBase Shell.

15. HBase Shell in OS Scripts

您可以在操作系统脚本解释器(例如Bash shell)中使用HBase shell,而Bash shell是大多数Linux和UNIX发行版的默认命令解释器. 以下准则使用Bash语法,但可以进行调整以与C样式的外壳程序(例如csh或tcsh)一起使用,并且可以进行修改以与Microsoft Windows脚本解释器一起使用. 欢迎提交.

以这种方式生成HBase Shell命令的速度很慢,因此在决定何时将HBase操作与操作系统命令行结合使用时要牢记这一点.
例子8.将命令传递给HBase Shell

您可以使用echo命令和|以非交互方式将命令传递到HBase Shell(请参见hbasee.shell.noninteractive| (管道)运算符. 确保在HBase命令中转义字符,否则这些字符会被Shell解释. 下面的示例已截断了某些调试级别的输出.

$ echo "describe 'test1'" | ./hbase shell -n

Version 0.98.3-hadoop2, rd5e65a9144e315bb0a964e7730871af32f5018d5, Sat May 31 19:56:09 PDT 2014

describe 'test1'

DESCRIPTION                                          ENABLED
 'test1', {NAME => 'cf', DATA_BLOCK_ENCODING => 'NON true
 E', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0',
  VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIO
 NS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS =>
 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false'
 , BLOCKCACHE => 'true'}
1 row(s) in 3.2410 seconds

要取消所有输出,请将其回显到/ dev / null:

$ echo "describe 'test'" | ./hbase shell -n > /dev/null 2>&1
例子9.检查脚本命令的结果

由于脚本并非旨在以交互方式运行,因此您需要一种方法来检查命令是失败还是成功. HBase的外壳采用返回的值的标准约定0成功的命令,并为失败的命令一些非零值. Bash将命令的返回值存储在名为$?的特殊环境变量中$? . 由于该变量每次外壳程序运行任何命令时都会被覆盖,因此您应将结果存储在脚本定义的其他变量中.

这是一个幼稚的脚本,它显示了一种存储返回值并基于该值进行决策的方法.

#!/bin/bash

echo "describe 'test'" | ./hbase shell -n > /dev/null 2>&1
status=$?
echo "The status was " $status
if ($status == 0); then
    echo "The command succeeded"
else
    echo "The command may have failed."
fi
return $status

15.1. Checking for Success or Failure In Scripts

退出代码为0表示您编写的命令肯定成功. 但是,获得非零的退出代码并不一定意味着命令失败. 该命令可能已经成功,但是客户端失去了连接,或者其他事件掩盖了其成功. 这是因为RPC命令是无状态的. 确保操作状态的唯一方法是检查. 例如,如果您的脚本创建了一个表,但是返回了一个非零的退出值,则应在再次尝试创建表之前检查该表是否已真正创建.

16. Read HBase Shell Commands from a Command File

您可以将HBase Shell命令输入到文本文件中,每行一个命令,然后将该文件传递给HBase Shell.

例子10.例子命令文件
create 'test', 'cf'
list 'test'
put 'test', 'row1', 'cf:a', 'value1'
put 'test', 'row2', 'cf:b', 'value2'
put 'test', 'row3', 'cf:c', 'value3'
put 'test', 'row4', 'cf:d', 'value4'
scan 'test'
get 'test', 'row1'
disable 'test'
enable 'test'
例子11.指示HBase Shell执行命令

将路径传递到命令文件作为hbase shell命令的唯一参数. 每个命令都会执行,并显示其输出. 如果脚本中未包含exit命令,则会返回到HBase Shell提示符. 无法以编程方式检查每个单独的命令是否成功. 另外,尽管您看到了每个命令的输出,但命令本身并未回显到屏幕上,因此很难将命令与其输出对齐.

$ ./hbase shell ./sample_commands.txt
0 row(s) in 3.4170 seconds

TABLE
test
1 row(s) in 0.0590 seconds

0 row(s) in 0.1540 seconds

0 row(s) in 0.0080 seconds

0 row(s) in 0.0060 seconds

0 row(s) in 0.0060 seconds

ROW                   COLUMN+CELL
 row1                 column=cf:a, timestamp=1407130286968, value=value1
 row2                 column=cf:b, timestamp=1407130286997, value=value2
 row3                 column=cf:c, timestamp=1407130287007, value=value3
 row4                 column=cf:d, timestamp=1407130287015, value=value4
4 row(s) in 0.0420 seconds

COLUMN                CELL
 cf:a                 timestamp=1407130286968, value=value1
1 row(s) in 0.0110 seconds

0 row(s) in 1.5630 seconds

0 row(s) in 0.4360 seconds

17. Passing VM Options to the Shell

You can pass VM options to the HBase Shell using the HBASE_SHELL_OPTS environment variable. You can set this in your environment, for instance by editing ~/.bashrc, or set it as part of the command to launch HBase Shell. The following example sets several garbage-collection-related variables, just for the lifetime of the VM running the HBase Shell. The command should be run all on a single line, but is broken by the \ character, for readability.

$ HBASE_SHELL_OPTS="-verbose:gc -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps \
  -XX:+PrintGCDetails -Xloggc:$HBASE_HOME/logs/gc-hbase.log" ./bin/hbase shell

18. Overriding configuration starting the HBase Shell

从hbase-2.0.5 / hbase-2.1.3 / hbase-2.2.0 / hbase-1.4.10 / hbase-1.5.0开始,您可以通过传递或覆盖hbase-*.xml指定的hbase配置在命令行上以-D为前缀的键/值,如下所示:

$ ./bin/hbase shell -Dhbase.zookeeper.quorum=ZK0.remote.cluster.example.org,ZK1.remote.cluster.example.org,ZK2.remote.cluster.example.org -Draining=false
...
hbase(main):001:0> @shell.hbase.configuration.get("hbase.zookeeper.quorum")
=> "ZK0.remote.cluster.example.org,ZK1.remote.cluster.example.org,ZK2.remote.cluster.example.org"
hbase(main):002:0> @shell.hbase.configuration.get("raining")
=> "false"

19. Shell Tricks

19.1. Table variables

HBase 0.95添加了Shell命令,这些命令为表提供了jruby样式的面向对象的引用. 以前,作用于表的所有shell命令都具有一种程序样式,该样式始终将表的名称作为参数. HBase 0.95引入了将表分配给jruby变量的功能. 该表引用可用于执行数据读写操作,例如放置,扫描以及获取良好的管理功能,例如禁用,删除,描述表.

例如,以前您总是要指定一个表名:

hbase(main):000:0> create ‘t’, ‘f’
0 row(s) in 1.0970 seconds
hbase(main):001:0> put 't', 'rold', 'f', 'v'
0 row(s) in 0.0080 seconds

hbase(main):002:0> scan 't'
ROW                                COLUMN+CELL
 rold                              column=f:, timestamp=1378473207660, value=v
1 row(s) in 0.0130 seconds

hbase(main):003:0> describe 't'
DESCRIPTION                                                                           ENABLED
 't', {NAME => 'f', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_ true
 SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2
 147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false
 ', BLOCKCACHE => 'true'}
1 row(s) in 1.4430 seconds

hbase(main):004:0> disable 't'
0 row(s) in 14.8700 seconds

hbase(main):005:0> drop 't'
0 row(s) in 23.1670 seconds

hbase(main):006:0>

现在,您可以将表分配给变量,并在jruby shell代码中使用结果.

hbase(main):007 > t = create 't', 'f'
0 row(s) in 1.0970 seconds

=> Hbase::Table - t
hbase(main):008 > t.put 'r', 'f', 'v'
0 row(s) in 0.0640 seconds
hbase(main):009 > t.scan
ROW                           COLUMN+CELL
 r                            column=f:, timestamp=1331865816290, value=v
1 row(s) in 0.0110 seconds
hbase(main):010:0> t.describe
DESCRIPTION                                                                           ENABLED
 't', {NAME => 'f', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_ true
 SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2
 147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false
 ', BLOCKCACHE => 'true'}
1 row(s) in 0.0210 seconds
hbase(main):038:0> t.disable
0 row(s) in 6.2350 seconds
hbase(main):039:0> t.drop
0 row(s) in 0.2340 seconds

如果已经创建了表,则可以使用get_table方法将表分配给变量:

hbase(main):011 > create 't','f'
0 row(s) in 1.2500 seconds

=> Hbase::Table - t
hbase(main):012:0> tab = get_table 't'
0 row(s) in 0.0010 seconds

=> Hbase::Table - t
hbase(main):013:0> tab.put ‘r1’ ,’f’, ‘v’
0 row(s) in 0.0100 seconds
hbase(main):014:0> tab.scan
ROW                                COLUMN+CELL
 r1                                column=f:, timestamp=1378473876949, value=v
1 row(s) in 0.0240 seconds
hbase(main):015:0>

列表功能也得到了扩展,因此它以字符串形式返回表名列表. 然后,您可以使用jruby根据这些名称对表操作进行脚本编写. list_snapshots命令的行为也类似.

hbase(main):016 > tables = list(‘t.*’)
TABLE
t
1 row(s) in 0.1040 seconds

=> #<#<Class:0x7677ce29>:0x21d377a4>
hbase(main):017:0> tables.map { |t| disable t ; drop  t}
0 row(s) in 2.2510 seconds

=> [nil]
hbase(main):018:0>

19.2. irbrc

在您的主目录中为自己创建一个.irbrc文件. 添加自定义项. 命令历史记录是一个有用的命令,因此可以在Shell调用之间保存命令:

$ more .irbrc
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"

如果要避免将对每个表达式求值的结果打印到stderr,例如,从" list"命令返回的表数组:

$ echo "IRB.conf[:ECHO] = false" >>~/.irbrc

请参阅.irbrcruby文档以了解其他可能的配置.

19.3. LOG data to timestamp

要将日期" 08/08/16 20:56:29"从hbase日志转换为时间戳,请执行以下操作:

hbase(main):021:0> import java.text.SimpleDateFormat
hbase(main):022:0> import java.text.ParsePosition
hbase(main):023:0> SimpleDateFormat.new("yy/MM/dd HH:mm:ss").parse("08/08/16 20:56:29", ParsePosition.new(0)).getTime() => 1218920189000

要走另一个方向:

hbase(main):021:0> import java.util.Date
hbase(main):022:0> Date.new(1218920189000).toString() => "Sat Aug 16 20:56:29 UTC 2008"

以与HBase日志格式完全相同的格式输出将使SimpleDateFormat有点混乱.

19.4. Debug

19.4.1. Shell debug switch

您可以在外壳程序中设置调试开关,以在运行命令时查看更多输出(例如,更多有关异常的堆栈跟踪):

hbase> debug <RETURN>

19.4.2. DEBUG log level

要在外壳中启用DEBUG级别的日志记录,请使用-d选项启动它.

$ ./bin/hbase shell -d

19.5. Commands

19.5.1. count

Count命令返回表中的行数. 配置正确的CACHE时,速度非常快

hbase> count '<tablename>', CACHE => 1000

上面的计数一次获取1000行. 如果行很大,请将CACHE设置为较低. 默认值为一次获取​​一行.

Data Model

在HBase中,数据存储在具有行和列的表中. 这是与关系数据库(RDBMS)的术语重叠,但这并不是一个有用的类比. 相反,将HBase表视为多维映射可能会有所帮助.

HBase数据模型术语
Table

一个HBase表由多行组成.

Row

HBase中的一行由行键和一列或多列与它们相关联的值组成. 行在存储时按行键按字母顺序排序. 因此,行键的设计非常重要. 目的是以相关行彼此靠近的方式存储数据. 常见的行密钥模式是网站域. 如果行键是域,则可能应该将它们反向存储(org.apache.www,org.apache.mail,org.apache.jira). 这样,表中所有的Apache域都彼此靠近,而不是根据子域的第一个字母散布开来.

Column

HBase中的列由列族和列限定符组成,它们由:冒号)字符分隔.

Column Family

出于性能考虑,列族实际上将一组列及其值并置在一起. 每个列族都有一组存储属性,例如是否应将其值缓存在内存中,如何压缩其数据或对其行键进行编码等. 表中的每一行都具有相同的列族,尽管给定的行可能不会在给定的列族中存储任何内容.

Column Qualifier

将列限定符添加到列族,以提供给定数据段的索引. 给定列族content ,列限定符可能是content:html ,另一个可能是content:pdf . 尽管列族在创建表时是固定的,但列限定符是可变的,并且行之间可能有很大差异.

Cell

A cell is a combination of row, column family, and column qualifier, and contains a value and a timestamp, which represents the value’s version.

Timestamp

时间戳与每个值一起写入,并且是值的给定版本的标识符. 默认情况下,时间戳表示写入数据时RegionServer上的时间,但是在将数据放入单元格时可以指定其他时间戳值.

20. Conceptual View

您可以在Jim R. Wilson的博客文章了解HBase和BigTable中阅读有关HBase数据模型的非常容易理解的解释. Amandeep Khurana的PDF 《基本模式设计简介》中提供了另一个很好的解释.

可能有助于阅读不同的观点,以便对HBase模式设计有深入的了解. 链接的文章与本节中的信息内容相同.

The following example is a slightly modified form of the one on page 2 of the BigTable paper. There is a table called webtable that contains two rows (com.cnn.www and com.example.www) and three column families named contents, anchor, and people. In this example, for the first row (com.cnn.www), anchor contains two columns (anchor:cssnsi.com, anchor:my.look.ca) and contents contains one column (contents:html). This example contains 5 versions of the row with the row key com.cnn.www, and one version of the row with the row key com.example.www. The contents:html column qualifier contains the entire HTML of a given website. Qualifiers of the anchor column family each contain the external site which links to the site represented by the row, along with the text it used in the anchor of its link. The people column family represents people associated with the site.

列名

By convention, a column name is made of its column family prefix and a qualifier. For example, the column contents:html is made up of the column family contents and the html qualifier. The colon character (:) delimits the column family from the column family qualifier.

表4.表webtable
行键 时标 ColumnFamily contents ColumnFamily anchor ColumnFamily people

"com.cnn.www"

t9

锚:cnnsi.com =" CNN"

"com.cnn.www"

t8

anchor:my.look.ca = "CNN.com"

"com.cnn.www"

t6

contents:html =" <html>…

"com.cnn.www"

t5

contents:html =" <html>…

"com.cnn.www"

t3

contents:html =" <html>…

该表中看起来为空的单元格在HBase中不占用空间,或者实际上不存在. 这就是使HBase"稀疏"的原因. 表格视图不是查看HBase中数据的唯一可能方法,甚至不是最准确的方法. 以下代表与多维地图相同的信息. 这仅是出于说明目的的模型,可能并非严格准确.

{
  "com.cnn.www": {
    contents: {
      t6: contents:html: "<html>..."
      t5: contents:html: "<html>..."
      t3: contents:html: "<html>..."
    }
    anchor: {
      t9: anchor:cnnsi.com = "CNN"
      t8: anchor:my.look.ca = "CNN.com"
    }
    people: {}
  }
  "com.example.www": {
    contents: {
      t5: contents:html: "<html>..."
    }
    anchor: {}
    people: {
      t5: people:author: "John Doe"
    }
  }
}

21. Physical View

尽管从概念上讲,表可以看作是行的稀疏集合,但它们实际上是按列族存储的. 可以随时将新的列限定符(column_family:column_qualifier)添加到现有的列族中.

表5. ColumnFamily anchor
行键 时标 列族anchor

"com.cnn.www"

t9

anchor:cnnsi.com = "CNN"

"com.cnn.www"

t8

anchor:my.look.ca = "CNN.com"

表6. ColumnFamily contents
行键 时标 ColumnFamily contents:

"com.cnn.www"

t6

contents:html =" <html>…

"com.cnn.www"

t5

contents:html =" <html>…

"com.cnn.www"

t3

contents:html = "<html>…​"

概念视图中显示的空单元格根本不存储. 因此,在时间戳记t8处对contents:html列的值的请求将不返回任何值. 同样,在时间戳记t9处请求anchor:my.look.ca值的请求将不返回任何值. 但是,如果未提供时间戳记,则将返回特定列的最新值. 给定多个版本,最新的也是找到的第一个版本,因为时间戳以降序存储. 因此,如果未指定时间戳,则对com.cnn.www行中所有列的值的请求将是:来自时间戳t6anchor:cnnsi.com contents:html的值,来自时间戳t9anchor:cnnsi.com的值,时间戳记t8 anchor:my.look.ca .

有关Apache HBase如何存储数据的内部信息的更多信息,请参见regions.arch .

22. Namespace

命名空间是表的逻辑分组,类似于关系数据库系统中的数据库. 这种抽象为即将到来的多租户相关功能奠定了基础:

  • 配额管理( HBASE-8410 )-限制名称空间可以消耗的资源(即区域,表)数量.

  • 命名空间安全管理( HBASE-9206 )-为租户提供另一级安全管理.

  • 区域服务器组( HBASE-6721 )-可以将名称空间/表固定到RegionServers的子集上,从而确保课程的隔离级别.

22.1. Namespace management

可以创建,删除或更改名称空间. 命名空间成员资格是在表创建期间通过指定以下格式的标准表名来确定的:

<table namespace>:<table qualifier>
例子12.例子
#Create a namespace
create_namespace 'my_ns'
#create my_table in my_ns namespace
create 'my_ns:my_table', 'fam'
#drop namespace
drop_namespace 'my_ns'
#alter namespace
alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}

22.2. Predefined namespaces

有两个预定义的特殊名称空间:

  • hbase-系统名称空间,用于包含HBase内部表

  • 默认-没有显式指定名称空间的表将自动落入该名称空间

例子13.例子
#namespace=foo and table qualifier=bar
create 'foo:bar', 'fam'

#namespace=default and table qualifier=bar
create 'bar', 'fam'

23. Table

表在架构定义时预先声明.

24. Row

行键是未解释的字节. 按字典顺序对行进行排序,最低顺序在表中排在首位. 空字节数组用于表示表名称空间的开始和结束.

25. Column Family

Apache HBase中的分为多个列族 . 列族的所有列成员都具有相同的前缀. 例如,列courses:historycourses:math都是courses列族的成员. 冒号( : )划界柱族预选赛柱族. 列族前缀必须由可打印字符组成. 限定尾部(列族限定符 )可以由任意字节组成. 列族必须在架构定义时预先声明,而不必在架构时定义列,但可以在表运行时动态地对其进行构想.

实际上,所有列族成员都一起存储在文件系统上. 由于调整和存储规范是在列族级别上完成的,因此建议所有列族成员具有相同的常规访问模式和大小特征.

26. Cells

{行,列,版本}元组精确地指定了HBase中的一个cell . 单元格内容是未解释的字节

27. Data Model Operations

四个主要的数据模型操作是"获取","放置","扫描"和"删除". 通过Table实例应用操作.

27.1. Get

获取指定行的返回属性. 通过Table.get执行获取.

27.2. Put

Put可以将新行添加到表中(如果键是新键),也可以更新现有行(如果键已经存在). 通过Table.put (writeBuffer)或链接执行看跌期权:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#batch(java.util.List,java.lang .Object [])[Table.batch](非writeBuffer).

27.3. Scans

扫描允许对指定属性的多行进行迭代.

以下是"扫描表"实例的示例. 假设一个表中填充了键为" row1"," row2"," row3"的行,然后填充了另一组键为" abc1"," abc2"和" abc3"的行. 下面的示例演示如何设置Scan实例以返回以" row"开头的行.

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...

Table table = ...      // instantiate a Table instance

Scan scan = new Scan();
scan.addColumn(CF, ATTR);
scan.setRowPrefixFilter(Bytes.toBytes("row"));
ResultScanner rs = table.getScanner(scan);
try {
  for (Result r = rs.next(); r != null; r = rs.next()) {
    // process result...
  }
} finally {
  rs.close();  // always close the ResultScanner!
}

请注意,通常,为扫描指定特定停止点的最简单方法是使用InclusiveStopFilter类.

27.4. Delete

删除从表中删除一行. 删除是通过Table.delete执行的.

HBase不会就地修改数据,因此删除操作通过创建称为墓碑的新标记来处理. 这些墓碑以及固定价值的墓碑在大压实时得以清理.

有关删除列版本的更多信息,请参见version.delete ;有关压缩的更多信息,请参见压缩.

28. Versions

{行,列,版本}元组精确地指定了HBase中的一个cell . 可能会有无数个单元格,其中行和列相同,但单元格地址仅在其版本维度上有所不同.

当行键和列键表示为字节时,使用长整数指定版本. 通常,此long包含一些时间实例,例如java.util.Date.getTime()System.currentTimeMillis()返回的那些实例,即: 当前时间与UTC 1970年1月1日午夜之间的差(以毫秒为单位) .

HBase版本维以降序存储,因此从存储文件中读取时,将首先找到最新值.

在HBase中,关于cell版本的语义存在很多混乱. 尤其是:

  • 如果对一个单元的多次写入具有相同版本,则只有最后一次写入是可获取的.

  • 可以按非递增版本顺序写入单元格.

下面我们描述HBase中版本维度当前的工作方式. 有关HBase版本的讨论,请参见HBASE-2406 . HBase中的弯曲时间使您可以更好地阅读HBase中的版本或时间维度. 关于版本控制的更多信息,比此处提供的更多. 在撰写本文时,HBase中不再存在本文中提到的在现有时间戳上覆盖值的限制. 这部分基本上是Bruno Dumon撰写的本文的提要.

28.1. Specifying the Number of Versions to Store

给定列存储的最大版本数是列模式的一部分,并在创建表时指定,或通过alter命令(通过HColumnDescriptor.DEFAULT_VERSIONS . 在HBase 0.96之前,保留的默认版本数是3 ,但在0.96和更高版本中已更改为1 .

示例14.修改列族的最大版本数

本示例使用HBase Shell保留列族f1中所有列的最多5个版本. 您也可以使用HColumnDescriptor .

hbase> alter ‘t1′, NAME => ‘f1′, VERSIONS => 5
例子15.修改列族的最小版本数

您还可以指定每个列系列要存储的最小版本数. 默认情况下,它设置为0,这意味着该功能被禁用. 以下示例通过HBase Shell将列族f1所有列的最小版本数设置为2 . 您也可以使用HColumnDescriptor .

hbase> alter ‘t1′, NAME => ‘f1′, MIN_VERSIONS => 2

从HBase 0.98.2开始,可以通过在hbase-site.xml中设置hbase.column.max.version来为所有新创建的列保留的最大版本数指定全局默认值. 参见hbase.column.max.version .

28.2. Versions and HBase Operations

在本节中,我们研究每个核心HBase操作的版本维度的行为.

28.2.1. Get/Scan

获取是在扫描之上实现的. 以下有关Get的讨论同样适用于Scans .

默认情况下,即,如果您未指定任何显式版本,则在执行get ,将返回其版本具有最大值的单元格(该单元格可能不是最新写入的单元格,请参阅下文). 可以通过以下方式修改默认行为:

  • 返回多个版本,请参见Get.setMaxVersions()

  • 返回最新版本以外的版本,请参见Get.setTimeRange()

    要检索小于或等于给定值的最新版本,从而在某个时间点给出记录的"最新"状态,只需使用0到所需版本的范围并将最大版本设置为1 .

28.2.2. Default Get Example

以下"获取"将仅检索该行的当前版本

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(Bytes.toBytes("row1"));
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR);  // returns current version of value

28.2.3. Versioned Get Example

下面的Get将返回该行的最后3个版本.

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Get get = new Get(Bytes.toBytes("row1"));
get.setMaxVersions(3);  // will return last 3 versions of row
Result r = table.get(get);
byte[] b = r.getValue(CF, ATTR);  // returns current version of value
List<KeyValue> kv = r.getColumn(CF, ATTR);  // returns all versions of this column

28.2.4. Put

做一个看跌总是会创建一个新版本的cell ,在一定的时间戳记. 默认情况下,系统使用服务器的currentTimeMillis ,但是您可以在每个列级别上自己指定版本(=长整数). 这意味着您可以分配过去或将来的时间,或将long值用于非时间目的.

要覆盖现有值,请在与要覆盖的单元格完全相同的行,列和版本上进行放置.

Implicit Version Example

HBase将使用当前时间对以下Put进行隐式版本控制.

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Put put = new Put(Bytes.toBytes(row));
put.add(CF, ATTR, Bytes.toBytes( data));
table.put(put);
Explicit Version Example

下面的Put具有明确设置的版本时间戳.

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...
Put put = new Put( Bytes.toBytes(row));
long explicitTimeInMs = 555;  // just an example
put.add(CF, ATTR, explicitTimeInMs, Bytes.toBytes(data));
table.put(put);

Caution: the version timestamp is used internally by HBase for things like time-to-live calculations. It’s usually best to avoid setting this timestamp yourself. Prefer using a separate timestamp attribute of the row, or have the timestamp as a part of the row key, or both.

28.2.5. Delete

有三种不同类型的内部删除标记. 请参阅Lars Hofhansl的博客,以了解有关他尝试添加其他内容的尝试,即" 在HBase中扫描:前缀删除标记" .

  • 删除:用于列的特定版本.

  • 删除列:适用于列的所有版本.

  • 删除族:针对特定ColumnFamily的所有列

删除整行时,HBase会在内部为每个ColumnFamily(即不是每个单独的列)创建一个逻辑删除.

通过创建逻辑删除标记来删除工作. 例如,假设我们要删除一行. 为此,您可以指定一个版本,否则默认使用currentTimeMillis . 这意味着删除版本小于或等于此版本的所有单元格 . HBase永远不会修改数据,例如,删除操作不会立即删除(或标记为已删除)存储文件中与删除条件相对应的条目. 而是写了一个所谓的墓碑 ,它将掩盖已删除的值. 当HBase进行重大压缩时,将处理逻辑删除以实际删除无效值以及逻辑删除本身. 如果删除行时指定的版本大于该行中任何值的版本,则可以考虑删除整个行.

有关删除和版本控制如何交互的信息性讨论,请参阅线程在用户邮件列表上出现" 放置w /时间戳"→Deleteall→"放置w /时间戳"失败 .

另请参阅键值 ,以获取有关内部键值格式的更多信息.

除非在列族中设置了KEEP_DELETED_CELLS选项,否则在KEEP_DELETED_CELLS商店的主要压缩期间将删除删除标记(请参见保留已删除的单元格 ). 要使删除保持可配置的时间,可以通过hbase-site.xml中的hbase.hstore.time.to.purge.deletes属性设置删除TTL. 如果未设置hbase.hstore.time.to.purge.deletes或将其设置为0,则在下一次主要压缩期间将清除所有删除标记,包括将来带有时间戳的标记. 否则,将保留将来带有时间戳的删除标记,直到在该标记的时间戳加上hbase.hstore.time.to.purge.deletes的值所表示的时间之后的主要压缩hbase.hstore.time.to.purge.deletes (以毫秒为单位).

此行为表示对HBase 0.94中引入的意外更改的修复,并在HBASE-10118中进行了修复 . 所做的更改已反向移植到HBase 0.94和更新的分支中.

28.3. Current Limitations

28.3.1. Deletes mask Puts

删除蒙版看跌期权,甚至是输入删除后发生的看跌期权. 参见HBASE-2256 . 请记住,删除操作会写入一个墓碑,该墓碑只有在下一次重大压缩运行后才会消失. 假设您删除了所有内容⇐T.此后,您将使用时间戳⇐T进行新的放置.此放置,即使它在删除后发生,也会被删除逻辑删除掩盖. 进行认沽不会失败,但是当您进行认沽时,您会注意到认沽没有任何效果. 在大型压实运行之后,它将重新开始工作. 如果您对行中的新看跌期权使用总是递增版本,则这些问题应该不会成为问题. 但是,即使您不在乎时间,它们也可能发生:只需删除并立即放置就可以了,它们有可能在同一毫秒内发生.

28.3.2. Major compactions change query results

…在t1,t2和t3处创建三个单元格版本,最大版本设置为2.因此,获取所有版本时,将仅返回t2和t3处的值. 但是,如果您在t2或t3删除了版本,则t1的版本会再次出现. 显然,一旦进行了重大压实,这种情况就不再存在了...... (See 垃圾收集 in Bending time in HBase.)

29. Sort Order

所有数据模型操作HBase都按排序顺序返回数据. 首先是按行,然后是ColumnFamily,然后是列限定符,最后是时间戳(按相反顺序排序,因此首先返回最新记录).

30. Column Metadata

在ColumnFamily的内部KeyValue实例之外没有任何列元数据存储. 因此,尽管HBase不仅可以支持每行大量列,而且还支持行之间的异构列集,但是您有责任跟踪列名.

获取ColumnFamily存在的一组完整列的唯一方法是处理所有行. 有关HBase如何在内部存储数据的更多信息,请参见keyvalue .

31. Joins

HBase是否支持联接是dist-list上的一个常见问题,并且有一个简单的答案:至少在RDBMS支持联接的方式上(例如,在SQL中使用等联接或外部联接) ). 如本章所述,HBase中的读取数据模型操作是Get和Scan.

但是,这并不意味着您的应用程序不支持等效的联接功能,而是您必须自己做. 两种主要策略是在写入HBase时对数据进行非规范化,或者在应用程序或MapReduce代码中具有查找表并在HBase表之间进行联接(并且正如RDBMS所演示的那样,有多种策略可用于此操作,具体取决于表,例如嵌套循环与哈希联接). 那么哪种方法最好呢? 这取决于您要尝试执行的操作,因此,没有一个适用于每个用例的答案.

32. ACID

请参阅ACID语义 . Lars Hofhansl还在HBase中撰写了有关ACID的说明.

HBase and Schema Design

Ian Varley的硕士论文《 无关系:非关系数据库的混合祝福》很好地介绍了各种非rdbms数据存储上的优缺点模型. 另外,读键值为HBase的存储如何在内部数据,并在部分schema.casestudies .

33. Schema Creation

可以使用Apache HBase Shell或Java API中的Admin创建或更新HBase模式.

进行ColumnFamily修改时,必须禁用表,例如:

Configuration config = HBaseConfiguration.create();
Admin admin = new Admin(conf);
String table = "myTable";

admin.disableTable(table);

HColumnDescriptor cf1 = ...;
admin.addColumn(table, cf1);      // adding new ColumnFamily
HColumnDescriptor cf2 = ...;
admin.modifyColumn(table, cf2);    // modifying existing ColumnFamily

admin.enableTable(table);

有关配置客户端连接的更多信息,请参见客户端依赖性 .

0.92.x代码库支持联机模式更改,但是0.90.x代码库要求禁用该表.

33.1. Schema Updates

当对Tables或ColumnFamilies进行更改(例如,区域大小,块大小)时,这些更改将在下一次进行重大压缩并重写StoreFile时生效.

有关StoreFiles的更多信息,请参见store .

34. On the number of column families

HBase当前不能很好地处理超过两个或三个列族的任何事物,因此请保持架构中列族的数量少. 当前,刷新和压缩是在每个区域的基础上进行的,因此,如果一个列族承载着大量要进行刷新的数据,即使相邻族族携带的数据量很小,也将对其进行刷新. 当存在许多色谱柱系列时,冲洗和压实相互作用会导致大量不必要的I / O(通过更改冲洗和压实以在每个色谱柱族的基础上解决). 有关压缩的更多信息,请参见[compaction] .

如果可以,请尝试使用一个列族. 仅在通常以列范围访问数据的情况下才引入第二和第三列族. 即,您查询一个列族或另一个列族,但通常一次不查询.

34.1. Cardinality of ColumnFamilies

如果单个表中存在多个ColumnFamilies,请注意基数(即行数). 如果ColumnFamilyA有100万行,而ColumnFamilyB有10亿行,则ColumnFamilyA的数据可能会分布在许多区域(和RegionServers)中. 这使得对ColumnFamilyA进行批量扫描的效率较低.

35. Rowkey Design

35.1. Hotspotting

HBase中的行按行键按字典顺序排序. 该设计针对扫描进行了优化,使您可以将相关的行或将一起读取的行彼此靠近存储. 但是,设计不当的行键是引起热点的常见原因 . 当大量客户端流量定向到群集的一个节点或仅几个节点时,就会发生热点. 此流量可能表示读取,写入或其他操作. 流量使负责托管该区域的单台计算机不堪重负,从而导致性能下降并可能导致区域不可用. 这也可能对由同一区域服务器托管的其他区域产生不利影响,因为该主机无法满足请求的负载. 设计数据访问模式非常重要,这样才能充分,均匀地利用群集.

为防止写入时出现热点,请设计行键,以使确实确实需要位于同一区域的行位于,但从更大的角度看,数据被写入集群中的多个区域,而不是一次写入一个区域. 下面介绍了一些避免热点的常用技术,以及它们的一些优点和缺点.

Salting

从这种意义上讲,加盐与加密无关,而是指将随机数据添加到行密钥的开头. 在这种情况下,加盐是指在行键上添加一个随机分配的前缀,以使其与行键的排序方式不同. 可能的前缀数量对应于您要分布数据的区域数量. 如果您在其他分布更均匀的行中反复出现一些"热"行键模式,则盐析会有所帮助. 考虑下面的示例,该示例表明加盐可以将写入负载分散到多个RegionServer中,并说明对读取的某些负面影响.

例子16.加盐例子

假设您具有以下行键列表,并且对表进行了拆分,以使字母表中的每个字母都有一个区域. 前缀" a"是一个区域,前缀" b"是另一个区域. 在此表中,所有以'f'开头的行都在同一区域中. 本示例重点介绍具有以下键的行:

foo0001
foo0002
foo0003
foo0004

Now, imagine that you would like to spread these across four different regions. You decide to use four different salts: a, b, c, and d. In this scenario, each of these letter prefixes will be on a different region. After applying the salts, you have the following rowkeys instead. Since you can now write to four separate regions, you theoretically have four times the throughput when writing that you would have if all the writes were going to the same region.

a-foo0003
b-foo0001
c-foo0004
d-foo0002

然后,如果您添加另一行,则会为该行随机分配四个可能的盐值之一,并最终靠近现有行之一.

a-foo0003
b-foo0001
c-foo0003
c-foo0004
d-foo0002

由于此分配是随机的,因此,如果要按字典顺序检索行,则需要做更多的工作. 这样,盐化会尝试增加写入的吞吐量,但会在读取期间增加成本.

Hashing

可以使用单向哈希来代替给定行,该哈希始终使给定的行使用相同的前缀"加盐",而不是随机分配,这样可以将负载分散到RegionServer上,但允许在读取过程中进行可预测性. 使用确定性哈希可以使客户端重建完整的行键,并使用Get操作正常检索该行.

Example 17. Hashing Example
鉴于上面的盐析例如同样的情况,你可以改为应用单向散列会导致与键行foo0003总是和预见的是,收到a前缀. 然后,要检索该行,您将已经知道密钥. 您还可以优化事物,例如使某些对密钥始终位于同一区域.
倒转钥匙

防止热点的第三个常见技巧是反转固定宽度或数字行键,以使变化最频繁的部分(最低有效位)在第一位. 这有效地使行键随机化,但牺牲了行排序属性.

35.2. Monotonically Increasing Row Keys/Timeseries Data

在汤姆·怀特(Tom White)的书《 Hadoop:权威指南》 (O'Reilly)的HBase章节中,有一个优化说明,注意当导入过程与所有客户协调一致地敲击表中一个区域时,这种现象(因此是单个节点),然后移至下一个区域,依此类推.随着单调增加行键(即使用时间戳),这种情况将会发生. 请参阅IKai Lan的漫画,了解为何在类似BigTable的数据存储区中单调递增的行键会出现问题: 单调递增的值是不好的 . 可以通过将输入记录随机化为不按排序顺序来缓解单调递增键在单个区域上的堆积,但是通常最好避免使用时间戳或序列(例如1、2、3)作为行键.

如果确实需要将时间序列数据上传到HBase,则应学习OpenTSDB作为成功的示例. 它具有描述链接的页面:它在HBase中使用的架构 . OpenTSDB中的密钥格式实际上是[metric_type] [event_timestamp],乍一看似乎与先前关于不使用时间戳作为密钥的建议相矛盾. 但是,不同之处在于时间戳不在密钥的领先位置,而设计假设是存在数十个或数百个(或更多)不同的度量标准类型. 因此,即使连续输入数据流具有多种度量标准类型,Put也会分布在表中区域的各个点上.

有关某些行键设计示例,请参见schema.casestudies .

35.3. Try to minimize row and column sizes

在HBase中,值总是随其坐标一起传送; 当单元格值通过系统时,将始终伴随其行,列名和时间戳记. 如果行名和列名很大,尤其是与单元格值的大小相比,则可能会遇到一些有趣的情况. Marc Limotte在HBASE-3551的尾部描述了这种情况(推荐!). 其中,为方便随机访问而保留在HBase存储文件( StoreFile(HFile) )上的索引可能最终会占用HBase分配的RAM的大块,因为单元值坐标很大. 上面引用的注释中的Mark建议增加块大小,以便存储文件索引中的条目以较大的间隔发生或修改表模式,从而使行和列名较小. 压缩还将使索引更大. 请在用户邮件列表中查看有关问题storefileIndexSize的线程.

在大多数情况下,效率低下并不重要. 不幸的是,这是他们这样做的情况. 无论为ColumnFamilies,属性和行键选择了哪种模式,它们都可以在数据中重复数十亿次.

有关HBase内部存储数据的更多信息,请参见keyvalue ,以了解为什么这很重要.

35.3.1. Column Families

尝试使ColumnFamily名称尽可能的小,最好是一个字符(例如," d"表示数据/默认值).

有关HBase内部存储数据的更多信息,请参见[keyvalue] ,以了解为什么这很重要.

35.3.2. Attributes

尽管详细的属性名称(例如" myVeryImportantAttribute")更易于阅读,但更喜欢使用较短的属性名称(例如" via")存储在HBase中.

有关HBase内部存储数据的更多信息,请参见keyvalue ,以了解为什么这很重要.

35.3.3. Rowkey Length

使其尽可能短,以使它们仍可用于所需的数据访问(例如,获取与扫描). 对于数据访问无用的短键并不比具有更好的获取/扫描属性的长键更好. 设计行键时需要权衡取舍.

35.3.4. Byte Patterns

长为8个字节. 您可以在这八个字节中存储最多18,446,744,073,709,551,615个无符号数. 如果将此数字存储为字符串(每个字符假定一个字节),则需要将近3倍的字节.

不服气吗? 以下是一些可以自己运行的示例代码.

// long
//
long l = 1234567890L;
byte[] lb = Bytes.toBytes(l);
System.out.println("long bytes length: " + lb.length);   // returns 8

String s = String.valueOf(l);
byte[] sb = Bytes.toBytes(s);
System.out.println("long as string length: " + sb.length);    // returns 10

// hash
//
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(Bytes.toBytes(s));
System.out.println("md5 digest bytes length: " + digest.length);    // returns 16

String sDigest = new String(digest);
byte[] sbDigest = Bytes.toBytes(sDigest);
System.out.println("md5 digest as string length: " + sbDigest.length);    // returns 26

不幸的是,使用类型的二进制表示形式会使您的数据难以在代码外部读取. 例如,这是您在增加值时在外壳中看到的内容:

hbase(main):001:0> incr 't', 'r', 'f:q', 1
COUNTER VALUE = 1

hbase(main):002:0> get 't', 'r'
COLUMN                                        CELL
 f:q                                          timestamp=1369163040570, value=\x00\x00\x00\x00\x00\x00\x00\x01
1 row(s) in 0.0310 seconds

外壳程序会尽力打印字符串,在这种情况下,它决定只打印十六进制. 区域名称中的行键也会发生同样的情况. 如果您知道要存储的内容,可以这样做,但是如果可以将任意数据放在相同的单元格中,则可能也不可读. 这是主要的权衡.

35.4. Reverse Timestamps

反向扫描API

HBASE-4811实现了一个API,可以反向扫描表或表中的范围,从而减少了为进行正向或反向扫描而优化架构的需求. HBase 0.98和更高版本中提供了此功能. 有关更多信息,请参见https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html#setReversed(boolean .

数据库处理中的一个常见问题是快速找到值的最新版本. 使用反向时间戳作为键的一部分的技术可以在此问题的特殊情况下极大地帮助您. 该技术还可以在汤姆·怀特(Tom White)的《 Hadoop:权威指南》(O'Reilly)的HBase一章中找到,该技术包括将( Long.MAX_VALUE - timestamp )附加到任何键的末尾,例如[key] [reverse_timestamp].

通过执行[key]扫描并获取第一条记录,可以找到表中[key]的最新值. 由于HBase键是按排序顺序排列的,因此此键在[key]的任何较旧的行键之前进行排序,因此是第一个.

将使用此技术代替使用"版本号",以"永久"(或很长时间)保留所有版本,并同时使用相同的"扫描"技术快速获取对任何其他版本的访问权限.

35.5. Rowkeys and ColumnFamilies

Rowkeys are scoped to ColumnFamilies. Thus, the same rowkey could exist in each ColumnFamily that exists in a table without collision.

35.6. Immutability of Rowkeys

行键不能更改. 可以在表中"更改"它们的唯一方法是删除行然后将其重新插入. 这是HBase dist-list上一个相当普遍的问题,因此第一次(和/或在插入大量数据之前)正确获取行键是值得的.

35.7. Relationship Between RowKeys and Region Splits

如果您预先分割了表格,那么了解行键如何在区域边界上分布至关重要 . 作为说明为什么如此重要的示例,请考虑使用可显示的十六进制字符作为键的开头位置的示例(例如," 0000000000000000"到" ffffffffffffffff"). 通过Bytes.split (这是在Admin.createTable(byte[] startKey, byte[] endKey, numRegions)创建区域时使用的分割策略Admin.createTable(byte[] startKey, byte[] endKey, numRegions)来运行10个区域的键范围将生成以下分割...

48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48                                // 0
54 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10                 // 6
61 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -68                 // =
68 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -126  // D
75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 72                                // K
82 18 18 18 18 18 18 18 18 18 18 18 18 18 18 14                                // R
88 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -44                 // X
95 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -102                // _
102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102                // f

(请注意:引导字节在右侧列为注释.)鉴于第一个分割为'0',最后一个分割为'f',一切都很好,对吗? 没那么快.

问题在于所有数据都将在前两个区域和最后一个区域堆积,从而造成"块状"(可能还有"热")区域问题. 要了解原因,请参考ASCII表 . " 0"是字节48,而" f"是字节102,但是字节值(字节58至96)之间存在巨大差异,该间隙永远不会出现在此键空间中,因为唯一的值是[0-9]和[af ]. 因此,中间区域将永远不会被使用. 为了使此示例键空间可以进行预拆分,需要自定义拆分定义(即,不依赖于内置的split方法).

第1课:预拆分表通常是最佳实践,但是您需要以可在键空间中访问所有区域的方式预拆分表. 尽管此示例演示了十六进制键空间的问题,但任何键空间都可能发生相同的问题. 了解您的数据.

第2课:虽然通常不建议这样做,但是只要在键空间中可访问所有创建的区域,使用十六进制键(更常见的是可显示的数据)仍然可以与预分割表一起使用.

总结这个例子,下面是一个例子,说明如何为十六进制键预先创建适当的分割:

public static boolean createTable(Admin admin, HTableDescriptor table, byte[][] splits)
throws IOException {
  try {
    admin.createTable( table, splits );
    return true;
  } catch (TableExistsException e) {
    logger.info("table " + table.getNameAsString() + " already exists");
    // the table already exists...
    return false;
  }
}

public static byte[][] getHexSplits(String startKey, String endKey, int numRegions) {
  byte[][] splits = new byte[numRegions-1][];
  BigInteger lowestKey = new BigInteger(startKey, 16);
  BigInteger highestKey = new BigInteger(endKey, 16);
  BigInteger range = highestKey.subtract(lowestKey);
  BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegions));
  lowestKey = lowestKey.add(regionIncrement);
  for(int i=0; i < numRegions-1;i++) {
    BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i)));
    byte[] b = String.format("%016x", key).getBytes();
    splits[i] = b;
  }
  return splits;
}

36. Number of Versions

36.1. Maximum Number of Versions

通过HColumnDescriptor为每个列系列配置要存储的最大行版本数. 为最大版本默认值为1.这是一个重要的参数,因为在描述数据模型部分HBase的覆盖行的值,而是通过时间(和限定),而存储每行不同的值. 大型压缩期间将删除多余的版本. 最大版本的数量可能需要根据应用程序的需要增加或减少.

不建议将最大版本数设置为过高的级别(例如,数百个或更多),除非您非常喜欢那些旧值,因为这会大大增加StoreFile的大小.

36.2. Minimum Number of Versions

与最大行版本数类似,通过HColumnDescriptor为每个列系列配置要保留的最小行版本数. 最低版本的默认值为0,这表示该功能已禁用. 参数与时间的生存参数一起使用,并且可以与行版本的数量参数,以允许配置,例如"保留的数据的最后Ť分钟值得,至多N个版本进行组合行版本的最小数量, 但至少保持M个版本在 " 附近 "(其中M是最小行版本数的值,M <N). 仅当为列系列启用生存时间时才应设置此参数,并且该参数必须小于行版本的数量.

37. Supported Datatypes

HBase通过PutResult支持" bytes-in / bytes-out"接口,因此任何可以转换为字节数组的内容都可以存储为值. 输入可以是字符串,数字,复杂的对象,甚至是图像,只要它们可以呈现为字节即可.

值的大小有实际限制(例如,在HBase中存储10-50MB的对象可能要求太多); 在邮件列表中搜索有关此主题的对话. HBase中的所有行均符合Data Model ,其中包括版本控制. 在进行设计时,请考虑到这一点,以及ColumnFamily的块大小.

37.1. Counters

值得特别提及的一种受支持的数据类型是"计数器"(即执行原子原子递增数字的功能). 请参阅Table 增量 .

计数器同步是在RegionServer上完成的,而不是在客户端上完成的.

38. Joins

如果您有多个表,请不要忘记将[joins]纳入模式设计的可能性.

39. Time To Live (TTL)

ColumnFamilies可以设置以秒为单位的TTL长度,并且一旦达到到期时间,HBase将自动删除行. 这适用于一行的所有版本-甚至是当前版本. 在HBase中为该行编码的TTL时间以UTC指定.

较小的压缩会删除仅包含过期行的存储文件. 将hbase.store.delete.expired.storefile设置为false将禁用此功能. 将最小版本数设置为非0也会禁用此功能.

有关更多信息,请参见HColumnDescriptor .

HBase的最新版本还支持设置每个单元的生存时间. 有关更多信息,请参见HBASE-10560 . 使用mutation#setTTL将单元TTL作为属性提交给突变请求(追加,增量,放置等). 如果设置了TTL属性,它将应用于通过该操作在服务器上更新的所有单元. 单元TTL处理和ColumnFamily TTL之间有两个显着差异:

  • 单元TTL以毫秒为单位而不是秒.

  • 单元格TTL无法将单元格的有效寿命延长到ColumnFamily级别TTL设置之外.

40. Keeping Deleted Cells

By default, delete markers extend back to the beginning of time. Therefore, Get or Scan operations will not see a deleted cell (row or column), even when the Get or Scan operation indicates a time range before the delete marker was placed.

ColumnFamilies可以选择保留已删除的单元格. 在这种情况下,只要这些操作指定的时间范围在会影响该单元格的任何删除的时间戳记之前结束,仍然可以检索已删除的单元格. 即使存在删除操作,这也可以进行时间点查询.

删除的单元格仍然受TTL的约束,并且删除的单元格永远不会超过"最大版本数". 新的"原始"扫描选项返回所有已删除的行和删除标记.

例18.使用HBase Shell更改KEEP_DELETED_CELLS的值
hbase> hbase> alter ‘t1′, NAME => ‘f1′, KEEP_DELETED_CELLS => true
例子19.使用API​​更改KEEP_DELETED_CELLS的值
...
HColumnDescriptor.setKeepDeletedCells(true);
...

让我们说明在表上设置KEEP_DELETED_CELLS属性的基本效果.

首先,没有:

create 'test', {NAME=>'e', VERSIONS=>2147483647}
put 'test', 'r1', 'e:c1', 'value', 10
put 'test', 'r1', 'e:c1', 'value', 12
put 'test', 'r1', 'e:c1', 'value', 14
delete 'test', 'r1', 'e:c1',  11

hbase(main):017:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                              COLUMN+CELL
 r1                                              column=e:c1, timestamp=14, value=value
 r1                                              column=e:c1, timestamp=12, value=value
 r1                                              column=e:c1, timestamp=11, type=DeleteColumn
 r1                                              column=e:c1, timestamp=10, value=value
1 row(s) in 0.0120 seconds

hbase(main):018:0> flush 'test'
0 row(s) in 0.0350 seconds

hbase(main):019:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                              COLUMN+CELL
 r1                                              column=e:c1, timestamp=14, value=value
 r1                                              column=e:c1, timestamp=12, value=value
 r1                                              column=e:c1, timestamp=11, type=DeleteColumn
1 row(s) in 0.0120 seconds

hbase(main):020:0> major_compact 'test'
0 row(s) in 0.0260 seconds

hbase(main):021:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                              COLUMN+CELL
 r1                                              column=e:c1, timestamp=14, value=value
 r1                                              column=e:c1, timestamp=12, value=value
1 row(s) in 0.0120 seconds

请注意如何释放删除单元格.

现在,仅在表上设置了KEEP_DELETED_CELLS运行相同的测试(您可以执行表或每个列的家庭):

hbase(main):005:0> create 'test', {NAME=>'e', VERSIONS=>2147483647, KEEP_DELETED_CELLS => true}
0 row(s) in 0.2160 seconds

=> Hbase::Table - test
hbase(main):006:0> put 'test', 'r1', 'e:c1', 'value', 10
0 row(s) in 0.1070 seconds

hbase(main):007:0> put 'test', 'r1', 'e:c1', 'value', 12
0 row(s) in 0.0140 seconds

hbase(main):008:0> put 'test', 'r1', 'e:c1', 'value', 14
0 row(s) in 0.0160 seconds

hbase(main):009:0> delete 'test', 'r1', 'e:c1',  11
0 row(s) in 0.0290 seconds

hbase(main):010:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                                                                          COLUMN+CELL
 r1                                                                                          column=e:c1, timestamp=14, value=value
 r1                                                                                          column=e:c1, timestamp=12, value=value
 r1                                                                                          column=e:c1, timestamp=11, type=DeleteColumn
 r1                                                                                          column=e:c1, timestamp=10, value=value
1 row(s) in 0.0550 seconds

hbase(main):011:0> flush 'test'
0 row(s) in 0.2780 seconds

hbase(main):012:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                                                                          COLUMN+CELL
 r1                                                                                          column=e:c1, timestamp=14, value=value
 r1                                                                                          column=e:c1, timestamp=12, value=value
 r1                                                                                          column=e:c1, timestamp=11, type=DeleteColumn
 r1                                                                                          column=e:c1, timestamp=10, value=value
1 row(s) in 0.0620 seconds

hbase(main):013:0> major_compact 'test'
0 row(s) in 0.0530 seconds

hbase(main):014:0> scan 'test', {RAW=>true, VERSIONS=>1000}
ROW                                                                                          COLUMN+CELL
 r1                                                                                          column=e:c1, timestamp=14, value=value
 r1                                                                                          column=e:c1, timestamp=12, value=value
 r1                                                                                          column=e:c1, timestamp=11, type=DeleteColumn
 r1                                                                                          column=e:c1, timestamp=10, value=value
1 row(s) in 0.0650 seconds

KEEP_DELETED_CELLS是避免将单元格从HBase中删除的唯一原因是删除标记. 因此,在启用KEEP_DELETED_CELLS的情况下,如果您编写的版本超过配置的最大值,或者您拥有TTL并且单元格超出配置的超时时间,则删除的单元格将被删除.

41. Secondary Indexes and Alternate Query Paths

这部分也可以题为"如果我的表rowkey看起来是这样 ,但我也希望我的查询表那样 ." dist列表上的一个常见示例是其中行键的格式为" user-timestamp",但是对于某些时间范围内的用户活动有报告要求. 因此,由用户进行选择很容易,因为它处于键的引导位置,而时间却不然.

解决这一问题的最佳方法没有一个答案,因为这取决于...

  • 用户数

  • 数据大小和数据到达率

  • 报告要求的灵活性(例如,完全临时的日期选择与预配置的范围)

  • 所需的查询执行速度(例如,对于某些临时报告,90秒可能是合理的,而对于另一些报告,这可能太长)

解决方案还受群集大小以及必须在解决方案上投入多少处理能力的影响. 常用技术在下面的小节中. 这是方法的综合列表,但并不详尽.

二级索引需要额外的群集空间和处理也就不足为奇了. 这正是RDBMS中发生的情况,因为创建备用索引的操作需要空间和处理周期来进行更新. RDBMS产品在这方面更先进,可以立即处理替代索引管理. 但是,HBase在较大的数据量时可更好地扩展,因此这是一个功能折衷.

实施任何一种方法时,请注意Apache HBase性能调优 .

此外,请在此dist-list线程HBase中查看David Butler的响应,邮件#用户-Stargate + hbase

41.1. Filter Query

根据情况,使用Client Request Filters是合适的. 在这种情况下,不会创建二级索引. 但是,请勿尝试从应用程序(即单线程客户端)对大型表进行完全扫描.

41.2. Periodic-Update Secondary Index

可以在另一个表中创建二级索引,该表通过MapReduce作业定期更新. 该作业可以在一天之内执行,但是根据负载策略,它仍可能与主数据表不同步.

See mapreduce.example.readwrite for more information.

41.3. Dual-Write Secondary Index

另一种策略是在将数据发布到群集时(例如,写入数据表,写入索引表)构建辅助索引. 如果在已存在数据表之后采用这种方法,则对于具有MapReduce作业的辅助索引,将需要进行引导(请参见secondary.indexes.periodic ).

41.4. Summary Tables

在时间范围很广的地方(例如,长达一年的报告),并且数据量很大,因此汇总表是一种常见的方法. 这些将通过MapReduce作业生成到另一个表中.

有关更多信息,请参见mapreduce.example.summary .

41.5. Coprocessor Secondary Index

协处理器的行为类似于RDBMS触发器. 这些以0.92添加. 有关更多信息,请参见协处理器.

42. Constraints

HBase当前在传统(SQL)数据库中支持"约束". 建议将Constraints用于约束表中属性的业务规则(例如,确保值在1到10的范围内). 约束也可以用于强制执行参照完整性,但是强烈建议不要这样做,因为它将大大降低启用完整性检查的表的写吞吐量. 有关使用约束的大量文档,请参见:自0.94版以来的约束 .

43. Schema Design Case Studies

下面将介绍一些使用HBase的典型数据摄取用例,以及如何进行行键设计和构造. 注意:这仅是潜在方法的说明,而不是详尽的清单. 了解您的数据,并了解您的处理要求.

强烈建议您在阅读这些案例研究之前先阅读HBase和Schema Design的其余部分.

描述了以下案例研究:

  • 日志数据/时间序列数据

  • 在类固醇上记录数据/时间序列

  • Customer/Order

  • 高/宽/中方案设计

  • 清单资料

43.1. Case Study - Log Data and Timeseries Data

假设正在收集以下数据元素.

  • Hostname

  • Timestamp

  • 记录事件

  • Value/message

我们可以将它们存储在名为LOG_DATA的HBase表中,但是行键是什么? 从这些属性中,行键将是主机名,时间戳和日志事件的某种组合-但是具体是什么?

43.1.1. Timestamp In The Rowkey Lead Position

行键[timestamp][hostname][log-event]遭受单调增加行键/时间序列数据中描述的单调增加行键问题.

通过在时间戳上执行mod操作,在dist列表中经常提到另一种关于"存储桶"时间戳的模式. 如果面向时间的扫描很重要,那么这可能是一种有用的方法. 必须注意存储桶的数量,因为这将需要相同数量的扫描才能返回结果.

long bucket = timestamp % numBuckets;

构造:

[bucket][timestamp][hostname][log-event]

如上所述,要选择特定时间范围的数据,将需要对每个存储桶执行一次扫描. 例如,100个存储桶将在键空间中提供广泛的分布,但是需要100次扫描才能获得单个时间戳的数据,因此需要权衡取舍.

43.1.2. Host In The Rowkey Lead Position

如果有大量主机在键空间上分布写入和读取操作,则行键[hostname][log-event][timestamp]是候选. 如果按主机名扫描是优先级,则此方法将很有用.

43.1.3. Timestamp, or Reverse Timestamp?

如果最重要的访问路径是提取最新事件,则将时间戳存储为反向时间戳(例如, timestamp = Long.MAX_VALUE – timestamp )将创建能够对[hostname][log-event] ,以快速获取最近捕获的事件.

两种方法都没有错,仅取决于最适合这种情况的方法.

反向扫描API

HBASE-4811实现了一个API,可以反向扫描表或表中的范围,从而减少了为进行正向或反向扫描而优化架构的需求. HBase 0.98和更高版本中提供了此功能. 有关更多信息,请参见https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Scan.html#setReversed(boolean .

43.1.4. Variangle Length or Fixed Length Rowkeys?

重要的是要记住,行键标记在HBase的每一列上. 如果主机名是a并且事件类型是e1则结果行键将非常小. 但是,如果提取的主机名是myserver1.mycompany.com ,事件类型是com.package1.subpackage2.subsubpackage3.ImportantService ,该com.package1.subpackage2.subsubpackage3.ImportantService办?

在行键中使用某些替换可能很有意义. 至少有两种方法:散列和数字. 在" Rowkey Lead Position中的主机名"示例中,它可能如下所示:

带有哈希的复合行键:

  • [主机名的MD5哈希] = 16个字节

  • [事件类型的MD5哈希] = 16个字节

  • [时间戳记] = 8个字节

带有数字替换的复合行键:

对于这种方法,除了LOG_DATA外,还需要另一个查询表,称为LOG_TYPES. LOG_TYPES的行键为:

  • [类型](例如,指示主机名与事件类型的字节)

  • [bytes] variable length bytes for raw hostname or event-type.

此行键的列可能是带有指定编号的长整数,可以使用http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/Table.html#incrementColumnValue(byte获得,%20byte [],%20byte [],%20long%29 [HBase计数器].

因此,生成的复合行键将为:

  • [substituted long for hostname] = 8 bytes

  • [事件类型的长整数替换] = 8个字节

  • [时间戳记] = 8个字节

在哈希或数字替换方法中,主机名和事件类型的原始值可以存储为列.

43.2. Case Study - Log Data and Timeseries Data on Steroids

这实际上是OpenTSDB方法. OpenTSDB要做的是重写数据,并在特定时间段内将行打包为列. 有关详细说明,请参见:链接:http://opentsdb.net/schema.html,以及从HBaseCon2012的OpenTSDB获得的经验教训 .

但这就是一般概念的工作原理:例如以这种方式摄取数据...

[hostname][log-event][timestamp1]
[hostname][log-event][timestamp2]
[hostname][log-event][timestamp3]

每个详细事件都有单独的行键,但是像这样重写...

[hostname][log-event][timerange]

并将上述每个事件转换为以相对于开始时间范围的时间偏移(例如,每5分钟)存储的列. 这显然是一种非常先进的处理技术,但是HBase使得这成为可能.

43.3. Case Study - Customer/Order

假设使用HBase来存储客户和订单信息. 提取了两种核心记录类型:客户记录类型和订单记录类型.

The Customer record type would include all the things that you’d typically expect:

  • 顾客号码

  • 顾客姓名

  • 地址(例如,城市,州,邮政编码)

  • 电话号码等

订单记录类型将包括以下内容:

  • 顾客号码

  • 订单号

  • 销售日期

  • A series of nested objects for shipping locations and line-items (see Order Object Design for details)

假设客户编号和销售订单的组合唯一地标识了一个订单,则这两个属性将组成行键,特别是一个组合键,例如:

[customer number][order number]

用于ORDER表. 但是,还有更多的设计决策: 原始值是行键的最佳选择吗?

Log Data用例中的相同设计问题在这里也面临着我们. 客户编号的键空间是什么,格式是什么(例如,数字?字母数字?),因为在HBase中使用固定长度的键以及可以在键空间中支持合理分布的键是有利的,类似选项出现:

带有哈希的复合行键:

  • [客户编号的MD5] = 16字节

  • [订单号的MD5] = 16个字节

复合数字/哈希组合行键:

  • [substituted long for customer number] = 8 bytes

  • [订单号的MD5] = 16个字节

43.3.1. Single Table? Multiple Tables?

传统的设计方法将为客户和销售提供单独的表格. 另一个选择是将多个记录类型打包到一个表中(例如CUSTOMER ++).

客户记录类型行键:

  • [customer-id]

  • [type] =表示客户记录类型为" 1"的类型

订单记录类型行键:

  • [customer-id]

  • [type] =指示订单记录类型为" 2"的类型

  • [order]

这种特定的CUSTOMER ++方法的优点是可以通过客户ID组织许多不同的记录类型(例如,一次扫描就可以为您提供有关该客户的所有信息). 缺点是扫描特定的记录类型并不容易.

43.3.2. Order Object Design

现在我们需要解决如何对Order对象建模. 假定类结构如下:

Order

(一个订单可以有多个发货地点

LineItem

(一个ShippingLocation可以有多个LineItem

存储此数据有多种选择.

Completely Normalized

使用这种方法,将为ORDER,SHIPPING_LOCATION和LINE_ITEM提供单独的表.

上面描述了ORDER表的行键: schema.casestudies.custorder

SHIPPING_LOCATION的复合行键如下所示:

  • [order-rowkey]

  • [托运地点编号](例如,第一地点,第二地点等)

LINE_ITEM表的复合行键如下所示:

  • [order-rowkey]

  • [托运地点编号](例如,第一地点,第二地点等)

  • [订单项编号](例如,第一个订单项,第二个订单项等)

这种标准化的模型可能是RDBMS的方法,但这并不是HBase的唯一选择. 这种方法的缺点是要检索有关任何订单的信息,您将需要:

  • 进入订单的ORDER表

  • 在SHIPPING_LOCATION表上扫描该订单以获取ShippingLocation实例

  • 在LINE_ITEM上扫描每个送货地点

当然,这是RDBMS会在后台进行的操作,但是由于HBase中没有联接,因此您只需要了解这一事实.

Single Table With Record Types

使用这种方法,将存在一个单个表ORDER,其中包含

订单行键已在上面进行了描述: schema.casestudies.custorder

  • [order-rowkey]

  • [订单记录类型]

ShippingLocation复合行键将如下所示:

  • [order-rowkey]

  • [运输记录类型]

  • [托运地点编号](例如,第一地点,第二地点等)

LineItem复合行键将如下所示:

  • [order-rowkey]

  • [LINE记录类型]

  • [托运地点编号](例如,第一地点,第二地点等)

  • [订单项编号](例如,第一个订单项,第二个订单项等)

Denormalized

"带有记录类型的单表"方法的一种变体是对某些对象层次结构进行非规范化和扁平化,例如将ShippingLocation属性折叠到每个LineItem实例上.

LineItem复合行键将如下所示:

  • [order-rowkey]

  • [LINE记录类型]

  • [订单项编号](例如,第一个订单项,第二个订单项等,必须注意整个订单中的商品是唯一的)

而LineItem列将如下所示:

  • itemNumber

  • quantity

  • price

  • shipToLine1(从ShippingLocation规范化)

  • shipToLine2(从ShippingLocation规范化)

  • shipToCity(从ShippingLocation规范化)

  • shipToState(从ShippingLocation规范化)

  • shipToZip(从ShippingLocation规范化)

The pros of this approach include a less complex object hierarchy, but one of the cons is that updating gets more complicated in case any of this information changes.

Object BLOB

通过这种方法,整个Order对象图以一种或另一种方式被视为BLOB. 例如,上面描述了ORDER表的行键: schema.casestudies.custorder和一个名为" order"的列将包含一个可以反序列化的对象,该对象包含容器Order,ShippingLocations和LineItems.

这里有许多选项:JSON,XML,Java序列化,Avro,Hadoop可写文件等.它们都是相同方法的变体:将对象图编码为字节数组. 如果对象模型发生更改,以确保仍可以从HBase中读取较旧的持久化结构,则应谨慎使用此方法以确保向后兼容.

专业人士能够以最少的I / O管理复杂的对象图(例如,在此示例中为单个"按订单获取HBase"),但是缺点包括上述关于序列化向后兼容性,序列化的语言依赖性(例如Java序列化)的警告仅适用于Java客户端),必须对整个对象进行反序列化以在BLOB中获取任何信息这一事实,以及使诸如Hive之类的框架无法与此类自定义对象一起使用的困难.

43.4. Case Study - "Tall/Wide/Middle" Schema Design Smackdown

本节将描述出现在dist列表中的其他架构设计问题,特别是有关高大桌子的问题. 这些是一般准则,而不是法律-每个应用程序都必须考虑自己的需求.

43.4.1. Rows vs. Versions

一个常见的问题是,是应该使用行还是HBase的内置版本控制. 上下文通常是要保留行的"很多"版本的位置(例如,该位置明显高于HBase默认的1个最大版本). 行方法将需要在行键的某些部分中存储时间戳,以便它们不会在每次后续更新时都被覆盖.

首选项:行(通常而言).

43.4.2. Rows vs. Columns

另一个常见的问题是人们应该选择行还是列. 该上下文通常在宽表的极端情况下使用,例如具有1行具有1百万个属性,或具有1百万行具有1个每列的属性.

首选项:行(通常而言). 需要明确的是,该准则是在非常广泛的情况下使用的,而不是在需要存储几十或数百列的标准用例中使用的. 但是,这两个选项之间还有一条中间路径,即"行作为列".

43.4.3. Rows as Columns

行与列之间的中间路径是将某些行的数据打包成独立的行. OpenTSDB是这种情况的最佳示例,其中单行代表定义的时间范围,然后将离散事件视为列. 这种方法通常更复杂,并且可能需要重新写入数据的额外复杂性,但具有I / O效率高的优点. 有关此方法的概述,请参见schema.casestudies.log-steroids .

43.5. Case Study - List Data

以下是来自用户dist-list的一个相当常见的问题的交流:如何在Apache HBase中处理每个用户的列表数据.

  • QUESTION *

We’re looking at how to store a large amount of (per-user) list data in HBase, and we were trying to figure out what kind of access pattern made the most sense. One option is store the majority of the data in a key, so we could have something like:

<FixedWidthUserName><FixedWidthValueId1>:"" (no value)
<FixedWidthUserName><FixedWidthValueId2>:"" (no value)
<FixedWidthUserName><FixedWidthValueId3>:"" (no value)

我们还有另一个选择是完全使用以下方法:

<FixedWidthUserName><FixedWidthPageNum0>:<FixedWidthLength><FixedIdNextPageNum><ValueId1><ValueId2><ValueId3>...
<FixedWidthUserName><FixedWidthPageNum1>:<FixedWidthLength><FixedIdNextPageNum><ValueId1><ValueId2><ValueId3>...

每行将包含多个值. 因此,在一种情况下,读取前三十个值将是:

scan { STARTROW => 'FixedWidthUsername' LIMIT => 30}

在第二种情况下

get 'FixedWidthUserName\x00\x00\x00\x00'

一般的使用模式是只读取这些列表的前30个值,而很少的访问量会更深入地读取列表. 在这些列表中,某些用户的总价值为⇐30,而某些用户的百万价值(即幂律分布)

单值格式似乎会在HBase上占用更多空间,但会提供一些改进的检索/分页灵活性. 与获取扫描分页相比,通过获取分页是否会有明显的性能优势?

我最初的理解是,如果我们的分页大小未知(并且缓存设置适当),则扫描应该更快,但是如果我们始终需要相同的页面大小,则扫描应该更快. 我最终听到不同的人告诉我关于绩效的相反的事情. 我认为页面大小相对一致,因此对于大多数用例,我们可以保证在固定页面长度的情况下只需要一页数据. 我还要假设我们很少进行更新,但是可能在这些列表的中间插入了插入(这意味着我们需要更新所有后续行).

感谢您的帮助/建议/后续问题.

  • ANSWER *

如果我理解正确,那么您最终将尝试以"用户,valueid,值"的形式存储三元组,对吗? 例如,类似:

"user123, firstname, Paul",
"user234, lastname, Smith"

(但是用户名是固定宽度,而valueid是固定宽度).

而且,您的访问模式如下:"对于用户X,列出接下来的30个值,以valueid Y开头". 那正确吗? 这些值应该按valueid排序返回吗?

tl; dr版本是每个用户+值可能只包含一行,并且除非您确实确定需要,否则不要自己构建复杂的行内分页方案.

您的两个选择反映了人们在设计HBase模式时遇到的一个常见问题:我应该"高"还是"宽"? 您的第一个架构是"高层":每一行代表一个用户一个值,因此表中有许多行针对每个用户; 行键是用户+ valueid,并且(大概)将有一个单列限定符,表示"值". 如果您要按行键按排序顺序扫描行(这是我上面的问题,关于这些ID是否正确排序),这很好. 您可以在任何用户名+值id处开始扫描,然后读取下一个30并完成. 您要放弃的是能够为一个用户在所有行周围拥有事务保证,但这听起来并不是您需要的. 通常建议以这种方式进行操作(请参见此处的链接:http://hbase.apache.org/book.html#schema.smackdown).

第二个选项是"宽":使用不同的限定符(其中的限定符是valueid)将一堆值存储在一行中. 这样做的简单方法是只将一个用户的所有值存储在一行中. 我猜您跳到了"分页"版本,因为您假设在单行中存储数百万列会降低性能,这可能是正确的,也可能不是正确的. 只要您不打算在单个请求中执行太多操作,或者执行诸如扫描并返回该行中所有单元格之类的操作,从根本上讲,这应该不会更糟. 客户端具有允许您获取特定列列的方法.

请注意,两种情况都不会从根本上使用更多的磁盘空间. 您只是将标识信息的一部分"左移"(左移至选项1中的行键)或向右(右移至选项2中的列限定符). 在幕后,每个键/值仍存储整个行键和列族名称. (如果这有点令人困惑,请花一个小时,观看Lars George的精彩视频,内容涉及了解HBase模式设计:链接:http://www.youtube.com/watch?v = _HLoH_PgrLk).

如您所注意到的那样,手动分页版本具有更多的复杂性,例如必须跟踪每个页面中有多少东西,如果插入新值则需要重新洗牌等.这似乎要复杂得多. 它在极高的吞吐量下可能具有一些轻微的速度优势(或劣势!),要真正知道这一点,唯一的方法就是尝试一下. 如果您没有时间进行双向构建和比较,我的建议是从最简单的选项开始(每个用户+值一行). 从简单开始并进行迭代! :)

44. Operational and Performance Configuration Options

有关操作和性能模式设计选项的更多信息,请参见性能部分perf.schema ,例如Bloom Filters,表配置的区域大小,压缩和块大小.

HBase and MapReduce

Apache MapReduce是用于分析大量数据的软件框架,并且是最常用于Apache Hadoop的框架. MapReduce本身不在本文档的范围之内. 开始使用MapReduce的好地方是http://hadoop.apache.org/docs/r2.6.0/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html . MapReduce版本2(MR2)现在是YARN的一部分.

本章讨论在HBase中对数据使用MapReduce时需要采取的特定配置步骤. 此外,它还讨论了HBase和MapReduce作业之间的其他交互和问题.

mapred and mapreduce

与MapReduce本身一样,HBase中有两个mapreduce软件包: org.apache.hadoop.hbase.mapredorg.apache.hadoop.hbase.mapreduce . 前者使用旧样式的API,而后者则使用新样式. 后者具有更多功能,尽管您通常可以在较早的软件包中找到等效的软件包. 选择MapReduce部署随附的软件包. 如有疑问或从头开始,请选择org.apache.hadoop.hbase.mapreduce . 在下面的注释中,我们指的是oahhmapreduce,但如果您使用的是oahhmapred,则将其替换.

45. HBase, MapReduce, and the CLASSPATH

默认情况下,部署到MapReduce群集的MapReduce作业无法访问$HBASE_CONF_DIR下的HBase配置或HBase类.

要为MapReduce作业提供所需的访问权限,您可以将hbase-site.xml添加到$ HADOOP_HOME / conf中 ,并将HBase jars添加到$ HADOOP_HOME / lib目录中. 然后,您需要在整个集群中复制这些更改. 或者,您可以编辑$ HADOOP_HOME / conf / hadoop-env.sh并将它们添加到HADOOP_CLASSPATH变量中. 但是,不建议使用这种方法,因为它将使用HBase引用污染您的Hadoop安装. 它还要求您在Hadoop可以使用HBase数据之前重新启动Hadoop集群.

推荐的方法是让HBase自己添加其依赖罐,并使用HADOOP_CLASSPATH-libjars .

Since HBase 0.90.x, HBase adds its dependency JARs to the job configuration itself. The dependencies only need to be available on the local CLASSPATH. The following example runs the bundled HBase RowCounter MapReduce job against a table named usertable. If you have not set the environment variables expected in the command (the parts prefixed by a $ sign and surrounded by curly braces), you can use the actual system paths instead. Be sure to use the correct version of the HBase JAR for your system. The backticks (` symbols) cause ths shell to execute the sub-commands, setting the output of hbase classpath (the command to dump HBase CLASSPATH) to HADOOP_CLASSPATH. This example assumes you use a BASH-compatible shell.

$ HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase classpath` ${HADOOP_HOME}/bin/hadoop jar ${HBASE_HOME}/lib/hbase-server-VERSION.jar rowcounter usertable

当命令在内部运行时,HBase JAR会找到所需的依赖项,并将其添加到MapReduce作业配置中. 有关如何完成此操作,请参见TableMapReduceUtil#addDependencyJars(org.apache.hadoop.mapreduce.Job)的源.

hbase mapredcp命令还可以帮助您转储MapReduce所需的CLASSPATH条目,这些条目与TableMapReduceUtil#addDependencyJars将添加的jar相同. 您可以将它们与HBase conf目录一起添加到HADOOP_CLASSPATH . 对于不打包其依赖性或不调用TableMapReduceUtil#addDependencyJars ,以下命令结构是必需的:

$ HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase mapredcp`:${HBASE_HOME}/conf hadoop jar MyApp.jar MyJobMainClass -libjars $(${HBASE_HOME}/bin/hbase mapredcp | tr ':' ',') ...

如果您从其构建目录而不是安装位置运行HBase,则该示例可能无法正常工作. 您可能会看到类似以下的错误:

java.lang.RuntimeException: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.mapreduce.RowCounter$RowCounterMapper

如果发生这种情况,请尝试按如下所示修改命令,以便它使用构建环境中target /目录中的HBase JAR.

$ HADOOP_CLASSPATH=${HBASE_BUILD_HOME}/hbase-server/target/hbase-server-VERSION-SNAPSHOT.jar:`${HBASE_BUILD_HOME}/bin/hbase classpath` ${HADOOP_HOME}/bin/hadoop jar ${HBASE_BUILD_HOME}/hbase-server/target/hbase-server-VERSION-SNAPSHOT.jar rowcounter usertable
在0.96.1至0.98.4之间通知HBase的MapReduce用户

使用HBase的某些MapReduce作业无法启动. 该症状是与以下内容类似的异常:

Exception in thread "main" java.lang.IllegalAccessError: class
    com.google.protobuf.ZeroCopyLiteralByteString cannot access its superclass
    com.google.protobuf.LiteralByteString
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:792)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at
    org.apache.hadoop.hbase.protobuf.ProtobufUtil.toScan(ProtobufUtil.java:818)
    at
    org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.convertScanToString(TableMapReduceUtil.java:433)
    at
    org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:186)
    at
    org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:147)
    at
    org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:270)
    at
    org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:100)
...

这是由HBASE-9867中引入的优化引起的,该优化无意中引入了类加载器依赖项.

这将同时使用-libjars选项和"胖罐"(将其运行时依赖项打包在嵌套的lib文件夹中的那些文件)影响这两个作业.

In order to satisfy the new classloader requirements, hbase-protocol.jar must be included in Hadoop’s classpath. See HBase, MapReduce, and the CLASSPATH for current recommendations for resolving classpath errors. The following is included for historical purposes.

可以通过符号链接或将jar复制到新位置,在Hadoop的lib目录中包含对hbase-protocol.jar的引用来在系统范围内解决此问题.

通过在作业提交时将其包含在HADOOP_CLASSPATH环境变量中,也可以基于每个作业启动它. 启动打包其依赖关系的作业时,以下所有三个作业启动命令均满足此要求:

$ HADOOP_CLASSPATH=/path/to/hbase-protocol.jar:/path/to/hbase/conf hadoop jar MyJob.jar MyJobMainClass
$ HADOOP_CLASSPATH=$(hbase mapredcp):/path/to/hbase/conf hadoop jar MyJob.jar MyJobMainClass
$ HADOOP_CLASSPATH=$(hbase classpath) hadoop jar MyJob.jar MyJobMainClass

对于不打包依赖关系的jar,以下命令结构是必需的:

$ HADOOP_CLASSPATH=$(hbase mapredcp):/etc/hbase/conf hadoop jar MyApp.jar MyJobMainClass -libjars $(hbase mapredcp | tr ':' ',') ...

有关此问题的进一步讨论,请参见HBASE-10304 .

46. MapReduce Scan Caching

TableMapReduceUtil现在恢复在传入的Scan对象上设置扫描程序缓存(将结果返回给客户端之前缓存的行数)的选项.由于HBase 0.95( HBASE-11558 )中的错误,该功能丢失了,对于HBase 0.98.5和0.96.3是固定的. 选择扫描程序缓存的优先顺序如下:

  1. 在扫描对象上设置的缓存设置.

  2. 通过配置选项hbase.client.scanner.caching指定的缓存设置,可以在hbase-site.xml中手动设置,也可以通过辅助方法TableMapReduceUtil.setScannerCaching() .

  3. 默认值HConstants.DEFAULT_HBASE_CLIENT_SCANNER_CACHING设置为100 .

优化缓存设置是客户端等待结果的时间与客户端需要接收的结果集数量之间的平衡. 如果缓存设置太大,客户端可能会等待很长时间,甚至请求可能会超时. 如果设置太小,则扫描需要分多次返回结果. 如果您将扫描视为铲子,则较大的缓存设置类似于较大的铲子,而较小的缓存设置等效于进行更多铲斗以填充铲斗.

上面提到的优先级列表允许您设置合理的默认值,并针对特定操作覆盖它.

有关更多详细信息,请参见Scan的API文档.

47. Bundled HBase MapReduce Jobs

HBase JAR还可以用作某些捆绑的MapReduce作业的驱动程序. 要了解捆绑的MapReduce作业,请运行以下命令.

$ ${HADOOP_HOME}/bin/hadoop jar ${HBASE_HOME}/hbase-server-VERSION.jar
An example program must be given as the first argument.
Valid program names are:
  copytable: Export a table from local cluster to peer cluster
  completebulkload: Complete a bulk data load.
  export: Write table data to HDFS.
  import: Import data written by Export.
  importtsv: Import data in TSV format.
  rowcounter: Count rows in HBase table

每个有效的程序名称都是捆绑的MapReduce作业. 要运行作业之一,请在以下示例之后对命令进行建模.

$ ${HADOOP_HOME}/bin/hadoop jar ${HBASE_HOME}/hbase-server-VERSION.jar rowcounter myTable

48. HBase as a MapReduce Job Data Source and Data Sink

HBase可用作MapReduce作业的数据源TableInputFormat和数据接收器TableOutputFormatMultiTableOutputFormat . 编写MapReduce作业以读取或写入HBase时,建议将TableMapper和/或TableReducer子类 . 有关基本用法,请参见无作用传递类IdentityTableMapperIdentityTableReducer . 有关更多示例,请参阅RowCounter或查看org.apache.hadoop.hbase.mapreduce.TestTableMapReduce单元测试.

如果运行将HBase用作源或接收器的MapReduce作业,则需要在配置中指定源和接收器表及列名称.

从HBase读取时, TableInputFormat向HBase请求区域列表,并生成一个地图,该地图可以是map-per-region地图或mapreduce.job.maps地图,以较小者为准. 如果您的工作只有两个地图,请将mapreduce.job.maps增大到大于区域数的数字. 如果您在每个节点上运行TaskTracer / NodeManager和RegionServer,则地图将在相邻的TaskTracker / NodeManager上运行. 写入HBase时,应避免执行Reduce步骤,然后从地图内部写回HBase. 当您的工作不需要MapReduce对地图发出的数据执行的排序和排序规则时,此方法将起作用. 插入时,HBase会进行"排序",因此除非需要,否则就不会进行点双重排序(以及MapReduce集群周围的数据改组). 如果不需要精简,则地图可能会在作业结束时发出为报告而处理的记录计数,或者将精简数量设置为零并使用TableOutputFormat. 如果在您的情况下可以执行Reduce步骤,则通常应使用多个reducer,以便将负载分散在HBase群集上.

一个新的HBase分区程序HRegionPartitioner可以运行与现有区域数一样多的缩减程序 . HRegionPartitioner适用于表较大且上传完成后不会显着改变现有区域数的情况. 否则,请使用默认分区程序.

49. Writing HFiles Directly During Bulk Import

如果要导入到新表中,则可以绕过HBase API并将内容直接写入文件系统,并格式化为HBase数据文件(HFiles). 您的导入将运行得更快,也许要快一个数量级. 有关此机制如何工作的更多信息,请参见批量加载 .

50. RowCounter Example

所包含的RowCounter的MapReduce作业使用TableInputFormat并执行指定表中的所有行数. 要运行它,请使用以下命令:

$ ./bin/hadoop jar hbase-X.X.X.jar

这将调用HBase MapReduce驱动程序类. 从提供的作业中选择行rowcounter . 这会将行计数器使用建议打印到标准输出. 指定表名,要计数的列和输出目录. 如果您遇到类路径错误,请参见HBase,MapReduce和CLASSPATH .

51. Map-Task Splitting

51.1. The Default HBase MapReduce Splitter

当使用TableInputFormat为MapReduce作业中的HBase表提供源时,其拆分器将为该表的每个区域创建一个映射任务. 因此,如果表中有100个区域,则该作业将有100个映射任务-无论在"扫描"中选择了多少列族.

51.2. Custom Splitters

对于那些对实现自定义拆分器感兴趣的人,请参见getSplits中的getSplits方法. 这就是映射任务分配的逻辑所在.

52. HBase MapReduce Examples

52.1. HBase MapReduce Read Example

以下是以只读方式将HBase用作MapReduce源的示例. 具体来说,有一个Mapper实例,但没有Reducer,并且没有从Mapper发出任何东西. 该工作的定义如下...

Configuration config = HBaseConfiguration.create();
Job job = new Job(config, "ExampleRead");
job.setJarByClass(MyReadJob.class);     // class that contains mapper

Scan scan = new Scan();
scan.setCaching(500);        // 1 is the default in Scan, which will be bad for MapReduce jobs
scan.setCacheBlocks(false);  // don't set to true for MR jobs
// set other scan attrs
...

TableMapReduceUtil.initTableMapperJob(
  tableName,        // input HBase table name
  scan,             // Scan instance to control CF and attribute selection
  MyMapper.class,   // mapper
  null,             // mapper output key
  null,             // mapper output value
  job);
job.setOutputFormatClass(NullOutputFormat.class);   // because we aren't emitting anything from mapper

boolean b = job.waitForCompletion(true);
if (!b) {
  throw new IOException("error with job!");
}

...而mapper实例将扩展TableMapper ...

public static class MyMapper extends TableMapper<Text, Text> {

  public void map(ImmutableBytesWritable row, Result value, Context context) throws InterruptedException, IOException {
    // process data for the row from the Result instance.
   }
}

52.2. HBase MapReduce Read/Write Example

以下是通过MapReduce将HBase用作源和接收器的示例. 此示例将简单地将数据从一个表复制到另一个表.

Configuration config = HBaseConfiguration.create();
Job job = new Job(config,"ExampleReadWrite");
job.setJarByClass(MyReadWriteJob.class);    // class that contains mapper

Scan scan = new Scan();
scan.setCaching(500);        // 1 is the default in Scan, which will be bad for MapReduce jobs
scan.setCacheBlocks(false);  // don't set to true for MR jobs
// set other scan attrs

TableMapReduceUtil.initTableMapperJob(
  sourceTable,      // input table
  scan,             // Scan instance to control CF and attribute selection
  MyMapper.class,   // mapper class
  null,             // mapper output key
  null,             // mapper output value
  job);
TableMapReduceUtil.initTableReducerJob(
  targetTable,      // output table
  null,             // reducer class
  job);
job.setNumReduceTasks(0);

boolean b = job.waitForCompletion(true);
if (!b) {
    throw new IOException("error with job!");
}

需要解释TableMapReduceUtil功能,特别是对于reducer. TableOutputFormat用作outputFormat类,并且在配置上设置了几个参数(例如TableOutputFormat.OUTPUT_TABLE ),并将reducer输出键设置为ImmutableBytesWritable而reducer值设置为Writable . 这些可以由程序员在job和conf上设置,但是TableMapReduceUtil试图使事情变得更容易.

以下是示例映射器,它将创建一个Put并匹配输入的Result并将其发出. 注意:这就是CopyTable实用程序的作用.

public static class MyMapper extends TableMapper<ImmutableBytesWritable, Put>  {

  public void map(ImmutableBytesWritable row, Result value, Context context) throws IOException, InterruptedException {
    // this example is just copying the data from the source table...
      context.write(row, resultToPut(row,value));
    }

    private static Put resultToPut(ImmutableBytesWritable key, Result result) throws IOException {
      Put put = new Put(key.get());
      for (KeyValue kv : result.raw()) {
        put.add(kv);
      }
      return put;
    }
}

实际上没有reducer步骤,因此TableOutputFormat负责Put发送到目标表.

这只是一个示例,开发人员可以选择不使用TableOutputFormat并自己连接到目标表.

52.3. HBase MapReduce Read/Write Example With Multi-Table Output

TODO: MultiTableOutputFormat示例.

52.4. HBase MapReduce Summary to HBase Example

以下示例将HBase用作MapReduce源和接收器,并进行了总结. 本示例将对一个表中某个值的不同实例的数量进行计数,并将这些汇总计数写入另一个表中.

Configuration config = HBaseConfiguration.create();
Job job = new Job(config,"ExampleSummary");
job.setJarByClass(MySummaryJob.class);     // class that contains mapper and reducer

Scan scan = new Scan();
scan.setCaching(500);        // 1 is the default in Scan, which will be bad for MapReduce jobs
scan.setCacheBlocks(false);  // don't set to true for MR jobs
// set other scan attrs

TableMapReduceUtil.initTableMapperJob(
  sourceTable,        // input table
  scan,               // Scan instance to control CF and attribute selection
  MyMapper.class,     // mapper class
  Text.class,         // mapper output key
  IntWritable.class,  // mapper output value
  job);
TableMapReduceUtil.initTableReducerJob(
  targetTable,        // output table
  MyTableReducer.class,    // reducer class
  job);
job.setNumReduceTasks(1);   // at least one, adjust as required

boolean b = job.waitForCompletion(true);
if (!b) {
  throw new IOException("error with job!");
}

在此示例映射器中,选择具有字符串值的列作为要汇总的值. 此值用作从映射器发出的键,并且IntWritable表示实例计数器.

public static class MyMapper extends TableMapper<Text, IntWritable>  {
  public static final byte[] CF = "cf".getBytes();
  public static final byte[] ATTR1 = "attr1".getBytes();

  private final IntWritable ONE = new IntWritable(1);
  private Text text = new Text();

  public void map(ImmutableBytesWritable row, Result value, Context context) throws IOException, InterruptedException {
    String val = new String(value.getValue(CF, ATTR1));
    text.set(val);     // we can only emit Writables...
    context.write(text, ONE);
  }
}

在reducer中,对" 1"进行计数(就像其他任何执行此操作的MR示例一样),然后发出Put .

public static class MyTableReducer extends TableReducer<Text, IntWritable, ImmutableBytesWritable>  {
  public static final byte[] CF = "cf".getBytes();
  public static final byte[] COUNT = "count".getBytes();

  public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
    int i = 0;
    for (IntWritable val : values) {
      i += val.get();
    }
    Put put = new Put(Bytes.toBytes(key.toString()));
    put.add(CF, COUNT, Bytes.toBytes(i));

    context.write(null, put);
  }
}

52.5. HBase MapReduce Summary to File Example

这与上面的摘要示例非常相似,不同的是,它使用HBase作为MapReduce源,但使用HDFS作为接收器. 区别在于作业设置和减速机. 映射器保持不变.

Configuration config = HBaseConfiguration.create();
Job job = new Job(config,"ExampleSummaryToFile");
job.setJarByClass(MySummaryFileJob.class);     // class that contains mapper and reducer

Scan scan = new Scan();
scan.setCaching(500);        // 1 is the default in Scan, which will be bad for MapReduce jobs
scan.setCacheBlocks(false);  // don't set to true for MR jobs
// set other scan attrs

TableMapReduceUtil.initTableMapperJob(
  sourceTable,        // input table
  scan,               // Scan instance to control CF and attribute selection
  MyMapper.class,     // mapper class
  Text.class,         // mapper output key
  IntWritable.class,  // mapper output value
  job);
job.setReducerClass(MyReducer.class);    // reducer class
job.setNumReduceTasks(1);    // at least one, adjust as required
FileOutputFormat.setOutputPath(job, new Path("/tmp/mr/mySummaryFile"));  // adjust directories as required

boolean b = job.waitForCompletion(true);
if (!b) {
  throw new IOException("error with job!");
}

如上所述,在此示例中,以前的Mapper可以不变地运行. 至于Reducer,它是一个"通用" Reducer,而不是扩展TableMapper和发出Puts.

public static class MyReducer extends Reducer<Text, IntWritable, Text, IntWritable>  {

  public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
    int i = 0;
    for (IntWritable val : values) {
      i += val.get();
    }
    context.write(key, new IntWritable(i));
  }
}

52.6. HBase MapReduce Summary to HBase Without Reducer

如果将HBase用作化简器,也可以不使用化简器执行摘要.

HBase目标表将需要存在以用于作业摘要. Table方法incrementColumnValue将用于原子地递增值. 从性能的角度来看,最好保留一个值映射,并为每个映射任务增加其值,并在映射器的cleanup方法期间对每个键进行一次更新. 但是,您的里程可能会有所不同,具体取决于要处理的行数和唯一键.

In the end, the summary results are in HBase.

52.7. HBase MapReduce Summary to RDBMS

有时,为RDBMS生成摘要更为合适. 对于这些情况,可以通过定制化简器直接向RDBMS生成摘要. setup方法可以连接到RDBMS(可以通过上下文中的自定义参数传递连接信息),而cleanup方法可以关闭连接.

至关重要的是要了解该工作的减速器数量会影响汇总实现,因此您必须将其设计到减速器中. 具体来说,它是设计为以单例(一个减速器)运行还是以多个减速器运行. 对与错都取决于您的用例. 认识到分配给该作业的减速器越多,将创建到RDBMS的同时连接越多-这将扩展,但仅限于一点.

public static class MyRdbmsReducer extends Reducer<Text, IntWritable, Text, IntWritable>  {

  private Connection c = null;

  public void setup(Context context) {
    // create DB connection...
  }

  public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
    // do summarization
    // in this example the keys are Text, but this is just an example
  }

  public void cleanup(Context context) {
    // close db connection
  }

}

最后,汇总结果将写入您的RDBMS表.

53. Accessing Other HBase Tables in a MapReduce Job

尽管该框架当前允许一个HBase表作为MapReduce作业的输入,但可以通过在Mapper的setup方法中创建Table实例,在MapReduce作业中将其他HBase表作为查找表等进行访问.

public class MyMapper extends TableMapper<Text, LongWritable> {
  private Table myOtherTable;

  public void setup(Context context) {
    // In here create a Connection to the cluster and save it or use the Connection
    // from the existing table
    myOtherTable = connection.getTable("myOtherTable");
  }

  public void map(ImmutableBytesWritable row, Result value, Context context) throws IOException, InterruptedException {
    // process Result...
    // use 'myOtherTable' for lookups
  }

54. Speculative Execution

通常建议对使用HBase作为源的MapReduce作业关闭推测执行. 这可以在整个集群上通过属性逐个作业地完成. 特别是对于长时间运行的作业,推测性执行将创建重复的映射任务,这会将您的数据双重写入HBase. 这可能不是您想要的.

有关更多信息,请参见spec.ex.

Securing Apache HBase

报告安全漏洞
为了保护现有的HBase安装不受攻击,请不要使用JIRA报告与安全性有关的错误. 而是将您的报告发送到邮件列表private@apache.org ,该列表允许任何人发送消息,但限制了可以读取消息的人. 该列表中的某人将与您联系以跟进您的报告.

HBase遵守Apache Software Foundation关于已报告漏洞的政策,该政策可从http://apache.org/security/获得 .

If you wish to send an encrypted report, you can use the GPG details provided for the general ASF security list. This will likely increase the response time to your report.

HBase提供了一些机制来保护HBase的各个组件和方面以及它与Hadoop基础架构的其余部分以及Hadoop外部的客户端和资源之间的关系.

55. Using Secure HTTP (HTTPS) for the Web UI

默认的HBase安装使用主服务器和区域服务器的Web UI的HTTP连接不安全. 要启用,而不是安全的HTTP(HTTPS)连接,设置hadoop.ssl.enabledtrueHBase的-site.xml中 . 这不会更改Web UI使用的端口. 要更改给定HBase组件的Web UI的端口,请在hbase-site.xml中配置该端口的设置. 这些设置是:

  • hbase.master.info.port

  • hbase.regionserver.info.port

如果启用HTTPS,客户端应避免使用非安全的HTTP连接.

如果启用安全HTTP,则客户端应使用https:// URL连接到HBase. 使用http:// URL的客户端将收到200的HTTP响应,但不会收到任何数据. 记录以下异常:

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

这是因为同一端口用于HTTP和HTTPS.

HBase将Jetty用于Web UI. 如果不修改Jetty本身,似乎无法配置Jetty将一个端口重定向到同一主机上的另一个端口. 有关更多信息,请参见Nick Dimiduk在此Stack Overflow线程上的贡献. 如果您知道如何解决此问题而又没有为HTTPS打开第二个端口,那么不胜感激.

56. Using SPNEGO for Kerberos authentication with Web UIs

可以通过使用hbase-site.xml中hbase.security.authentication.ui属性配置SPNEGO来启用对HBase Web UI的Kerberos身份验证. 启用此身份验证需要将HBase还配置为对RPC使用Kerberos身份验证(例如hbase.security.authentication = kerberos ).

<property>
  <name>hbase.security.authentication.ui</name>
  <value>kerberos</value>
  <description>Controls what kind of authentication should be used for the HBase web UIs.</description>
</property>
<property>
  <name>hbase.security.authentication</name>
  <value>kerberos</value>
  <description>The Kerberos keytab file to use for SPNEGO authentication by the web server.</description>
</property>

存在许多属性,可以为Web服务器配置SPNEGO身份验证:

<property>
  <name>hbase.security.authentication.spnego.kerberos.principal</name>
  <value>HTTP/_HOST@EXAMPLE.COM</value>
  <description>Required for SPNEGO, the Kerberos principal to use for SPNEGO authentication by the
  web server. The _HOST keyword will be automatically substituted with the node's
  hostname.</description>
</property>
<property>
  <name>hbase.security.authentication.spnego.kerberos.keytab</name>
  <value>/etc/security/keytabs/spnego.service.keytab</value>
  <description>Required for SPNEGO, the Kerberos keytab file to use for SPNEGO authentication by the
  web server.</description>
</property>
<property>
  <name>hbase.security.authentication.spnego.kerberos.name.rules</name>
  <value></value>
  <description>Optional, Hadoop-style `auth_to_local` rules which will be parsed and used in the
  handling of Kerberos principals</description>
</property>
<property>
  <name>hbase.security.authentication.signature.secret.file</name>
  <value></value>
  <description>Optional, a file whose contents will be used as a secret to sign the HTTP cookies
  as a part of the SPNEGO authentication handshake. If this is not provided, Java's `Random` library
  will be used for the secret.</description>
</property>

57. Secure Client Access to Apache HBase

较新的Apache HBase版本(> = 0.92)支持客户端的可选SASL身份验证. 另请参见Matteo Bertozzi的文章, 了解Apache HBase中的用户身份验证和授权 .

这说明了如何设置Apache HBase和客户端以连接到安全的HBase资源.

57.1. Prerequisites

Hadoop Authentication Configuration

要使用强身份验证运行HBase RPC,必须将hbase.security.authentication设置为kerberos . 在这种情况下,还必须在core-site.xml中将hadoop.security.authentication设置为kerberos . 否则,您将对HBase使用强身份验证,而不对基础HDFS使用强身份验证,这将抵消任何好处.

Kerberos KDC

您需要有一个有效的Kerberos KDC.

57.2. Server-side Configuration for Secure Operation

首先,请参阅security.prerequisites,并确保基础HDFS配置是安全的.

将以下内容添加到群集中每台服务器计算机上的hbase-site.xml文件中:

<property>
  <name>hbase.security.authentication</name>
  <value>kerberos</value>
</property>
<property>
  <name>hbase.security.authorization</name>
  <value>true</value>
</property>
<property>
<name>hbase.coprocessor.region.classes</name>
  <value>org.apache.hadoop.hbase.security.token.TokenProvider</value>
</property>

部署这些配置更改时,需要完全关闭并重新启动HBase服务.

57.3. Client-side Configuration for Secure Operation

首先,请参阅先决条件,并确保基础HDFS配置是安全的.

将以下内容添加到每个客户端的hbase-site.xml文件中:

<property>
  <name>hbase.security.authentication</name>
  <value>kerberos</value>
</property>

必须先通过kinit命令从KDC或keytab登录客户端环境,然后才能与HBase群集进行通信.

请注意,如果客户端和服务器端站点文件中的hbase.security.authentication不匹配,则客户端将无法与群集进行通信.

一旦为安全RPC配置了HBase,就可以选择配置加密通信. 为此,请将以下内容添加到每个客户端的hbase-site.xml文件中:

<property>
  <name>hbase.rpc.protection</name>
  <value>privacy</value>
</property>

也可以在每个连接的基础上设置此配置属性. 在提供给TableConfiguration中进行Configuration

Configuration conf = HBaseConfiguration.create();
Connection connection = ConnectionFactory.createConnection(conf);
conf.set("hbase.rpc.protection", "privacy");
try (Connection connection = ConnectionFactory.createConnection(conf)) {
  try (Table table = connection.getTable(TableName.valueOf(tablename)) {
  .... do your stuff
  }
}

预计加密通信的性能会降低约10%.

57.4. Client-side Configuration for Secure Operation - Thrift Gateway

将以下内容添加到每个Thrift网关的hbase-site.xml文件中:

<property>
  <name>hbase.thrift.keytab.file</name>
  <value>/etc/hbase/conf/hbase.keytab</value>
</property>
<property>
  <name>hbase.thrift.kerberos.principal</name>
  <value>$USER/_HOST@HADOOP.LOCALDOMAIN</value>
  <!-- TODO: This may need to be  HTTP/_HOST@<REALM> and _HOST may not work.
   You may have  to put the concrete full hostname.
   -->
</property>

分别用适当的凭据和$ keytab替换$ USER$ KEYTAB .

为了使用Thrift API主体与HBase进行交互,还必须将hbase.thrift.kerberos.principal添加到acl表中. 例如,要给Thrift API主体thrift_server管理访问,这样的命令就足够了:

grant 'thrift_server', 'RWCA'

有关ACL的更多信息,请参见访问控制标签(ACL)部分.

Thrift网关将使用提供的凭据对HBase进行身份验证. Thrift网关本身不会执行任何身份验证. 所有通过Thrift网关的客户端访问都将使用Thrift网关的凭据并拥有其特权.

57.5. Configure the Thrift Gateway to Authenticate on Behalf of the Client

安全操作的客户端配置-Thrift网关介绍了如何使用固定用户向HBase认证Thrift客户端. 或者,您可以将Thrift网关配置为代表客户端对HBase进行身份验证,并使用代理用户访问HBase. 这在实施HBASE-11349为节俭1,和HBASE-11474为节俭2.

节俭式运输的局限性

如果您使用框架传输,则您将无法利用此功能,因为SASL目前不适用于Thrift框架传输.

要启用它,请执行以下操作.

  1. 通过遵循安全操作客户端配置-Thrift Gateway中描述的过程,确保Thrift在安全模式下运行.

  2. 确保将HBase配置为允许代理用户,如REST网关模拟配置中所述 .

  3. 在每个运行Thrift网关的群集节点的hbase-site.xml中,将属性hbase.thrift.security.qop设置为以下三个值之一:

    • privacy -身份验证,完整性和机密性检查.

    • integrity -身份验证和完整性检查

    • authentication - authentication checking only

  4. 重新启动Thrift网关进程以使更改生效. 如果节点正在运行Thrift,则jps命令的输出将列出ThriftServer进程. 要在节点上停止Thrift,请运行命令bin/hbase-daemon.sh stop thrift . 要在节点上启动Thrift,请运行命令bin/hbase-daemon.sh start thrift .

57.6. Configure the Thrift Gateway to Use the doAs Feature

配置Thrift网关代表客户端进行身份验证介绍了如何配置Thrift网关代表客户端对HBase进行身份验证以及如何使用代理用户访问HBase. 此方法的局限性在于,在使用特定的一组凭据初始化客户端之后,它无法在会话期间更改这些凭据. doAs功能提供了一种使用同一客户端模拟多个主体的灵活方法. 此功能已在HBASE-12640中为Thrift 1实现,但当前不适用于Thrift 2.

要允许代理用户 ,请将以下内容添加到每个HBase节点的hbase-site.xml文件中:

<property>
  <name>hadoop.security.authorization</name>
  <value>true</value>
</property>
<property>
  <name>hadoop.proxyuser.$USER.groups</name>
  <value>$GROUPS</value>
</property>
<property>
  <name>hadoop.proxyuser.$USER.hosts</name>
  <value>$GROUPS</value>
</property>

要启用doAs功能 ,请将以下内容添加到每个Thrift网关的hbase-site.xml文件中:

<property>
  <name>hbase.regionserver.thrift.http</name>
  <value>true</value>
</property>
<property>
  <name>hbase.thrift.support.proxyuser</name>
  <value>true/value>
</property>

查看演示客户端,以了解如何在客户端中使用此功能的总体思路.

57.7. Client-side Configuration for Secure Operation - REST Gateway

将以下内容添加到每个REST网关的hbase-site.xml文件中:

<property>
  <name>hbase.rest.keytab.file</name>
  <value>$KEYTAB</value>
</property>
<property>
  <name>hbase.rest.kerberos.principal</name>
  <value>$USER/_HOST@HADOOP.LOCALDOMAIN</value>
</property>

分别用适当的凭据和$ keytab替换$ USER$ KEYTAB .

REST网关将使用提供的凭据对HBase进行身份验证.

为了使用REST API主体与HBase进行交互,还必须将hbase.rest.kerberos.principal添加到acl表中. 例如,要授予REST API主体rest_server管理访问权限,只需执行以下命令即可:

grant 'rest_server', 'RWCA'

有关ACL的更多信息,请参见访问控制标签(ACL)部分.

HBase REST网关支持SPNEGO HTTP身份验证 ,以使客户端可以访问网关. 要为客户端访问启用REST网关Kerberos身份验证,请将以下内容添加到每个REST网关的hbase-site.xml文件中.

<property>
  <name>hbase.rest.authentication.type</name>
  <value>kerberos</value>
</property>
<property>
  <name>hbase.rest.authentication.kerberos.principal</name>
  <value>HTTP/_HOST@HADOOP.LOCALDOMAIN</value>
</property>
<property>
  <name>hbase.rest.authentication.kerberos.keytab</name>
  <value>$KEYTAB</value>
</property>

将keytab替换为$ KEYTAB的 HTTP.

HBase REST网关支持不同的" hbase.rest.authentication.type":简单,kerberos. 您还可以通过实现Hadoop AuthenticationHandler来实现自定义身份验证,然后将完整的类名称指定为" hbase.rest.authentication.type"值. 有关更多信息,请参阅SPNEGO HTTP身份验证 .

57.8. REST Gateway Impersonation Configuration

默认情况下,REST网关不支持模拟. 它以上一节中配置的用户身份代表客户端访问HBase. 对于HBase服务器,所有请求均来自REST网关用户. 实际用户未知. 您可以打开模拟支持. 通过模拟,REST网关用户是代理用户. HBase服务器知道每个请求的实际/实际用户. 因此,它可以应用适当的授权.

要打开REST网关模拟,我们需要配置HBase服务器(主服务器和区域服务器)以允许代理用户. 配置REST网关以启用模拟.

要允许代理用户,请将以下内容添加到每个HBase服务器的hbase-site.xml文件中:

<property>
  <name>hadoop.security.authorization</name>
  <value>true</value>
</property>
<property>
  <name>hadoop.proxyuser.$USER.groups</name>
  <value>$GROUPS</value>
</property>
<property>
  <name>hadoop.proxyuser.$USER.hosts</name>
  <value>$GROUPS</value>
</property>

将REST网关代理用户替换为$ USER ,并将允许的组列表替换为$ GROUPS .

要启用REST网关模拟,请将以下内容添加到每个REST网关的hbase-site.xml文件中.

<property>
  <name>hbase.rest.authentication.type</name>
  <value>kerberos</value>
</property>
<property>
  <name>hbase.rest.authentication.kerberos.principal</name>
  <value>HTTP/_HOST@HADOOP.LOCALDOMAIN</value>
</property>
<property>
  <name>hbase.rest.authentication.kerberos.keytab</name>
  <value>$KEYTAB</value>
</property>

将keytab替换为$ KEYTAB的 HTTP.

58. Simple User Access to Apache HBase

较新的Apache HBase版本(> = 0.92)支持客户端的可选SASL身份验证. 另请参见Matteo Bertozzi的文章, 了解Apache HBase中的用户身份验证和授权 .

这描述了如何设置Apache HBase和客户端以简化用户对HBase资源的访问.

58.1. Simple versus Secure Access

以下部分显示了如何设置简单的用户访问. 简单的用户访问不是操作HBase的安全方法. 此方法用于防止用户犯错误. 它可以用来模拟在开发系统上使用的访问控制,而无需设置Kerberos.

此方法不用于防止恶意或黑客尝试. 要使HBase抵御这些类型的攻击,必须将HBase配置为安全操作. 请参阅" 对Apache HBase的安全客户端访问 "部分并完成此处描述的所有步骤.

58.2. Prerequisites

None

58.3. Server-side Configuration for Simple User Access Operation

将以下内容添加到群集中每台服务器计算机上的hbase-site.xml文件中:

<property>
  <name>hbase.security.authentication</name>
  <value>simple</value>
</property>
<property>
  <name>hbase.security.authorization</name>
  <value>true</value>
</property>
<property>
  <name>hbase.coprocessor.master.classes</name>
  <value>org.apache.hadoop.hbase.security.access.AccessController</value>
</property>
<property>
  <name>hbase.coprocessor.region.classes</name>
  <value>org.apache.hadoop.hbase.security.access.AccessController</value>
</property>
<property>
  <name>hbase.coprocessor.regionserver.classes</name>
  <value>org.apache.hadoop.hbase.security.access.AccessController</value>
</property>

对于0.94,请将以下内容添加到群集中每台服务器计算机上的hbase-site.xml文件中:

<property>
  <name>hbase.rpc.engine</name>
  <value>org.apache.hadoop.hbase.ipc.SecureRpcEngine</value>
</property>
<property>
  <name>hbase.coprocessor.master.classes</name>
  <value>org.apache.hadoop.hbase.security.access.AccessController</value>
</property>
<property>
  <name>hbase.coprocessor.region.classes</name>
  <value>org.apache.hadoop.hbase.security.access.AccessController</value>
</property>

部署这些配置更改时,需要完全关闭并重新启动HBase服务.

58.4. Client-side Configuration for Simple User Access Operation

将以下内容添加到每个客户端的hbase-site.xml文件中:

<property>
  <name>hbase.security.authentication</name>
  <value>simple</value>
</property>

对于0.94,请将以下内容添加到群集中每台服务器计算机上的hbase-site.xml文件中:

<property>
  <name>hbase.rpc.engine</name>
  <value>org.apache.hadoop.hbase.ipc.SecureRpcEngine</value>
</property>

请注意,如果客户端和服务器端站点文件中的hbase.security.authentication不匹配,则客户端将无法与群集进行通信.

58.4.1. Client-side Configuration for Simple User Access Operation - Thrift Gateway

Thrift网关用户将需要访问. 例如,要给Thrift API用户thrift_server管理访问,这样的命令就足够了:

grant 'thrift_server', 'RWCA'

有关ACL的更多信息,请参见访问控制标签(ACL)部分.

Thrift网关将使用提供的凭据对HBase进行身份验证. Thrift网关本身不会执行任何身份验证. 所有通过Thrift网关的客户端访问都将使用Thrift网关的凭据并拥有其特权.

58.4.2. Client-side Configuration for Simple User Access Operation - REST Gateway

REST网关将使用提供的凭据对HBase进行身份验证. REST网关本身不会执行任何身份验证. 通过REST网关进行的所有客户端访问都将使用REST网关的凭据并拥有其特权.

REST网关用户将需要访问. 例如,要给REST API用户rest_server管理访问,这样的命令就足够了:

grant 'rest_server', 'RWCA'

有关ACL的更多信息,请参见访问控制标签(ACL)部分.

客户端应该可以通过SPNEGO HTTP身份验证通过REST网关通过HBase群集进行身份验证. 这是未来的工作.

59. Securing Access to HDFS and ZooKeeper

安全的HBase需要安全的ZooKeeper和HDFS,以便用户无法从HBase下访问和/或修改元数据和数据. HBase使用HDFS(或配置的文件系统)来保留其数据文件以及预写日志(WAL)和其他数据. HBase使用ZooKeeper存储一些用于操作的元数据(主地址,表锁,恢复状态等).

59.1. Securing ZooKeeper Data

ZooKeeper具有可插入的身份验证机制,以允许使用不同方法从客户端进行访问. ZooKeeper甚至可以同时允许经过身份验证和未经身份验证的客户端. 可以通过为每个znode提供访问控制列表(ACL)来限制对znode的访问. ACL包含两个组件,身份验证方法和主体. ACL不是分层实施的. 有关详细信息,请参见ZooKeeper程序员指南 .

HBase守护程序通过SASL和kerberos向ZooKeeper进行身份验证 (请参阅使用ZooKeeper的SASL身份验证 ). HBase设置znode ACL,以便只有HBase用户和配置的hbase superuser( hbase.superuser )可以访问和修改数据. 如果将ZooKeeper用于服务发现或与客户端共享状态,则HBase创建的znode也将允许任何人(无论身份验证如何)读取这些znode(clusterId,主地址,元位置等),但只能读取HBase.用户可以修改它们.

59.2. Securing File System (HDFS) Data

所有管理的数据都保存在文件系统( hbase.rootdir )的根目录下. 应该限制​​对文件系统中数据和WAL文件的访问,以使用户无法绕过HBase层,并从文件系统中窥视基础数据文件. HBase假定使用的文件系统(HDFS或其他文件系统)强制执行权限. 如果没有提供足够的文件系统保护(授权和身份验证),则HBase级别授权控制(ACL,可见性标签等)将毫无意义,因为用户始终可以从文件系统访问数据.

HBase对其根目录强制执行类似posix的权限700( rwx------ ). 这意味着只有HBase用户可以读取或写入FS中的文件. 可以通过在hbase-site.xml中配置hbase.rootdir.perms来更改默认设置. 需要重新启动活动的主服务器,以便更改使用的权限. 对于1.2.0之前的版本,您可以检查是否提交了HBASE-13780,如果没有提交,则可以根据需要手动设置根目录的权限. 使用HDFS,命令将是:

sudo -u hdfs hadoop fs -chmod 700 /hbase

如果使用其他hbase.rootdir则应更改/hbase hbase.rootdir .

在安全模式下,应配置SecureBulkLoadEndpoint并将其用于正确地将从MR作业创建的用户文件移交给HBase守护程序和HBase用户. 用于批量加载的分布式文件系统中的登台目录( hbase.bulkload.staging.dir ,默认为/tmp/hbase-staging )应具有(模式711或rwx—​x—​x ),以便用户可以访问在该父目录下创建的暂存目录,但不能执行任何其他操作. 有关如何配置SecureBulkLoadEndPoint的信息,请参阅安全大容量加载 .

60. Securing Access To Your Data

在HBase客户端与服务器进程和网关之间配置了安全身份验证之后,需要考虑数据本身的安全性. HBase提供了几种保护数据的策略:

  • 基于角色的访问控制(RBAC)使用熟悉的角色范例控制哪些用户或组可以读写给定的HBase资源或执行协处理器端点.

  • 可见性标签允许您标记单元格并控制对标记单元格的访问,以进一步限制谁可以读取或写入数据的某些子集. 可见性标签存储为标签. 有关更多信息,请参见hbase.tags .

  • HFiles和WAL中基础文件系统上静态数据的透明加密. 这样可以保护您的静态数据,使其免受攻击者的攻击,这些攻击者可以访问基础文件系统,而无需更改客户端的实现. 它还可以防止因磁盘放置不当而造成的数据泄漏,这对于法律和法规遵从性很重要.

下面讨论了每个功能的服务器端配置,管理和实现细节,以及所有性能折衷. 最后给出了一个示例安全配置,以显示所有这些功能一起使用,就像它们在现实世界中一样.

HBase中的安全性的各个方面都处于积极发展之中并且正在迅速发展. 您为数据安全性采用的任何策略都应经过彻底测试. 此外,其中一些功能仍处于试验开发阶段. 要利用其中的许多功能,必须运行HBase 0.98+并使用HFile v3文件格式.
保护敏感文件

本节中的几个过程要求您在群集节点之间复制文件. 复制密钥,配置文件或其他包含敏感字符串的文件时,请使用诸如ssh类的安全方法,以避免泄漏敏感数据.

过程:基本服务器端配置
  1. 启用HFILE V3,通过设置hfile.format.versionHBase的-site.xml中以3. 这是HBase 1.0及更高版本的默认设置.

    <property>
      <name>hfile.format.version</name>
      <value>3</value>
    </property>
  2. 启用RPC和ZooKeeper的SASL和Kerberos身份验证,如security.prerequisites使用ZooKeeper的SASL身份验证中所述.

60.1. Tags

标签是HFile v3的功能. 标签是一部分元数据,它是单元的一部分,与键,值和版本分开. 标签是一个实现细节,它为其他与安全相关的功能(如单元级ACL和可见性标签)奠定了基础. 标记存储在HFiles本身中. 将来可能会使用标签来实现其他HBase功能. 您不需要对标签了解太多,就可以使用它们启用的安全功能.

60.1.1. Implementation Details

每个单元格可以具有零个或多个标签. 每个标签都有一个类型和实际的标签字节数组.

Just as row keys, column families, qualifiers and values can be encoded (see data.block.encoding.types), tags can also be encoded as well. You can enable or disable tag encoding at the level of the column family, and it is enabled by default. Use the HColumnDescriptor#setCompressionTags(boolean compressTags) method to manage encoding settings on a column family. You also need to enable the DataBlockEncoder for the column family, for encoding of tags to take effect.

如果还启用了WAL压缩,则可以通过将hbase-site.xml中hbase.regionserver.wal.tags.enablecompression的值设置为true来启用WAL中每个标签的压缩. 标签压缩使用字典编码.

使用WAL加密时,不支持标签压缩.

60.2. Access Control Labels (ACLs)

60.2.1. How It Works

HBase中的ACL基于用户在组中的成员身份或从组中排除,以及给定的组访问给定资源的权限. ACL被实现为称为AccessController的协处理器.

HBase不维护私有组映射,而是依赖Hadoop组映射器 ,该映射在LDAP或Active Directory等目录中的实体与HBase用户之间进行映射. 任何受支持的Hadoop组映射器都将起作用. 然后,向用户授予针对资源(全局,名称空间,表,单元或端点)的特定权限(读取,写入,执行,创建,管理).

启用Kerberos和访问控制后,将对客户端对HBase的访问进行身份验证,并且用户数据为私有数据,除非已明确授予访问权限.

HBase具有比关系数据库更简单的安全模型,尤其是在客户端操作方面. 例如,插入(新记录)和更新(现有记录)之间没有区别,因为两者都折叠成Put.

Understanding Access Levels

HBase访问级别彼此独立授予,并允许在给定范围内进行不同类型的操作.

  • 读取(R) -可以读取给定范围的数据

  • 写入(W) -可以在给定范围内写入数据

  • 执行(X) -可以在给定范围内执行协处理器端点

  • 创建(C) -可以在给定范围内创建表或删除表(甚至包括未创建的表)

  • 管理员(A) -可以执行群集操作,例如平衡群集或在给定范围内分配区域

可能的范围是:

  • 超级用户 -超级用户可以对任何资源执行HBase中可用的任何操作. 在群集上运行HBase的用户是超级用户,在HMaster的hbase-site.xml中分配给配置属性hbase.superuser任何主体也是如此.

  • 全局 -在全局范围内授予的权限允许管理员对集群的所有表进行操作.

  • 命名空间 -在命名空间范围内授予的权限适用于给定命名空间内的所有表.

  • -在范围内授予的权限适用于给定表内的数据或元数据.

  • ColumnFamily-ColumnFamily范围内授予的权限适用于该ColumnFamily中的单元格.

  • 单元格 -在单元格范围内授予的权限适用于该确切的单元格坐标(键,值,时间戳). 这允许策略与数据一起发展.

    要更改特定单元格上的ACL,请使用新ACL将更新后的单元格写入原始单元格的精确坐标.

    如果您具有多版本架构,并且想要在所有可见版本上更新ACL,则需要为所有可见版本编写新的单元格. 该应用程序可以完全控制策略的演变.

    上述规则的例外是appendincrement处理. 追加和递增操作中可以携带ACL. 如果该操作中包含一个,则它将应用于appendincrement的结果. 否则,将保留要添加或递增的现有单元的ACL.

访问级别和范围的组合创建了可以授予用户的可能访问级别的矩阵. 在生产环境中,考虑完成特定工作所需的访问级别是很有用的. 下表描述了一些常见HBase用户类型的访问级别. 重要的是,不要授予超出给定用户执行其所需任务所需的权限.

  • 超级用户 -在生产系统中,只有HBase用户应具有超级用户访问权限. 在开发环境中,管理员可能需要超级用户访问权限才能快速控制和管理集群. 但是,这种类型的管理员通常应该是全局管理员,而不是超级用户.

  • 全局管理员 -全局管理员可以执行任务并访问HBase中的每个表. 在典型的生产环境中,管理员不应具有对表中数据的读取或写入权限.

  • 具有管理员权限的全局管理员可以在群集上执行群集范围内的操作,例如平衡,分配或取消分配区域,或调用显式主要压缩. 这是操作角色.

  • 具有"创建"权限的全局管理员可以在HBase中创建或删除任何表. 这更像是DBA类型的角色.

    在生产环境中,不同的用户可能只有Admin和Create权限之一.

    在当前实现中,具有Admin权限的Global Admin可以授予自己对表的ReadWrite权限,并可以访问该表的数据. 因此,仅将Global Admin权限授予实际需要它们的受信任用户.

    还应注意,具有" Create权限的Global Admin可以在ACL表上执行" Put操作,模拟grantrevoke并绕过Global Admin权限的授权检查.

    由于这些问题,请谨慎授予Global Admin特权.

  • 命名空间管理员 -具有" Create权限的命名空间管理员可以在该命名空间中创建或删除表,以及获取和还原快照. 具有Admin权限的名称空间管理员可以对该名称空间内的表执行诸如拆分或主要压缩之类的操作.

  • 表管理员 -表管理员只能在该表上执行管理操作. 具有" Create权限的表管理员可以从该表创建快照,也可以从快照还原该表. 具有Admin权限的表管理员可以在该表上执行诸如拆分或主要压缩之类的操作.

  • 用户 -用户可以读取或写入数据,或同时读取和写入数据. 如果被赋予Executable权限,用户也可以执行协处理器端点.

表7.访问级别的真实示例
职称 Scope Permissions Description

Senior Administrator

Global

访问,创建

管理群集并授予初级管理员访问权限.

初级管理员

Global

Create

创建表并授予表管理员访问权限.

表管理员

Table

Access

从操作角度维护表.

数据分析师

Table

Read

根据HBase数据创建报告.

Web应用程序

Table

读,写

将数据放入HBase并使用HBase数据执行操作.

ACL矩阵

有关ACL如何映射到特定HBase操作和任务的更多详细信息,请参见附录acl矩阵 .

Implementation Details

单元级ACL是使用标签实现的(请参见标签 ). 为了使用单元级别的ACL,您必须使用HFile v3和HBase 0.98或更高版本.

  1. 由HBase创建的文件归运行HBase进程的操作系统用户所有. 要与HBase文件进行交互,应使用API​​或批量加载工具.

  2. HBase不在HBase内部对"角色"建模. 而是可以授予组名权限. 这允许通过组成员资格对角色进行外部建模. 通过Hadoop组映射服务,可以在HBase的外部创建和操作组.

Server-Side Configuration
  1. 作为前提条件,请执行[security.data.basic.server.side]中的步骤.

  2. 通过在hbase-site.xml中设置以下属性来安装和配置AccessController协处理器. 这些属性采用类列表.

    如果将AccessController与VisibilityController一起使用,则AccessController必须在列表中排在第一位,因为在两个组件都处于活动状态的情况下,VisibilityController会将其系统表上的访问控制委托给AccessController. 有关将两者一起使用的示例,请参阅" 安全性配置示例" .
     <property>
      <name>hbase.security.authorization</name>
      <value>true</value>
    </property>
    <property>
      <name>hbase.coprocessor.region.classes</name>
      <value>org.apache.hadoop.hbase.security.access.AccessController, org.apache.hadoop.hbase.security.token.TokenProvider</value>
    </property>
    <property>
      <name>hbase.coprocessor.master.classes</name>
      <value>org.apache.hadoop.hbase.security.access.AccessController</value>
    </property>
    <property>
      <name>hbase.coprocessor.regionserver.classes</name>
      <value>org.apache.hadoop.hbase.security.access.AccessController</value>
    </property>
    <property>
      <name>hbase.security.exec.permission.checks</name>
      <value>true</value>
    </property>

    (可选)您可以通过将hbase.rpc.protection设置为privacy来启用传输安全性. 这需要HBase 0.98.4或更高版本.

  3. 在Hadoop名称节点的core-site.xml中设置Hadoop组映射器. 这是Hadoop文件,而不是HBase文件. 根据您的站点需求对其进行自定义. 以下是一个示例.

    <property>
      <name>hadoop.security.group.mapping</name>
      <value>org.apache.hadoop.security.LdapGroupsMapping</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.url</name>
      <value>ldap://server</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.bind.user</name>
      <value>Administrator@example-ad.local</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.bind.password</name>
      <value>****</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.base</name>
      <value>dc=example-ad,dc=local</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.search.filter.user</name>
      <value>(&amp;(objectClass=user)(sAMAccountName={0}))</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.search.filter.group</name>
      <value>(objectClass=group)</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.search.attr.member</name>
      <value>member</value>
    </property>
    
    <property>
      <name>hadoop.security.group.mapping.ldap.search.attr.group.name</name>
      <value>cn</value>
    </property>
  4. (可选)启用提前评估策略. 在HBase 0.98.0之前,如果未授予用户访问列族或至少一个列限定符的权限,则将引发AccessDeniedException. HBase 0.98.0删除了此异常,以便允许单元级别的特殊授予. 要恢复旧的行为在HBase的0.98.0-0.98.6,设置hbase.security.access.early_outtrueHBase的-site.xml中 . 在HBase 0.98.6中,默认值已返回true .

  5. Distribute your configuration and restart your cluster for changes to take effect.

  6. 要测试您的配置,请以给定用户身份登录到HBase Shell,并使用whoami命令报告您的用户所属的组. 在此示例中,该用户被报告为services组的成员.

    hbase> whoami
    service (auth:KERBEROS)
        groups: services
Administration

Administration tasks can be performed from HBase Shell or via an API.

API范例

以下许多API示例均来自源文件hbase-server / src / test / java / org / apache / hadoop / hbase / security / access / TestAccessController.javahbase-server / src / test / java / org / apache /hadoop/hbase/security/access/SecureTestUtil.java .

Neither the examples, nor the source files they are taken from, are part of the public HBase API, and are provided for illustration only. Refer to the official API for usage instructions.

  1. 用户和组管理

    用户和组在目录的HBase外部维护.

  2. 授予对命名空间,表,列族或单元格的访问权限

    There are a few different types of syntax for grant statements. The first, and most familiar, is as follows, with the table and column family being optional:

    grant 'user', 'RWXCA', 'TABLE', 'CF', 'CQ'

    以相同的方式为组和用户授予访问权限,但组前面带有@符号. 以相同的方式,表和名称空间以相同的方式指定,但是名称空间以@符号为前缀.

    如本例所示,还可以在单​​个语句中授予对同一资源的多个权限. 第一个子句将用户映射到ACL,第二个子句指定资源.

    HBase Shell在单元级别授予和撤消访问的支持是用于测试和验证支持,不应用于生产用途,因为它不会将权限应用于尚不存在的单元. 应用单元格级别权限的正确方法是在存储值时在应用程序代码中进行操作.
    ACL粒度和评估顺序

    从最小粒度到最精细粒度对ACL进行评估,并且在达到授予许可的ACL时,评估将停止. 这意味着单元ACL不会以较小的粒度覆盖ACL.

    例子20. HBase Shell
    • Global:

      hbase> grant '@admins', 'RWXCA'
    • Namespace:

      hbase> grant 'service', 'RWXCA', '@test-NS'
    • Table:

      hbase> grant 'service', 'RWXCA', 'user'
    • 列族:

      hbase> grant '@developers', 'RW', 'user', 'i'
    • Column Qualifier:

      hbase> grant 'service, 'RW', 'user', 'i', 'foo'
    • Cell:

      授予单元ACL的语法使用以下语法:

      grant <table>, \
        { '<user-or-group>' => \
          '<permissions>', ... }, \
        { <scanner-specification> }
    • <user-or-group>是用户或组名,对于组,以@开头.

    • <permissions>是包含任何或所有" RWXCA"的字符串,尽管只有R和W在单元格范围内有意义.

    • <scanner-specification>是'scan'shell命令使用的扫描仪规范语法和约定. 有关扫描仪规格的一些示例,请发出以下HBase Shell命令.

      hbase> help "scan"

      此示例在与过滤器匹配的" pii"列中的单元格上授予" testuser"用户的读取访问权和对" developers"组的读/写访问权限.

      hbase> grant 'user', \
        { '@developers' => 'RW', 'testuser' => 'R' }, \
        { COLUMNS => 'pii', FILTER => "(PrefixFilter ('test'))" }

      外壳程序将使用给定的标准运行扫描程序,用新的ACL重写找到的单元,然后将其存储回其精确坐标.

    例子21. API

    下面的示例显示如何在表级别授予访问权限.

    public static void grantOnTable(final HBaseTestingUtility util, final String user,
        final TableName table, final byte[] family, final byte[] qualifier,
        final Permission.Action... actions) throws Exception {
      SecureTestUtil.updateACLs(util, new Callable<Void>() {
        @Override
        public Void call() throws Exception {
          Configuration conf = HBaseConfiguration.create();
          Connection connection = ConnectionFactory.createConnection(conf);
          try (Connection connection = ConnectionFactory.createConnection(conf)) {
            try (Table table = connection.getTable(TableName.valueOf(tablename)) {
              AccessControlLists.ACL_TABLE_NAME);
              try {
                BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
                AccessControlService.BlockingInterface protocol =
                    AccessControlService.newBlockingStub(service);
                ProtobufUtil.grant(protocol, user, table, family, qualifier, actions);
              } finally {
                acl.close();
              }
              return null;
            }
          }
        }
      }
    }

    要在单元级别授予权限,可以使用Mutation.setACL方法:

    Mutation.setACL(String user, Permission perms)
    Mutation.setACL(Map<String, Permission> perms)

    具体来说,此示例为特定put操作中包含的任何单元格上的名为user1的用户提供读取权限:

    put.setACL(user1, new Permission(Permission.Action.READ))
  3. 撤消命名空间,表,列族或单元格中的访问控制

    revoke命令和API是grant命令和API的双胞胎,语法完全相同. 唯一的例外是您不能撤消单元级别的权限. 您只能撤消先前已授予的访问权限,并且revoke语句与显式拒绝资源不同.

    HBase Shell对授予和撤消访问的支持是用于测试和验证支持,不应用于生产用途,因为它不会将权限应用于尚不存在的单元. 应用单元格级别权限的正确方法是在存储值时在应用程序代码中进行操作.
    例子22.撤销对表的访问
    public static void revokeFromTable(final HBaseTestingUtility util, final String user,
        final TableName table, final byte[] family, final byte[] qualifier,
        final Permission.Action... actions) throws Exception {
      SecureTestUtil.updateACLs(util, new Callable<Void>() {
        @Override
        public Void call() throws Exception {
          Configuration conf = HBaseConfiguration.create();
          Connection connection = ConnectionFactory.createConnection(conf);
          Table acl = connection.getTable(util.getConfiguration(), AccessControlLists.ACL_TABLE_NAME);
          try {
            BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
            AccessControlService.BlockingInterface protocol =
                AccessControlService.newBlockingStub(service);
            ProtobufUtil.revoke(protocol, user, table, family, qualifier, actions);
          } finally {
            acl.close();
          }
          return null;
        }
      });
    }
  4. 显示用户的有效权限

    例子23. HBase Shell
    hbase> user_permission 'user'
    
    hbase> user_permission '.*'
    
    hbase> user_permission JAVA_REGEX
例子24. API
public static void verifyAllowed(User user, AccessTestAction action, int count) throws Exception {
  try {
    Object obj = user.runAs(action);
    if (obj != null && obj instanceof List&lt;?&gt;) {
      List&lt;?&gt; results = (List&lt;?&gt;) obj;
      if (results != null && results.isEmpty()) {
        fail("Empty non null results from action for user '" ` user.getShortName() ` "'");
      }
      assertEquals(count, results.size());
    }
  } catch (AccessDeniedException ade) {
    fail("Expected action to pass for user '" ` user.getShortName() ` "' but was denied");
  }
}

60.3. Visibility Labels

可见性标签控件只能用于允许与给定标签关联的用户或主体读取或访问带有该标签的单元格. 例如,您可能标记了一个top-secret的单元格,而只将该访问权授予了managers组. 可见性标签是使用标签实现的,标签是HFile v3的功能,它允许您按单元存储元数据. 标签是字符串,可以使用逻辑运算符(&,|或!)并使用括号将标签组合成表达式. 除了基本的格式正确之外,HBase不会对表达式进行任何形式的验证. 可见性标签本身没有含义,可以用来表示敏感度级别,特权级别或任何其他任意语义.

如果用户的标签与单元格的标签或表达式不匹配,则拒绝用户访问该单元格.

在HBase 0.98.6和更高版本中,可见性标签和表达式支持UTF-8编码. 使用org.apache.hadoop.hbase.security.visibility.VisibilityClient类提供的addLabels(conf, labels)方法创建标签并通过"扫描"或"获取"在"授权"中传递标签时,标签可以包含UTF-8字符以及可见性标签中通常使用的逻辑运算符,带有普通的Java表示法,而无需任何转义方法. 但是,当您通过Mutation传递CellVisibility表达式时,如果使用UTF-8字符或逻辑运算符,则必须使用CellVisibility.quote()方法将该表达式括起来. 见TestExpressionParser和源文件HBase的客户端/ src目录/测试/ JAVA /组织/阿帕奇/的Hadoop / HBase的/客户机/ TestScan.java.

用户在Put操作期间向单元格添加可见性表达式. 在默认配置中,用户不需要访问标签即可为标签添加单元格. 此行为由配置选项hbase.security.visibility.mutations.checkauths . 如果将此选项设置为true ,则用户必须将与突变相关的用户正在修改的标签与该用户相关联,否则该突变将失败. 在"获取"或"扫描"过程中确定用户是否有权读取标记的单元格,并过滤掉不允许用户读取的结果. 这将产生与返回结果相同的I / O损失,但会减少网络上的负载.

还可以在"删除"操作期间指定可见性标签. 有关可见性标签和删除的详细信息,请参见HBASE-10885 .

当RegionServer首次接收到请求时,用户的有效标签集将建立在RPC上下文中. 用户与标签关联的方式是可插入的. 默认插件将通过添加到"获取"或"扫描"中的"授权"中指定的标签,并对照主叫用户的已认证标签列表检查这些标签. 当客户端传递未经用户验证的标签时,默认插件会丢弃它们. 您可以通过Get#setAuthorizations(Authorizations(String,…​))Scan#setAuthorizations(Authorizations(String,…​));传递用户身份验证标签的子集Scan#setAuthorizations(Authorizations(String,…​)); 方法.

可以向组授予与用户相同的可见性标签. 组以@符号为前缀. 当检查用户的可见性标签时,服务器将包括用户所属的组的可见性标签以及用户自己的标签. 当使用API VisibilityClient#getAuths或Shell命令get_auths为用户检索可见性标签时,我们将仅返回专门为该用户添加的标签,而不是组级别标签.

可见性标签访问检查由VisibilityController协处理器执行. 您可以使用VisibilityLabelService接口提供自定义实现和/或控制将可见性标签与单元格一起存储的方式. 有关一个示例,请参见源文件hbase-server / src / test / java / org / apache / hadoop / hbase / security / visibility / TestVisibilityLabelsWithCustomVisLabService.java .

可见性标签可以与ACL结合使用.

必须先明确定义标签,然后才能在可见性标签中使用它们. 请参阅以下示例,了解如何完成此操作.
当前无法确定已将哪些标签应用于单元格. 有关详细信息,请参见HBASE-12470 .
可见性标签当前不适用于超级用户.
表8.可见性表达的示例
Expression Interpretation
fulltime

允许访问与全职标签关联的用户.

!public

允许访问未与公共标签关联的用户.

( secret | topsecret ) & !probationary

Allow access to users associated with either the secret or topsecret label and not associated with the probationary label.

60.3.1. Server-Side Configuration

  1. 作为前提条件,请执行[security.data.basic.server.side]中的步骤.

  2. 通过在hbase-site.xml中设置以下属性来安装和配置VisibilityController协处理器. 这些属性采用类名列表.

    <property>
      <name>hbase.coprocessor.region.classes</name>
      <value>org.apache.hadoop.hbase.security.visibility.VisibilityController</value>
    </property>
    <property>
      <name>hbase.coprocessor.master.classes</name>
      <value>org.apache.hadoop.hbase.security.visibility.VisibilityController</value>
    </property>
     <property>
      <name>hbase.security.authorization</name>
      <value>true</value>
    </property>
    如果同时使用AccessController和VisibilityController协处理器,则AccessController必须在列表中排在第一位,因为在两个组件都处于活动状态的情况下,VisibilityController会将其系统表上的访问控制委托给AccessController.
  3. 调整配置

    默认情况下,用户可以使用任何标签来标记单元格,包括与它们不相关的标签,这意味着用户可以放置他无法读取的数据. 例如,即使用户没有与该标签相关联,用户也可以使用(假设的)"最高机密"标签对其进行标签. 如果只希望用户能够使用与其关联的标签来标记单元格,请将hbase.security.visibility.mutations.checkauths设置为true . 在这种情况下,如果突变使用了用户未关联的标签,则它将失败.

  4. 分发配置并重新启动集群以使更改生效.

60.3.2. Administration

可以使用HBase Shell或Java API执行管理任务. 为了定义可见性标签列表并将标签与用户相关联,HBase Shell可能更简单.

API范例

本节中的许多Java API示例均来自源文件hbase-server / src / test / java / org / apache / hadoop / hbase / security / visibility / TestVisibilityLabels.java . 有关更多上下文,请参考该文件或API文档.

这些示例或它们的源文件均不是公共HBase API的一部分,并且仅出于说明目的而提供. 有关使用说明,请参考官方API.

  1. 定义可见性标签列表

    例子25. HBase Shell
    hbase> add_labels [ 'admin', 'service', 'developer', 'test' ]
    例子26. Java API
    public static void addLabels() throws Exception {
      PrivilegedExceptionAction<VisibilityLabelsResponse> action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
        public VisibilityLabelsResponse run() throws Exception {
          String[] labels = { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE, COPYRIGHT, ACCENT,
              UNICODE_VIS_TAG, UC1, UC2 };
          try {
            VisibilityClient.addLabels(conf, labels);
          } catch (Throwable t) {
            throw new IOException(t);
          }
          return null;
        }
      };
      SUPERUSER.runAs(action);
    }
  2. 将标签与用户相关联

    例子27. HBase Shell
    hbase> set_auths 'service', [ 'service' ]

    +

    hbase> set_auths 'testuser', [ 'test' ]

    +

    hbase> set_auths 'qa', [ 'test', 'developer' ]

    +

    hbase> set_auths '@qagroup', [ 'test' ]
    例子28. Java API
    public void testSetAndGetUserAuths() throws Throwable {
      final String user = "user1";
      PrivilegedExceptionAction<Void> action = new PrivilegedExceptionAction<Void>() {
        public Void run() throws Exception {
          String[] auths = { SECRET, CONFIDENTIAL };
          try {
            VisibilityClient.setAuths(conf, auths, user);
          } catch (Throwable e) {
          }
          return null;
        }
        ...
  3. 清除用户标签

    Example 29. HBase Shell
    hbase> clear_auths 'service', [ 'service' ]

    +

    hbase> clear_auths 'testuser', [ 'test' ]

    +

    hbase> clear_auths 'qa', [ 'test', 'developer' ]

    +

    hbase> clear_auths '@qagroup', [ 'test', 'developer' ]
    例子30. Java API
    ...
    auths = new String[] { SECRET, PUBLIC, CONFIDENTIAL };
    VisibilityLabelsResponse response = null;
    try {
      response = VisibilityClient.clearAuths(conf, auths, user);
    } catch (Throwable e) {
      fail("Should not have failed");
      ...
    }
  4. 将标签或表达式应用于单元格

    仅在写入数据时才应用标签. 标签与单元的给定版本相关联.

    例子31. HBase Shell
    hbase> set_visibility 'user', 'admin|service|developer', { COLUMNS => 'i' }

    +

    hbase> set_visibility 'user', 'admin|service', { COLUMNS => 'pii' }

    +

    hbase> set_visibility 'user', 'test', { COLUMNS => [ 'i', 'pii' ], FILTER => "(PrefixFilter ('test'))" }
    HBase Shell支持将标签或权限应用于单元格是为了进行测试和验证支持,不应将其用于生产用途,因为它不会将标签应用于尚不存在的单元格. 正确应用单元格级别标签的方法是在存储值时在应用程序代码中进行操作.
    例子32. Java API
    static Table createTableAndWriteDataWithLabels(TableName tableName, String... labelExps)
        throws Exception {
      Configuration conf = HBaseConfiguration.create();
      Connection connection = ConnectionFactory.createConnection(conf);
      Table table = NULL;
      try {
        table = TEST_UTIL.createTable(tableName, fam);
        int i = 1;
        List<Put> puts = new ArrayList<Put>();
        for (String labelExp : labelExps) {
          Put put = new Put(Bytes.toBytes("row" + i));
          put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
          put.setCellVisibility(new CellVisibility(labelExp));
          puts.add(put);
          i++;
        }
        table.put(puts);
      } finally {
        if (table != null) {
          table.flushCommits();
        }
      }

[reading_cells_with_labels] ====读取带有标签的单元格发出"扫描"或"获取"时,HBase使用默认的授权集来过滤掉您无权访问的单元格. 超级用户可以使用set_auths HBase Shell命令或[ ],%20java.lang.String)[VisibilityClient.setAuths()方法来设置给定用户的默认授权集.

您可以通过在HBase Shell中传递AUTHORIZATIONS选项或者在使用API​​的情况下通过setAuthorizations()方法来在"扫描"或"获取"期间指定其他授权. 该授权将与您的默认设置结合在一起作为附加过滤器. 它将进一步过滤您的结果,而不是给您其他授权.

例子33. HBase Shell
hbase> get_auths 'myUser'
hbase> scan 'table1', AUTHORIZATIONS => ['private']
例子34. Java API
...
public Void run() throws Exception {
  String[] auths1 = { SECRET, CONFIDENTIAL };
  GetAuthsResponse authsResponse = null;
  try {
    VisibilityClient.setAuths(conf, auths1, user);
    try {
      authsResponse = VisibilityClient.getAuths(conf, user);
    } catch (Throwable e) {
      fail("Should not have failed");
    }
  } catch (Throwable e) {
  }
  List<String> authsList = new ArrayList<String>();
  for (ByteString authBS : authsResponse.getAuthList()) {
    authsList.add(Bytes.toString(authBS.toByteArray()));
  }
  assertEquals(2, authsList.size());
  assertTrue(authsList.contains(SECRET));
  assertTrue(authsList.contains(CONFIDENTIAL));
  return null;
}
...

60.3.3. Implementing Your Own Visibility Label Algorithm

解释为给定的获取/扫描请求验证的标签是可插入的算法.

您可以使用属性hbase.regionserver.scan.visibility.label.generator.class指定一个或多个自定义插件. 第一个ScanLabelGenerator的输出将是下一个ScanLabelGenerator的输入,直到列表末尾.

默认实现是在HBASE-12466中实现的,它加载两个插件FeedUserAuthScanLabelGeneratorDefinedSetFilterScanLabelGenerator . 参见[reading_cells_with_labels] .

60.3.4. Replicating Visibility Tags as Strings

如以上各节所述,接口VisibilityLabelService可用于实现以不同方式在单元格中存储可见性表达式的方式. 启用复制的群集还必须将可见性表达式复制到对等群集. 如果将DefaultVisibilityLabelServiceImpl用作VisibilityLabelService的实现,则基于标签表中存储的每个可见性标签的所有序号,所有可见性表达式都将转换为相应的表达式. 在复制过程中,可见细胞也将以基于序数的表达完整地复制. 对等群集可能不具有相同的labels表,并且具有相同的可见性标签顺序映射. 在这种情况下,复制普通字母毫无意义. 如果复制以字符串形式传输的可见性表达式发生,那将更好. 要将可见性表达式作为字符串复制到对等集群,请创建一个RegionServerObserver配置,该配置基于VisibilityLabelService接口的实现来工作. 通过以下配置,可以将可见性表达式作为字符串复制到对等群集. 有关更多详细信息,请参见HBASE-11639 .

<property>
  <name>hbase.coprocessor.regionserver.classes</name>
  <value>org.apache.hadoop.hbase.security.visibility.VisibilityController$VisibilityReplication</value>
</property>

60.4. Transparent Encryption of Data At Rest

HBase提供了一种机制,用于保护位于HDFS或另一个分布式文件系统中的HFiles和WAL中的静态数据. 两层体系结构用于灵活和非侵入式密钥旋转. "透明"表示无需在客户端进行任何实现更改. 写入数据时,将对其进行加密. 读取后,将按需解密.

60.4.1. How It Works

管理员为群集设置一个主密钥,该主密钥存储在密钥提供程序中,每个信任的HBase进程均可访问该密钥提供程序,包括管理工作站上的HMaster,RegionServers和客户端(例如HBase Shell). 默认密钥提供者与Java KeyStore API以及任何支持它的密钥管理系统集成在一起. 其他自定义密钥提供程序实现也是可能的. 密钥检索机制在hbase-site.xml配置文件中进行配置. 主密钥可以存储在群集服务器上,受安全的KeyStore文件保护,也可以存储在外部密钥服务器上,或者存储在硬件安全模块中. HBase进程会通过配置的密钥提供程序根据需要解析此主密钥.

接下来,可以通过创建或修改列描述符以包括两个附加属性,在模式中为每个列族指定加密使用:所使用的加密算法的名称(当前仅支持" AES"),以及可选的用集群主密钥包装(加密)的数据密钥. 如果未为ColumnFamily显式配置数据密钥,则HBase将为每个HFile创建一个随机数据密钥. 与替代方案相比,这提供了安全性方面的增量改进. 除非需要提供显式的数据密钥,例如在生成加密的HFile以使用给定的数据密钥批量导入的情况下,否则,仅在ColumnFamily模式元数据中指定加密算法,然后让HBase根据需要创建数据密钥. 每列族键可促进低冲击的增量键旋转,并减小键材料外部泄漏的范围. 包装的数据密钥存储在ColumnFamily架构元数据中,并存储在Column Family的每个HFile中,并使用集群主密钥进行加密. 配置列系列进行加密后,所有新的HFile将被写入加密状态. 为确保对所有HFile进行加密,请在启用此功能后触发重大压缩.

打开HFile时,将从HFile中提取数据密钥,并使用群集主密钥对其进行解密,然后将其用于解密HFile的其余部分. 如果主密钥不可用,则HFile将不可读. 如果远程用户由于HDFS权限的某些失效或从不当丢弃的媒体而以某种方式获得了对HFile数据的访问权限,则将无法解密数据密钥或文件数据.

也可以对WAL进行加密. 即使WAL是瞬态的,在基础文件系统遭到破坏的情况下,也有必要对WALEdits进行加密,以避免绕过HFile对加密列族的保护. 启用WAL加密后,所有WAL都会被加密,无论相关的HFile是否已加密.

60.4.2. Server-Side Configuration

此过程假定您正在使用默认的Java密钥库实现. 如果您使用的是自定义实现,请查看其文档并进行相应调整.

  1. 使用keytool实用程序为AES加密创建适当长度的秘密密钥.

    $ keytool -keystore /path/to/hbase/conf/hbase.jks \
      -storetype jceks -storepass **** \
      -genseckey -keyalg AES -keysize 128 \
      -alias <alias>

    ****替换为密钥库文件的密码,将<alias>替换为HBase服务帐户的用户名或任意字符串. 如果使用任意字符串,则需要配置HBase才能使用它,下面将对此进行介绍. 指定适当的密钥大小. 不要为密钥指定单独的密码,而是在出现提示时按Return键.

  2. 在密钥文件上设置适当的权限,并将其分发给所有HBase服务器.

    上一条命令在HBase conf /目录中创建了一个名为hbase.jks的文件. 对此文件设置权限和所有权,以便只有HBase服务帐户用户可以读取该文件,并将密钥安全地分发给所有HBase服务器.

  3. 配置HBase守护程序.

    在区域服务器上的hbase-site.xml中设置以下属性,以配置HBase守护程序以使用由KeyStore文件支持的密钥提供者或检索集群主密钥. 在下面的示例中,将****替换为密码.

    <property>
      <name>hbase.crypto.keyprovider</name>
      <value>org.apache.hadoop.hbase.io.crypto.KeyStoreKeyProvider</value>
    </property>
    <property>
      <name>hbase.crypto.keyprovider.parameters</name>
      <value>jceks:///path/to/hbase/conf/hbase.jks?password=****</value>
    </property>

    By default, the HBase service account name will be used to resolve the cluster master key. However, you can store it with an arbitrary alias (in the keytool command). In that case, set the following property to the alias you used.

    <property>
      <name>hbase.crypto.master.key.name</name>
      <value>my-alias</value>
    </property>

    您还需要确保您的HFiles使用HFile v3,以便使用透明加密. 这是HBase 1.0及更高版本的默认配置. 对于以前的版本,请在hbase-site.xml文件中设置以下属性.

    <property>
      <name>hfile.format.version</name>
      <value>3</value>
    </property>

    (可选)您可以使用其他密码提供程序,即Java密码学加密(JCE)算法提供程序或自定义HBase密码实现.

    • JCE:

      • 安装签名的JCE提供程序(支持具有128位密钥的AES/CTR/NoPadding模式)

      • 以最高优先级将其添加到JCE站点配置文件$ JAVA_HOME / lib / security / java.security中 .

      • 更新hbase.crypto.algorithm.aes.provider -site.xml中的 hbase.crypto.algorithm.aes.providerhbase.crypto.algorithm.rng.provider选项.

    • 自定义HBase密码:

      • Implement org.apache.hadoop.hbase.io.crypto.CipherProvider.

      • 将实现添加到服务器类路径.

      • Update hbase.crypto.cipherprovider in hbase-site.xml.

  4. 配置WAL加密.

    通过设置以下属性,在每个RegionServer的hbase-site.xml中配置WAL加密. 您也可以将它们包含在HMaster的hbase-site.xml中,但是HMaster没有WAL,因此不会使用它们.

    <property>
      <name>hbase.regionserver.hlog.reader.impl</name>
      <value>org.apache.hadoop.hbase.regionserver.wal.SecureProtobufLogReader</value>
    </property>
    <property>
      <name>hbase.regionserver.hlog.writer.impl</name>
      <value>org.apache.hadoop.hbase.regionserver.wal.SecureProtobufLogWriter</value>
    </property>
    <property>
      <name>hbase.regionserver.wal.encryption</name>
      <value>true</value>
    </property>
  5. hbase-site.xml文件上配置权限.

    由于密钥库密码存储在hbase-site.xml中,因此需要确保只有HBase用户可以使用文件所有权和权限来读取hbase-site.xml文件.

  6. 重新启动集群.

    将新的配置文件分发到所有节点,然后重新启动集群.

60.4.3. Administration

可以在HBase Shell或Java API中执行管理任务.

Java API

本节中的Java API示例摘自源文件hbase-server / src / test / java / org / apache / hadoop / hbase / util / TestHBaseFsckEncryption.java . .

这些示例以及它们的源文件均不是公共HBase API的一部分,并且仅出于说明目的而提供. 有关使用说明,请参考官方API.

Enable Encryption on a Column Family

要在列族上启用加密,可以使用HBase Shell或Java API. 启用加密后,触发一次重大压缩. 当主要压缩完成时,将对HFiles进行加密.

Rotate the Data Key

要旋转数据键,请首先更改列描述符中的ColumnFamily键,然后触发主要压缩. 压缩完成后,将使用新的数据密钥重新加密所有HFile. 在压缩完成之前,仍可以使用旧密钥读取旧的HFile.

Switching Between Using a Random Data Key and Specifying A Key

如果您将列系列配置为使用特定键,并且想要返回使用对该列系列使用随机生成的键的默认行为,请使用Java API更改HColumnDescriptor以便不随键ENCRYPTION_KEY发送任何值.

Rotate the Master Key

要旋转主密钥,请首先生成并分发新密钥. 然后更新密钥库以包含新的主密钥,并使用其他别名将旧的主密钥保留在密钥库中. 接下来,将回退配置为hbase-site.xml文件中的旧主密钥.

60.5. Secure Bulk Load

安全模式下的批量加载比普通设置要复杂得多,因为客户端必须将MapReduce作业生成的文件的所有权转移到HBase. 安全大容量加载由名为SecureBulkLoadEndpoint的协处理器实现,该协处理器使用由配置属性hbase.bulkload.staging.dir配置的暂存目录,该配置属性默认为/ tmp / hbase-staging / .

安全批量加载算法
  • 仅创建一个暂存目录,该暂存目录可在世界范围内遍历并由运行HBase的用户拥有(模式711或rwx—​x—​x ). 该目录的清单将类似于以下内容:

    $ ls -ld /tmp/hbase-staging
    drwx--x--x  2 hbase  hbase  68  3 Sep 14:54 /tmp/hbase-staging
  • 用户将数据写到该用户拥有的安全输出目录中. 例如, / user / foo / data .

  • 在内部,HBase创建一个可全局读取/写入的秘密登台目录( -rwxrwxrwx, 777 ). 例如, / tmp / hbase-staging / averylongandrandomdirectoryname . 该目录的名称和位置不向用户公开. HBase管理此目录的创建和删除.

  • 用户使数据可全球读取和写入,然后将其移动到随机暂存目录中,然后调用SecureBulkLoadClient#bulkLoadHFiles方法.

安全性的强度在于秘密目录的长度和随机性.

要启用安全的批量加载,请将以下属性添加到hbase-site.xml .

<property>
  <name>hbase.bulkload.staging.dir</name>
  <value>/tmp/hbase-staging</value>
</property>
<property>
  <name>hbase.coprocessor.region.classes</name>
  <value>org.apache.hadoop.hbase.security.token.TokenProvider,
  org.apache.hadoop.hbase.security.access.AccessController,org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint</value>
</property>
 <property>
  <name>hbase.security.authorization</name>
  <value>true</value>
</property>

61. Security Configuration Example

此配置示例包括对HFile v3,ACL,可见性标签的支持,以及对静态数据和WAL的透明加密. 所有选项已在上文各节中分别讨论.

例子35. hbase-site.xml中的例子安全设置
<!-- HFile v3 Support -->
<property>
  <name>hfile.format.version</name>
  <value>3</value>
</property>
<!-- HBase Superuser -->
<property>
  <name>hbase.superuser</name>
  <value>hbase, admin</value>
</property>
<!-- Coprocessors for ACLs and Visibility Tags -->
<property>
  <name>hbase.coprocessor.region.classes</name>
  <value>org.apache.hadoop.hbase.security.access.AccessController,
  org.apache.hadoop.hbase.security.visibility.VisibilityController,
  org.apache.hadoop.hbase.security.token.TokenProvider</value>
</property>
<property>
  <name>hbase.coprocessor.master.classes</name>
  <value>org.apache.hadoop.hbase.security.access.AccessController,
  org.apache.hadoop.hbase.security.visibility.VisibilityController</value>
</property>
<property>
  <name>hbase.coprocessor.regionserver.classes</name>
  <value>org.apache.hadoop/hbase.security.access.AccessController,
  org.apache.hadoop.hbase.security.access.VisibilityController</value>
</property>
<!-- Executable ACL for Coprocessor Endpoints -->
<property>
  <name>hbase.security.exec.permission.checks</name>
  <value>true</value>
</property>
<!-- Whether a user needs authorization for a visibility tag to set it on a cell -->
<property>
  <name>hbase.security.visibility.mutations.checkauth</name>
  <value>false</value>
</property>
<!-- Secure RPC Transport -->
<property>
  <name>hbase.rpc.protection</name>
  <value>privacy</value>
 </property>
 <!-- Transparent Encryption -->
<property>
  <name>hbase.crypto.keyprovider</name>
  <value>org.apache.hadoop.hbase.io.crypto.KeyStoreKeyProvider</value>
</property>
<property>
  <name>hbase.crypto.keyprovider.parameters</name>
  <value>jceks:///path/to/hbase/conf/hbase.jks?password=***</value>
</property>
<property>
  <name>hbase.crypto.master.key.name</name>
  <value>hbase</value>
</property>
<!-- WAL Encryption -->
<property>
  <name>hbase.regionserver.hlog.reader.impl</name>
  <value>org.apache.hadoop.hbase.regionserver.wal.SecureProtobufLogReader</value>
</property>
<property>
  <name>hbase.regionserver.hlog.writer.impl</name>
  <value>org.apache.hadoop.hbase.regionserver.wal.SecureProtobufLogWriter</value>
</property>
<property>
  <name>hbase.regionserver.wal.encryption</name>
  <value>true</value>
</property>
<!-- For key rotation -->
<property>
  <name>hbase.crypto.master.alternate.key.name</name>
  <value>hbase.old</value>
</property>
<!-- Secure Bulk Load -->
<property>
  <name>hbase.bulkload.staging.dir</name>
  <value>/tmp/hbase-staging</value>
</property>
<property>
  <name>hbase.coprocessor.region.classes</name>
  <value>org.apache.hadoop.hbase.security.token.TokenProvider,
  org.apache.hadoop.hbase.security.access.AccessController,org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint</value>
</property>
 <property>
  <name>hbase.security.authorization</name>
  <value>true</value>
</property>
示例36. Hadoop core-site.xml中的示例组映射器

调整这些设置以适合您的环境.

<property>
  <name>hadoop.security.group.mapping</name>
  <value>org.apache.hadoop.security.LdapGroupsMapping</value>
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.url</name>
  <value>ldap://server</value>
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.bind.user</name>
  <value>Administrator@example-ad.local</value>
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.bind.password</name>
  <value>****</value> <!-- Replace with the actual password -->
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.base</name>
  <value>dc=example-ad,dc=local</value>
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.search.filter.user</name>
  <value>(&amp;(objectClass=user)(sAMAccountName={0}))</value>
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.search.filter.group</name>
  <value>(objectClass=group)</value>
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.search.attr.member</name>
  <value>member</value>
</property>
<property>
  <name>hadoop.security.group.mapping.ldap.search.attr.group.name</name>
  <value>cn</value>
</property>

Architecture

62. Overview

62.1. NoSQL?

HBase是一种" NoSQL"数据库. " NoSQL"是一个通用术语,表示该数据库不是支持SQL作为其主要访问语言的RDBMS,但是NoSQL数据库的类型很多:BerkeleyDB是本地NoSQL数据库的示例,而HBase在很大程度上分布式数据库. 从技术上讲,HBase实际上比"数据库"更像是"数据存储",因为它缺少您在RDBMS中发现的许多功能,例如类型化的列,二级索引,触发器和高级查询语言等.

但是,HBase具有支持线性和模块化缩放的许多功能. HBase群集通过添加在商品类服务器上托管的RegionServer来扩展. 例如,如果一个群集从10个RegionServer扩展到20个,则在存储和处理能力方面都将翻倍. RDBMS可以很好地扩展,但是只能扩展到一个点-特别是单个数据库服务器的大小-为了获得最佳性能,需要专用的硬件和存储设备. 注意的HBase功能包括:

  • 高度一致的读/写:HBase不是"最终一致"的DataStore. 这使得它非常适合诸如高速计数器聚合之类的任务.

  • 自动分片:HBase表通过区域分布在集群上,并且随着数据的增长,区域会自动拆分和重新分布.

  • 自动RegionServer故障转移

  • Hadoop / HDFS集成:HBase开箱即用地支持HDFS作为其分布式文件系统.

  • MapReduce:HBase通过MapReduce支持大规模并行化处理,以将HBase用作源和接收器.

  • Java客户端API:HBase支持易于使用的Java API进行编程访问.

  • Thrift/REST API: HBase also supports Thrift and REST for non-Java front-ends.

  • 块缓存和Bloom过滤器:HBase支持块缓存和Bloom过滤器,以进行大量查询优化.

  • 运营管理:HBase提供了内置的网页,以提供运营见解以及JMX指标.

62.2. When Should I Use HBase?

HBase并不适合所有问题.

首先,请确保您有足够的数据. 如果您有数亿或数十亿行,那么HBase是一个很好的选择. 如果您只有数千行/百万行,则使用传统的RDBMS可能是一个更好的选择,原因是您的所有数据都可能在单个节点(或两个节点)上结束,而集群的其余部分可能处于停顿状态闲.

其次,确保没有RDBMS提供的所有其他功能(例如,类型化的列,二级索引,事务,高级查询语言等),您就可以生存.仅仅通过更改,不能将基于RDBMS构建的应用程序"移植"到HBase.例如JDBC驱动程序. 考虑从RDBMS迁移到HBase,作为与端口相对的完整重新设计.

第三,确保您有足够的硬件. 即使少于5个DataNode(由于诸如HDFS块复制(默认值为3)之类的东西)以及一个NameNode,HDFS也不能很好地处理.

HBase在笔记本电脑上可以很好地独立运行-但这仅应视为开发配置.

62.3. What Is The Difference Between HBase and Hadoop/HDFS?

HDFS是一个分布式文件系统,非常适合存储大文件. 它的文档指出,它不是通用文件系统,并且不提供文件中快速的单个记录查找. 另一方面,HBase构建在HDFS之上,并为大型表提供快速记录查找(和更新). 有时这可能是概念上的混乱点. HBase在内部将数据放入HDFS上存在的索引" StoreFiles"中,以进行高速查找. 有关HBase如何实现其目标的更多信息,请参见数据模型和本章的其余部分.

63. Catalog Tables

目录表hbase:meta作为HBase表存在,并hbase:meta HBase Shell的list命令中过滤出来,但实际上是一个表,与其他任何表一样.

63.1. -ROOT-

在HBase 0.96.0中删除了-ROOT-表. 这里的信息应视为历史信息.

-ROOT-表跟踪.META 0.96之前的.META表(该表的.META名称,现在称为hbase:meta )的位置. -ROOT-表结构如下:

Key
  • .META. 区域密钥( .META.,,1

Values
  • info:regioninfo regioninfohbase:meta序列化HRegionInfo实例)

  • info:server (RegionServer的服务器:端口,持有hbase:meta

  • info:serverstartcode (保存hbase:meta的RegionServer进程的开始时间)

63.2. hbase:meta

hbase:meta表(以前称为.META. )保留了系统中所有区域的列表. hbase:meta的位置以前在-ROOT-表中被跟踪过,但是现在存储在ZooKeeper中.

hbase:meta表结构如下:

Key
  • 格式的区域键( [table],[region start key],[region id]

Values
  • info:regioninfo regioninfo (此区域的序列化HRegionInfo实例)

  • info:server (包含该区域的RegionServer的server:port)

  • info:serverstartcode (包含该区域的RegionServer进程的开始时间)

When a table is in the process of splitting, two other columns will be created, called info:splitA and info:splitB. These columns represent the two daughter regions. The values for these columns are also serialized HRegionInfo instances. After the region has been split, eventually this row will be deleted.

关于HRegionInfo的说明

空键用于表示表的开始和结束. 起始键为空的区域是表中的第一个区域. 如果一个区域同时具有空的开始键和空的结束键,则它是表中唯一的区域

在(极有希望)事件中,需要对目录元数据进行编程处理,请参见http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Writables.html#getHRegionInfo(byte%29 [ [可写内容]实用程序.

63.3. Startup Sequencing

首先,在ZooKeeper中查找hbase:meta的位置. 接下来,使用服务器和起始码值更新hbase:meta .

有关region-RegionServer分配的信息,请参见Region-RegionServer分配 .

64. Client

HBase客户端找到正在服务的特定行范围的RegionServer. 它通过查询hbase:meta表来做到这一点. 有关详细信息,请参见hbase:meta . 找到所需的区域后,客户端将联系服务于该区域的RegionServer,而不是通过主服务器,并发出读取或写入请求. 此信息被缓存在客户端中,因此后续请求无需经过查找过程. 如果由主负载平衡器重新分配了区域,或者由于RegionServer已经失效,则客户端将重新查询目录表以确定用户区域的新位置.

有关主服务器对HBase客户端通信的影响的更多信息,请参见运行时影响 .

管理功能通过Admin实例完成

64.1. Cluster Connections

API在HBase 1.0中已更改. 有关连接配置的信息,请参阅连接到HBase群集的客户端配置和依赖项 .

64.1.1. API as of HBase 1.0.0

它已被清理,并且向用户返回了要使用的接口,而不是针对特定类型的接口. 在HBase 1.0中,从ConnectionFactory获取一个Connection对象,然后根据需要从中获取TableAdminRegionLocator实例. 完成后,关闭获得的实例. 最后,请确保在退出前清理Connection实例. Connections是重量级的对象,但是线程安全的,因此您可以为您的应用程序创建一个连接并保留该实例. TableAdminRegionLocator实例是轻量级的. 随心所欲创建,然后在关闭时立即放手. 有关新HBase 1.0 API的示例用法,请参阅客户端软件包Javadoc说明 .

64.1.2. API before HBase 1.0.0

HTable实例是与1.0.0之前的HBase群集进行交互的方式. 实例不是线程安全的 . 在任何给定时间,只有一个线程可以使用Table的实例. 创建表实例时,建议使用相同的HBaseConfiguration实例. 这将确保通常将ZooKeeper和套接字实例共享到RegionServer. 例如,这是首选:

HBaseConfiguration conf = HBaseConfiguration.create();
HTable table1 = new HTable(conf, "myTable");
HTable table2 = new HTable(conf, "myTable");

与此相反:

HBaseConfiguration conf1 = HBaseConfiguration.create();
HTable table1 = new HTable(conf1, "myTable");
HBaseConfiguration conf2 = HBaseConfiguration.create();
HTable table2 = new HTable(conf2, "myTable");

有关如何在HBase客户端中处理连接的更多信息,请参见ConnectionFactory .

Connection Pooling

对于需要高端多线程访问的应用程序(例如,可能在单个JVM中服务多个应用程序线程的Web服务器或应用程序服务器),您可以预先创建一个Connection ,如以下示例所示:

例子37.预创建一个Connection
// Create a connection to the cluster.
Configuration conf = HBaseConfiguration.create();
try (Connection connection = ConnectionFactory.createConnection(conf)) {
  try (Table table = connection.getTable(TableName.valueOf(tablename)) {
    // use table as needed, the table returned is lightweight
  }
}

构造HTableInterface实现非常轻巧,并且可以控制资源.

HTablePool已弃用

本指南的先前版本讨论了HTablePoolHTablePool在HBase HTablePool和0.96中已弃用,并在0.98.1中由HBASE-6500HConnection ,而HConnection在HBase 1.0中已由Connection弃用. 请改用Connection .

64.2. WriteBuffer and Batch Methods

在HBase 1.0和更高版本中,不推荐使用HTable,而推荐使用Table . Table不使用自动刷新. 要进行缓冲写入,请使用BufferedMutator类.

在丢弃TableHTable实例之前,请调用close()flushCommits() ,这样`Put`不会丢失.

有关写持久性的其他信息,请查看ACID语义页面.

要对PutDelete的批处理进行细粒度控制,请参阅表上的批处理方法.

64.3. External Clients

Apache HBase外部API涵盖了有关非Java客户端和自定义协议的信息.

65. Client Request Filters

可以选择使用在RegionServer上应用的筛选器来配置GetScan实例.

过滤器可能会造成混乱,因为存在许多不同的类型,因此最好通过了解过滤器功能组来接近它们.

65.1. Structural

结构过滤器包含其他过滤器.

65.1.1. FilterList

FilterList表示过滤器列表,在过滤器之间具有FilterList.Operator.MUST_PASS_ALLFilterList.Operator.MUST_PASS_ONE关系. 以下示例显示了两个过滤器之间的"或"(检查同一属性上的"我的值"或"我的其他值").

FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);
SingleColumnValueFilter filter1 = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  Bytes.toBytes("my value")
  );
list.add(filter1);
SingleColumnValueFilter filter2 = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  Bytes.toBytes("my other value")
  );
list.add(filter2);
scan.setFilter(list);

65.2. Column Value

65.2.1. SingleColumnValueFilter

SingleColumnValueFilter可用于测试列值的等效性( CompareOp.EQUAL ),不等式( CompareOp.NOT_EQUAL )或范围(例如CompareOp.GREATER ). 以下是测试将列与字符串值" my value"等价的示例……

SingleColumnValueFilter filter = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  Bytes.toBytes("my value")
  );
scan.setFilter(filter);

65.3. Column Value Comparators

Filter包中有几个Comparator类值得特别提及. 这些比较器与其他过滤器(例如SingleColumnValueFilter)一起使用 .

65.3.1. RegexStringComparator

RegexStringComparator支持用于值比较的正则表达式.

RegexStringComparator comp = new RegexStringComparator("my.");   // any value that starts with 'my'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  comp
  );
scan.setFilter(filter);

有关Java中受支持的RegEx模式的信息,请参见Oracle JavaDoc.

65.3.2. SubstringComparator

SubstringComparator可用于确定值中是否存在给定的子字符串. 比较不区分大小写.

SubstringComparator comp = new SubstringComparator("y val");   // looking for 'my value'
SingleColumnValueFilter filter = new SingleColumnValueFilter(
  cf,
  column,
  CompareOp.EQUAL,
  comp
  );
scan.setFilter(filter);

65.3.3. BinaryPrefixComparator

65.3.4. BinaryComparator

65.4. KeyValue Metadata

由于HBase在内部将数据存储为键值对,因此键值元数据过滤器会评估行的键(即ColumnFamily:Column限定符)的存在,而不是上一节中的值.

65.4.1. FamilyFilter

FamilyFilter可用于对ColumnFamily进行过滤. 通常,在"扫描"中选择ColumnFamilies比使用"过滤器"更好.

65.4.2. QualifierFilter

QualifierFilter可用于根据列(又称Qualifier)名称进行过滤.

65.4.3. ColumnPrefixFilter

ColumnPrefixFilter可用于基于Column(aka限定符)名称的开头部分进行过滤.

ColumnPrefixFilter在与每一行和每个涉及的列族匹配的第一列之前搜索. 它可用于有效地获取非常宽的行中的列的子集.

注意:同一列限定符可用于不同的列族. 该过滤器返回所有匹配的列.

示例:查找行和族中以" abc"开头的所有列

HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] prefix = Bytes.toBytes("abc");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnPrefixFilter(prefix);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
  for (KeyValue kv : r.raw()) {
    // each kv represents a column
  }
}
rs.close();

65.4.4. MultipleColumnPrefixFilter

MultipleColumnPrefixFilter的行为类似于ColumnPrefixFilter,但允许指定多个前缀.

与ColumnPrefixFilter一样,MultipleColumnPrefixFilter可以高效地搜索与最低前缀匹配的第一列,并且还可以搜索前缀之间的列的过去范围. 它可用于有效地从非常宽的行中获取不连续的列集.

示例:查找行和族中以" abc"或" xyz"开头的所有列

HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[][] prefixes = new byte[][] {Bytes.toBytes("abc"), Bytes.toBytes("xyz")};
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new MultipleColumnPrefixFilter(prefixes);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
  for (KeyValue kv : r.raw()) {
    // each kv represents a column
  }
}
rs.close();

65.4.5. ColumnRangeFilter

ColumnRangeFilter允许有效的行内扫描.

ColumnRangeFilter可以针对每个涉及的列族向前搜索第一个匹配列. 它可以用于有效地获取非常宽的行的列的"切片". 也就是说,您连续有一百万列,但您只想查看bbbb-bbdd列.

注意:同一列限定符可用于不同的列族. 该过滤器返回所有匹配的列.

示例:查找" bbbb"(包括)和" bbdd"(包括)之间的行和族的所有列

HTableInterface t = ...;
byte[] row = ...;
byte[] family = ...;
byte[] startColumn = Bytes.toBytes("bbbb");
byte[] endColumn = Bytes.toBytes("bbdd");
Scan scan = new Scan(row, row); // (optional) limit to one row
scan.addFamily(family); // (optional) limit to one family
Filter f = new ColumnRangeFilter(startColumn, true, endColumn, true);
scan.setFilter(f);
scan.setBatch(10); // set this if there could be many columns returned
ResultScanner rs = t.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
  for (KeyValue kv : r.raw()) {
    // each kv represents a column
  }
}
rs.close();

注意:在HBase 0.92中引入

65.5. RowKey

65.5.1. RowFilter

通常最好在Scan上使用startRow / stopRow方法进行行选择,但是也可以使用RowFilter .

65.6. Utility

65.6.1. FirstKeyOnlyFilter

这主要用于行数作业. 参见FirstKeyOnlyFilter .

66. Master

HMaster是主服务器的实现. 主服务器负责监视群集中的所有RegionServer实例,并且是所有元数据更改的接口. 在分布式群集中,主服务器通常在NameNode上运行. J Mohamed Zahoor在此博客文章HBase HMaster Architecture中进一步介绍了Master Architecture .

66.1. Startup Behavior

如果在多主服务器环境中运行,则所有主服务器都将竞争运行集群. 如果活动的主服务器失去了在ZooKeeper中的租约(或主服务器关闭),则剩余的主服务器将争夺接管主服务器的角色.

66.2. Runtime Impact

常见的分发列表问题涉及当主服务器崩溃时,HBase群集会发生什么情况. 因为HBase客户端直接与RegionServer通信,所以群集仍可以在"稳定状态"下运行. 此外,对于每个Catalog Tableshbase:meta作为HBase表存在,并且不驻留在Master中. 但是,主服务器控制着关键功能,例如RegionServer故障转移和完成区域划分. 因此,尽管在没有主机的情况下群集仍可以短时间运行,但是应尽快重新启动主机.

66.3. Interface

HMasterInterface公开的方法主要是面向元数据的方法:

  • 表(createTable,modifyTable,removeTable,启用,禁用)

  • ColumnFamily(addColumn,modifyColumn,removeColumn)

  • 区域(移动,分配,取消分配)例如,当调用Admin方法disableTable ,它由主服务器提供服务.

66.4. Processes

主服务器运行几个后台线程:

66.4.1. LoadBalancer

周期性地,当没有过渡区域时,负载均衡器将运行并移动区域以平衡集群的负载. 请参阅平衡器以配置此属性.

有关区域分配的更多信息,请参见Region-RegionServer分配 .

66.4.2. CatalogJanitor

定期检查并清理hbase:meta表. 有关元表的更多信息,请参见<arch.catalog.meta >>.

67. RegionServer

HRegionServer是RegionServer实现. 它负责服务和管理区域. 在分布式群集中,RegionServer在DataNode上运行.

67.1. Interface

HRegionRegionInterface公开的方法HRegionRegionInterface包含面向数据的方法和区域维护方法:

  • 数据(获取,放置,删除,下一个等)

  • 区域(splitRegion,compactRegion等)例如,当在表上调用Admin方法majorCompact时,客户端实际上会遍历指定表的所有区域,并直接向每个区域请求大压缩.

67.2. Processes

RegionServer运行各种后台线程:

67.2.1. CompactSplitThread

检查是否有裂痕并处理较小的压实.

67.2.2. MajorCompactionChecker

检查重大压实.

67.2.3. MemStoreFlusher

定期将MemStore中的内存中写入刷新到StoreFiles.

67.2.4. LogRoller

定期检查RegionServer的WAL.

67.3. Coprocessors

Coprocessors were added in 0.92. There is a thorough Blog Overview of CoProcessors posted. Documentation will eventually move to this reference guide, but the blog is the most current information available at this time.

67.4. Block Cache

HBase提供了两种不同的BlockCache实现:默认的堆上LruBlockCacheBucketCache (通常是堆外). 本节讨论每种实现的优缺点,如何选择适当的选项以及每种实现的配置选项.

块缓存报告:UI

有关缓存部署的详细信息,请参见RegionServer UI. 自HBase 0.98.4起,块缓存详细信息已得到显着扩展,显示了配置,大小,当前使用情况,缓存时间,甚至块计数和类型的详细信息.

67.4.1. Cache Choices

LruBlockCache是原始实现,并且完全在Java堆中. BucketCache主要用于使块缓存数据不在堆中,尽管BucketCache也可以使数据在堆中并从文件支持的缓存中提供服务.

自HBase 0.98.6起,BucketCache已投入生产

要与BucketCache一起运行,您需要HBASE-11678. 这包括在0.98.6中.

与本地堆上的LruBlockCache相比,从BucketCache进行获取时,获取总是比较慢. 但是,随着时间的流逝,延迟往往不那么固定,因为使用BucketCache时,由于它管理的是BlockCache分配而不是GC,因此垃圾收集较少. 如果以非堆模式部署BucketCache,则此内存完全不受GC管理. 这就是为什么要使用BucketCache的原因,因此延迟较小,可以减少GC和堆碎片. 请参阅Nick Dimiduk的BlockCache 101,以进行堆上和堆外测试的比较. 另请参阅比较BlockCache部署 ,该发现发现如果您的数据集适合您的LruBlockCache部署,请使用它,否则,如果您遇到缓存混乱(或者您希望缓存存在于Java GC的多变之外),请使用BucketCache.

启用BucketCache时,将启用两层缓存系统,即由LruBlockCache实例实现的L1缓存和由BucketCache实现的堆外L2缓存. 这两个层的管理以及指示块之间如何移动的策略是由CombinedBlockCache . 它将所有DATA块保留在L2 BucketCache中,将meta块(INDEX和BLOOM块) LruBlockCache在L1 LruBlockCache . 有关脱堆的更多详细信息,请参见堆外块缓存 .

67.4.2. General Cache Configurations

除了缓存实现本身之外,您还可以设置一些常规配置选项来控制缓存的执行方式. 请参阅http://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/io/hfile/CacheConfig.html . 设置任何这些选项之后,请重新启动或滚动重新启动群集以使配置生效. 检查日志中是否有错误或意外行为.

See also Prefetch Option for Blockcache, which discusses a new option introduced in HBASE-9857.

67.4.3. LruBlockCache Design

LruBlockCache是​​一个LRU缓存,其中包含三个级别的块优先级,以允许进行扫描抵抗和内存中的ColumnFamilies:

  • 单一访问优先级:首次从HDFS加载块时,它通常具有此优先级,它将成为驱逐期间要考虑的第一个组的一部分. 优点是,与使用率更高的块相比,扫描的块更有可能被驱逐.

  • 多路访问优先级:如果再次访问先前优先级组中的块,则它将升级到该优先级. 因此,它是驱逐期间考虑的第二组的一部分.

  • 内存中访问优先级:如果将块的族配置为"内存中",则无论访问次数如何,它都是该优先级的一部分. 目录表的配置如下. 该小组是驱逐期间考虑的最后一个小组.

    To mark a column family as in-memory, call

HColumnDescriptor.setInMemory(true);

如果从Java创建表,或者在外壳中创建或更改表时将IN_MEMORY ⇒ true设置为:

hbase(main):003:0> create  't', {NAME => 'f', IN_MEMORY => 'true'}

有关更多信息,请参见LruBlockCache源.

67.4.4. LruBlockCache Usage

默认情况下,所有用户表都启用块缓存,这意味着任何读取操作都将加载LRU缓存. 这对于许多用例而言可能是好的,但是通常需要进行进一步的调整才能获得更好的性能. 一个重要的概念是工作集大小或WSS,即:"计算问题答案所需的内存量". 对于网站而言,这就是在短时间内回答查询所需要的数据.

计算HBase中可用于缓存的内存量的方法是:

number of region servers * heap size * hfile.block.cache.size * 0.99

块高速缓存的默认值为0.25,占可用堆的25%. 最后一个值(99%)是LRU缓存中默认的可接受的加载因子,在此之后开始逐出. 之所以将其包含在此等式中,是因为说有可能使用100%的可用内存是不切实际的,因为这会使进程从加载新块的位置开始阻塞. 这里有些例子:

  • 一台将堆大小设置为1 GB并且默认块高速缓存大小的区域服务器将具有253 MB的块高速缓存可用.

  • 20个区域服务器(堆大小设置为8 GB)和默认块高速缓存大小将具有39.6的块高速缓存.

  • 100个区域服务器(堆大小设置为24 GB,块缓存大小为0.5)将具有约1.16 TB的块缓存.

您的数据不是块缓存的唯一居民. 以下是您可能需要考虑的其他事项:

Catalog Tables

-ROOT- (在HBase 0.96之前,请参见arch.catalog.root )和hbase:meta表被强制进入块缓存,并且具有内存中优先级,这意味着它们更难于退出. 前者使用的字节永远不会超过几百个字节,而后者则可以占用几个MB(取决于区域的数量).

HFiles Indexes

HFile是HBase用于在HDFS中存储数据的文件格式. 它包含一个多层索引,该索引使HBase无需读取整个文件即可查找数据. 这些索引的大小是块大小(默认为64KB),键的大小和要存储的数据量的因素. 对于大数据集,每个区域服务器大约有1GB的数据是很常见的,尽管并非所有数据都将存储在缓存中,因为LRU会驱逐未使用的索引.

Keys

存储的值仅是图片的一半,因为每个值都与其键(行键,家庭限定符和时间戳记)一起存储. 请参阅尝试最小化行和列的大小 .

Bloom Filters

就像HFile索引一样,那些数据结构(启用时)也存储在LRU中.

Currently the recommended way to measure HFile indexes and bloom filters sizes is to look at the region server web UI and checkout the relevant metrics. For keys, sampling can be done by using the HFile command line tool and look for the average key size metric. Since HBase 0.98.3, you can view details on BlockCache stats and metrics in a special Block Cache section in the UI.

当WSS不能容纳在内存中时,通常使用块缓存是很糟糕的. 例如,当您在所有区域服务器的块缓存中都有40GB的可用空间,但是需要处理1TB的数据时,就是这种情况. 原因之一是驱逐产生的流失将不必要地触发更多垃圾收集. 这是两个用例:

  • 完全随机读取模式:在这种情况下,您几乎不会在短时间内访问同一行两次,因此命中缓存块的机会接近0.在这样的表上设置块缓存是浪费内存和CPU周期,因此它将产生更多垃圾以供JVM处理. 有关监视GC的更多信息,请参阅《 JVM垃圾收集日志》 .

  • 映射表:在典型的MapReduce作业中,输入一个表,每行将仅被读取一次,因此无需将它们放入块缓存中. 扫描对象可以通过setCaching方法将其关闭(将其设置为false). 如果您需要快速随机读取访问权限,则仍可以在此表上保持块缓存打开状态. 一个例子是计算服务于实时流量的表中的行数,缓存该表的每个块都会造成巨大的客户流失,并且肯定会逐出当前正在使用的数据.

Caching META blocks only (DATA blocks in fscache)

一种有趣的设置是仅缓存META块,并在每次访问时读取DATA块. 如果DATA块适合fscache,则当跨非常大的数据集进行完全随机访问时,此替代方法可能有意义. 要启用此设置,请更改表,并为每个列族设置BLOCKCACHE ⇒ 'false' . 您仅针对此列系列"禁用" BlockCache. 您永远不能禁用META块的缓存. 由于HBASE-4683始终缓存索引块和Bloom块 ,因此即使禁用BlockCache,我们也将缓存META块.

67.4.5. Off-heap Block Cache

How to Enable BucketCache

BucketCache的通常部署是通过管理类进行的,该管理类设置了两个缓存层:由LruBlockCache实现的L1堆上缓存和由BucketCache实现的第二个L2缓存. 默认情况下,管理类为CombinedBlockCache . 前面的链接描述了CombinedBlockCache实现的缓存"策略". 简而言之,它通过将元数据块(IND1和BLOOM保留在L1堆上的LruBlockCache层中)和DATA数据块保留在L2的BucketCache层中而起作用. 可以在版本1.0的HBase中修改此行为,并要求通过(HColumnDescriptor.setCacheDataInL1(true)或在外壳程序中设置cacheDataInL1来在L1层cacheDataInL1列族的meta和DATA块都托管在堆上或修改将CACHE_DATA_IN_L1设置为true的列族:例如

hbase(main):003:0> create 't', {NAME => 't', CONFIGURATION => {CACHE_DATA_IN_L1 => 'true'}}

BucketCache块缓存可以部署在堆上,堆外或基于文件的位置. 您可以通过hbase.bucketcache.ioengine设置进行设置. 将其设置为heap将在分配的Java堆内部部署BucketCache. 将其设置为offheap将使BucketCache使其分配脱离堆,而ioengine的file:PATH_TO_FILE PATH_TO_FILE设置将指示BucketCache使用文件缓存(尤其是当您将一些快速I / O附加到包装盒(例如SSD)时,这很有用) .

可以部署L1 + L2设置,在此我们绕过CombinedBlockCache策略,并让BucketCache充当L1 LruBlockCache的严格L2缓存. 对于这种设置,请将CacheConfig.BUCKET_CACHE_COMBINED_KEY设置为false . 在此模式下,从L1逐出时,块进入L2. 缓存块时,首先将其缓存在L1中. 当我们寻找缓存块时,我们首先在L1中查找,如果找不到,则搜索L2. 让我们将此部署格式称为Raw L1 + L2 .

其他BucketCache配置包括:指定一个位置,以在重新启动后将缓存持久化,使用多少个线程来写入缓存,等等.有关配置选项和描述,请参见CacheConfig.html类.

BucketCache示例配置

此示例提供了4 GB的堆外BucketCache和1 GB的堆上缓存的配置.

配置在RegionServer上执行.

设置hbase.bucketcache.ioenginehbase.bucketcache.size > 0将启用CombinedBlockCache . 让我们假设RegionServer已设置为可以5G堆运行:即HBASE_HEAPSIZE=5g .

  1. 首先,编辑RegionServer的的hbase-env.sh和集HBASE_OFFHEAPSIZE的值大于离堆大小想,在这种情况下,4 GB(表示为4G). 让我们将其设置为5G. 对于我们的堆外缓存,这将是4G,对于堆外内存的任何其他用途,它将是1G(除BlockCache之外,还有其他堆外内存用户;例如,RegionServer中的DFSClient可以使用堆外内存). 请参见HBase中的直接内存使用 .

    HBASE_OFFHEAPSIZE=5G
  2. 接下来,将以下配置添加到RegionServer的hbase-site.xml中 .

    <property>
      <name>hbase.bucketcache.ioengine</name>
      <value>offheap</value>
    </property>
    <property>
      <name>hfile.block.cache.size</name>
      <value>0.2</value>
    </property>
    <property>
      <name>hbase.bucketcache.size</name>
      <value>4196</value>
    </property>
  3. 重新启动或滚动重新启动群集,并检查日志中是否有任何问题.

在上面,我们将BucketCache设置为4G. 我们将堆上的LruBlockCache配置为具有RegionServer堆大小的20%(0.2)(0.2 * 5G = 1G). 换句话说,您可以像通常那样配置L1 LruBlockCache(就像没有L2缓存一样).

HBASE-10641引入了在HBase 0.98及更高版本中为BucketCache的存储桶配置多个大小的功能. 要配置多个存储桶大小,请将新属性hfile.block.cache.sizes (而不是hfile.block.cache.size )配置为以逗号分隔的块大小列表,从最小到最大顺序排列,没有空格. 目标是根据您的数据访问模式优化存储桶大小. 以下示例配置了大小为4096和8192的存储桶.

<property>
  <name>hfile.block.cache.sizes</name>
  <value>4096,8192</value>
</property>
HBase中的直接内存使用情况

默认最大直接内存因JVM而异. 传统上,它是64M或与分配的堆大小(-Xmx)有某种关系,或者根本没有限制(显然是JDK7). HBase服务器使用直接内存,特别是短路读取,托管的DFSClient将分配直接内存缓冲区. 如果您进行堆外块缓存,则将使用直接内存. 启动JVM,请确保conf / hbase-env.sh中-XX:MaxDirectMemorySize设置被设置为某个值,该值大于您分配给堆外BlockCache( hbase.bucketcache.size )的值. 它应大于堆外块缓存,然后大于DFSClient的使用量(DFSClient使用的数量不容易量化;这是打开的HFiles的数量* hbase.dfs.client.read.shortcircuit.buffer.size其中在HBase hbase.dfs.client.read.shortcircuit.buffer.size设置为128k(请参阅hbase-default.xml默认配置). 直接内存是Java进程堆的一部分,与-Xmx分配的对象堆是分开的. MaxDirectMemorySize分配的值不得超过物理RAM,并且由于其他内存要求和系统限制,可能会小于可用的总RAM.

您可以通过查看UI中的" 服务器度量标准:内存"选项卡,查看将RegionServer配置为使用堆上和堆外/直接的内存量,以及在任何时候使用的内存量 . 也可以通过JMX获得. 特别是可以在java.nio.type=BufferPool,name=direct bean上找到服务器当前使用的直接内存. Terracotta在使用Java中的堆外内存方面写得很好 . 它是针对其产品BigMemory的,但是提到的许多问题通常都适用于任何试图摆脱困境的尝试. 一探究竟.

hbase.bucketcache.percentage.in.combinedcache

这是HBase 1.0之前的配置已删除,因为它令人困惑. 您可以将其设置为0.0到1.0之间的一个浮点值. 默认值为0.9. 如果部署使用的是CombinedBlockCache,则LruBlockCache L1的大小计算为(1 - hbase.bucketcache.percentage.in.combinedcache) * size-of-bucketcache缓存的大小,而BucketCache的大小为hbase.bucketcache.percentage.in.combinedcache * size-of-bucket-cache . 如果将桶缓存的大小本身指定为兆字节或hbase.bucketcache.size * -XX:MaxDirectMemorySize如果hbase.bucketcache.size在0到1.0之间),则配置hbase.bucketcache.size的值就是该值.

在1.0中,它应该更简单. 使用hfile.block.cache.size setting (不是最佳名称) hfile.block.cache.size setting L1 LruBlockCache大小设置为Java堆的一部分,而以绝对兆字节或分配的最大直接内存的一部分将L2设置为上述值.

67.4.6. Compressed BlockCache

HBASE- 11331引入了惰性BlockCache解压缩,简称为压缩BlockCache. 启用压缩的BlockCache后,数据和编码的数据块将以其磁盘上的格式缓存在BlockCache中,而不是在缓存之前进行解压缩和解密.

For a RegionServer hosting more data than can fit into cache, enabling this feature with SNAPPY compression has been shown to result in 50% increase in throughput and 30% improvement in mean latency while, increasing garbage collection by 80% and increasing overall CPU load by 2%. See HBASE-11331 for more details about how performance was measured and achieved. For a RegionServer hosting data that can comfortably fit into cache, or if your workload is sensitive to extra CPU or garbage-collection load, you may receive less benefit.

默认情况下,压缩的BlockCache是​​禁用的. 要启用它,设置hbase.block.data.cachecompressedtrueHBase的-site.xml中所有RegionServers.

67.5. RegionServer Splitting Implementation

当写入请求由区域服务器处理时,它们会累积在称为memstore的内存存储系统中. 内存存储填满后,其内容将作为其他存储文件写入磁盘. 此事件称为内存存储刷新 . 随着存储文件的累积,RegionServer将把它们压缩为更少,更大的文件. 每次刷新或压缩完成后,该区域中存储的数据量已更改. RegionServer会查询区域拆分策略,以确定该区域是否太大或由于其他特定于策略的原因而应拆分. 如果策略建议,则将区域划分请求加入队列.

从逻辑上讲,分割区域的过程很简单. 我们在区域的键空间中找到一个合适的点,该区域应将区域分成两半,然后在该点将区域的数据分为两个新区域. 但是,该过程的细节并不简单. 发生拆分时,新创建的子区域不会立即将所有数据重写到新文件中. 相反,它们创建类似于符号链接文件的小文件,称为参考文件 ,该文件根据拆分点指向父存储文件的顶部或底部. 参考文件的使用与常规数据文件一样,但是只考虑了一半的记录. 仅当没有更多对父区域的不可变数据文件的引用时,才可以分割区域. 这些参考文件将通过压缩逐步清除,因此该区域将停止引用其父文件,并且可以进一步拆分.

尽管分割区域是RegionServer做出的本地决定,但是分割过程本身必须与许多参与者协调. RegionServer在拆分之前和之后通知主服务器,更新.META. 表,以便客户端可以发现新的子区域,并在HDFS中重新排列目录结构和数据文件. 拆分是一个多任务过程. 为了在发生错误的情况下启用回滚,RegionServer会在内存中保留有关执行状态的日志. RegionServer拆分过程中说明了RegionServer执行拆分的步骤. 每个步骤均标有其步骤编号. 来自RegionServers或Master的操作以红色显示,而来自客户端的操作以绿色显示.

Region Split Process
Figure 1. RegionServer Split Process
  1. RegionServer在本地决定分割区域,并准备分割. 分割交易开始. 第一步,RegionServer获取表上的共享读取锁,以防止在拆分过程中修改架构. 然后,它在zookeeper中的/hbase/region-in-transition/region-name下创建一个znode,并将znode的状态设置为SPLITTING .

  2. 主节点了解此znode,因为它具有父region-in-transition znode的监视程序.

  3. RegionServer在HDFS中父级的region目录下创建一个名为.splits的子目录.

  4. RegionServer关闭父区域,并在其本地数据结构中将该区域标记为脱机. 分割区域现在离线. 此时,到达父区域的客户端请求将抛出NotServingRegionException . 客户端将重试一些退避. 关闭区域被冲洗.

  5. RegionServer在.splits目录下为子区域A和B创建区域目录,并创建必要的数据结构. 然后,它将拆分存储文件,这意味着它会在父区域中为每个存储文件创建两个参考文件. 这些参考文件将指向父区域的文件.

  6. RegionServer在HDFS中创建实际的区域目录,并移动每个子级的参考文件.

  7. RegionServer将Put请求发送到.META. 表,以在.META.父级设置为脱机.META. 表并添加有关子区域的信息. 此时, .META.中将没有单独的条目.META. 给女儿们 如果客户端扫描.META.他们将看到父区域已拆分.META. ,但直到女儿出现在.META.他们才知道.META. . 另外,如果Put .META . 成功后,父母将被有效分割. 如果RegionServer在此RPC成功之前失败,则Master和下一个打开该区域的Region Server将清除有关区域拆分的脏状态. .META. 不过,如果更新,区域划分将由Master进行前滚.

  8. RegionServer并行打开子节点A和B.

  9. RegionServer将子项A和B添加到.META. ,以及托管区域的信息. 分割区域(参考父母的女儿)现在在线. 此后,客户可以发现新区域并向他们发出请求. 客户端缓存.META. 本地条目,但当它们向RegionServer或.META.发出请求时.META. ,其缓存将失效,并且他们将从.META.了解新区域.META. .

  10. RegionServer将ZooKeeper中的znode /hbase/region-in-transition/region-nameSPLIT ,以便主服务器可以了解它. 必要时,平衡器可以将子区域自由地重新分配给其他区域服务器. 现在已完成拆分交易.

  11. 拆分后, .META. 并且HDFS仍将包含对父区域的引用. 当子区域中的压缩重写数据文件时,这些引用将被删除. 主服务器中的垃圾收集任务会定期检查子区域是否仍引用父区域的文件. 否则,父区域将被删除.

67.6. Write Ahead Log (WAL)

67.6.1. Purpose

预写日志(WAL)将对HBase中数据的所有更改记录到基于文件的存储中. 在正常操作下,不需要WAL,因为数据更改从MemStore移到StoreFiles. 但是,如果在刷新MemStore之前RegionServer崩溃或变得不可用,则WAL确保可以重放对数据的更改. 如果写入WAL失败,则修改数据的整个操作将失败.

HBase使用WAL接口的实现. 通常,每个RegionServer只有一个WAL实例. RegionServer会在其中记录放置和删除,然后再将它们记录到受影响的[store]MemStore中.

在2.0之前的版本中,HBase中用于WAL的接口称为HLog . 在0.94中,HLog是WAL实施的名称. 您可能会在针对这些旧版本量身定制的文档中找到对HLog的引用.

WAL驻留在/ hbase / WALs /目录中的HDFS中(在HBase 0.94之前,它们存储在/hbase/.logs/中 ),每个区域都有子目录.

有关写日志概念的更多常规信息,请参阅Wikipedia 预写日志文章.

67.6.2. MultiWAL

每个RegionServer使用单个WAL,RegionServer必须串行写入WAL,因为HDFS文件必须是顺序的. 这导致WAL成为性能瓶颈.

HBase 1.0在HBASE-5699中引入了对MultiWal的支持. MultiWAL允许RegionServer通过在基础HDFS实例中使用多个管道来并行写入多个WAL流,这将增加写入期间的总吞吐量. 并行化是通过按区域对传入编辑进行分区来完成的. 因此,当前的实现将无助于增加单个区域的吞吐量.

使用原始WAL实现的RegionServer和使用MultiWAL实现的RegionServer都可以处理任意一组WAL的恢复,因此可以通过滚动重启来实现零停机配置更新.

配置MultiWAL

配置MultiWAL为RegionServer的,设置属性的值hbase.wal.providermultiwal由下面的XML粘贴:

<property>
  <name>hbase.wal.provider</name>
  <value>multiwal</value>
</property>

重新启动RegionServer,以使更改生效.

要为RegionServer禁用MultiWAL,请取消设置该属性,然后重新启动RegionServer.

67.6.3. WAL Flushing

一切(描述).

67.6.4. WAL Splitting

RegionServer服务于许多区域. 区域服务器中的所有区域共享相同的活动WAL文件. WAL文件中的每个编辑都包含有关它属于哪个区域的信息. 打开区域后,需要重播WAL文件中属于该区域的编辑. 因此,必须按区域对WAL文件中的编辑进行分组,以便可以重放特定的集以重新生成特定区域中的数据. 按地区对WAL编辑进行分组的过程称为日志拆分 . 如果区域服务器发生故障,这是恢复数据的关键过程.

日志拆分是由HMaster在群集启动期间完成的,或者由ServerShutdownHandler在区域服务器关闭时完成的. 为了保证一致性,在恢复数据之前,受影响的区域将不可用. 必须恢复并重放所有WAL编辑,然后才能再次使给定区域可用. 结果,受日志拆分影响的区域将不可用,直到该过程完成.

过程:逐步拆分日志
  1. / hbase / WALs / <主机>,<端口>,<开始代码>目录已重命名.

    重命名目录很重要,因为即使HMaster认为它已关闭,RegionServer可能仍处于启动状态并接受请求. 如果RegionServer没有立即响应并且没有对其ZooKeeper会话进行心跳检测,则HMaster可能会将其解释为RegionServer故障. 重命名日志目录可确保活动的但繁忙的RegionServer仍在使用的现有有效WAL文件不会被意外写入.

    新目录根据以下模式命名:

    /hbase/WALs/<host>,<port>,<startcode>-splitting

    此类重命名目录的示例可能如下所示:

    /hbase/WALs/srv.example.com,60020,1254173957298-splitting
  2. Each log file is split, one at a time.

    日志拆分器一次读取日志文件中的一个编辑条目,并将每个编辑条目放入与该编辑区域相对应的缓冲区中. 同时,拆分器启动多个写程序线程. 编写器线程将拾取相应的缓冲区,并将缓冲区中的编辑条目写入到临时恢复的编辑文件中. 临时编辑文件使用以下命名模式存储到磁盘:

    /hbase/<table_name>/<region_id>/recovered.edits/.temp

    此文件用于将所有编辑存储在该区域的WAL日志中. 日志拆分完成后, .temp文件将重命名为写入该文件的第一个日志的序列ID.

    为了确定是否已写入所有编辑,将序列ID与最后写入HFile的编辑序列进行比较. 如果上次编辑的序列大于或等于文件名中包含的序列ID,则很明显,已完成对编辑文件的所有写操作.

  3. 日志拆分完成后,将每个受影响的区域分配给RegionServer.

    When the region is opened, the recovered.edits folder is checked for recovered edits files. If any such files are present, they are replayed by reading the edits and saving them to the MemStore. After all edit files are replayed, the contents of the MemStore are written to disk (HFile) and the edit files are deleted.

Handling of Errors During Log Splitting

如果将hbase.hlog.split.skip.errors选项设置为true ,则错误将按以下方式处理:

  • 分割期间遇到的任何错误都将被记录.

  • 有问题的WAL日志将HBase的下移入.corrupt目录rootdir

  • WAL的处理将继续

如果hbase.hlog.split.skip.errors选项设置为false ,则默认情况下,将传播异常,并且拆分将记录为失败. 请参见HBASE-2958.如果将hbase.hlog.split.skip.errors设置为false,则分割失败,仅此而已 . 如果设置了此标志,我们需要做的不仅仅是失败分割.

拆分崩溃的RegionServer的WAL时如何处理EOFException

If an EOFException occurs while splitting logs, the split proceeds even when hbase.hlog.split.skip.errors is set to false. An EOFException while reading the last log in the set of files to split is likely, because the RegionServer was likely in the process of writing a record at the time of a crash. For background, see HBASE-2643 Figure how to deal with eof splitting logs

Performance Improvements during Log Splitting

WAL日志的拆分和恢复可能会占用大量资源,并且会花费很长时间,具体取决于崩溃中涉及的RegionServer的数量和区域的大小. 开发了分布式日志拆分分布式日志重播以提高日志拆分期间的性能.

分布式日志拆分

Facebook的Prakash Khemani在HBase版本0.92( HBASE-1364 )中添加了分布式日志拆分 . 它大大减少了完成日志拆分的时间,从而提高了区域和表的可用性. 例如,使用单线程日志拆分恢复崩溃的群集大约需要9个小时,而使用分布式日志拆分仅花费大约6分钟.

本节中的信息来自Jimmy Xiang的博客文章, 网址http://blog.cloudera.com/blog/2012/07/hbase-log-splitting/ .

启用或禁用分布式日志拆分

从HBase 0.92开始,默认情况下启用分布式日志处理. 该设置由hbase.master.distributed.log.splitting属性控制,可以将其设置为truefalse ,但默认为true .

分布式日志拆分,分步进行

配置分布式日志拆分后,HMaster控制该过程. HMaster在日志拆分过程中注册每个RegionServer,拆分日志的实际工作由RegionServer完成. 分布式日志拆分(分步进行)中描述的常规日志拆分过程仍在此处适用.

  1. 如果启用了分布式日志处理,则在启动群集时,HMaster将创建一个拆分日志管理器实例.

    1. 拆分日志管理器管理所有需要扫描和拆分的日志文件.

    2. 拆分日志管理器将所有日志作为任务放置到ZooKeeper拆分日志节点( / hbase / splitlog )中.

    3. 您可以通过发出以下zkCli命令来查看splitlog的内容. 显示示例输出.

      ls /hbase/splitlog
      [hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%2Fhost8.sample.com%2C57020%2C1340474893275-splitting%2Fhost8.sample.com%253A57020.1340474893900,
      hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%2Fhost3.sample.com%2C57020%2C1340474893299-splitting%2Fhost3.sample.com%253A57020.1340474893931,
      hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%2Fhost4.sample.com%2C57020%2C1340474893287-splitting%2Fhost4.sample.com%253A57020.1340474893946]

      输出包含一些非ASCII字符. 解码后,它看起来要简单得多:

      [hdfs://host2.sample.com:56020/hbase/.logs
      /host8.sample.com,57020,1340474893275-splitting
      /host8.sample.com%3A57020.1340474893900,
      hdfs://host2.sample.com:56020/hbase/.logs
      /host3.sample.com,57020,1340474893299-splitting
      /host3.sample.com%3A57020.1340474893931,
      hdfs://host2.sample.com:56020/hbase/.logs
      /host4.sample.com,57020,1340474893287-splitting
      /host4.sample.com%3A57020.1340474893946]

      该清单表示要扫描和拆分的WAL文件名,这是日志拆分任务的列表.

  2. 拆分日志管理器监视日志拆分任务和工作程序.

    拆分日志管理器负责以下正在进行的任务:

    • 一旦拆分日志管理器将所有任务发布到splitlog znode,它就会监视这些任务节点并等待它们被处理.

    • 检查是否有排队等待死的拆分日志工作程序. 如果发现未响应的工作人员主张任务,它将重新提交这些任务. 如果由于某些ZooKeeper异常而导致重新提交失败,则已死亡的工作程序将再次排队等待重试.

    • 检查是否有未分配的任务. 如果找到,它将创建一个临时重新扫描节点,以便通过nodeChildrenChanged ZooKeeper事件通知每个拆分日志工作程序重新扫描未分配的任务.

    • 检查已分配但已过期的任务. 如果找到任何内容,它们将再次移回TASK_UNASSIGNED状态,以便可以重试. 这些任务有可能分配给了慢工,或者可能已经完成. 这不是问题,因为日志拆分任务具有幂等性. 换句话说,同一日志拆分任务可以多次处理而不会引起任何问题.

    • 拆分日志管理器不断监视HBase拆分日志znode. 如果任何拆分日志任务节点数据已更改,则拆分日志管理器将检索节点数据. 节点数据包含任务的当前状态. 您可以使用zkCli get命令来检索任务的当前状态. 在下面的示例输出中,输出的第一行显示任务当前未分配.

      get /hbase/splitlog/hdfs%3A%2F%2Fhost2.sample.com%3A56020%2Fhbase%2F.logs%2Fhost6.sample.com%2C57020%2C1340474893287-splitting%2Fhost6.sample.com%253A57020.1340474893945
      
      unassigned host2.sample.com:57000
      cZxid = 0×7115
      ctime = Sat Jun 23 11:13:40 PDT 2012
      ...

      根据数据已更改的任务的状态,拆分日志管理器执行以下操作之一:

    • 如果任务未分配,请重新提交

    • 对任务执行心跳(如果已分配)

    • 重新提交或使任务失败(如果任务已辞职)(请参阅任务失败的原因

    • 如果错误完成任务,则重新提交或使任务失败(请参阅任务失败的原因

    • 如果由于错误而无法完成任务,请重新提交或使任务失败(请参阅任务失败的原因

    • 如果任务成功完成或失败,则将其删除

      任务失败的原因
      • 该任务已被删除.

      • 该节点不再存在.

      • 日志状态管理器无法将任务状态移动到TASK_UNASSIGNED .

      • 重新提交的次数超过了重新提交的阈值.

  3. 每个RegionServer的拆分日志工作器都执行日志拆分任务.

    每个RegionServer都运行一个名为split log worker的守护程序线程,该线程负责拆分日志. 守护程序线程在RegionServer启动时启动,并进行注册以监视HBase znode. 如果任何splitlog znode子级发生更改,它将通知睡眠中的工作线程唤醒并抓取更多任务. 如果某个工作程序的当前任务的节点数据已更改,则该工作程序会检查该任务是否已由另一工作程序执行. 如果是这样,工作线程将停止当前任务的工作.

    工作程序会持续监视splitlog znode. 当出现新任务时,拆分日志工作程序将检索任务路径并检查每个路径,直到找到未声明的任务并尝试声明该任务. 如果索赔成功,它将尝试执行任务并根据拆分结果更新任务的state属性. 此时,拆分日志工作程序将扫描另一个无人认领的任务.

    拆分日志工作程序如何处理任务
    • 它查询任务状态,并且仅在任务处于" TASK_UNASSIGNED"状态时才采取措施.

    • 如果任务处于TASK_UNASSIGNED状态,则工作程序会尝试自行将状态设置为TASK_OWNED . 如果无法设置状态,则其他工作人员将尝试获取它. 如果任务仍未分配,则拆分日志管理器还将要求所有工作人员稍后重新扫描.

    • 如果工作人员成功获得任务的所有权,它将尝试再次获取任务状态,以确保它确实是异步获取的. 同时,它启动一个拆分任务执行程序来执行实际工作:

      • 获取HBase根文件夹,在根目录下创建一个temp文件夹,然后将日志文件拆分到temp文件夹.

      • 如果拆分成功,则任务执行器将任务设置为状态TASK_DONE .

      • 如果工作程序捕获到意外的IOException,则该任务将设置为状态TASK_ERR .

      • 如果工作人员正在关闭,请将任务设置为状态TASK_RESIGNED .

      • 如果任务是由其他工作人员执行的,则只需记录下来即可.

  4. 拆分日志管理器监视未完成的任务.

    当所有任务成功完成时,拆分日志管理器将返回. 如果所有任务均因某些失败而完成,则拆分日志管理器将引发异常,以便可以重试日志拆分. 由于异步实现,在极少数情况下,拆分日志管理器无法跟踪某些已完成的任务. 因此,它会定期检查其任务图中或ZooKeeper中是否还有未完成的任务. 如果未找到,它将引发异常,以便可以立即重试日志拆分,而不是挂在这里等待不会发生的事情.

分布式日志重播

After a RegionServer fails, its failed regions are assigned to another RegionServer, which are marked as "recovering" in ZooKeeper. A split log worker directly replays edits from the WAL of the failed RegionServer to the regions at its new location. When a region is in "recovering" state, it can accept writes but no reads (including Append and Increment), region splits or merges.

分布式日志重播扩展了分布式日志拆分框架. 它的工作原理通过直接重放WAL编辑另一个RegionServer的,而不是创建recovered.edits文件. 与单独的分布式日志拆分相比,它具有以下优点:

  • 它消除了写入和读取大量restore.edits文件的开销. 在RegionServer恢复期间同时创建和写入数千个restore.edits文件并不罕见. 许多小的随机写入会降低整体系统性能.

  • 即使区域处于恢复状态,它也允许写入. 恢复区域只需几秒钟即可再次接受写入.

启用分布式日志重播

要启用分布式日志重播,请将hbase.master.distributed.log.replay设置为true . 这将是HBase 0.99( HBASE-10888 )的默认设置.

您还必须启用HFile版本3(这是从HBase 0.99开始的默认HFile格式.请参见HBASE-10855 ). 分布式日志重播对于滚动升级是不安全的.

67.6.5. Disabling the WAL

可以禁用WAL,以提高某些特定情况下的性能. 但是,禁用WAL会使您的数据处于危险之中. 推荐这样做的唯一情况是在大负载期间. 这是因为,如果出现问题,可以重新运行大容量负载,而不会丢失数据.

通过调用HBase客户端字段Mutation.writeToWAL(false)禁用WAL. 使用Mutation.setDurability(Durability.SKIP_WAL)和Mutation.getDurability()方法来设置和获取字段的值. 无法仅对特定表禁用WAL.

如果对大容量负载以外的任何其他功能禁用WAL,则数据将受到威胁.

68. Regions

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

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文件的外观的说明,请参阅浏览HFS对象的HDFS .

68.1. Considerations for Number of Regions

通常,HBase被设计为在每个服务器上以少量(20-200)个相对较大(5-20​​Gb)的区域运行. 注意事项如下:

68.1.1. Why should I keep my Region count low?

Typically you want to keep your region count low on HBase for numerous reasons. Usually right around 100 regions per RegionServer has yielded the best results. Here are some of the reasons below for keeping region count low:

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

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

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

  4. 在旧版本的HBase(HFile v2之前的版本,0.90和更低版本)中,少数RS上的大量区域可能导致存储文件索引增加,从而增加堆使用率,并可能在RS上造成内存压力或OOME

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

有关配置准则,请参阅确定区域数和大小 .

68.2. Region-RegionServer Assignment

本节介绍如何将区域分配给RegionServer.

68.2.1. Startup

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

  1. 主机在启动时调用AssignmentManager .

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

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

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

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

68.2.2. Failover

当RegionServer发生故障时:

  1. 由于RegionServer已关闭,因此这些区域立即变得不可用.

  2. 主服务器将检测到RegionServer发生故障.

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

  4. 机上查询将重试,并且不会丢失.

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

    ZooKeeper session timeout + split time + assignment/replay time

68.2.3. Region Load Balancing

Regions can be periodically moved by the LoadBalancer.

68.2.4. Region State Transition

HBase为每个区域维护一个状态,并将该状态hbase:metahbase:meta . 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
Figure 2. Region State Transitions
图例
  • Brown: Offline state, a special state that can be transient (after closed before opening), terminal (regions of disabled tables), or initial (regions of newly created tables)

  • Palegreen:在线状态表明区域可以满足请求

  • 浅蓝色:瞬态

  • 红色:故障状态需要OPS注意

  • 黄金:地区的最终状态已拆分/合并

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

过渡状态说明
  1. 主服务器将区域从OFFLINE移到OPENING状态,然后尝试将该区域分配给RegionServer. RegionServer可能会或可能未收到开放区域请求. 主服务器重试将打开的区域请求发送到RegionServer,直到RPC通过或主服务器用尽重试. RegionServer收到打开区域请求后,RegionServer开始打开区域.

  2. 如果主服务器用尽了重试时间,则即使RegionServer开始打开区域,主服务器也可以通过将区域移至CLOSING状态并尝试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. When a RegionServer is about to split a region, it notifies the master. The master moves the region to be split from OPEN to SPLITTING state and add the two new regions to be created to the RegionServer. These two regions are in SPLITING_NEW state initially.

  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通知其合并已完成之前,主服务器不会更新区域状态. 如果合并成功,两家合并区域从移动MERGINGMERGED的状态和新的区域是从移动MERGING_NEWOPEN状态.

  16. 如果合并失败,则将两个合并区域从MERGINGOPEN状态,并将创建用于保存合并区域内容的新区域从MERGING_NEW移至OFFLINE状态.

  17. 对于处于FAILED_OPENFAILED_CLOSE状态的区域,当操作员通过HBase Shell重新分配它们时,主服务器尝试再次将其关闭.

68.3. Region-RegionServer Locality

随着时间的流逝,Region-RegionServer的本地性是通过HDFS块复制实现的. 在选择写入副本的位置时,HDFS客户端默认情况下会执行以下操作:

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

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

  3. 第三个副本与第二个副本位于相同的机架上,但在随机选择的不同节点上

  4. 随后的副本将写入集群中的随机节点上. 请参阅此页面上的副本位置:"第一步之初"HDFS体系结构

因此,在冲洗或压实之后,HBase最终实现了区域的局部性. 在RegionServer故障转移情况下,可能会向RegionServer分配具有非本地StoreFiles的区域(因为所有副本都不是本地的),但是当在该区域中写入新数据或压缩表并重新编写StoreFiles时,它们将成为RegionServer的"本地".

有关更多信息,请参见本页上的副本位置:第一步HDFS体系结构以及Lars George关于HBase和HDFS本地性的博客.

68.4. Region Splits

区域达到配置的阈值时会分裂. 下面我们简短地讨论该主题. 有关更详细的说明,请参见我们的Enis Soztutar撰写的