• 沒有找到結果。

HBase分布式存储系统应用 - 万水书苑-出版资源网

N/A
N/A
Protected

Academic year: 2021

Share "HBase分布式存储系统应用 - 万水书苑-出版资源网"

Copied!
136
0
0

加載中.... (立即查看全文)

全文

(1)
(2)

CONTENTS

课程目标

第一章 HBase 介绍

ITEMS

1

ITEMS

2

第二章 HBase 模型和系统架构

第三章 HBase 数据读写流程

ITEMS

3

ITEMS

4

第四章 HBase 环境搭建

第五章 HBase Shell

ITEMS

5

ITEMS

6

第六章 HBase

程序开发

第七章 HBase 高级特性

(3)

1 HBase 介绍

• HBase 是一种构建在 HDFS 之上的分布式、面向列的存储系统。在需要实时读写、随机访问超大规模数据集时,可以使用 HBase 。

Apache HBase 是 Google BigTable 的开源实现,就像 BigTable 利用了 GFS 所提供的分布式数据存储一样, HBase 在 Ha

doop 之上提供了类似于 BigTable 的能力

(4)

1.1 面向行和面向列存储对比

• 1.1.1 数据库以行、列的二维表的形式存储数据

• 1.1.2 列式数据库把一列中的数据值串在一起存储起来,然后再存储下一列的数据

• 1.1.3 两种存储方式的对比

id name age sex jobs

1 张三 35 男 教师 2 李丹 18 女 学生 3 John 26IT工程师 id 1 2 3 name 张三 李丹 John age 男 女 男 sex 35 18 26 表 1-3 行 / 列存储对比 行存储 列存储 优点 写入效率高,提供数据完整性保证。 读取过程有冗余,适合数据定长的大数 据计算。 缺点 数据读取有冗余现象,影响计算速度。 缺乏数据完整性保证,写入效率低。 改进 优化的存储格式,保证能够在内存快速 多磁盘多线程并行写入 / 读 ( 需要增加

(5)

1.2 HDFS 分布式存储特点

• HDFS(Hadoop Distributed File System) 是 Hadoop 项目的核心子项目,是分布式计算中数据存储管理的基础,是基于

流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。

• 1. 优点

(1) 高容错性 • (2) 适合大数据的处理 • (3) 流式文件写入 • (4) 可构建在廉价机器上

• 2. 缺陷

• (1) 不适合低延迟数据访问 • (2) 无法高效存储大量的小文件 • (3) 不支持多用户写入及任意修改文件

(6)

1.3 HBase 的使用场景

• HBase 不是关系型数据库,也不支持 SQL ,但是它有自己的特长,这是关系型数据库不能处理的。

• 1. 平台类 • 2. 内容服务类 • 3. 信息展示类

(7)

2.1 HBase 相关概念

• HBase 的数据模型也是由一张张的表组成,每一张表里也有数据行和列,但是在 HBase 数据库中的行和列又和关系型数据库的

稍有不同。

• 1. Table( 表 )

• 2. Row( 行 )

• 3. Column( 列 )

• 4. Column Family( 列族 )

• 5. Column Qualifier( 列标识符 )

• 6. Cell( 单元格 )

• 7. Timestamp( 时间戳 )

(8)

2.2 HBase 逻辑模型

• HBase 是一个类似 BigTable 的分布式数据库,它是一个稀疏的长期存储的 ( 存储在硬盘上 ) 、多维度的、排序的映射表,这张

表的索引是行关键字、列关键字和时间戳, HBase 中的数据都是字符串,没有类型。

表 2-1 HBase 的逻辑模型 行健 时间戳 列族 anchor 列族 info "database.software.www" t4 anchor:tel="01012345678" info:PC="100000" t3 anchor:name="James" t2 info:address="BeiJing" t1 anchor:name="John" "c.software.www" t3 info:address="BeiJing" t2 anchor:tel="01012345678" t1 anchor:name="James"

(9)

2.3 HBase 物理模型

• 虽然从逻辑模型来看每个表格是由很多行组成的,但是在物理存储上面,它是按照列来保存的。

表 2-2 HBase 的物理模型

行健 时间戳 列 单元格 ( 值 )

"database.software.www" t1 anchor:name John

"database.software.www" t2 info:address BeiJing

"database.software.www" t3 anchor:name James

"database.software.www" t4 anchor:tel 01012345678

"database.software.www" t4 info:PC 100000

"c.software.www" t1 anchor:name James

"c.software.www" t2 anchor:tel 01012345678

(10)

2.4 HBase 的特点

• 非关系型数据库严格上不是一种数据库,而是一种数据结构化存储方法的集合。 HBase 作为一个典型的非关系型数据库,仅支持

单行事务,通过不断增加集群中节点数据量来增加计算能力,其具有以下特点。

• 1. 容量巨大

• 2. 面向列

• 3. 稀疏性

• 4. 数据多版本

• 5. 可扩展性

• 6. 高可靠性

• 7. 高性能

• 8. 数据类型单一

(11)

2.5 HBase 系统架构

• HBase 同样是主从分布式架构,它隶属于 Hadoop 生态系统,由以下组件组成: Client , ZooKeeper , HMaster , HRegi

onServer 和 HRegion ;在底层,它将数据存储于 HDFS 中

(12)

2.5 HBase 系统架构

• 2.5.1 Client

• Client 包含访问 HBase 的接口,使用 RPC 机制与 HMaster 和 HRegionServer 进行通信并维护 Cache 来加快对 HBase 的访问,比如 HReg ion 的位置信息。

• 2.5.2 ZooKeeper

ZooKeeper 的引入使得 Master 不再是单点故障,通过选举,保证任何时候集群中只有一个处于 Active 状态的 Master , HMaster 和 HReg ionServer 启动时会向 ZooKeeper 注册。

• 2.5.3 HMaster

• HMaster 是 HBase 集群的主控服务器,负责集群状态的管理维护。 • (1) 管理用户对表的增、删、改、查操作。 • (2) 为 HRegionServer 分配 HRegion 。 • (3) 管理 HRegionServer 的负载均衡,调整 HRegion 分布。 • (4) 发现失效的 HRegionServer 并重新分配其上的 HRegion 。 • (5) 当 HRegion 切分后,负责两个新生成 HRegion 的分配。 • (6) 处理元数据的更新请求。

(13)

3.1 HRegionServer 详解

(14)

3.1 HRegionServer 详解

3.1.1 WAL

1. WAL 滚动

2. WAL 失效

3. WAL 删除

3.1.2 MemStore

MemStore 是一个写缓存 (In Memory Sorted Buffer) ,所有数据的写在完成 WAL 日志写后,会写入 MemStore 中,

由 MemStore 根据一定的算法将数据 Flush 到底层 HDFS 文件中 (HFile) 。

(15)

3.1 HRegionServer 详解

3.1.3 BlockCache

客户的读请求会先到 MemStore 中查数据,若查不到就到 BlockCache 中查,再查不到就会从磁盘上读,并把读入的数据

同时放入 BlockCache 。

HBase RegionServer 包含三个级别的 Block 优先级队列:

(1)Single 队列,如果一个 Block 第一次被访问,则放在这一优先级队列中。

(2)Multi 队列,如果一个 Block 被多次访问,则从 Single 队列移到 Multi 队列中。

(3)InMemory 队列,如果一个 Block 是 InMemory 的,则放到这个队列中。

(16)

3.1 HRegionServer 详解

3.1.4 HFile

HBase 的数据以 KeyValue(Cell) 的形式顺序的存储在 HFile 中,在 MemStore 的 Flush 过程中生成 HFile ,在 HFi

le 中的数据是按 Row Key , Column Family , Column 排序,对相同的 Cell( 即这三个值都一样 ) 则按 Timestamp 倒序排列

1. 数据块

2. 元数据块

3. FileInfo

4. 数据块索引

5. 元数据块索引

6. 文件尾

表 3-1 HFile 组成部分

名称

描述

数据块 由多个 lock( 块 ) 组成,每个块的格式为: [ 块头 ] + [Key 长 ] + [Value 长 ] + [Key] + [Value] 。 元数据 元数据是 Key-Value 类型的值,但元数据块只保存元数据的 Value 值,元数据的 Key 值保存在第五项 ( 元数据索引块 ) 中。该块由多个元数据值组成。

块 该块保存与 HFile 相关的一些信息。 FileInfo 是以 Key 值排序 Key-Value 类型的值,基本格式为:KeyValue元素的个数 + (Key + Value 类型 id + Value) + (Key + Value 类型 id + Value) + …… 数据索引块 该块的组成为:索引块头 + ( 数据块在文件中的偏移 + 数据块长 + 数据块的第一个 Key) + ( 数据块在文件中的偏移 + 数据块长 + 数据块的第一个 Key) + …… 元数据索引块 该块组成格式同数据块索引,只是部分的意义不一样,组成格式:索引块头 + ( 元数据在文件中的偏移 + 元数据 Value 长 + 元数据 Key) + ( 元数据在文件中的偏移 + 元数据 Value 长 + 元数据 Key) + ……

文件尾 该块记录了其他各块在 HFile 文件中的偏移信息和其他一些元信息。组成格式如下:文件尾 + Fileinfo 偏移 + 数据块索引偏移 + 数据块索引个数 + 元数据索引偏移 + 元数据索引个数 + 数据块中未压缩数据字节 数 + 数据块中全部数据的 Key-Value 个数 + 压缩代码标识 + 版本标识

(17)

3.1 HRegionServer 详解

3.1.5 HRegionServer 的恢复

当一台 HRegionServer 宕机时,由于它不再发送心跳包给 ZooKeeper 而被监测到,此时 ZooKeeper 会通知 HMaster

, HMaster 会检测到哪台 HRegionServer 宕机,它将宕机的 HRegionServer 中的 HRegion 重新分配给其它的 HRegionServ

er ,同时 HMaster 会把宕机的 HRegionServer 相关的 WAL 拆分分配给相应的 HRegionServer( 将拆分出的 WAL 文件写入对应

HRegionServer 的 WAL 目录中,并写入相应的 DataNode) ,从而使这些 HRegionServer 可以滚动分到的 WAL 来重建 MemSto

re 。

3.1.6 HRegionServer 的上线下线

HMaster 使用 ZooKeeper 来跟踪 HRegionServer 状态。当某个 HRegionServer 启动时,会首先在 ZooKeeper 上的

Server 目录下建立代表自己的文件,并获得该文件的独占锁。

(18)

3.2 HRegion

• 在 HBase 中,一个表的表行的多少决定了 HRegion 的大小,表的列族个数又决定了 Store 的多少,一个 Store 对应一个 MemSt

ore 和多个 StoreFile , StoreFile 则对应一个 HFile

• HBase 表创建时候默认就是一个 HRegion ,在行记录不断增加下,达到一定的数值 HRegion 会自动切分,变成多个 HRegion ,

每一个 HRegion 里面由多个 Store 组成 (Store 的个数是由 HBase 表列族个数决定 ) 。

(19)

3.2 HRegion

3.2.1 HRegion 分配

任何时刻,一个 HRegion 只能分配给一个 HRegionServer 。 HMaster 记录了当前有哪些可用的 HRegionServer ,以及

当前哪些 HRegion 分配给了哪些 HRegionServer ,哪些 HRegion 还没有分配。

3.2.2 HRegion Split

最初,一个 Table 只有一个 HRegion ,随着数据写入增加,如果一个 HRegion 到达一定的大小,就需要 Split 成两个 HRe

gion ,这个大小由 hbase.hregion.max.filesize 指定,默认为 10GB 。

3.2.3 HRegion Compact

当文件达到一定数量 ( 默认 3) 就会触发 Compact 操作,多个 HFile 合并成一个 HFile 文件,将多个 StoreFile 文件合

并成一个 StoreFile ,而大文件恰恰又是 HDFS 所擅长。

(20)

3.3 HMaster 上线

HMaster 启动进行以下步骤:

(1) 从 ZooKeeper 上获取唯一一个代表 HMaster 的锁,用来阻止其它 HMaster 成为 Master 。

(2) 扫描 ZooKeeper 上的 Server 目录,获得当前可用的 HRegionServer 列表。

(3) 和 2 中的每个 HRegionServer 通信,获得当前已分配的 HRegion 和 HRegionServer 的对应关系。

(4) 扫描 .META. Region 的集合,计算得到当前还未分配的 HRegion ,将他们放入待分配 HRegion 列表。

(21)

3.4 数据读流程

(1)-ROOT- HRegion 永远不会被 Split ,保证了最多需要三次跳转就能定位到任意 HRegion 。

(2).META. 表每行保存一个 HRegion 的位置信息, Row Key

采用表名 + 表的最后一样编码而成。

(3) 为了加快访问, .META. 表的全部 HRegion 都保存在内存中。

(22)

3.5 数据写流程

当客户端发起 Put 等请求时, HBase 会执行数据写流程。

(1) 客户端首先访问 ZooKeeper 查找 -ROOT- 表,然后获取 .META. 表信息。

(2).META. 表记录了每个 HRegionServer 包含 HRegion 的 Row Key 范围,根据 Row Key 找到对应的 HRegionServer 地址,

HRegionServer 会将请求匹配到某个具体的 HRegion 上面。

(3)HRegion 首先把数据写入 WAL 。

(4)WAL 写入成功后,把数据写入缓存 MemStore ,写完后检查所有 MemStore 大小的总和是否达到 Flush 阀值,如果达到, HReg

ionServer 处理 Flush 请求,将数据写入 StoreFile 并以 HFile 的形式存到 HDFS 上。

(23)

3.6 删除数据流程

• HBase 删除操作不会立即删除 HFile ,会先将数据打一个删除标签,当开启一个大的合并,才会将打标记的数据删除,这个大合

并消耗比较大的性能,只有在晚上或者资源使用少时才使用。

(24)

4.HBase 环境搭建

• HBase 运行环境需要依赖于 Hadoop 集群,如果 Hadoop 尚未搭建,可以参考同套教材《 Hadoop 大数据开发》相关章节。 HBas

e 引入 ZooKeeper 来管理集群的 Master 和入口地址,因此需要先安装 ZooKeeper ,再设置 HBase 。

(25)

4.HBase 环境搭建

• 1 ZooKeeper 的安装

• 在 ZooKeeper 集群环境下只要一半以上的机器正常启动了,那么 Zookeeper 服务将是可用的。因此,集群上部署 Zookeeper 最好使用奇数台机器,这样 如果有 5 台机器,只要 3 台正常工作则服务将正常。在目前的实际生产环境中,一个 Hadoop 集群最多有三台节点做备用 Master ,即并不是所有节点都安 装 ZooKeeper ;如果以实验为目的,可以将所有节点都安装 ZooKeeper 并作为 Master 使用。

• 1. 解压

• 将下载好的 ZooKeeper 文件上传到 Hadoop 集群中的 master 节点,使用命令 "tar -zxvf zookeeper-3.4.5.tar.gz -C /hadoop/" 将其解压。 • 2. 修改配置文件

• (1) 创建文件夹

• mkdir /hadoop/zookeeper-3.4.5/data /hadoop/zookeeper-3.4.5/log • (2) 修改 zoo.cfg

• 进入 zookeeper 的 conf 目录修改 zoo.cfg 。 • cp zoo_sample.cfg zoo.cfg • 修改 zoo.cfg 的内容为: • dataDir=/hadoop/zookeeper-3.4.5/data • dataLogDir=/hadoop/zookeeper-3.4.5/log • server.0=192.168.254.128:2888:3888 • server.1=192.168.254.129:2888:3888 • server.2=192.168.254.131:2888:3888 • 除了 dataDir 的内容为修改外,其他配置信息均为新增。

(26)

4.HBase 环境搭建

(3) 创建 myid 文件

在 /hadoop/zookeeper-3.4.5/data 文件夹下创建 myid 文件,将其值修改为 0 。需要注意的是, zoo.cfg 中 server.后面的数值必须和 =” 后面 IP 中的 myid 值保持一致,即 IP 为 192.168.149.129 的节点中 myid 的值必须为 1 , IP 为 192.168.149.131 的节点中 myid 的值必须为 2 。 • (4) 分发到 slave1 和 slave2 节点scp -r /hadoop/zookeeper-3.4.5/ slave1:/hadoop/scp -r /hadoop/zookeeper-3.4.5/ slave2:/hadoop/同时按照第三步要求修改 myid 文件对应的值3. 修改三个节点的环境变量

在 /etc/profile 文件末尾添加 export PATH=$PATH:/hadoop/zookeeper-3.4.5/bin ,并执行命令 "source /etc/profile" 使配置的 环境变量生效。

(27)

4.HBase 环境搭建

本书使用的 HBase 版本是 hbase-1.3.1( 不采用 1.4.0 的原因是该版本基于 Hadoop2.7.4 平台开发,而本书使用的 Hadoop 版本是 2.6.5 ,会存在部分 版本兼容性问题 ) ,可以在 Apache 的官网下载,下载地址为 http://archive.apache.org/dist/hbase/ 。

• 1. 解压

• 将下载好的 HBase 文件上传到 Hadoop 集群中的 master 节点,使用命令 "tar -zxvf hbase-1.3.1-bin.tar.gz -C /hadoop/" 将其解压。

2. 修改 HBase 的配置文件 • (1) 修改 hbase-env.sh 文件 • 新增四项配置 • export HBASE_CLASSPATH=/hadoop/hadoop-2.6.5/etc/hadoop • export HBASE_PID_DIR=/var/hadoop/pids • export JAVA_HOME=/Java/jdk1.8.0_144/ • export HBASE_MANAGES_ZK=false

(28)

4.HBase 环境搭建

一个分布式运行的 HBase 依赖一个 Zookeeper 集群,所有的节点和客户端都必须能够访问 Zookeeper 。默认的情况下 HBase 会管理一个 Zookeep 集群 ,即 HBase 默认自带一个 Zookeep 集群,这个集群会随着 HBase 的启动而启动。而在实际的商业项目中通常自己管理一个 Zookeeper 集群更便于优化配 置提高集群工作效率,但需要配置 HBase 。需要修改 conf/hbase-env.sh 里面的 HBASE_MANAGES_ZK 来切换,这个值默认是 true ,作用是让 HBase 启动的时候同时也启动 Zookeeper 。在安装过程中,采用独立运行 Zookeeper 集群的方式,故将其属性值改为 false 。

(2) 修改 regionservers 文件

regionservers 文件负责配置 HBase 集群中哪台节点做 RegionServer 服务器,本书的规划是所有 slave 节点均可当 RegionServer 服务器,故其配 置内容为:

slave1slave2

(29)

4.HBase 环境搭建

• (3) 修改 hbase-site.xml 文件 • hbase-site.xml 文件内容修改为: • <?xml version="1.0"?>

• <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> • <configuration> • <property> • <name>hbase.rootdir</name> • <value>hdfs://192.168.254.128:9000/hbase</value> • </property> • <property> • <name>hbase.master</name> • <value>hdfs://192.168.254.128:60000</value> • </property> • <property> • <name>hbase.zookeeper.property.dataDir</name>

(30)

4.HBase 环境搭建

• <property> • <name>hbase.cluster.distributed</name> • <value>true</value> • </property> • <property> • <name>hbase.zookeeper.quorum</name> • <value>master,slave1,slave2</value> • </property> • <property> • <name>hbase.zookeeper.property.clientPort</name> • <value>2181</value> • </property> • <property> • <name>hbase.master.info.port</name> • <value>60010</value>

(31)

4.HBase 环境搭建

(4) 分发到 slave1 和 slave2 节点

scp -r /hadoop/hbase-1.3.1/ slave1:/hadoop/scp -r /hadoop/hbase-1.3.1/ slave2:/hadoop/

3. 修改三个节点的环境变量

在 /etc/profile 文件末尾添加 export PATH=$PATH:/hadoop/zookeeper-3.4.5/bin: /hadoophbase-1.3.1-bin.tar.gz/bin ,并执行命 令 "source /etc/profile" 使配置的环境变量生效

4. 测试

(32)

4.HBase 环境搭建

Lorem ipsum dolor sit amet, consectetur adipisicing elit.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit.Lorem ipsum dolor sit amet, consectetur adipisici

(33)

4.HBase 环境搭建

(34)

4.HBase 环境搭建

在 master 节点,使用命令 "hbase-daemon.sh stop master" ,等待一会发现 slave1 成为 master ,当 HBase 的 master 节点故障后, ZooKeepe r 会从备份中自动推选一个作为 master ,如图 4-11 所示:

(35)

5 HBase Shell

• 在实际应用中,需要经常通过 Shell 命令操作 HBase 数据库。 HBase Shell 是 HBase 的命令行工具;通过 HBase Shell ,用

户不仅可以方便地创建、删除及修改表,还可以向表中添加数据、列出表中的相关信息等

(36)

5.1 HBase Shell 启动

• 在任意一个 HBase 节点运行命令: hbase shell ,即可进入 HBase 的 Shell 命令行模式

• HBase Shell 没法使用退格键删除文字,需要通过 ctrl + backspace 的方式进行删除,或者通过 " 文件 " -> " 属性 " ->

" 终端 " -> " 键盘 " 设置 Xshell ,将 "Backspace 键序列 " 的值设置为 "ASCII 127"

(37)

5.1 HBase Shell 启动

• HBase Shell 的每个命令具体用法,都可以直接输入查看,如输入 create ,可以看到其用法

• HBase Shell 基本命令操作

操作 命令表达式 说明

创建表 create 'table_name, 'family1','family2','familyN' 创建表和列族。 添加记录 put 'table_name', 'rowkey', 'family:column', 'value' 向列插入一条数据。

查看记录 get 'table_name', 'rowkey' 查询单条记录,也是 HBase 最常 用的命令。

查看表中的

记录总数 count 'table_name' 这个命令并不快,且目前没有找到更快的方式统计行数。 删除记录 delete 'table_name' ,'rowkey','family_name:column

'deleteall 'table_name','rowkey' 第一种方式删除一条记录单列的数 据;第二种方式删除整条记录。 删除一张表 1. disable 'table_name' 先停用,再删除表。 2. drop 'table_name' 查看所有记

录 scan "table_name" ,{LIMIT=>10}

LIMIT=>10表示只返回 10 条记录 ,否则将全部显示。 10 条 记 录 , 否 则 将 全 部

(38)

5.2 表的管理

• 1. list 命令

• 2. create 命令

创建表。语法格式: create <table>, {NAME => <family>, VERSIONS => <VERSIONS>}

• 3. describe 命令

• 4. disable 命令

(39)

5.2 表的管理

• 5. exists

查看一个表是否存在。语法格式: exists <table>

• 6. is_enabled

判断表是否 enable 。语法格式: enable <table>

• 7. is_disabled

判断表是否 disable 。语法格式: disable <table>

• 8. alter 命令

修改表结构。语法格式: alter <table>, {NAME => <family>}, {NAME => <family>, METHOD => 'delete'}

• 9. 删除列族

(40)

5.2 表的管理

• 10. whoami

• 11. version

(41)

5.3 表数据的增删改查

• 1. put 命令

向表中插入数据。语法格式: put <table>, <rowKey>, <family:column>, <value>, <timestamp> 。

• 2. get 命令

查询数据。语法格式: get <table>,<rowKey>,[<family:column>,....]

• 3. scan 命令

扫描表。语法格式: scan <table>, {COLUMNS => [ <family:column>,.... ], LIMIT => num} ;另外,还可以

添加 STARTROW 、 TIMERANGE 和 FITLER 等高级功能

• 4. delete 命令

删除数据。语法格式: delete <table>, <rowKey>, <family:column> , <timestamp>

• 5. deleteall 命令

• 6. count

• 7. truncate

(42)

5.3 表数据的增删改查

• 5. deleteall 命令

删除行。语法格式: deleteall <table>, <rowKey>, <family:column> , <timestamp>

• 6. count

查询表中总共有多少行数据。语法格式: count <table> 。

• 7. truncate

(43)

5.4 数据迁移的 importsv 的使用

• HBase 数据来源于日志文件或者 RDBMS ,把数据迁移到 HBase 表中。常见的有三种方法:使用 HBase Put API ;使用 HBase

批量加载工具;自定义 MapReduce 实现。

• importtsv 是 HBase 官方提供的基于 MapReduce 的批量数据导入工具,同时也是 HBase 提供的一个命令行工具,可以将存储在

HDFS 上的自定义分隔符 ( 默认是 \t) 的数据文件,通过一条命令方便的导入到 HBase 中。

(44)

6. HBase 程序开发

• HBase 提供了丰富的 Java API 接口供用户使用,可以通过 HBase Java API 完成和 HBase Shell 相同的功能。本章不仅介绍

如何通过 Java API 完成表的相关操作,还会讲解相关高级用法,如过滤器、计数器、协处理器的使用, NameSpace 的开发和快

照的创建等。

(45)

6.1 表的相关操作

• 1. API 介绍

HBase Java API 核心类主要有 HBaseConfiguration , HBaseAdmin , HTable 和数据操作类组成

HBase Java

HBase

数据模型

HBaseAdmin 数据库 (DataBase)

HBaseConfiguration

HTable 表 (Table)

HTableDescriptor 列族 (Column Family)

Put

列标识符 (Column Qualifier) Get

(46)

6.1 表的相关操作

• 2. HBaseConfiguration

HBaseConfiguration 位于 org.apache.hadoop.hbase.HbaseConfiguration ,完成对 HBase 的配置,主要设置一

些关键属性

返回值 函数 说明

void addResource(Path file) 通过给定的路径所指的文件来添加资源。

void clear() 清空所有已设置的属性。

string get(String name) 获取属性名对应的值。

String getBoolean(String name, boolean defaultValue)

获取为 boolean 类型的属性值,如果其属 性值类型不为 boolean ,则返回默认属性

值。

void set(String name, String value) 通过属性名来设置值。

(47)

6.1 表的相关操作

• 3. HBaseAdmin

• HBaseAdmin 位于 org.apache.hadoop.hbase.client.HbaseAdmin ,提供了一个接口来管理 HBase 数据库的表信息;它

提供的方法如表 6-3 所示,包括:创建表,删除表,列出表项,使表有效或无效,以及添加或删除表列族成员等。

返回值 函数 说明

void addColumn(String tableName, HColumnDescriptor column) 向一个已经存在的表添加列。 void checkHBaseAvailable(HBaseConfiguration conf) 静态函数,查看 HBase 是否处于运行状态

void createTable(HTableDescriptor desc) 创建一个表,同步操作。

void deleteTable(byte[] tableName) 删除一个已经存在的表。

void enableTable(byte[] tableName) 使表处于有效状态。

void disableTable(byte[] tableName) 使表处于无效状态。

HTableDescriptor[] listTables() 列出所有用户表。

void modifyTable(byte[] tableName, HTableDescriptor htd) 修改表的模式,是异步的操作,可能需要花费一定的时间。

(48)

6.1 表的相关操作

• 4. HTableDescriptor

HTableDescriptor 位于 org.apache.hadoop.hbase.HtableDescriptor ,包含了表的名字及其对应表的列族

返回值 函数 说明

void addFamily(HColumnDescriptor) 添加一个列族。

HColumnDescriptor removeFamily(byte[] column) 移除一个列族。

byte[] getName() 获取表的名字。

byte[] getValue(byte[] key) 获取属性的值。

(49)

6.1 表的相关操作

• 5. HColumnDescriptor

HColumnDescriptor 类位于 org.apache.hadoop.hbase.HcolumnDescriptor ,维护着关于列族的信息,例如版本号

,压缩设置等,它通常在创建表或者为表添加列族的时候使用。列族被创建后不能直接修改,只能通过删除然后重新创建的方式;列

族被删除的时候,列族里面的数据也会同时被删除。

返回值 函数 说明 byte[] getName() 获取列族的名字。

byte[] getValue(byte[] key) 获取对应的属性的值。

(50)

6.1 表的相关操作

• 6. HTable

HTable 类位于 org.apache.hadoop.hbase.client.HTable ,可以用来和 HBase 表直接通信,此方法对于更新操作来

说是非线程安全的。

返回值 函数 说明

void checkAndPut(byte[] row, byte[] family, byte[] qualifier, byte[] value, Put put 自动的检查 row , family , qualifier 是否 与给定的值匹配。

void close() 释放所有的资源或挂起内部缓冲区中的更

新。

Boolean exists(Get get) 检查 Get 实例所指定的值是否存在于

HTable的列中。

Result get(Get get) 获取指定行的某些单元格所对应的值。

byte[][] getEndKeys() 获取当前一打开的表每个区域的结束键值

ResultScanner getScanner(byte[] family) 获取当前给定列族的 Scanner 实例。

HTableDescriptor getTableDescriptor() 获取当前表的 HTableDescriptor 实例。

byte[] getTableName() 获取表名。

(51)

6.1 表的相关操作

• 7. Put

Put 类位于 org.apache.hadoop.hbase.client.Put ,用来对单个行执行添加操作。

返回值 函数 说明

Put add(byte[] family, byte[] qualifier, byte[] value) 将指定的列和对应的值添加到 Put 实例中 。

Put add(byte[] family, byte[] qualifier, long ts, byte[] value) 将指定的列和对应的值及时间戳添加到 Put实例中。

byte[] getRow() 获取 Put 实例的行。

RowLock getRowLock() 获取 Put 实例的行锁。

long getTimeStamp() 获取 Put 实例的时间戳。

boolean isEmpty() 检查 familyMap 是否为空。

(52)

6.1 表的相关操作

• 8. Get

Get 类位于 org.apache.hadoop.hbase.client.Get ,用来获取单个行的相关信息。

返回值 函数 说明

Get addColumn(byte[] family, byte[] qualifier) 获取指定列族和列标识符对应的列。

Get addFamily(byte[] family) 通过指定的列族获取其对应的所有列。

Get setTimeRange(long minStamp,long maxStamp) 获取指定时间的列的版本号。

(53)

6.1 表的相关操作

• 9. Result

Result 类位于 org.apache.hadoop.hbase.client.Result ,用于存储 Get 或者 Scan 操作后获取表的单行值,使用此

类提供的方法可以直接获取值或者各种 Map 结构 (Key-Value 对 ) 。

返回值 函数 说明

boolean containsColumn(byte[] family, byte[] qualifier) 检查指定的列是否存在。

NavigableMap<byte[],byte[]> getFamilyMap(byte[] family) 获取对应列族所包含的修饰符与值的键值对。 byte[] getValue(byte[] family, byte[] qualifier) 获取对应列的最新值。

(54)

6.1 表的相关操作

• 10. ResultScanner

ResultScanner 是一个客户端获取值的接口。

返回值 函数 说明

void close() 关闭 Scanner 并释放分配给它的资源。

(55)

6.2 创建 Configuration 对象

• HBase 所有 Java API 操作,都需要首先创建 Configuration 对象,并指定 hbase-site.xml 作为资源文件。

Configuration config = HBaseConfiguration.create();

config.addResource(new Path("/hadoop/hbase-1.3.1/conf "));

• 默认的构造方式会从 hbase-default.xml 和 hbase-site.xml 中读取配置,如果 classpath 中没有这两个文件,需要自己配

置,在 Configuration 对象中设置 hbase.zookeeper.quorum 参数和 hbase.zookeeper.property.clientPort 参数的

值,这些值也可以在 hbase-site.xml 配置文件中找到:

Configuration config = HBaseConfiguration.create();

config.set("hbase.rootdir", "hdfs://192.168.254.128:9000/hbase"); config.set("hbase.zookeeper.property.clientPort", "2181");

//hbase.zookeeper.quorum 值不能采用 IP 方式,必须使用名称

config.set("hbase.zookeeper.quorum", "master,slave1,slave2"); config.set("hbase.master", "60000");

(56)

6.3 创建表

• HBase 建表函数提供了四个重载函数,分别是:

• (1)void createTable(HTableDescriptor desc)

• (2)void createTable(HTableDescriptor desc, byte[] startKey,byte[] endKey, int numRegions)

• (3)void createTable(HTableDescriptor desc, byte[][] splitKeys)

(57)

6.4 数据插入

• HBase 数据插入使用 Put 对象, Put 对象在进行数据插入时,首先会向 HBase 集群发送一个 RPC 请求,得到响应后将 Put 类中

的数据通过序列化的方式传给 HBase 集群,集群节点拿到数据后进行添加功能。

• 1. 单行插入: put(Put p)

• 2. 批量插入 :put(List<Put> list)

• 3. 检查并写入: checkAndPut(byte[] row, byte[] family, byte[] qualifier, byte[] value, Put put)

• 4. 缓存块操作

(58)

6.5 数据查询

分为单条查询和批量查询,单条查询通过 get 查询,批量查询通过 HTable 的 getScanner 实现。

1. 按行查询

按行查询是在构造 Get

对象的时候只传入行健

参考代码: 6-5 下的 QueryDemo.java

2. 按列查询

按列查询是在构造 Get

对象的时候传入行健,列族和列 参考代码: 6-5 下的 QueryDemo2.java

3. 查询历史数据

要想查询历史版本数据,需要在建表的时候使用 setMaxVersions(n) ,其中 n

表示设置的版本数。

参考代码: 6-5 下的 QueryDemo3.java

(59)

6.6 数据删除

• 1. 删除指定列

删除指定列是在构造 Delete 对象的时候,传入行健,列族和列,代码参考: 6-5 下的 DeleteDemo.java

• 2. 删除指定行

删除指定的行是在构造 Delete 对象的时候只传入行健

• 3. 删除表

删除表的时候要先停用再删除,代码参考: DeleteDemo3.java

(60)

6.7 Scan 查询

• 扫描类似于关系型数据库的游标 (Cursor) ,并利用到了 HBase 底层顺序存储的特性。使用扫描的一般步骤是:

• (1) 创建 Scan 实例。

• (2) 为 Scan 实例增加扫描的限制条件。

• (3) 调用 HTable 的 getScanner() 方法获取 ResultScanner 对象,如果通过 HTablePool 的方式,则是调用 HTablePool

的 getScanner 方法。 ( 注意, HTable 类实现了 HTableInterface 接口,这个接口用于与单个 HBase 表通信。 )

(61)

6.8 Filter

• HBase 为筛选数据提供了一组过滤器,通过这个过滤器可以在 HBase 中的数据的多个维度 ( 行,列,数据版本 ) 上对数据进行筛

选操作,也就是说过滤器最终筛选的数据能够细化到具体的一个存储单元格上 ( 由行键,列名,时间戳定位 ) 。通常来说,通过行

键值来筛选数据的应用场景较多。

• 1. RowFilter

• 2. PrefixFilter

• 3. KeyOnlyFilter

• 4. RandomRowFilter

• 5. InclusiveStopFilter

• 6. FirstKeyOnlyFilter

• 7. ColumnPrefixFilter

• 8. ValueFilter

• 9. ColumnCountGetFilter

(62)

6.9 行数统计

• 1. HBase Shell 统计行数

• 2. HBase 自带 MapReduce 表行数统计 RowCounter

• 3. Java API 统计行数

(63)

6.10 NameSpace 开发

• 在 HBase 中, NameSpace 命名空间指对一组表的逻辑分组,类似 RDBMS 中的 DataBase ,方便对表在业务上划分。 HBase 从 0.98.0

, 0.95.2 两个版本开始支持 NameSpace 级别的授权操作, HBase 全局管理员可以创建、修改和回收 NameSpace 的授权。

• HBase 系统默认定义了两个缺省的 NameSpace :

• (1)hbase :系统内建表,包括 NameSpace 和 meta 表。

• (2)default :用户建表时未指定 NameSpace 的表都创建在此。

• 1. HBase Sehll 操作 NameSpace

创建 NameSpace create_namespace 'ns1' 查看 NameSpace describe_namespace 'ns1'列出所有 NameSpace list_namespace

修改命名空间相关属性 alter_namespace 'ns2', {METHOD => 'set', 'hbase.namespace.quota.maxtables'=>'8'}在 NameSpace下创建表 create 'ns2:stu1', 'info'

查看 NameSpace下的表 list_namespace_tables 'hbase'

• 2. Java API 操作 NameSpace

Admin.createNamespace 方法可以创建一个命名空间,同时在创建表的时候同时指定已定义好的命名空间即可,代码参考 6-10 下的 NameSpaceDemo.java

(64)

6.11 计数器

• 1. 创建计数器

在 HBase 中, HBase 将某一列作为计数器来使用,因此创建计数器与创建行是相同的。

• 2. 计数器的增加

计数器增加值是增加一个 long 值,其增加的值也有正有负,不同的数据进行增加时有不同的效果:(1) 大于 0 :增加计数器的值。(2) 等于 0 :不更改计数器的值。(3) 小于 0 :减少计数器的值。

• 3. HBase shell 操作计数器

• 4. Java API 操作计数器

• 5. 多列增加

(65)

6.12 协处理器

• 1. 协处理器类型

• 2. HBase shell 操作协处理器

• 3. Java API 操作协处理器

(66)

6.13 HBase 快照

• 1. 快照的使用场景

• 2. HBase shell 快照操作

• 3. Java API 操作快照

(67)

7.1 HBase 表设计

• HBase 与 RDBMS 的区别在于: HBase 的 Cell( 每条数据记录中的数据项 ) 是具有版本描述的,行是有序的,列在所属列族存

在的情况下,由客户端自由添加。以下的几个因素是 HBase Schema 设计需要考虑的问题:

(1)Row Key 的结构该如何设置,而 Row Key 中又该包含什么样的信息。 • (2) 表中应该有多少列族。

• (3) 每个列族中存储多少列数据。

(4) 单元中 (Cell) 应该存储什么样的信息。 • (5) 每个单元中存储多少个版本信息。

• 在 HBase 表设计中最重要的就是定义 Row Key 的结构

• (1)HBase 中 Row Key 是按照字典序排列的,表中每一块区域的划分都是通过起始 Row Key 和结束 Row Key 来决定的。 • (2) 列族表创建之前就要定义好,不同列族的数据,在物理上是分开的。

• (3) 列族中的列标识可以在表创建完以后动态插入数据时添加。

• (4)HBase 中没有 join 的概念,但是大表的结构可以使得不需要 join 的存在而解决这一问题,需要考虑的是,一行记录加上一个特定的行关键字 ,实现把所有关于 join 的数据并在一起。

(68)

7.1 HBase 表设计

• 1. 预先分区

默认情况下,在创建 HBase 表的时候会自动创建一个 Region 分区,当导入数据的时候,所有 HBase 的客户端都向这一个 Region 写数据,直到这个 Region 足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的 Region ,这样当数据写入 HBase 时,会按照 Region 分区 情况,在集群内做数据的负载均衡。

• 2. Row Key

HBase 中 Row Key 是按照字典序存储,因此,设计 Row Key 时,要充分利用排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数 据放在一块。此外, Row Key 若是递增的生成,建议不要使用正序直接写入 Row Key ,而是采用 reverse 的方式反转 Row Key ,使得 Row Key 大 致均衡分布,这样设计有个好处是能将 RegionServer 负载均衡,否则容易产生所有新数据都在一个 RegionServer 上堆积的现象,这一点还可以结 合表的预切分一起设计。

Row Key 是 HBase 的 Key-Value 存储中的 Key ,通常使用用户要查询的字段作为 Row Key ,查询结果作为 Value

• (1) 单个查询,需要尽量缩小 Key 的长度。如果 Row Key 太长,第一存储开销会增加,影响存储效率,第二内存中 Row Key 字段过长,会导致内 存的利用率低,进而降低索引命中率。

(2) 范围查询,根据 Row Key 按字典序排列的特点,针对查询需求设计 Row Key ,保证范围查询的 Row Key 在物理上存放在一起。

1) 数字 Row Key 的从大到小排序:原生 HBase 只支持从小到大的排序,这样就对于排行榜一类的查询需求很尴尬。那么采用 rowkey = Int eger.MAX_VALUE - rowkey 的方式将 Row Key 进行转换,最大的变最小,最小的变最大,在应用层再转回来即可完成排序需求。

2) Row Key 的散列原则:如果 Row Key 是类似时间戳的方式递增的生成,建议不要使用正序直接写入 Row Key ,而是采用 reverse 的方式 反转 Row Key 。

(69)

7.1 HBase 表设计

• 3. 列族设计

设计 HBase Schema 的时候,要尽量只有一个 Column Family ,目前 HBase 并不能很好的处理超过 2~3 个 Column Family 的表。

Flush 和 Compaction 触发的基本单位都是 Region 级别,当一个列族有大量的数据的时候会触发整个 Region 里面的其他列族的 MemStore( 其实这 些 MemStore 可能仅有少量的数据,还不需要 Flush) 也发生 Flush 动作;另外 Compaction 触发的条件是当 StoreFile 的个数 ( 不是总的 Store File 的大小 ) 达到一定数量的时候会发生,而 Flush 产生的大量 StoreFile 通常会导致 Compaction , Flush 和 Compaction 会发生很多 I/O 相 关的负载,这对 HBase 的整体性能有很大影响,所以选择合适的列族个数很重要。

• 4. 列

对于列需要扩展的应用,列可以按普通的方式设计,但是对于列相对固定的应用,最好采用将一行记录封装到一个列中的方式,这样能够节省存储空间。 封装的方式推荐使用 Protocol Buffer 。

例:身份证表 Card 和人表 Person 之间一对一关系 ( 左是 MySQL 设计,右图是 HBase 设计 )

Card 表 字段 说明 属性 id Card 表主键 整型,自动增加 1 code 身份证编码 字符串 Person 表 字段 说明 属性 id People 表主键 整型,自动增加 1 name 姓名 字符串 age 年龄 整型 sex 性别 字符串 HBase Person 表 字段 说明

Row Key person_id 行健

Column Family info:code 身份证编码 info:name 姓名 info:age 年龄 info:sex 性别 info:address 家庭住址

(70)

7.1 HBase 表设计

• 4. 列

例:用户表 User 和订单表 Order 之间一对多的关系 一个用户可以有多个订单,而一个订单只能属于一个用户。 ( 上边是 MySQL 设计,下图是 HBase 设计 ) User 表 字段 说明 属性 id User 表主键 整型,自动增加 1 username 用户名 字符串 password 密码 字符串 address 家庭住址 字符串 Order 表 字段 说明 属性 id Order 表主键 整型,自动增加 1 code 订单编码 字符串 order_date 订单日期 日期 user_id 外键关联 User 表 id 主键 整型 HBase Orders 表 字段 说明

Row Key order_code 订单编码,行健,逆排序 Column Family

info:username 用户名 info:password 密码 info:address 家庭住址 info:order_date 订单日期

(71)

7.1 HBase 表设计

• 4. 列

例:商品表 Product 和订单表 Order 之间多对多的关系

一个商品可能被多个订单购买,而一个订单也可能有多个商品。为了表达两者多对多的关系,需要通过中间表 Orders_Item 表达多对多关系。 ( 上边是 MySQL 设计,下图是 HBase 设计 )

Product 表 Order 表 Orders_Item 表

字段 说明 属性 字段 说明 属性 字段 说明 属性

id Product 表主键 整型,自动增加 1 id Order 表主键 整型,自动增加 1 product_id 外键关联 Product 表 id 主键 整型 product_code 商品编码 字符串 code 订单编码 字符串 order_id 外键关联 Order 表 id 主键 整型 product_name 商品名称 字符串 order_date 订单日期 日期

product_price 商品价格 浮点型 user_id 外键关联 User 表 id 主 整型

HBase Product 表 HBase Order 表

字段 说明 字段 说明

Row Key product_code 商品编码,行健,逆排序 Row Key order_code 订单编码,行健,逆排序 Column Family product:name 商品名称 Column Family info:date 订单日期

product:price 商品价格 info:price 商品价格 Column Family order:code 订单编码

Column Family

product_code 商品编码 order:date 订单日期 product:name 商品名称 product:price 商品价格

(72)

7.2 列族设计优化

• 简介

列族的设计需遵循:尽量避免一次请求需要拿到的列分布在不同的列族中。

HBase 中基本属性都是以列族为单位进行设置的,如下示例,用户创建了一张称为 "news" 的表,表中只有一个列族 "info" ,紧接着的属性都是对此 列族进行设置。这些属性基本都会或多或少地影响该表的读写性能,但有些属性用户只需要理解其意义就知道如何设置,而有些属性却需要根据场景、 业务来设置,比如块大小属性 (Block Size) 在不同场景下应该如何设置? 块大小是 HBase 的一个重要配置选项,默认块大小为 64K 。对于不同的业务数据,块大小的合理设置对读写性能有很大的影响,而对块大小的调整,主 要取决于两点: • 1. 用户平均读取数据的大小 理论上讲,如果用户平均读取数据的大小较小,建议将块大小设置较小,这样可以使得内存可以缓存更多块,读性能自然会更好。相反,建 议将块大小设置较大。 随着 Block Size 的增大,系统随机读的吞吐量不断降低,延迟不断增大。 64K 大小比 16K 大小的吞吐量大约降低 13% ,延迟增大 13% 。 同样的, 128K 大小比 64K 大小的吞吐量降低约 22% ,延迟增大 27% 。因此,对于以随机读为主的业务,可以适当调低 Block Size 的大 小,以获得更好的读性能。 可见,如果业务请求以 Get 请求为主,可以考虑将块大小设置较小;如果以 Scan 请求为主,可以将块大小调大;默认的 64K 块大小是在 S can 和 Get 之间取得的一个平衡。 • 2. 数据平均键值对规模

(73)

7.2 列族设计优化

• 2. 数据平均键值对规模

可以使用 HFile 命令查看平均键值对规模,如下:

hbase org.apache.hadoop.hbase.io.hfile.HFile -m -f /hbase/data/default/stu6/9669e8e736d1857b04df1a8afb1da056/in fo/92458ec14e7c46dda7cada717beb5458 执行结果: 输出的信息可以看出,该 HFile 的平均键值对规模为 24B + 3B = 27B ,相对较小,在这种情况下可以适当将块大小调小 ( 例如 16KB) 。这样可以 使得一个块内不会有太多键值对,键值对太多会增大块内寻址的延迟时间,因为 HBase 在读数据时,一个块内部的查找是顺序查找。 注意:默认块大小适用于多种数据使用模式,调整块大小是比较高级的操作,配置错误将对性能产生负面影响。因此建议在调整之后进行测试,根据测 试结果决定是否可以线上使用。

Block index size as per heapsize: 392

reader=/hbase/data/default/stu6/9669e8e736d1857b04df1a8afb1da056/info/92458ec14e7c46dda7cad a717beb5458, compression=none, cacheConf=CacheConfig:disabled, firstKey=rw001/info:age/1517276499875/Put, lastKey=rw003/info:name/1517276500200/Put, avgKeyLen=24, avgValueLen=3,

(74)

7.3 写性能优化策略

• 写数据流程

HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。

HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同

1. 是否需要写 WAL , WAL 是否需要同步写入

数据写入流程可以理解为一次顺序写 WAL 加一次写缓存,通常情况下写缓存延迟很低,因此提升写性能就只能从 WAL 入手。 WAL 机制一方面是为了确 保数据即使写入缓存丢失也可以恢复,另一方面是为了集群之间异步复制,默认 WAL 机制开启且使用同步机制写入 WAL 。首先考虑业务是否需要写 WAL ,通常情况下大多数业务都会开启 WAL 机制 ( 默认 ) ,但是对于部分业务可能并不特别关心异常情况下部分数据的丢失,而更关心数据写入吞吐量,比 如某些推荐业务,这类业务即使丢失一部分用户行为数据也对推荐结果并不构成很大影响,但是对于写入吞吐量要求很高,不能造成数据队列阻塞。这 种场景下可以考虑关闭 WAL 写,写入吞吐量可以提升二到三倍。退而求其次,有些业务不能接受不写 WAL ,但可以接受 WAL 异步写入,也是可以考虑 优化的,通常也会带来一倍多的性能提升。

(75)

7.3 写性能优化策略

• 写数据流程

HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。

HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同

2. Put 是否可以同步批量提交

HBase 分别提供了单条 Put 以及批量 Put 的 API 接口,使用批量 Put 接口可以减少客户端到 RegionServer 之间的 RPC 连接数,提高写入性能。另 外需要注意的是,批量 Put 请求要么全部成功返回,要么抛出异常。

(76)

7.3 写性能优化策略

• 写数据流程

HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。 HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同 • 3. Put 是否可以异步批量提交 业务如果可以接受异常情况下少量数据丢失的话,还可以使用异步批量提交的方式提交请求。提交分为两阶段执行:用户提交写请求之后,数据会写入 客户端缓存,并返回用户写入成功;当客户端缓存达到阈值 ( 默认 2M) 之后批量提交给 RegionServer 。需要注意的是,在某些情况下客户端异常的 情况下缓存数据有可能丢失。

(77)

7.3 写性能优化策略

• 写数据流程

HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。

HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同

4. Region 是否太少

当前集群中表的 Region 个数如果小于 RegionServer 个数,即 Num(Region of Table) < Num(RegionServer) ,可以考虑切分 Region 并尽 可能分布到不同 RegionServer 来提高系统请求并发度,如果 Num(Region of Table) > Num(RegionServer) ,再增加 Region 个数效果并不 明显。

(78)

7.3 写性能优化策略

• 写数据流程

HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。 HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同 • 5. 写入请求是否不均衡 另一个需要考虑的问题是写入请求是否均衡,如果不均衡,一方面会导致系统并发度较低,另一方面也有可能造成部分节点负载很高,进而影响其他业 务。分布式系统中要特别避免一个节点负载很高的情况出现,一个节点负载很高可能会拖慢整个集群,这是因为很多业务会使用多批量提交读写请求, 一旦其中一部分请求落到该节点无法得到及时响应,就会导致整个批量请求超时。

(79)

7.3 写性能优化策略

• 写数据流程

HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。 HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同 • 6. 写入 KeyValue 数据是否太大 KeyValue 大小对写入性能的影响巨大,一旦遇到写入性能比较差的情况,需要考虑是否由于写入 KeyValue 数据太大导致。试想,我们去肯德基排队 买汉堡,有 5 个窗口服务,正常情况下大家买一个很快,这样 5 个窗口可能只需要 3 个服务。假设忽然来了一批人,要定全家桶,好了,所有的窗口都 工作起来,而且因为全家桶不好制作导致服务很慢,这样必然会导致其他排队的用户长时间等待,直至超时。 可回头一想这可是写请求,怎么会有这么大的请求延迟!和业务方沟通之后确认该表主要存储资料库文档信息,都是平均 100K 左右的数据,就是因为 这个业务 KeyValue 太大导致。 KeyValue 太大会导致 WAL 文件写入频繁切换, Flush 以及 Compaction 频繁触发,写入性能急剧下降。

(80)

7.4 读性能优化策略

• 7.4.1 HBase 客户端优化

一般情况下,读请求延迟较大通常存在三种场景,分别为: (1) 仅有某业务延迟较大,集群其他业务都正常。 (2) 整个集群所有业务都反应延迟较大。 (3) 某个业务起来之后集群其他部分业务延迟较大。 这三种场景是表象,通常某业务反应延迟异常,首先需要明确具体是哪种场景,然后针对性解决问题。读性能优化主要分为四个方面:客户端优化、服 务器端优化以及 HDFS 相关优化,下面分别进行详细讲解

• 7.4.1 HBase 客户端优化

• 1. Scan 缓存是否设置合理 一次 Scan 会返回大量数据,因此客户端发起一次 Scan 请求,实际并不会一次就将所有数据加载到本地,而是分成多次 RPC 请求进行加载,这样设计 一方面是因为大量数据请求可能会导致网络带宽严重消耗进而影响其他业务,另一方面也有可能因为数据量太大导致本地客户端发生内存溢出。在这样 的设计体系下用户会首先加载一部分数据到本地,然后遍历处理,再加载下一部分数据到本地处理,如此往复,直至所有数据都加载完成。数据加载到 本地就存放在 Scan 缓存中,默认 100 条数据大小。

通常情况下,默认的 Scan 缓存设置就可以正常工作的。但是在一些大 Scan( 一次 Scan 可能需要查询几万甚至几十万行数据 ) 来说,每次请求 100 条 数据意味着一次 Scan 需要几百甚至几千次 RPC 请求,这种交互的代价无疑是很大的。因此可以考虑将 Scan 缓存设置增大,比如设为 500 或者 1000 ,用以减少 RPC 次数。

(81)

7.4 读性能优化策略

• 7.4.1 HBase 客户端优化

• 2. Get 请求是否可以使用批量请求

HBase 分别提供了单条 Get 以及批量 Get 的 API 接口,使用批量 Get 接口可以减少客户端到 RegionServer 之间的 RPC 连接数,提高读取性能。另 外需要注意的是,批量 Get 请求要么成功返回所有请求数据,要么抛出异常。

(82)

7.4 读性能优化策略

• 7.4.1 HBase 客户端优化

• 3. 请求是否可以显式指定列族或者列

HBase 是典型的列数据库,意味着同一列族的数据存储在一起,不同列族的数据分开存储在不同的目录下。如果一个表有多个列族,只是根据 Row Key 而不指定列族进行检索的话不同列族的数据需要独立进行检索,性能必然会比指定列族的查询差很多,很多情况下甚至会有二倍到三倍的性能损失,可 以指定列族或者列进行精确查找的尽量指定查找。

(83)

7.4 读性能优化策略

• 7.4.1 HBase 客户端优化

• 4. 离线批量读取请求是否设置禁止缓存 通常离线批量读取数据会进行一次性全表扫描,一方面数据量很大,另一方面请求只会执行一次。这种场景下如果使用 Scan 默认设置,就会将数据从 H DFS 加载出来之后放到缓存。可想而知,大量数据进入缓存必将其他实时业务热点数据挤出,其他业务不得不从 HDFS 加载,进而会造成明显的读延迟 ,当离线批量读取请求时应设置禁用缓存。

(84)

7.4.2 HBase 服务器端优化

• 服务器端问题一旦导致业务读请求延迟较大的话,通常是集群级别的,即整个集群的业务都会反映读延迟较大。可以从四个方面

入手:

• 1. 读请求是否均衡

• 极端情况下假如所有的读请求都落在一台 RegionServer 的某几个 Region 上,这一方面不能发挥整个集群的并发处理能力,

另一方面势必造成此台 RegionServer 资源严重消耗 ( 比如 I/O 耗尽、 Handler 耗尽等 ) ,落在该台 RegionServer 上的其

他业务会因此受到很大的波及。可见,读请求不均衡不仅会造成本身业务性能很差,还会严重影响其他业务。当然,写请求不均

衡也会造成类似的问题,可见负载不均衡是 HBase 的大忌。 Row Key 必须进行散列化处理 ( 比如 MD5 散列 ) ,同时建表必须进

行预分区处理。

(85)

7.4.2 HBase 服务器端优化

• 2. BlockCache 是否设置合理

• BlockCache 作为读缓存,对于读性能来说至关重要,默认情况下 BlockCache 和 MemStore 的配置相对比较均衡 ( 各占 40%)

,可以根据集群业务进行修正,比如读多写少业务可以将 BlockCache 占比调大。另一方面, BlockCache 的策略选择也很重

要,不同策略对读性能来说影响并不是很大,但是对网络通信的影响却相当显著,尤其 BucketCache 的 offheap 模式下网络

通信表现很优越。 JVM 内存配置量小于 20G 时, BlockCache 策略选择 LRUBlockCache ;否则选择 BucketCache 策略的 o

ffheap 模式。

(86)

7.4.2 HBase 服务器端优化

• 3. HFile 文件是否太多

• HBase 读取数据通常首先会到 MemStore 和 BlockCache 中检索 ( 读取最近写入数据 ) ,如果查找不到就会到文件中检索。 HB

ase 的类 LSM 结构会导致每个 Store 包含多个 HFile 文件,文件越多,检索所需的 I/O 次数必然越多,读取延迟也就越高。文

件数量通常取决于 Compaction 的执行策略,一般和两个配置参数有关: hbase.hstore.compactionThreshold 和 hbase

.hstore.compaction.max.size ,前者表示一个 Store 中的文件数超过多少就应该进行合并,后者表示参数合并的文件大

小最大是多少,超过此大小的文件不能参与合并。这两个参数不能设置太松 ( 前者不能设置太大,后者不能设置太小 ) ,否则会

导致 Compaction 合并文件的实际效果不明显,进而很多文件得不到合并,这样就会导致 HFile 文件数变多。 hbase.hstore

.compactionThreshold 设置不能太大,默认是 3 个;设置需要根据 Region 大小确定,通常可以简单的认为 hbase.hstor

e.compaction.max.size = RegionSize / hbase.hstore.compactionThreshold

(87)

7.4.2 HBase 服务器端优化

• 4. Compaction 是否消耗系统资源过多

• Compaction 是将小文件合并为大文件,提高后续业务随机读性能,但是也会带来 I/O 压力以及带宽消耗问题 ( 数据远程读取以

及三副本写入都会消耗系统带宽 ) 。正常配置情况下 Minor Compaction 并不会带来很大的系统资源消耗,除非因为配置不合

理导致 Minor Compaction 太过频繁,或者 Region 设置太大情况下发生 Major Compaction 。

• (1)Minor Compaction 设置

• hbase.hstore.compactionThreshold 设置不能太小,又不能设置太大,因此建议设置为 5 ~ 6 ;大小为 hbase.hstore.

compaction.max.size = RegionSize / hbase.hstore.compactionThreshold

• (2)Major Compaction 设置

• 大 Region 读延迟敏感业务 (100G 以上 ) 通常不建议开启自动 Major Compaction ,手动低峰期触发,小 Region 或者延迟

不敏感业务可以开启 Major Compaction ,但建议限制流量。

(88)

7.4.3 HDFS 相关优化

• HDFS 作为 HBase 最终数据存储系统,通常会使用三副本策略存储 HBase 数据文件以及日志文件。从 HDFS 的角度往上层看, H

Base 即是它的客户端, HBase 通过调用它的客户端进行数据读写操作,因此 HDFS 的相关优化也会影响 HBase 的读写性能。这

里主要关注如下三个方面:

• 1. Short-Circuit Local Read 功能是否开启

• 当前 HDFS 读取数据都需要经过 DataNode ,客户端会向 DataNode 发送读取数据的请求, DataNode 接收到请求之后从硬盘中

将文件读出来,再通过 RPC 发送给客户端。 Short Circuit 策略允许客户端绕过 DataNode 直接读取本地数据,开启 Short

Circuit Local Read 功能,具体配置如下:

(89)

7.4.3 HDFS 相关优化

• 2. Hedged Read 功能是否开启

• HBase 数据在 HDFS 中一般都会存储三份,而且优先会通过 Short-Circuit Local Read 功能尝试本地读。但是在某些特殊

情况下,有可能会出现因为磁盘问题或者网络问题引起的短时间本地读取失败,为了应对这类问题,提出了补偿重试机制 --Hed

ged Read 。该机制基本工作原理为:客户端发起一个本地读,一旦一段时间之后还没有返回,客户端将会向其他 DataNode 发

送相同数据的请求,哪一个请求先返回,另一个就会被丢弃。开启 Hedged Read 功能,具体配置如下:

(90)

7.4.3 HDFS 相关优化

• 3. 数据本地率是否太低

• HDFS 数据通常存储三份,假如当前 RegionA 处于 Node1 上,数据 a 写入的时候三副本为 Node1 , Node2 , Node3 ;数据 b

写入三副本是 Node1 , Node4 , Node5 ;数据 c 写入三副本是 Node1 , Node3 , Node5 。可以看出来所有数据写入本地 No

de1 肯定会写一份,数据都在本地可以读到,因此数据本地率是 100% 。现在假设 RegionA 被迁移到了 Node2 上,只有数据 a

在该节点上,其他数据 (b 和 c) 读取只能远程跨节点读,本地率就为 33%( 假设 a , b 和 c 的数据大小相同 ) 。

• 数据本地率太低很显然会产生大量的跨网络 I/O 请求,必然会导致读请求延迟较高,因此提高数据本地率可以有效优化随机读性

能。数据本地率低的原因一般是因为 Region 迁移 ( 自动 Balance 开启, RegionServer 宕机迁移,手动迁移等 ) ,因此一方

面可以通过避免 Region 无故迁移来保持数据本地率,关闭自动 Balance ,及时迁移 Region 等;另一方面如果数据本地率很

低,也可以在业务低峰期执行 Major Compaction 提升数据本地率到 100% 。

數據

表 2-2 HBase 的物理模型

參考文獻

相關文件

在軟體的使用方面,使用 Simulink 來進行。Simulink 是一種分析與模擬動態

過去有許多學者使用過幾種方法來評估組織績效,以下舉出常用的八種 方法:(1)比例分析法(Ratio Approach)。(2)平衡計分卡(Balanced Scorecard)

本研究是以景觀指數進行對 1993 年、2008 年與擴大土地使用三個時期之評 估,其評估結果做比較討論。而目前研究提供研究方法的應用-GIS 與 FRAGSTATS 之使用方法。從 1993 年至

在集群分析方法中,Stuart Lloyd 於 1957 年提出了 K-Means 分析法。它是利用劃分方 式的ㄧ種聚類算法。此種方式以隨機選取

衡量一个地区或一个国家水资源的丰歉 程度的指标:

微积分的创立是数学发展中的里程碑, 它的发展 和广泛应用开启了向近代数学过渡的新时期, 为研究 变量和函数提供了重要的方法和手段. 运动物体的瞬

一般说来, 对于一个区间上单调的函数的 图形都存在一个需要判别弧段位于相应的弦线

本章我们又一次经历了用函数研究变化规律的过程 ,用反比例函数刻画具 有反比例关系的两个变量之间的对应关系 :在变量y 随变量x 的变化而变化的