CONTENTS
课程目标
第一章 HBase 介绍
ITEMS
1
ITEMS
2
第二章 HBase 模型和系统架构
第三章 HBase 数据读写流程
ITEMS
3
ITEMS
4
第四章 HBase 环境搭建
第五章 HBase Shell
ITEMS
5
ITEMS
6
第六章 HBase
程序开发
第七章 HBase 高级特性
1 HBase 介绍
• HBase 是一种构建在 HDFS 之上的分布式、面向列的存储系统。在需要实时读写、随机访问超大规模数据集时,可以使用 HBase 。
Apache HBase 是 Google BigTable 的开源实现,就像 BigTable 利用了 GFS 所提供的分布式数据存储一样, HBase 在 Ha
doop 之上提供了类似于 BigTable 的能力
1.1 面向行和面向列存储对比
• 1.1.1 数据库以行、列的二维表的形式存储数据
• 1.1.2 列式数据库把一列中的数据值串在一起存储起来,然后再存储下一列的数据
• 1.1.3 两种存储方式的对比
id name age sex jobs
1 张三 35 男 教师 2 李丹 18 女 学生 3 John 26 男 IT工程师 id 1 2 3 name 张三 李丹 John age 男 女 男 sex 35 18 26 表 1-3 行 / 列存储对比 行存储 列存储 优点 写入效率高,提供数据完整性保证。 读取过程有冗余,适合数据定长的大数 据计算。 缺点 数据读取有冗余现象,影响计算速度。 缺乏数据完整性保证,写入效率低。 改进 优化的存储格式,保证能够在内存快速 多磁盘多线程并行写入 / 读 ( 需要增加
1.2 HDFS 分布式存储特点
• HDFS(Hadoop Distributed File System) 是 Hadoop 项目的核心子项目,是分布式计算中数据存储管理的基础,是基于
流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。
• 1. 优点
• (1) 高容错性 • (2) 适合大数据的处理 • (3) 流式文件写入 • (4) 可构建在廉价机器上• 2. 缺陷
• (1) 不适合低延迟数据访问 • (2) 无法高效存储大量的小文件 • (3) 不支持多用户写入及任意修改文件1.3 HBase 的使用场景
• HBase 不是关系型数据库,也不支持 SQL ,但是它有自己的特长,这是关系型数据库不能处理的。
• 1. 平台类 • 2. 内容服务类 • 3. 信息展示类
2.1 HBase 相关概念
• HBase 的数据模型也是由一张张的表组成,每一张表里也有数据行和列,但是在 HBase 数据库中的行和列又和关系型数据库的
稍有不同。
• 1. Table( 表 )
• 2. Row( 行 )
• 3. Column( 列 )
• 4. Column Family( 列族 )
• 5. Column Qualifier( 列标识符 )
• 6. Cell( 单元格 )
• 7. Timestamp( 时间戳 )
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"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
2.4 HBase 的特点
• 非关系型数据库严格上不是一种数据库,而是一种数据结构化存储方法的集合。 HBase 作为一个典型的非关系型数据库,仅支持
单行事务,通过不断增加集群中节点数据量来增加计算能力,其具有以下特点。
• 1. 容量巨大
• 2. 面向列
• 3. 稀疏性
• 4. 数据多版本
• 5. 可扩展性
• 6. 高可靠性
• 7. 高性能
• 8. 数据类型单一
2.5 HBase 系统架构
• HBase 同样是主从分布式架构,它隶属于 Hadoop 生态系统,由以下组件组成: Client , ZooKeeper , HMaster , HRegi
onServer 和 HRegion ;在底层,它将数据存储于 HDFS 中
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) 处理元数据的更新请求。3.1 HRegionServer 详解
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) 。
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 的,则放到这个队列中。
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 个数 + 压缩代码标识 + 版本标识
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 目录下建立代表自己的文件,并获得该文件的独占锁。
3.2 HRegion
• 在 HBase 中,一个表的表行的多少决定了 HRegion 的大小,表的列族个数又决定了 Store 的多少,一个 Store 对应一个 MemSt
ore 和多个 StoreFile , StoreFile 则对应一个 HFile
• HBase 表创建时候默认就是一个 HRegion ,在行记录不断增加下,达到一定的数值 HRegion 会自动切分,变成多个 HRegion ,
每一个 HRegion 里面由多个 Store 组成 (Store 的个数是由 HBase 表列族个数决定 ) 。
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 所擅长。
3.3 HMaster 上线
HMaster 启动进行以下步骤:
(1) 从 ZooKeeper 上获取唯一一个代表 HMaster 的锁,用来阻止其它 HMaster 成为 Master 。
(2) 扫描 ZooKeeper 上的 Server 目录,获得当前可用的 HRegionServer 列表。
(3) 和 2 中的每个 HRegionServer 通信,获得当前已分配的 HRegion 和 HRegionServer 的对应关系。
(4) 扫描 .META. Region 的集合,计算得到当前还未分配的 HRegion ,将他们放入待分配 HRegion 列表。
3.4 数据读流程
(1)-ROOT- HRegion 永远不会被 Split ,保证了最多需要三次跳转就能定位到任意 HRegion 。
(2).META. 表每行保存一个 HRegion 的位置信息, Row Key
采用表名 + 表的最后一样编码而成。
(3) 为了加快访问, .META. 表的全部 HRegion 都保存在内存中。
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 上。
3.6 删除数据流程
• HBase 删除操作不会立即删除 HFile ,会先将数据打一个删除标签,当开启一个大的合并,才会将打标记的数据删除,这个大合
并消耗比较大的性能,只有在晚上或者资源使用少时才使用。
4.HBase 环境搭建
• HBase 运行环境需要依赖于 Hadoop 集群,如果 Hadoop 尚未搭建,可以参考同套教材《 Hadoop 大数据开发》相关章节。 HBas
e 引入 ZooKeeper 来管理集群的 Master 和入口地址,因此需要先安装 ZooKeeper ,再设置 HBase 。
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 的内容为修改外,其他配置信息均为新增。
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" 使配置的 环境变量生效。
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
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 服务器,故其配 置内容为:
• slave1 • slave2
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>
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>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. 测试
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
4.HBase 环境搭建
4.HBase 环境搭建
• 在 master 节点,使用命令 "hbase-daemon.sh stop master" ,等待一会发现 slave1 成为 master ,当 HBase 的 master 节点故障后, ZooKeepe r 会从备份中自动推选一个作为 master ,如图 4-11 所示:
5 HBase Shell
• 在实际应用中,需要经常通过 Shell 命令操作 HBase 数据库。 HBase Shell 是 HBase 的命令行工具;通过 HBase Shell ,用
户不仅可以方便地创建、删除及修改表,还可以向表中添加数据、列出表中的相关信息等
5.1 HBase Shell 启动
• 在任意一个 HBase 节点运行命令: hbase shell ,即可进入 HBase 的 Shell 命令行模式
• HBase Shell 没法使用退格键删除文字,需要通过 ctrl + backspace 的方式进行删除,或者通过 " 文件 " -> " 属性 " ->
" 终端 " -> " 键盘 " 设置 Xshell ,将 "Backspace 键序列 " 的值设置为 "ASCII 127"
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 条 记 录 , 否 则 将 全 部
5.2 表的管理
• 1. list 命令
• 2. create 命令
创建表。语法格式: create <table>, {NAME => <family>, VERSIONS => <VERSIONS>}
• 3. describe 命令
• 4. disable 命令
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. 删除列族
5.2 表的管理
• 10. whoami
• 11. version
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
5.3 表数据的增删改查
• 5. deleteall 命令
删除行。语法格式: deleteall <table>, <rowKey>, <family:column> , <timestamp>
• 6. count
查询表中总共有多少行数据。语法格式: count <table> 。
• 7. truncate
5.4 数据迁移的 importsv 的使用
• HBase 数据来源于日志文件或者 RDBMS ,把数据迁移到 HBase 表中。常见的有三种方法:使用 HBase Put API ;使用 HBase
批量加载工具;自定义 MapReduce 实现。
• importtsv 是 HBase 官方提供的基于 MapReduce 的批量数据导入工具,同时也是 HBase 提供的一个命令行工具,可以将存储在
HDFS 上的自定义分隔符 ( 默认是 \t) 的数据文件,通过一条命令方便的导入到 HBase 中。
6. HBase 程序开发
• HBase 提供了丰富的 Java API 接口供用户使用,可以通过 HBase Java API 完成和 HBase Shell 相同的功能。本章不仅介绍
如何通过 Java API 完成表的相关操作,还会讲解相关高级用法,如过滤器、计数器、协处理器的使用, NameSpace 的开发和快
照的创建等。
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
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) 通过属性名来设置值。
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) 修改表的模式,是异步的操作,可能需要花费一定的时间。
6.1 表的相关操作
• 4. HTableDescriptor
HTableDescriptor 位于 org.apache.hadoop.hbase.HtableDescriptor ,包含了表的名字及其对应表的列族
返回值 函数 说明
void addFamily(HColumnDescriptor) 添加一个列族。
HColumnDescriptor removeFamily(byte[] column) 移除一个列族。
byte[] getName() 获取表的名字。
byte[] getValue(byte[] key) 获取属性的值。
6.1 表的相关操作
• 5. HColumnDescriptor
HColumnDescriptor 类位于 org.apache.hadoop.hbase.HcolumnDescriptor ,维护着关于列族的信息,例如版本号
,压缩设置等,它通常在创建表或者为表添加列族的时候使用。列族被创建后不能直接修改,只能通过删除然后重新创建的方式;列
族被删除的时候,列族里面的数据也会同时被删除。
返回值 函数 说明 byte[] getName() 获取列族的名字。byte[] getValue(byte[] key) 获取对应的属性的值。
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() 获取表名。
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 是否为空。
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) 获取指定时间的列的版本号。
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) 获取对应列的最新值。
6.1 表的相关操作
• 10. ResultScanner
ResultScanner 是一个客户端获取值的接口。
返回值 函数 说明
void close() 关闭 Scanner 并释放分配给它的资源。
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");
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)
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. 缓存块操作
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
6.6 数据删除
• 1. 删除指定列
删除指定列是在构造 Delete 对象的时候,传入行健,列族和列,代码参考: 6-5 下的 DeleteDemo.java
• 2. 删除指定行
删除指定的行是在构造 Delete 对象的时候只传入行健
• 3. 删除表
删除表的时候要先停用再删除,代码参考: DeleteDemo3.java
6.7 Scan 查询
• 扫描类似于关系型数据库的游标 (Cursor) ,并利用到了 HBase 底层顺序存储的特性。使用扫描的一般步骤是:
• (1) 创建 Scan 实例。
• (2) 为 Scan 实例增加扫描的限制条件。
• (3) 调用 HTable 的 getScanner() 方法获取 ResultScanner 对象,如果通过 HTablePool 的方式,则是调用 HTablePool
的 getScanner 方法。 ( 注意, HTable 类实现了 HTableInterface 接口,这个接口用于与单个 HBase 表通信。 )
6.8 Filter
• HBase 为筛选数据提供了一组过滤器,通过这个过滤器可以在 HBase 中的数据的多个维度 ( 行,列,数据版本 ) 上对数据进行筛
选操作,也就是说过滤器最终筛选的数据能够细化到具体的一个存储单元格上 ( 由行键,列名,时间戳定位 ) 。通常来说,通过行
键值来筛选数据的应用场景较多。
• 1. RowFilter
• 2. PrefixFilter
• 3. KeyOnlyFilter
• 4. RandomRowFilter
• 5. InclusiveStopFilter
• 6. FirstKeyOnlyFilter
• 7. ColumnPrefixFilter
• 8. ValueFilter
• 9. ColumnCountGetFilter
6.9 行数统计
• 1. HBase Shell 统计行数
• 2. HBase 自带 MapReduce 表行数统计 RowCounter
• 3. Java API 统计行数
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
6.11 计数器
• 1. 创建计数器
• 在 HBase 中, HBase 将某一列作为计数器来使用,因此创建计数器与创建行是相同的。• 2. 计数器的增加
• 计数器增加值是增加一个 long 值,其增加的值也有正有负,不同的数据进行增加时有不同的效果: • (1) 大于 0 :增加计数器的值。 • (2) 等于 0 :不更改计数器的值。 • (3) 小于 0 :减少计数器的值。• 3. HBase shell 操作计数器
• 4. Java API 操作计数器
• 5. 多列增加
6.12 协处理器
• 1. 协处理器类型
• 2. HBase shell 操作协处理器
• 3. Java API 操作协处理器
6.13 HBase 快照
• 1. 快照的使用场景
• 2. HBase shell 快照操作
• 3. Java API 操作快照
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 的数据并在一起。
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 。
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 家庭住址
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 订单日期
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 商品价格
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. 数据平均键值对规模
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,
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 异步写入,也是可以考虑 优化的,通常也会带来一倍多的性能提升。
7.3 写性能优化策略
• 写数据流程
HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。
HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同
• 2. Put 是否可以同步批量提交
HBase 分别提供了单条 Put 以及批量 Put 的 API 接口,使用批量 Put 接口可以减少客户端到 RegionServer 之间的 RPC 连接数,提高写入性能。另 外需要注意的是,批量 Put 请求要么全部成功返回,要么抛出异常。
7.3 写性能优化策略
• 写数据流程
HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。 HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同 • 3. Put 是否可以异步批量提交 业务如果可以接受异常情况下少量数据丢失的话,还可以使用异步批量提交的方式提交请求。提交分为两阶段执行:用户提交写请求之后,数据会写入 客户端缓存,并返回用户写入成功;当客户端缓存达到阈值 ( 默认 2M) 之后批量提交给 RegionServer 。需要注意的是,在某些情况下客户端异常的 情况下缓存数据有可能丢失。
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 个数效果并不 明显。
7.3 写性能优化策略
• 写数据流程
HBase 写数据流程:数据先顺序写入 WAL ,再写入对应的缓存 MemStore ,当 MemStore 中数据大小达到一定阈值 (128M) 之后,系统会异步将 MemS tore 中数据 Flush 到 HDFS 形成小文件。 HBase 数据写入通常会遇到两类问题,一类是写性能较差,另一类是数据根本写不进去,这两类问题的切入点也不尽相同 • 5. 写入请求是否不均衡 另一个需要考虑的问题是写入请求是否均衡,如果不均衡,一方面会导致系统并发度较低,另一方面也有可能造成部分节点负载很高,进而影响其他业 务。分布式系统中要特别避免一个节点负载很高的情况出现,一个节点负载很高可能会拖慢整个集群,这是因为很多业务会使用多批量提交读写请求, 一旦其中一部分请求落到该节点无法得到及时响应,就会导致整个批量请求超时。
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 频繁触发,写入性能急剧下降。
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 次数。
7.4 读性能优化策略
• 7.4.1 HBase 客户端优化
• 2. Get 请求是否可以使用批量请求
HBase 分别提供了单条 Get 以及批量 Get 的 API 接口,使用批量 Get 接口可以减少客户端到 RegionServer 之间的 RPC 连接数,提高读取性能。另 外需要注意的是,批量 Get 请求要么成功返回所有请求数据,要么抛出异常。
7.4 读性能优化策略
• 7.4.1 HBase 客户端优化
• 3. 请求是否可以显式指定列族或者列
HBase 是典型的列数据库,意味着同一列族的数据存储在一起,不同列族的数据分开存储在不同的目录下。如果一个表有多个列族,只是根据 Row Key 而不指定列族进行检索的话不同列族的数据需要独立进行检索,性能必然会比指定列族的查询差很多,很多情况下甚至会有二倍到三倍的性能损失,可 以指定列族或者列进行精确查找的尽量指定查找。