本节中提到的编解码器用于编码和解码数据块或行键。有关复制编解码器的信息,请参见 cluster.replication.preserving.tags

本节中的一些信息来自 HBase Development 邮件列表中的讨论

HBase 支持几种不同的压缩算法,可以在 ColumnFamily 上启用。数据块编码试图限制密钥中信息的重复,利用 HBase 的一些基本设计和模式,例如排序的行键和给定表的模式。压缩器减少了单元中大型不透明字节数组的大小,并且可以显着减少存储未压缩数据所需的存储空间。

压缩器和数据块编码可以在同一 ColumnFamily 上一起使用。

压缩后的变化生效

如果更改 ColumnFamily 的压缩或编码,则更改将在压缩期间生效。

一些编解码器利用 Java 内置的功能,例如 GZip 压缩。其他人依赖本地图书馆。本机库可以作为 Hadoop 的一部分提供,例如 LZ4。在这种情况下,HBase 只需要访问适当的共享库。

其他编解码器,例如 Google Snappy,需要先安装。某些编解码器的许可方式与 HBase 的许可证相冲突,不能作为 HBase 的一部分提供。

本节讨论使用 HBase 进行测试的常用编解码器。无论您使用何种编解码器,请确保测试它是否已正确安装并且可在群集中的所有节点上使用。可能需要额外的操作步骤以确保编解码器在新部署的节点上可用。您可以使用 compression.test 实用程序检查给定的编解码器是否已正确安装。

要将 HBase 配置为使用压缩器,请参见 compressor.install 。要为 ColumnFamily 启用压缩器,请参阅 changing.compression 。要为 ColumnFamily 启用数据块编码,请参见 data.block.encoding.enable

块压缩机

  • 没有

  • 瞬间

  • LZO

  • LZ4

  • GZ

数据块编码类型

字首

通常,键非常相似。具体来说,密钥通常共享一个共同的前缀,并且只在末尾附近不同。例如,一个键可能是RowKey:Family:Qualifier0,下一个键可能是RowKey:Family:Qualifier1。在前缀编码中,添加了一个额外的列,其中包含当前键和前一个键之间共享的前缀长度。假设此处的第一个密钥与之前的密钥完全不同,则其前缀长度为 0。

第二个密钥的前缀长度为23,因为它们共有前 23 个字符。

显然,如果密钥往往没有任何共同点,Prefix 将不会提供太多好处。

下图显示了一个没有数据块编码的假设 ColumnFamily。

data block no encoding图 18.没有编码的 ColumnFamily

这是与前缀数据编码相同的数据。

data block prefix encoding图 19.带有前缀编码的 ColumnFamily

DIFF

差异编码扩展了前缀编码。不是将密钥顺序地视为单个字节序列,而是分割每个密钥字段,以便可以更有效地压缩密钥的每个部分。

添加了两个新字段:时间戳和类型。

如果 ColumnFamily 与上一行相同,则从当前行中省略它。

如果密钥长度,值长度或类型与前一行相同,则省略该字段。

此外,为了增加压缩,时间戳存储为前一行时间戳的 Diff,而不是完整存储。给定前缀示例中的两个行键,并给出时间戳和相同类型的精确匹配,第二行的值长度或类型都不需要存储,第二行的时间戳值只有 0,而不是一个完整的时间戳。

默认情况下禁用 Diff 编码,因为写入和扫描速度较慢但缓存了更多数据。

此图像显示与之前图像相同的 ColumnFamily,具有 Diff 编码。

data block diff encoding图 20.带有 Diff 编码的 ColumnFamily

快速差异

Fast Diff 与 Diff 类似,但使用更快的实现。它还添加了另一个字段,用于存储单个位以跟踪数据本身是否与前一行相同。如果是,则不再存储数据。

如果您有长键或多列,建议使用快速差异。

数据格式几乎与 Diff 编码相同,因此没有图像来说明它。

前缀树

在 HBase 0.96 中引入了前缀树编码作为实验特征。它为 Prefix,Diff 和 Fast Diff 编码器提供了类似的内存节省,但以较慢的编码速度为代价提供了更快的随机访问。它已在 hbase-2.0.0 中删除。这是一个好主意,但很少采用。如果有兴趣重振这项工作,请编写 hbase 开发列表。

D.1。使用哪种压缩器或数据块编码器

要使用的压缩或编解码器类型取决于数据的特征。选择错误的类型可能会导致数据占用更多空间而不是更少,并且可能会影响性能。

通常,您需要在较小尺寸和较快压缩/解压缩之间权衡您的选择。以下是一些一般性指南,从关于压缩和编解码器的文档指南的讨论中进行了扩展。

  • 如果您有长键(与值相比)或许多列,请使用前缀编码器。建议使用 FAST_DIFF。

  • 如果值很大(而不是预压缩,例如图像),请使用数据块压缩器。

  • 将 GZIP 用于 _ 冷数据 _,不经常访问。 GZIP 压缩比 Snappy 或 LZO 使用更多的 CPU 资源,但提供更高的压缩比。

  • 对于经常访问的 _ 热数据 _ 使用 Snappy 或 LZO。 Snappy 和 LZO 比 GZIP 使用更少的 CPU 资源,但不提供高压缩比。

  • 在大多数情况下,默认情况下启用 Snappy 或 LZO 是一个不错的选择,因为它们具有较低的性能开销并节省空间。

  • 在 2011 年 Snappy 成为谷歌之前,LZO 是默认的。 Snappy 具有与 LZO 相似的品质,但已被证明表现更好。

D.2。在 HBase 中使用 Hadoop 本机库

Hadoop 共享库有许多功能,包括压缩库和快速 crc'ing - 硬件 crc'ing,如果您的芯片组支持它。要使此工具可用于 HBase,请执行以下操作。如果找不到本机库版本,HBase / Hadoop 将回退使用替代品 - 或者如果你要求显式压缩器并且没有替代可用,则彻底失败。

首先确保你的 Hadoop。如果您看到它启动 Hadoop 进程,请修复此消息:

16/02/09 22:40:24 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 

这意味着没有正确指向其本机库,或者本地库是为另一个平台编译的。先解决这个问题。

然后,如果您在 HBase 日志中看到以下内容,则表示 HBase 无法找到 Hadoop 本机库:

2014-08-07 09:26:20,139 WARN  [main] util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 

如果库已成功加载,则不会显示 WARN 消息。通常这意味着你很高兴去阅读。

让我们假设您的 Hadoop 附带了一个适合您正在运行 HBase 的平台的本机库。要检查 Hadoop 本机库是否可用于 HBase,请运行以下工具(可在 Hadoop 2.1 及更高版本中使用):

$ ./bin/hbase --config ~/conf_hbase org.apache.hadoop.util.NativeLibraryChecker
2014-08-26 13:15:38,717 WARN  [main] util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Native library checking:
hadoop: false
zlib:   false
snappy: false
lz4:    false
bzip2:  false
2014-08-26 13:15:38,863 INFO  [main] util.ExitUtil: Exiting with status 1 

上图显示本地 hadoop 库在 HBase 上下文中不可用。

上面的 NativeLibraryChecker 工具可能会回来说所有的文件都是 hunky-dory - 即所有的库都显示'true',它们是可用的 - 但是无论如何都要按照下面的说明来确保本机库在 HBase 上下文中可用,当它们使用它们时。

要解决上述问题,如果 Hadoop 和 HBase 停顿在文件系统中相邻,则将 Hadoop 本机库本地或符号链接复制到它们。您还可以通过在 hbase-env.sh 中设置LD_LIBRARY_PATH环境变量来指向其位置。

JVM 寻找本机库的位置是“系统相关的”(参见java.lang.System#loadLibrary(name))。在 linux 上,默认情况下,将查看 lib / native / PLATFORM ,其中PLATFORM是安装 HBase 的平台的标签。在本地 linux 机器上,它似乎是 java 属性os.nameos.arch的串联,后跟是 32 位还是 64 位。启动时 HBase 打印出所有 java 系统属性,因此在日志中找到 os.name 和 os.arch。例如:

...
2014-08-06 15:27:22,853 INFO  [main] zookeeper.ZooKeeper: Client environment:os.name=Linux
2014-08-06 15:27:22,853 INFO  [main] zookeeper.ZooKeeper: Client environment:os.arch=amd64
... 

所以在这种情况下,PLATFORM 字符串是Linux-amd64-64。在 lib / native / Linux-amd64-64 复制 Hadoop 本机库或符号链接将确保找到它们。完成此更改后滚动重新启动。

以下是如何设置符号链接的示例。让 hadoop 和 hbase 安装在您的主目录中。假设您的 hadoop 本机库位于〜/ hadoop / lib / native。假设您使用的是 Linux-amd64-64 平台。在这种情况下,您将执行以下操作来链接 hadoop 本机库,以便 hbase 可以找到它们。

...
$ mkdir -p ~/hbaseLinux-amd64-64 -> /home/stack/hadoop/lib/native/lib/native/
$ cd ~/hbase/lib/native/
$ ln -s ~/hadoop/lib/native Linux-amd64-64
$ ls -la
# Linux-amd64-64 -> /home/USER/hadoop/lib/native
... 

如果您在堆栈轨道中看到 PureJavaCrc32C,或者如果在 perf 跟踪中看到类似下面的内容,则本机不起作用;您使用的是 java CRC 函数而不是 native 函数:

 5.02%  perf-53601.map      [.] Lorg/apache/hadoop/util/PureJavaCrc32C;.update 

请参阅 HBASE-11927 使用 Native Hadoop Library 进行 HFile 校验和(并将默认值从 CRC32 转换为 CRC32C),有关本机校验和支持的更多信息。请特别参阅发行说明,了解如何检查硬件是否支持处理器是否支持硬件 CRC。或者查看 HBase 博客文章中的 Apache Checksums。

以下是如何使用LD_LIBRARY_PATH环境变量指向 Hadoop 库的示例:

$ LD_LIBRARY_PATH=~/hadoop-2.5.0-SNAPSHOT/lib/native ./bin/hbase --config ~/conf_hbase org.apache.hadoop.util.NativeLibraryChecker
2014-08-26 13:42:49,332 INFO  [main] bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native
2014-08-26 13:42:49,337 INFO  [main] zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop: true /home/stack/hadoop-2.5.0-SNAPSHOT/lib/native/libhadoop.so.1.0.0
zlib:   true /lib64/libz.so.1
snappy: true /usr/lib64/libsnappy.so.1
lz4:    true revision:99
bzip2:  true /lib64/libbz2.so.1 

在启动 HBase 时在 hbase-env.sh 中设置 LD_LIBRARY_PATH 环境变量。

D.3。压缩器配置,安装和使用

D.3.1。为压缩器配置 HBase

在 HBase 可以使用给定的压缩器之前,它的库需要可用。由于许可问题,默认安装中只有 Gase 压缩可用于 HBase(通过本机 Java 库)。其他压缩库可通过与 hadoop 捆绑在一起的共享库提供。当 HBase 启动时,需要找到 hadoop 本机库。看到

主机上的压缩器支持

在 HBase 0.95 中引入了新的配置设置,以检查主服务器以确定在其上安装和配置了哪些数据块编码器,并假设整个群集配置相同。此选项hbase.master.check.compression默认为true。这可以防止 HBASE-6370 中描述的情况,其中创建或修改表以支持区域服务器不支持的编解码器,从而导致需要很长时间才能发生的故障并且难以调试。

如果启用了hbase.master.check.compression,则需要在主服务器上安装和配置所有所需压缩程序的库,即使主服务器未运行区域服务器也是如此。

通过本机库安装 GZ 支持

HBase 使用 Java 的内置 GZip 支持,除非 CLASSPATH 上有本机 Hadoop 库。将库添加到 CLASSPATH 的推荐方法是为运行 HBase 的用户设置环境变量HBASE_LIBRARY_PATH。如果本机库不可用且使用 Java 的 GZIP,则Got brand-new compressor报告将出现在日志中。见 brand.new.compressor )。

安装 LZO 支持

由于 HBase 使用 Apache 软件许可证(ASL)和使用 GPL 许可证的 LZO 之间不兼容,因此 HBase 无法附带 LZO。有关配置 HBase 的 LZO 支持的信息,请参阅 Twitter 上的 Hadoop-LZO。

如果您依赖于 LZO 压缩,请考虑在 LZO 不可用时将 RegionServers 配置为无法启动。参见 hbase.regionserver.codecs

配置 LZ4 支持

LZ4 支持与 Hadoop 捆绑在一起。启动 HBase 时,确保可以访问 hadoop 共享库(libhadoop.so)。配置完平台后(参见 hadoop.native.lib ),您可以建立从 HBase 到本机 Hadoop 库的符号链接。这假定两个软件安装是共同的。例如,如果我的'平台'是 Linux-amd64-64:

$ cd $HBASE_HOME
$ mkdir lib/native
$ ln -s $HADOOP_HOME/lib/native lib/native/Linux-amd64-64 

使用压缩工具检查所有节点上是否安装了 LZ4。启动(或重启)HBase。之后,您可以创建和更改表以使 LZ4 成为压缩编解码器:

hbase(main):003:0> alter 'TestTable', {NAME => 'info', COMPRESSION => 'LZ4'} 

安装 Snappy 支持

由于许可问题,HBase 不附带 Snappy 支持。您可以安装 Snappy 二进制文件(例如,在 CentOS 上使用 yum install snappy)或从源代码构建 Snappy。安装 Snappy 后,搜索共享库,它将被称为 libsnappy.so.X ,其中 X 是一个数字。如果您是从源构建的,请将共享库复制到系统上的已知位置,例如 / opt / snappy / lib /

除了 Snappy 库之外,HBase 还需要访问 Hadoop 共享库,它将被称为 libhadoop.so.X.Y ,其中 X 和 Y 都是数字。记下 Hadoop 库的位置,或将其复制到与 Snappy 库相同的位置。

| |

需要在群集的每个节点上提供 Snappy 和 Hadoop 库。请参阅 compression.test 以了解如何测试这种情况。

如果给定的压缩器不可用,请参见 hbase.regionserver.codecs 以配置 RegionServers 无法启动。

|

需要将每个库位置添加到运行 HBase 的操作系统用户的环境变量HBASE_LIBRARY_PATH中。您需要重新启动 RegionServer 才能使更改生效。

压缩测试

您可以使用 CompressionTest 工具验证您的压缩器是否可用于 HBase:

 $ hbase org.apache.hadoop.hbase.util.CompressionTest hdfs://host/path/to/hbase snappy 

在 RegionServer 上强制执行压缩设置

您可以通过将选项 hbase.regionserver.codecs 添加到 hbase-site.xml 并将其值设置为逗号分隔来配置 RegionServer,以便在压缩配置不正确时无法重新启动需要可用的编解码器列表。例如,如果将此属性设置为lzo,gz,则如果两个压缩程序都不可用,则 RegionServer 将无法启动。这样可以防止在没有正确配置编解码器的情况下将新服务器添加到群集中。

D.3.2。在 ColumnFamily 上启用压缩

要为 ColumnFamily 启用压缩,请使用alter命令。您无需重新创建表或复制数据。如果要更改编解码器,请确保旧的编解码器仍然可用,直到所有旧的 StoreFiles 都已压缩为止。

使用 HBase Shell 在现有表的列族上启用压缩

hbase> disable 'test'
hbase> alter 'test', {NAME => 'cf', COMPRESSION => 'GZ'}
hbase> enable 'test' 

在 ColumnFamily 上使用压缩创建新表

hbase> create 'test2', { NAME => 'cf2', COMPRESSION => 'SNAPPY' } 

验证 ColumnFamily 的压缩设置

hbase> describe 'test'
DESCRIPTION                                          ENABLED
 'test', {NAME => 'cf', DATA_BLOCK_ENCODING => 'NONE false
 ', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0',
 VERSIONS => '1', COMPRESSION => 'GZ', MIN_VERSIONS
 => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS => 'fa
 lse', BLOCKSIZE => '65536', IN_MEMORY => 'false', B
 LOCKCACHE => 'true'}
1 row(s) in 0.1070 seconds 

D.3.3。测试压缩性能

HBase 包含一个名为 LoadTestTool 的工具,它提供了测试压缩性能的机制。必须指定-write-update-read作为第一个参数,如果未指定其他参数,则为每个选项打印使用建议。

LoadTestTool 用法

$ bin/hbase org.apache.hadoop.hbase.util.LoadTestTool -h
usage: bin/hbase org.apache.hadoop.hbase.util.LoadTestTool <options>
Options:
 -batchupdate                 Whether to use batch as opposed to separate
                              updates for every column in a row
 -bloom <arg>                 Bloom filter type, one of [NONE, ROW, ROWCOL]
 -compression <arg>           Compression type, one of [LZO, GZ, NONE, SNAPPY,
                              LZ4]
 -data_block_encoding <arg>   Encoding algorithm (e.g. prefix compression) to
                              use for data blocks in the test column family, one
                              of [NONE, PREFIX, DIFF, FAST_DIFF, ROW_INDEX_V1].
 -encryption <arg>            Enables transparent encryption on the test table,
                              one of [AES]
 -generator <arg>             The class which generates load for the tool. Any
                              args for this class can be passed as colon
                              separated after class name
 -h,--help                    Show usage
 -in_memory                   Tries to keep the HFiles of the CF inmemory as far
                              as possible.  Not guaranteed that reads are always
                              served from inmemory
 -init_only                   Initialize the test table only, don't do any
                              loading
 -key_window <arg>            The 'key window' to maintain between reads and
                              writes for concurrent write/read workload. The
                              default is 0.
 -max_read_errors <arg>       The maximum number of read errors to tolerate
                              before terminating all reader threads. The default
                              is 10.
 -multiput                    Whether to use multi-puts as opposed to separate
                              puts for every column in a row
 -num_keys <arg>              The number of keys to read/write
 -num_tables <arg>            A positive integer number. When a number n is
                              speicfied, load test tool  will load n table
                              parallely. -tn parameter value becomes table name
                              prefix. Each table name is in format
                              <tn>_1...<tn>_n
 -read <arg>                  <verify_percent>[:<#threads=20>]
 -regions_per_server <arg>    A positive integer number. When a number n is
                              specified, load test tool will create the test
                              table with n regions per server
 -skip_init                   Skip the initialization; assume test table already
                              exists
 -start_key <arg>             The first key to read/write (a 0-based index). The
                              default value is 0.
 -tn <arg>                    The name of the table to read or write
 -update <arg>                <update_percent>[:<#threads=20>][:<#whether to
                              ignore nonce collisions=0>]
 -write <arg>                 <avg_cols_per_key>:<avg_data_size>[:<#threads=20>]
 -zk <arg>                    ZK quorum as comma-separated host names without
                              port numbers
 -zk_root <arg>               name of parent znode in zookeeper 

LoadTestTool 的示例用法

$ hbase org.apache.hadoop.hbase.util.LoadTestTool -write 1:10:100 -num_keys 1000000
          -read 100:30 -num_tables 1 -data_block_encoding NONE -tn load_test_tool_NONE 

D.4。启用数据块编码

编解码器内置于 HBase 中,因此无需额外配置。通过设置DATA_BLOCK_ENCODING属性在表上启用编解码器。在更改其 DATA_BLOCK_ENCODING 设置之前禁用该表。以下是使用 HBase Shell 的示例:

在表上启用数据块编码

hbase>  disable 'test'
hbase> alter 'test', { NAME => 'cf', DATA_BLOCK_ENCODING => 'FAST_DIFF' }
Updating all regions with the new schema...
0/1 regions updated.
1/1 regions updated.
Done.
0 row(s) in 2.2820 seconds
hbase> enable 'test'
0 row(s) in 0.1580 seconds 

验证 ColumnFamily 的数据块编码

hbase> describe 'test'
DESCRIPTION                                          ENABLED
 'test', {NAME => 'cf', DATA_BLOCK_ENCODING => 'FAST true
 _DIFF', BLOOMFILTER => 'ROW', REPLICATION_SCOPE =>
 '0', VERSIONS => '1', COMPRESSION => 'GZ', MIN_VERS
 IONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS =
 > 'false', BLOCKSIZE => '65536', IN_MEMORY => 'fals
 e', BLOCKCACHE => 'true'}
1 row(s) in 0.0650 seconds