《HBase 不睡觉书》是一本让人看了不会睡着的 HBase 技术书籍,写的非常不错,为了加深记忆,决定把书中重要的部分整理成读书笔记,便于后期查阅,同时希望为初学 HBase 的同学带来一些帮助。

目录

本文不会详细介绍 HBase 的按照过程,主要介绍一些安装的注意事项。

一、小技巧

1、添加 hadoop 用户并分配 sudo 权限

(1)切换到 root 用户,然后建立 hadoop 用户。

# useradd hadoop
# passwd hadoop
复制代码

(2)添加 hadoop 到 sudoers 列表。

# chmod u+w /etc/sudoers
# vi u+w /etc/sudoers
-- 添加下面的代码 --
hadoop ALL=NOPASSWD:ALL
复制代码

2、Hadoop 环境变量设置

切换到 hadoop 用户,并编辑 ~/.bashrc 文件,添加以下环境变量:

export HADOOP_HOME=/usr/local/hadoop
export HADOOP_PREFIX=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
expOrt HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDES_HOME=$HADOOP_HOME
eXpOrt YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin
export HADOOP_INSTALL=$HADOOP_HOME
复制代码

有的教程提到配置 HADOOP_HOME,而官方教程说是配置 HADOOP_PREFIX,那么究竟 Hadoop 是用哪个环境变量来标定 Hadoop 的程序文件夹位置?实际上,早期 Hadoop 主要用 HADOOP_HOME 来标定程序文件夹位置,后来改成了 HADOOP_PREFIX,所以为了兼容性,干脆都设置上,并且保持一样的值吧。

3、配置 hadoop-env.sh

编辑 hadoop 的 $HADOOP_PREFIX/etc/hadoop/hadoop-env.sh 文件,在文件开头添加以下变量:

export HADOOP_NAMENODE_OPTS="-Xms1024m -Xmx1024m -XX:+UseParallelGC"
export HADOOP_DATANODE_OPTS="-Xms1024m-Xmx1024m"
export HADOOP_LOG_DIR=/data/1ogs/hadoop
复制代码
  • JVM 运行的内存如果不设定占用大小的话,要么不够,要么就把机器的内存都占满了。只要用到 JVM 的地方都加入内存参数,至少内存多少自己心里有数,让情况可控。
  • 日志文件路径如果不设定的话,多半后期会遇到放日志的分区满了,各种奇怪故障层出不穷。

4、把 hbase 添加到 supergroup 组

由于在伪分布式和完全分布式的情况下 HBase 会直接在 HDFS 的根目录下建立 /hbase 文件夹,在根目录下要建立文件夹需要超级用户组权限。超级用户组权限由 hdfs-site.xml 中的 dfs.permissions.supergroup 来定义,如果你不设定这个参数,默认的超级用户组组名是 supergroup。假定大家都没有设定 dfs.permissions.supergroup 属性,现在需要把 hbase 添加到 Linux 的 supergroup 组去。CentOS 系统可执行下面的语句:

# groupadd supergroup
# groupmems -g supergroup -a hbase
复制代码

5、特别注意

HBase 自带了一个 ZooKeeper,而且会默认启动自己的 ZooKeeper,如果 HBase 用的是自己的 ZooKeeper,那你在 jps 中看到的 ZooKeeper 名字是 HQuorumPeer。如果你使用的是外部的 ZooKeeper 集群,那么它的名字叫 QuorumPeer 或者 QuorumPeerMain。

是否开启自带的 ZooKeeper 由 conf/hbase-env.sh 中定义的 HBASE_MANAGES_ZK 变量定义。这个变量默认为 true,如果不想使用自带的 ZK 你可以将值改为 false。

# Tell HBase whether it should manage it's own instance of Zookeeper or not.
export HBASE_MANAGES_ZK=false
复制代码

6、HBase 读取到 HDFS 的配置有三种方式

  • HADOOP_CONF_DIR 添加到 HBASE_CLASSPATH 中(推荐);
  • 把 HDFS 的配置文件复制一份到 HBase 的 conf 文件夹下,或者直接建一个 hdfs-site.xml 的软链接到 hbase/conf下;
  • 把 HDFS 的几个配置项直接写到 hbase-site.xml 文件里面去。

二、HBase 的基本架构

  • HBase 中有一个 Master 用来管理元数据,它就像 Hadoop 中的 namenode;
  • RegionServer 是用来存储数据的,相当于 Hadoop 中的 datanode;
  • ZooKeeper 负责维护 HBase 的所有节点,如果 ZooKeeper 宕掉了,你一个节点都连不上;
  • 生产环境下的完全部署模式是基于 HDFS 的,使用 HDFS 来存储数据,但是在单机模式下 HBase 可以直接使用普通文件系统来存储数据;
  • 在使用中就算把 Master 关掉了,依旧可以从 HBase 中读取数据和写入数据,只是不能建表或者修改表。这是因为客户端读取数据的时候只是跟 ZooKeeper 和 RegionServer 交互,所以,ZooKeeper 甚至比 Master 还重要。

HBase 的基本架构

三、启用数据块编码

1、数据块编码

数据块编码主要是针对 Key/Value 中的 Key 进行编码,减少 Key 存储所占用的空间,因为很多 Key 的前缀都是重复的。

假设有这样一个表,它的行键(Rowkey)、列族(Column Family)、列(Column)的定义规则是:行键以 myrow 前缀打头,后面跟上数字来组成行键,比如 myrow001、myrow002、myrow003 等,拥有一个列族叫 mycf,mycf 列族中有 5 个列,分别名叫 col1、col2、col3、col4、col5,它们的存储结构如下所示。

原始编码下的数据存储格式

可以看到这么多行的 Key 其实有很大一部分的字符是重复的,如果我们只存储递进值,就可以避免存储重复的前缀,这就是前缀编码(Prefix)。

2、前缀编码(Prefix)

如果使用前缀编码作为数据块编码方式,那么它只会存储第一个 Key 的完整字符串,后面的 key 只存储跟第一个 key 的差异字符,重新编码过的数据如下所示。

前缀编码后的数据存储格式

可以看到 Key 的存储空间极大地缩小了, 编码后的 Key 总存储空间只用了 37 个字符,而未编码前是 180 个字符,空间占用减少了 79%。

3、差异编码(Diff)

差异编码(Diff)比前缀编码更进一步,差异编码甚至把以下字段也一起进行了差异化的编码。

  • 键长度(KeyLen);
  • 值长度(ValueLen);
  • 时间戳(Timestamp),也即是 Version;
  • 类型(Type),也即是键类型。

采用了差异编码后的 KeyValue 结构为:

  • 1 byte:标志位;
  • 1-5 bytes:Key 长度(KeyLen);
  • 1-5 bytes:Value 长度(ValLen);
  • 1-5 bytes:前缀长度(Prefix Len);
  • ... bytes:剩余的部分;
  • ... bytes:真正的 Key 或者只是有差异的 key 后缀部分;
  • 1-8 bytes:时间戳(timestamp)或者时间戳的差异部分;
  • 1 byte:Key 类型(type);
  • ... bytes:值(value)。

前缀长度(Prefix Len)字段表示当前的 Key 跟与之相比的 Key 的相同前缀的长度。

差异编码后的数据存储格式

标志位(Flag)

它是一个二进制数。比如,5=11,7=111。它的作用就是记录当前这个 KeyValue 跟上一个 KeyValue 之间有哪几个字段有差异,以下是产生标志位的部分规则:

  • 如果当前 KeyValue 中的 KeyLen(Key 的长度)跟上一个 KeyValue 相等,则标志码为 1。
  • 如果当前 KeyValue 中的 ValLen(Value 长度)跟上一个 ValLen 相等,则标志码为 10。
  • 如果当前 KeyValue 中的 Type 跟上一个 Type 相等,则标志码为 100。

只需要把 flag 跟标志码做一个与(&)计算就可以快速地知道这个字段跟上一个字段的差异在哪里,即相同的位置标记为 1

这样编码几乎是最大程度地对数据进行了编码压缩,但是这个编码方式默认是不启用的。为什么?因为太慢了,每条数据都要这样计算一下,获取数据的速度很慢。除非你要追求极致的压缩比,但是不考虑读取性能的时候可以使用它,比如你想要把这部分数据当作归档数据的时候,可以考虑使用差异编码。

4、快速差异编码(Fast Diff)

快速差异编码(Fast Diff)借鉴了 Diff 编码的思路,也考虑到了差异编码速度慢的致命缺陷。快速差异编码的 KeyValue 结构跟差异编码一模一样,只有 Flag 的存储规则不一样,并且优化了 Timestamp 的计算。Fast Diff 的实现比 Diff 更快,也是比较推荐的算法。

如果你想用差异算法来压缩你的数据,那么最好用快速差异编码,不过这个“快速”只是相对本来的差异算法而言的,由于还是有很多计算过程存在,所以快速差异算法的速度依然属于比较慢的

5、前缀树编码(Prefix Tree)

前缀树编码(Prefix Tree)是前缀算法的变体,它是 0.96 版本之后才加入的特性。前缀树编码最大的作用就是提高了随机读的能力,但是其复杂的算法相对地降低了写入的速度,消耗了更多的 CPU 资源,使用时需要在资源的消耗和随机读的性能之间进行取舍。

综上,前缀编码与快速差异编码(Kylin 默认使用该方式)应该算是比较常用的两种数据块编码方式了。

四、启用压缩器

1、压缩器

压缩器的作用是可以把 HBase 的数据按压缩的格式存储,这样可以更节省磁盘空间。当然这完全是可选的,不过推荐大家还是安装 Snappy 压缩器,这是 HBase 官方目前排名比较高的压缩器。

可以通过修改列族描述启用压缩器:

hbase> alter 'mytable',{NAME =>'mycf',COMPRESSION=>'snappy'}
复制代码

2、共享 Hadoop 内置的压缩器

由于 Hadoop 的共享库(shared Library)拥有很多资源,包括压缩器,所以可以直接将它们用在 HBase 中。可以通过以下命令检查 Hadoop 目前有用的压缩器:

$ hbase --config $HBASE_HOME/conf org.apache.hadoop.util.NativeLibraryChecker
复制代码

如果遇到下面的报错信息,则表示 NativeLibraryChecker 无法读取到 Hadoop 的 native 库。

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
    1z4: false
    bzip2: false
复制代码

常规的解决方法是在 hbase-env.sh 加入下面的语句:

export HBASE_LIBRARY_PATH=Hadoop的Native包所在路径
复制代码

3、Snappy 压缩器

Snappy 是 Google 开发的压缩器,有以下特点:

  • 快速:压缩速度达到 250MB/s;
  • 稳定:已经用于 Google 多个产品长达数年;
  • 健壮:Snappy 的解压器可以保证在数据被损坏的时候也不会太糟;
  • 免费开源。

安装完成后,需要在 hbase-env.sh 加入下面的语句:

export HBASE_LIBRARY_PATH=编码器so文件所在路径:$HBASE_LIBRARY_PATH
复制代码

4、GZ 压缩器

一般情况下如果不是对速度要求很低的归档文件,一般不建议使用 GZ 压缩器,GZ 压缩器的特点:

  • GZ 压缩器拥有最高的压缩比;
  • 速度较慢,占用较多 CPU;
  • 安装简单。

Java 已经自带了一个 GZ 压缩器,所以 GZ 压缩器虽然不是性能最好的,但是却是最容易使用的,你什么都不需要设置,只需要直接修改列族的 COMPRESSION 属性为 GZ 即可。

alter test1',{NAME=>'mycf',COMPRESSION=>'GZ'}
复制代码

5、LZO 压缩器

在 Snappy 推出之前,LZO 是 HBase 官方推荐的压缩算法。主要原因是 GZ 压缩的速度太慢了,而 LZO 正好就是专注于速度,所以相比起来使用 LZO 会比 GZ 更好,不过自从 Snappy 出了之后,LZO 就没有什么优势了。

6、LZ4 压缩器

LZ4 的特点:

  • 拥有低丢失率;
  • 速度很快,可以达到 400M/s 每核。

LZ4 比 Snappy 更快,LZ4 压缩器已经集成在 libhadoop.so 中,所以只需要让 HBase 加载 Hadoop 自带的原生库即可。

五、总结

使用数据块编码还是压缩器取决于你存储的数据中是限定符占的空间较大还是值占的空间较大。

  • 如果是限定符占的空间较大,建议使用数据块编码。
  • 如果是值占的空间较大,建议使用编码器。

最开始学习 HBase 的时候,大多都是直接使用 Java API 去进行表操作,很少去关注 HBase 安装相关的内容;通过上述的介绍,至少数据块编码和压缩器在以后建表时候还是可以考虑的,官方推荐的 Snappy 压缩器以及前缀编码都是即简单又有效的调优方法。


Any Code,Code Any!

扫码关注『AnyCode』,编程路上,一起前行。

感谢    赞同    分享    收藏    关注    反对    举报    ...