一、简介
HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库。
1.1 数据模型
逻辑上,HBase的数据模型同关系型数据库很类似,数据存储在一张表中,有行有列。但从HBase的底层物理存储结构(K-V)来看,HBase更像是一个multi-dimensional map。
- 逻辑结构
- 物理存储结构
- 数据模型
- Name Space:命名空间,类似于关系型数据库的DatabBase概念,每个命名空间下有多个表。HBase有两个自带的命名空间,分别是hbase和default,hbase中存放的是HBase内置的表,default表是用户默认使用的命名空间。
- Region:类似于关系型数据库的表概念。不同的是,HBase定义表时只需要声明列族即可,不需要声明具体的列。这意味着,往HBase写入数据时,字段可以动态、按需指定。因此,和关系型数据库相比,HBase能够轻松应对字段变更的场景。
- Row:HBase表中的每行数据都由一个RowKey和多个Column(列)组成,数据是按照RowKey的字典顺序存储的,并且查询数据时只能根据RowKey进行检索,所以RowKey的设计十分重要。
- Column:HBase中的每个列都由Column Family(列族)和Column Qualifier(列限定符)进行限定,例如info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义。
- Time Stamp:用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入HBase的时间。
- Cell:由{rowkey, column Family:column Qualifier, time Stamp} 唯一确定的单元。cell中的数据是没有类型的,全部是字节数组形式存贮。
1.2 基本架构
- Region Server:Region的管理者,其实现类为HRegionServer,主要作用如下:对于数据的操作:get, put, delete;对于Region的操作:splitRegion、compactRegion。
- Master:所有Region Server的管理者,其实现类为HMaster,主要作用如下:对于表的操作:create, delete, alter;对于RegionServer的操作:分配regions到每个RegionServer,监控每个RegionServer的状态,负载均衡和故障转移。
- Zookeeper:HBase通过Zookeeper来做Master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作。
- HDFS:HDFS为HBase提供最终的底层数据存储服务,同时为HBase提供高可用的支持。
二、入门
2.1 集群搭建
- 准备软件环境
[omm@bigdata01 soft]$ tar -zxf hbase-2.0.5-bin.tar.gz -C /opt/module/
[omm@bigdata01 soft]$ ln -s /opt/module/hbase-2.0.5 /opt/module/hbase
[omm@bigdata01 soft]$ sudo vi /etc/profile
[omm@bigdata01 soft]$ tail -3 /etc/profile
# HBase
export HBASE_HOME=/opt/module/hbase
export PATH=$PATH:$HBASE_HOME/bin
[omm@bigdata01 soft]$ source /etc/profile
- 配置文件:
hbase-env.sh
[omm@bigdata01 conf]$ pwd
/opt/module/hbase/conf
[omm@bigdata01 conf]$ vi hbase-env.sh
[omm@bigdata01 conf]$ grep HBASE_MANAGES_ZK hbase-env.sh
export HBASE_MANAGES_ZK=false # 告诉HBase不要用自己内置的ZK
[omm@bigdata01 conf]$ grep JAVA_HOME hbase-env.sh
export JAVA_HOME=/opt/module/jdk
- 配置文件:
hbase-site.xml
[omm@bigdata01 conf]$ vi hbase-site.xml
[omm@bigdata01 conf]$ cat hbase-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
/**
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://bigdata01:8020/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>bigdata01,bigdata02,bigdata03</value>
</property>
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
<property>
<name>hbase.wal.provider</name>
<value>filesystem</value>
</property>
</configuration>
[omm@bigdata01 conf]$
- 配置文件:
regionservers
[omm@bigdata01 conf]$ vi regionservers
[omm@bigdata01 conf]$ cat regionservers
bigdata01
bigdata02
bigdata03
[omm@bigdata01 conf]$
- 启动集群
[omm@bigdata01 ~]$ start-hbase.sh
bigdata02: running regionserver, logging to /opt/module/hbase/bin/../logs/hbase-omm-regionserver-bigdata02.out
bigdata03: running regionserver, logging to /opt/module/hbase/bin/../logs/hbase-omm-regionserver-bigdata03.out
bigdata01: running regionserver, logging to /opt/module/hbase/bin/../logs/hbase-omm-regionserver-bigdata01.out
[omm@bigdata01 ~]$ jps
6065 HMaster
6241 HRegionServer
2210 NameNode
6549 Jps
1862 QuorumPeerMain
2381 DataNode
[omm@bigdata01 ~]$
2.2 HBase Shell
- 登录
[omm@bigdata01 ~]$ hbase shell
hbase(main):001:0> help
HBase Shell, version 2.0.5, r76458dd074df17520ad451ded198cd832138e929, Mon Mar 18 00:41:49 UTC 2019
Type 'help "COMMAND"', (e.g. 'help "get"' -- the quotes are necessary) for help on a specific command.
Commands are grouped. Type 'help "COMMAND_GROUP"', (e.g. 'help "general"') for help on a command group.
COMMAND GROUPS:
Group name: general
Commands: processlist, status, table_help, version, whoami
Group name: ddl
Commands: alter, alter_async, alter_status, create, describe, disable, disable_all, drop, drop_all, enable, enable_all, exists, get_table, is_disabled, is_enabled, list, list_regions, locate_region, show_filters
Group name: namespace
Commands: alter_namespace, create_namespace, describe_namespace, drop_namespace, list_namespace, list_namespace_tables
Group name: dml
Commands: append, count, delete, deleteall, get, get_counter, get_splits, incr, put, scan, truncate, truncate_preserve
Group name: tools
Commands: assign, balance_switch, balancer, balancer_enabled, catalogjanitor_enabled, catalogjanitor_run, catalogjanitor_switch, cleaner_chore_enabled, cleaner_chore_run, cleaner_chore_switch, clear_block_cache, clear_compaction_queues, clear_deadservers, close_region, compact, compact_rs, compaction_state, flush, is_in_maintenance_mode, list_deadservers, major_compact, merge_region, move, normalize, normalizer_enabled, normalizer_switch, split, splitormerge_enabled, splitormerge_switch, trace, unassign, wal_roll, zk_dump
Group name: replication
Commands: add_peer, append_peer_exclude_namespaces, append_peer_exclude_tableCFs, append_peer_namespaces, append_peer_tableCFs, disable_peer, disable_table_replication, enable_peer, enable_table_replication, get_peer_config, list_peer_configs, list_peers, list_replicated_tables, remove_peer, remove_peer_exclude_namespaces, remove_peer_exclude_tableCFs, remove_peer_namespaces, remove_peer_tableCFs, set_peer_bandwidth, set_peer_exclude_namespaces, set_peer_exclude_tableCFs, set_peer_namespaces, set_peer_replicate_all, set_peer_tableCFs, show_peer_tableCFs, update_peer_config
Group name: snapshots
Commands: clone_snapshot, delete_all_snapshot, delete_snapshot, delete_table_snapshots, list_snapshots, list_table_snapshots, restore_snapshot, snapshot
Group name: configuration
Commands: update_all_config, update_config
Group name: quotas
Commands: list_quota_snapshots, list_quota_table_sizes, list_quotas, list_snapshot_sizes, set_quota
Group name: security
Commands: grant, list_security_capabilities, revoke, user_permission
Group name: procedures
Commands: list_locks, list_procedures
Group name: visibility labels
Commands: add_labels, clear_auths, get_auths, list_labels, set_auths, set_visibility
Group name: rsgroup
Commands: add_rsgroup, balance_rsgroup, get_rsgroup, get_server_rsgroup, get_table_rsgroup, list_rsgroups, move_namespaces_rsgroup, move_servers_namespaces_rsgroup, move_servers_rsgroup, move_servers_tables_rsgroup, move_tables_rsgroup, remove_rsgroup, remove_servers_rsgroup
SHELL USAGE:
Quote all names in HBase Shell such as table and column names. Commas delimit
command parameters. Type <RETURN> after entering a command to run it.
Dictionaries of configuration used in the creation and alteration of tables are
Ruby Hashes. They look like this:
{'key1' => 'value1', 'key2' => 'value2', ...}
and are opened and closed with curley-braces. Key/values are delimited by the
'=>' character combination. Usually keys are predefined constants such as
NAME, VERSIONS, COMPRESSION, etc. Constants do not need to be quoted. Type
'Object.constants' to see a (messy) list of all constants in the environment.
If you are using binary keys or values and need to enter them in the shell, use
double-quote'd hexadecimal representation. For example:
hbase> get 't1', "key\x03\x3f\xcd"
hbase> get 't1', "key\003\023\011"
hbase> put 't1', "test\xef\xff", 'f1:', "\x01\x33\x40"
The HBase shell is the (J)Ruby IRB with the above HBase-specific commands added.
For more on the HBase Shell, see http://hbase.apache.org/book.html
hbase(main):002:0>
- 建表
hbase(main):002:0> list
TABLE
0 row(s)
Took 0.3675 seconds
=> []
hbase(main):003:0> create 'student','info'
Created table student
Took 1.6148 seconds
=> Hbase::Table - student
hbase(main):004:0> list
TABLE
student
1 row(s)
Took 0.0083 seconds
=> ["student"]
hbase(main):005:0> describe 'student'
Table student is ENABLED
student
COLUMN FAMILIES DESCRIPTION
{NAME => 'info', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR =
> 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCOD
ING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTE
R => 'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE =
> 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION => 'NONE', BLOCKCACHE => 'true'
, BLOCKSIZE => '65536'}
1 row(s)
Took 0.1136 seconds
hbase(main):006:0>
- 插入数据
hbase(main):006:0> put 'student','1001','info:name','zhangsan'
Took 0.0817 seconds
hbase(main):007:0> put 'student','1001','info:age','18'
Took 0.0089 seconds
hbase(main):008:0> put 'student','1002','info:name','lisi'
Took 0.0204 seconds
hbase(main):009:0> put 'student','1002','info:age','19'
Took 0.0198 seconds
- 查找数据
hbase(main):010:0> scan 'student'
ROW COLUMN+CELL
1001 column=info:age, timestamp=1615441661636, value=18
1001 column=info:name, timestamp=1615441655425, value=zhangsan
1002 column=info:age, timestamp=1615441683717, value=19
1002 column=info:name, timestamp=1615441676917, value=lisi
2 row(s)
Took 0.0292 seconds
hbase(main):012:0> scan 'student',{STARTROW => '1001', STOPROW => '1002'}
ROW COLUMN+CELL
1001 column=info:age, timestamp=1615441661636, value=18
1001 column=info:name, timestamp=1615441655425, value=zhangsan
1 row(s)
Took 0.0081 seconds
hbase(main):013:0>
hbase(main):013:0> get 'student','1001'
COLUMN CELL
info:age timestamp=1615441661636, value=18
info:name timestamp=1615441655425, value=zhangsan
1 row(s)
Took 0.7695 seconds
hbase(main):014:0>
- 更新数据
hbase(main):014:0> put 'student','1002','info:name','Lucy'
Took 0.0418 seconds
hbase(main):016:0> get 'student','1002'
COLUMN CELL
info:age timestamp=1615441683717, value=19
info:name timestamp=1615441838505, value=Lucy
1 row(s)
Took 0.0233 seconds
hbase(main):017:0>
- 统计数据
hbase(main):027:0> count 'student'
2 row(s)
Took 0.0539 seconds
=> 2
hbase(main):028:0>
- 删除数据
hbase(main):028:0> deleteall 'student','1001'
Took 0.0141 seconds
hbase(main):029:0> delete 'student','1002','info:age'
Took 0.0063 seconds
hbase(main):030:0> scan 'student'
ROW COLUMN+CELL
1002 column=info:name, timestamp=1615442248086, value=lisi
1 row(s)
Took 0.0052 seconds
hbase(main):031:0>
- 清空数据
hbase(main):017:0> truncate 'student'
Truncating 'student' table (it may take a while):
Disabling table...
Truncating table...
Took 2.5893 seconds
hbase(main):018:0> scan 'student'
ROW COLUMN+CELL
0 row(s)
Took 0.1274 seconds
hbase(main):019:0>
- 删除表
hbase(main):019:0> disable 'student'
Took 0.7698 seconds
hbase(main):020:0> drop 'student'
Took 0.2514 seconds
hbase(main):021:0> list
TABLE
0 row(s)
Took 0.0034 seconds
=> []
hbase(main):022:0>
2.3 高可用
[omm@bigdata01 conf]$ vi backup-masters
[omm@bigdata01 conf]$ cat backup-masters
bigdata02
[omm@bigdata01 conf]$ xsync backup-masters
[omm@bigdata01 conf]$ start-hbase.sh
bigdata02: running regionserver, logging to /opt/module/hbase/bin/../logs/hbase-omm-regionserver-bigdata02.out
bigdata03: running regionserver, logging to /opt/module/hbase/bin/../logs/hbase-omm-regionserver-bigdata03.out
bigdata01: running regionserver, logging to /opt/module/hbase/bin/../logs/hbase-omm-regionserver-bigdata01.out
bigdata02: running master, logging to /opt/module/hbase/bin/../logs/hbase-omm-master-bigdata02.out
[omm@bigdata01 conf]$
[omm@bigdata02 conf]$ jps
1793 QuorumPeerMain
3841 HRegionServer
2469 DataNode
3912 HMaster
4170 Jps
[omm@bigdata03 module]$ jps
1780 QuorumPeerMain
3333 HRegionServer
2055 DataNode
3495 Jps
2157 SecondaryNameNode
[omm@bigdata03 module]$
2.4 命名空间
- 命名空间操纵
命令 | 说明 |
---|---|
list_namespace | 列出命名空间 |
create_namespace | 新建命名空间 |
drop_namespace | 删除命名空间 |
- 命名空间使用
命令 | 说明 |
---|---|
create 'namespace:table', 'columnfamily01', 'columnfamily02' | 创建表 |
disble 'namespace:table'; drop 'namespace:table' | 删除表 |
scan 'namespace:table' | 查看所有数据 |
scan 'namespace:table', { LIMIT=>5 } | 查看前五行数据 |
put 'namespace:table', 'rowkey', 'columnfamily:cell', 'value' | 插入数据 |
2.5 权限
- Permission
权限 | 说明 |
---|---|
Read(R) | 允许对某个scope有读取权限 |
Write(W) | 允许对某个scope有写入权限 |
Execute(X) | 允许对某个scope有执行权限 |
Create(C) | 允许对某个scope有建表、删表权限 |
Admin(A) | 允许对某个scope做管理操作,如balance、split、snapshot等 |
- Scope
范围 | 说明 |
---|---|
superuser | 超级用户,一般为hbase用户,有所有的权限 |
global | 全局权限,针对所有的HBase表都有权限 |
namespace | namespace下面的所有表权限都有权限 |
table | 表级别权限 |
columnFamily | 列族级别权限 |
cell | 单元格级别权限 |
- 权限控制
命令 | 说明 |
---|---|
grant | 授权 |
revoke | 回收权限 |
user_permission | 查询权限。 |
hbase> grant <user> <permissions> [ @<namespace> [ <table>[ <column family>[ <column qualifier> ] ] ] ] # grants permissions
hbase> revoke <user> <permissions> [ @<namespace> [ <table> [ <column family> [ <column qualifier> ] ] ] # revokes permissions
hbase> user_permission <table>
- 下面是几个基本的例子,
--1 给trafodion用户授权全局的CA
grant 'trafodion','CA'
--2 回收trafodion用户全局的CA
revoke 'trafodion','CA'
--3 给trafodion用户namespace权限
grant 'trafodion','RWXCA','@TRAF_1500000'
--4 给trafodion用户table权限
grant 'trafodion','RWXCA','TABLE_A'
--5 查看所有用户权限
user_permission
--6 查看某个表的权限
user_permission 'TABLE_A'
--7 查看某个namespace的权限
user_permission '@TRAF_1500000'
三、进阶
3.1 架构原理
- StoreFile:保存实际数据的物理文件,StoreFile以HFile的形式存储在HDFS上。每个Store会有一个或多个StoreFile(HFile),数据在每个StoreFile中都是有序的。
- MemStore:写缓存,由于HFile中的数据要求是有序的,所以数据是先存储在MemStore中,排好序后,等到达刷写时机才会刷写到HFile,每次刷写都会形成一个新的HFile。
- WAL:由于数据要经MemStore排序后才能刷写到HFile,但把数据保存在内存中会有很高的概率导致数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入MemStore中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。
3.2 写流程
- Client先访问zookeeper,获取hbase:meta表位于哪个Region Server。
- 访问对应的Region Server,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问。
- 与目标Region Server进行通讯;
- 将数据顺序写入(追加)到WAL;
- 将数据写入对应的MemStore,数据会在MemStore进行排序;
- 向客户端发送ack;
- 等达到MemStore的刷写时机后,将数据刷写到HFile。
3.3 MemStore Flush
- 当某个 memstroe 的大小达到了
hbase.hregion.memstore.flush.size
(默认值128M),其所在 region 的所有 memstore 都会刷写; - 当 memstore 的大小达到了
hbase.hregion.memstore.flush.size
*hbase.hregion.memstore.block.multiplier
(默认值4)时,会阻止继续往该memstore写数据。 - 当 region server 中 memstore 的总大小达到
java_heapsize
*hbase.regionserver.global.memstore.size
(默认值0.4)*hbase.regionserver.global.memstore.size.upper.limit
(默认值0.95),region会按照其所有memstore的大小顺序(由大到小)依次进行刷写,直到region server中所有memstore的总大小减小到hbase.regionserver.global.memstore.size.lower.limit
以下。 - 当region server中memstore的总大小达到
java_heapsize*hbase.regionserver.global.memstore.size
(默认值0.4)时,会阻止继续往所有的memstore写数据。 - 到达自动刷写的时间,也会触发 memstore flush,自动刷新的时间间隔由该属性进行配置
hbase.regionserver.optionalcacheflushinterval
(默认1小时)。 - 当WAL文件的数量超过
hbase.regionserver.max.logs
,region会按照时间顺序依次进行刷写,直到WAL文件数量减小到hbase.regionserver.max.log
以下(该属性名已经废弃,现无需手动设置,最大值为32)。
3.4 读流程
- Client先访问zookeeper,获取hbase:meta表位于哪个Region Server。
- 访问对应的Region Server,获取hbase:meta表,根据读请求的
namespace:table/rowkey
,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问。 - 与目标Region Server进行通讯;
- 分别在Block Cache(读缓存),MemStore和Store File(HFile)中查询目标数据,并将查到的所有数据进行合并。此处所有数据是指同一条数据的不同版本(time stamp)或者不同的类型(Put/Delete)。
- 将从文件中查询到的数据块(Block,HFile数据存储单元,默认大小为64KB)缓存到Block Cache。
- 将合并后的最终结果返回给客户端。
3.5 StoreFile Compaction
- 由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。
- 为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile Compaction。
- Compaction分为两种,分别是Minor Compaction和Major Compaction。
- Minor Compaction会将临近的若干个较小的HFile合并成一个较大的HFile,但不会清理过期和删除的数据。
- Major Compaction会将一个Store下的所有的HFile合并成一个大HFile,并且会清理掉过期和删除的数据。
3.6 Region Split
- 默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。
- 刚拆分时,两个子Region都位于当前的Region Server,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的Region Server。
- HBase 2.0 引入了新的 split 策略:如果当前 RegionServer 上该表只有一个 Region,按照
2*hbase.hregion.memstore.flush.size
分裂,否则按照hbase.hregion.max.filesize
分裂。
四、Phoenix
Phoenix是HBase的开源SQL皮肤。可以使用标准JDBC API代替HBase客户端API来创建表,插入数据和查询HBase数据。
- 特点
- 容易集成:如Spark,Hive,Pig,Flume和Map Reduce;
- 操作简单:DML命令以及通过DDL命令创建和操作表和版本化增量更改;
- 支持HBase二级索引创建。
- 架构
4.1 安装
- 准备软件包
[omm@bigdata01 soft]$ tar -zxf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz -C /opt/module/
[omm@bigdata01 soft]$ ln -s /opt/module/apache-phoenix-5.0.0-HBase-2.0-bin /opt/module/phoenix
- 拷贝依赖
[omm@bigdata01 soft]$ cd /opt/module/phoenix/
[omm@bigdata01 phoenix]$ cpphoenix-core-5.0.0-HBase-2.0.jar /opt/module/hbase/lib/
[omm@bigdata01 phoenix]$ cp phoenix-5.0.0-HBase-2.0-server.jar /opt/module/hbase/lib/
[omm@bigdata01 phoenix]$ stop-hbase.sh
[omm@bigdata01 phoenix]$ cd /opt/module/hbase
[omm@bigdata01 hbase]$ xsync lib
[omm@bigdata01 hbase]$ start-hbase.sh
- 修改环境变量
[omm@bigdata01 ~]$ sudo vi /etc/profile
[omm@bigdata01 ~]$ tail -3 /etc/profile
# Phoenix
export PHOENIX_HOME=/opt/module/phoenix
export PATH=$PATH:$PHOENIX_HOME/bin
[omm@bigdata01 ~]$ source /etc/profile
[omm@bigdata01 ~]$ sql
sqlite3 sqlline.py sqlline-thin.py
4.2 Phoenix Shell
4.2.1 基本操作
- 连接
[omm@bigdata01 ~]$ sqlline.py bigdata01,bigdata02,bigdata03:2181
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> !table
+------------+--------------+-------------+---------------+----------+------------+----------------------------+--------------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_NAME | SELF_REFERENCING_COL_NAME | REF_GENERATI |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+--------------+
| | SYSTEM | CATALOG | SYSTEM TABLE | | | | |
| | SYSTEM | FUNCTION | SYSTEM TABLE | | | | |
| | SYSTEM | LOG | SYSTEM TABLE | | | | |
| | SYSTEM | SEQUENCE | SYSTEM TABLE | | | | |
| | SYSTEM | STATS | SYSTEM TABLE | | | | |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+--------------+
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
- 建表
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> create table student(id integer primary key,name varchar);
No rows affected (1.29 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> !table
+------------+--------------+-------------+---------------+----------+------------+----------------------------+--------------+
| TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_NAME | SELF_REFERENCING_COL_NAME | REF_GENERATI |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+--------------+
| | SYSTEM | CATALOG | SYSTEM TABLE | | | | |
| | SYSTEM | FUNCTION | SYSTEM TABLE | | | | |
| | SYSTEM | LOG | SYSTEM TABLE | | | | |
| | SYSTEM | SEQUENCE | SYSTEM TABLE | | | | |
| | SYSTEM | STATS | SYSTEM TABLE | | | | |
| | | STUDENT | TABLE | | | | |
+------------+--------------+-------------+---------------+----------+------------+----------------------------+--------------+
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
Phoenix 中建的表可以在 HBase Shell 中直接看到,如
STUDENT
;而 HBase Shell 中建的表却不可以在 Phoenix 中直接看到,如student
。
hbase(main):003:0> list
TABLE
STUDENT
SYSTEM.CATALOG
SYSTEM.FUNCTION
SYSTEM.LOG
SYSTEM.MUTEX
SYSTEM.SEQUENCE
SYSTEM.STATS
student
8 row(s)
Took 0.0044 seconds
=> ["STUDENT", "SYSTEM.CATALOG", "SYSTEM.FUNCTION", "SYSTEM.LOG", "SYSTEM.MUTEX", "SYSTEM.SEQUENCE", "SYSTEM.STATS", "student"]
hbase(main):004:0>
- 数据插入
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> upsert into student values(1001,'zhangsan');
1 row affected (0.052 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> upsert into student values(1002,'lisi');
1 row affected (0.009 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> upsert into student values(1003,'wangwu');
1 row affected (0.012 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> upsert into student values(1004,'zhangliu');
1 row affected (0.006 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
- 数据查询
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> select * from student;
+-------+-----------+
| ID | NAME |
+-------+-----------+
| 1001 | zhangsan |
| 1002 | lisi |
| 1003 | wangwu |
| 1004 | zhangliu |
+-------+-----------+
4 rows selected (0.033 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> select * from student where id=1001;
+-------+-----------+
| ID | NAME |
+-------+-----------+
| 1001 | zhangsan |
+-------+-----------+
1 row selected (0.016 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> select * from student s join student t on s.id=t.id;
+-------+-----------+-------+-----------+
| ID | NAME | ID | NAME |
+-------+-----------+-------+-----------+
| 1001 | zhangsan | 1001 | zhangsan |
| 1002 | lisi | 1002 | lisi |
| 1003 | wangwu | 1003 | wangwu |
| 1004 | zhangliu | 1004 | zhangliu |
+-------+-----------+-------+-----------+
4 rows selected (0.208 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
4.2.3 二级索引(联合索引)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> CREATE TABLE IF NOT EXISTS us_population (
. . . . . . . . . . . . . . . . . . . . . . .> State CHAR(2) NOT NULL,
. . . . . . . . . . . . . . . . . . . . . . .> City VARCHAR NOT NULL,
. . . . . . . . . . . . . . . . . . . . . . .> Population BIGINT
. . . . . . . . . . . . . . . . . . . . . . .> CONSTRAINT my_pk PRIMARY KEY (state, city));
No rows affected (1.424 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> upsert into us_population values ('US','New York', 1000000);
1 row affected (0.074 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> select * from us_population
. . . . . . . . . . . . . . . . . . . . . . .> ;
+--------+-----------+-------------+
| STATE | CITY | POPULATION |
+--------+-----------+-------------+
| US | New York | 1000000 |
+--------+-----------+-------------+
1 row selected (0.023 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
联合主键中的列全部出现 RowKey 中。
hbase(main):009:0> scan 'US_POPULATION'
ROW COLUMN+CELL
USNew York column=0:\x00\x00\x00\x00, timestamp=1615608717231, value=x
USNew York column=0:\x80\x0B, timestamp=1615608717231, value=\x80\x00\x00\x00\x00\x0FB@
1 row(s)
Took 0.6870 seconds
hbase(main):010:0>
4.2.4 视图映射
默认情况下,直接在HBase中创建的表,通过Phoenix是查看不到的。如果要在Phoenix中操作直接在HBase中创建的表,则需要在Phoenix中进行表的映射。映射方式有两种:视图映射和表映射。
hbase(main):015:0> create 'test','info1','info2'
Created table test
Took 0.7447 seconds
=> Hbase::Table - test
hbase(main):016:0> put 'test','1001','info1:name','zhangsan'
Took 0.0316 seconds
hbase(main):017:0> put 'test','1001','info2:age','18'
Took 0.0066 seconds
hbase(main):018:0> scan 'test'
ROW COLUMN+CELL
1001 column=info1:name, timestamp=1615609209743, value=zhangsan
1001 column=info2:age, timestamp=1615609220362, value=18
1 row(s)
Took 0.0047 seconds
hbase(main):019:0>
HBase 中建立的表须通过视图与 Phoenix 建立连接,且该视图是只读的。
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> select * from "test";
Error: ERROR 1012 (42M03): Table undefined. tableName=test (state=42M03,code=1012)
org.apache.phoenix.schema.TableNotFoundException: ERROR 1012 (42M03): Table undefined. tableName=test
...
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> create view "test"(id varchar primary key,"info1"."name" varchar, "info2"."age" varchar);
No rows affected (0.03 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> select * from "test";
+-------+-----------+------+
| ID | name | age |
+-------+-----------+------+
| 1001 | zhangsan | 18 |
+-------+-----------+------+
1 row selected (0.029 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> upsert into "test" values('1002','lisi','19');
Error: ERROR 505 (42000): Table is read only. (state=42000,code=505)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> drop view "test";
No rows affected (0.01 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
4.2.5 表的映射
- 创建方法
- HBase中不存在表时,可以直接使用create table指令创建需要的表,系统将会自动在Phoenix和HBase中创建person_infomation的表,并会根据指令内的参数对表结构进行初始化。
- 当HBase中已经存在表时,可以以类似创建视图的方式创建关联表,只需要将create view改为create table即可。
映射表 不是只读的。
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> drop view "test";
No rows affected (0.01 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> create table "test"(id varchar primary key,"info1"."name" varchar, "info2"."age" varchar) column_encoded_bytes=0;
1 row affected (6.528 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> upsert into "test" values('1002','lisi','19');
1 row affected (0.01 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> select * from "test";
+-------+-----------+------+
| ID | name | age |
+-------+-----------+------+
| 1001 | zhangsan | 18 |
| 1002 | lisi | 19 |
+-------+-----------+------+
2 rows selected (0.032 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
Phoenix 删除表,直接反映在 HBase 中。
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03> drop table "test";
No rows affected (0.988 seconds)
0: jdbc:phoenix:bigdata01,bigdata02,bigdata03>
hbase(main):019:0> list
TABLE
SYSTEM.CATALOG
SYSTEM.FUNCTION
SYSTEM.LOG
SYSTEM.MUTEX
SYSTEM.SEQUENCE
SYSTEM.STATS
6 row(s)
Took 0.0064 seconds
=> ["SYSTEM.CATALOG", "SYSTEM.FUNCTION", "SYSTEM.LOG", "SYSTEM.MUTEX", "SYSTEM.SEQUENCE", "SYSTEM.STATS"]
hbase(main):020:0>
4.3 Phoenix DBeaver
DBeaver 默认连接的是 Phoenix 胖客户端,现需更改为瘦客户端,需要先启动瘦客户端服务。
[omm@bigdata01 ~]$ queryserver.py start
starting Query Server, logging to /tmp/phoenix/phoenix-omm-queryserver.log
[omm@bigdata01 ~]$ jps | grep QueryServer
11278 QueryServer
[omm@bigdata01 ~]$
不知道为啥,只有把同时
添加工件:phoenix client
和 该 jar 包添加进去,才连接成功。
4.4 Phoenix JDBC
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-queryserver-client</artifactId>
<version>5.0.0-HBase-2.0</version>
</dependency>
package com.simwor.bigdata.hbase;
import org.apache.phoenix.queryserver.client.ThinClientUtil;
import java.sql.*;
public class MyPhoenixClient {
public static void main(String[] args) throws SQLException {
String url = ThinClientUtil.getConnectionUrl("bigdata01", 8765);
System.out.println(url);
Connection connection = DriverManager.getConnection(url);
PreparedStatement preparedStatement = connection.prepareStatement("select * from student");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next())
System.out.println(resultSet.getInt(1) + "\t" + resultSet.getString(2));
resultSet.close();
preparedStatement.close();
connection.close();
}
}
jdbc:phoenix:thin:url=http://bigdata01:8765;serialization=PROTOBUF
log4j:WARN No appenders could be found for logger
...
1001 zhangsan
1002 lisi
Process finished with exit code 0
4.5 Phoenix 全局索引
- 定义
- Global Index是默认的索引格式,创建全局索引时,会在HBase中建立一张新表。
- 也就是说索引数据和数据表是存放在不同的表中的,因此全局索引适用于多读少写的业务场景。
- 写数据的时候会消耗大量开销,因为索引表也要更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。
- 在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。
- 如何启用
- 修改配置文件
[omm@bigdata01 ~]$ cd /opt/module/hbase/conf/
[omm@bigdata01 conf]$ vi hbase-site.xml
[omm@bigdata01 conf]$ cat hbase-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://bigdata01:8020/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>bigdata01,bigdata02,bigdata03</value>
</property>
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
<property>
<name>hbase.wal.provider</name>
<value>filesystem</value>
</property>
<!-- phoenix regionserver 配置参数-->
<property>
<name>hbase.regionserver.wal.codec</name>
<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>
<property>
<name>hbase.region.server.rpc.scheduler.factory.class</name>
<value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>
<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
</property>
<property>
<name>hbase.rpc.controllerfactory.class</name>
<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>
</property>
<!-- phoenix master 配置参数 -->
<property>
<name>hbase.master.loadbalancer.class</name>
<value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value>
</property>
<property>
<name>hbase.coprocessor.master.classes</name>
<value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value>
</property>
</configuration>
[omm@bigdata01 conf]$ xsync hbase-site.xml
[omm@bigdata01 conf]$
- 重启服务
[omm@bigdata01 ~]$ queryserver.py stop
[omm@bigdata01 ~]$ stop-hbase.sh
[omm@bigdata01 ~]$ start-hbase.sh
[omm@bigdata01 ~]$ queryserver.py start
[omm@bigdata01 ~]$ sqlline-thin.py bigdata01:8765
- 效果演示
将 name 置于 where 没建立索引前为
FULL SCAN
,建立索引后RANGE SCAN
。
0: jdbc:phoenix:thin:url=http://bigdata01:876> explain select * from student where id=1001;
+----------------------------------------------------------------------------------------+
| PLAN |
+----------------------------------------------------------------------------------------+
| CLIENT 1-CHUNK 1 ROWS 108 BYTES PARALLEL 1-WAY ROUND ROBIN POINT LOOKUP ON 1 KEY OVER |
+----------------------------------------------------------------------------------------+
1 row selected (0.017 seconds)
0: jdbc:phoenix:thin:url=http://bigdata01:876> explain select * from student where name='lisi';
+-------------------------------------------------------------------+-----------------+--+
| PLAN | EST_BYTES_READ | |
+-------------------------------------------------------------------+-----------------+--+
| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER STUDENT | null | |
| SERVER FILTER BY NAME = 'lisi' | null | |
+-------------------------------------------------------------------+-----------------+--+
2 rows selected (0.02 seconds)
0: jdbc:phoenix:thin:url=http://bigdata01:876> create index student_name_index on student(name);
4 rows affected (5.924 seconds)
0: jdbc:phoenix:thin:url=http://bigdata01:876> explain select * from student where name='lisi';
+----------------------------------------------------------------------------------------+
| PLAN |
+----------------------------------------------------------------------------------------+
| CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN RANGE SCAN OVER STUDENT_NAME_INDEX ['lisi'] |
| SERVER FILTER BY FIRST KEY ONLY |
+----------------------------------------------------------------------------------------+
2 rows selected (0.042 seconds)
0: jdbc:phoenix:thin:url=http://bigdata01:876>
Phoenix 全局索引的原理就是在 HBase 中建立一张新表,以该列作为 RowKey 的一部分。
hbase(main):003:0> list
TABLE
STUDENT
STUDENT_NAME_INDEX
SYSTEM.CATALOG
SYSTEM.FUNCTION
SYSTEM.LOG
SYSTEM.MUTEX
SYSTEM.SEQUENCE
SYSTEM.STATS
8 row(s)
Took 0.0077 seconds
=> ["STUDENT", "STUDENT_NAME_INDEX", "SYSTEM.CATALOG", "SYSTEM.FUNCTION", "SYSTEM.LOG", "SYSTEM.MUTEX", "SYSTEM.SEQUENCE", "SYSTEM.STATS"]
hbase(main):004:0> scan 'STUDENT_NAME_INDEX'
ROW COLUMN+CELL
lisi\x00\x80\x00\x03\x column=0:\x00\x00\x00\x00, timestamp=1615615226290, value=x
EA
mazi\x00\x80\x00\x03\x column=0:\x00\x00\x00\x00, timestamp=1615615226290, value=x
EC
wanger\x00\x80\x00\x03 column=0:\x00\x00\x00\x00, timestamp=1615615226290, value=x
\xEB
zhangsan\x00\x80\x00\x column=0:\x00\x00\x00\x00, timestamp=1615615226290, value=x
03\xE9
4 row(s)
Took 0.1098 seconds
hbase(main):005:0> scan 'STUDENT'
ROW COLUMN+CELL
\x80\x00\x03\xE9 column=0:\x00\x00\x00\x00, timestamp=1615610821622, value=x
\x80\x00\x03\xE9 column=0:\x80\x0B, timestamp=1615610821622, value=zhangsan
\x80\x00\x03\xEA column=0:\x00\x00\x00\x00, timestamp=1615610827584, value=x
\x80\x00\x03\xEA column=0:\x80\x0B, timestamp=1615610827584, value=lisi
\x80\x00\x03\xEB column=0:\x00\x00\x00\x00, timestamp=1615615052597, value=x
\x80\x00\x03\xEB column=0:\x80\x0B, timestamp=1615615052597, value=wanger
\x80\x00\x03\xEC column=0:\x00\x00\x00\x00, timestamp=1615615060066, value=x
\x80\x00\x03\xEC column=0:\x80\x0B, timestamp=1615615060066, value=mazi
4 row(s)
Took 0.0191 seconds
hbase(main):006:0>
- 注意事项
如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。
创建携带其他字段的全局索引:CREATE INDEX my_index ON my_table (v1) INCLUDE (v2);
4.6 Phoenix 本地索引
Local Index适用于写操作频繁的场景。
- 原理
- 索引数据和数据表的数据是存放在同一张表中(且是同一个Region),避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。
- 查询的字段不是索引字段索引表也会被使用,这会带来查询速度的提升。
- 语法:
CREATE LOCAL INDEX my_index ON my_table (my_column);
先查找到 name 对应的 rowkey,然后根据 rowkey 得到最终数据,也就是查两次。
五、与Hive的集成
5.1 Hive -> HBase
应用场景:Hive 做离线分析,将所得结果插入 HBase 用于数据展示。
建立Hive表,关联HBase表,插入数据到Hive表的同时能够影响HBase表。
- 在Hive中创建表同时关联HBase
完成之后,可以分别进入Hive和HBase查看,都生成了对应的表。
CREATE TABLE hive_hbase_emp_table(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
- 在Hive中创建临时中间表,用于load文件中的数据。
不能将数据直接load进Hive所关联HBase的那张表中。
CREATE TABLE emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
row format delimited fields terminated by '\t';
- 向Hive中间表中load数据
hive> load data local inpath '/home/admin/softwares/data/emp.txt' into table emp;
- 通过insert命令将中间表中的数据导入到Hive关联Hbase的那张表中
hive> insert into table hive_hbase_emp_table select * from emp;
``
5. 查看Hive以及关联的HBase表中是否已经成功的同步插入了数据
```bash
hive> select * from hive_hbase_emp_table;
Hbase> scan ‘hbase_emp_table’
5.2 Hive <- HBase
- 目标
- 在HBase中已经存储了某一张表hbase_emp_table,然后在Hive中创建一个外部表来关联HBase中的hbase_emp_table这张表;
- 使之可以借助Hive来分析HBase这张表中的数据。
- 步骤
- 在Hive中创建外部表
CREATE EXTERNAL TABLE relevance_hbase_emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY
'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" =
":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
- 关联后就可以使用Hive函数进行一些分析操作了
hive (default)> select * from relevance_hbase_emp;
六、HBase优化
6.1 预分区
- 说明
- 每一个region维护着StartRow与EndRow,如果加入的数据符合某个Region维护的RowKey范围,则该数据交给这个Region维护。
- 那么依照这个原则,我们可以将数据所要投放的分区提前大致的规划好,以提高HBase性能。
- 方法
- 手动设定预分区
hbase(main):010:0> create 'staff1','info',SPLITS => ['1000','2000','3000','4000']
Created table staff1
Took 1.4370 seconds
=> Hbase::Table - staff1
hbase(main):011:0>
- 生成16进制序列预分区
create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
- 按照文件中设置的规则预分区
aaaa
bbbb
cccc
dddd
create 'staff3','partition3',SPLITS_FILE => 'splits.txt';
- 使用JavaAPI创建预分区
//自定义算法,产生一系列hash散列值存储在二维数组中
byte[][] splitKeys = 某个散列值函数
//创建HbaseAdmin实例
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
//创建HTableDescriptor实例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通过HTableDescriptor实例和散列值二维数组创建带有预分区的Hbase表
hAdmin.createTable(tableDesc, splitKeys);
6.2 RowKey设计
- 说明
- 一条数据的唯一标识就是RowKey;
- 一条数据存储于哪个分区,取决于RowKey处于哪个一个预分区的区间内;
- 设计RowKey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。
- 生成随机数、hash、散列值
在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。
原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7
原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd
原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913
- 字符串反转
这样也可以在一定程度上散列逐步put进来的数据。
20170524000001转成10000042507102
20170524000002转成20000042507102
- 字符串拼接
20170524000001_a12e
20170524000001_93i7
6.3 内存优化
- HBase操作过程中需要大量的内存开销,毕竟Table是可以缓存在内存中的,一般会分配整个可用内存的70%给HBase的Java堆。
- 但是不建议分配非常大的堆内存,因为GC过程持续太久会导致RegionServer处于长期不可用状态。
- 一般16~48G内存就可以了,如果因为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死。
6.4 基础优化
- 允许在HDFS的文件中追加内容
hdfs-site.xml、hbase-site.xml
属性:dfs.support.append
解释:开启HDFS追加同步,可以优秀的配合HBase的数据同步和持久化。默认值为true。
- 优化DataNode允许的最大文件打开数
hdfs-site.xml
属性:dfs.datanode.max.transfer.threads
解释:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为4096或者更高。默认值:4096
- 优化延迟高的数据操作的等待时间
hdfs-site.xml
属性:dfs.image.transfer.timeout
解释:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉。
- 优化数据的写入效率
mapred-site.xml
属性:
mapreduce.map.output.compress
mapreduce.map.output.compress.codec
解释:开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec或者其他压缩方式。
- 设置RPC监听数量
hbase-site.xml
属性:Hbase.regionserver.handler.count
解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。
- 优化HStore文件大小
hbase-site.xml
属性:hbase.hregion.max.filesize
解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。
- 优化HBase客户端缓存
hbase-site.xml
属性:hbase.client.write.buffer
解释:用于指定Hbase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。
- 指定scan.next扫描HBase所获取的行数
hbase-site.xml
属性:hbase.client.scanner.caching
解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。
- flush、compact、split机制
当MemStore达到阈值,将Memstore中的数据Flush进Storefile;compact机制则是把flush出来的小文件合并成大的Storefile文件。split则是当Region达到阈值,会把过大的Region一分为二。
涉及属性:
即:128M就是Memstore的默认阈值
hbase.hregion.memstore.flush.size:134217728
即:这个参数的作用是当单个HRegion内所有的Memstore大小总和超过指定值时,flush该HRegion的所有memstore。RegionServer的flush是通过将请求添加一个队列,模拟生产消费模型来异步处理的。那这里就有一个问题,当队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发OOM。
hbase.regionserver.global.memstore.upperLimit:0.4
hbase.regionserver.global.memstore.lowerLimit:0.38
即:当MemStore使用内存总量达到hbase.regionserver.global.memstore.upperLimit指定值时,将会有多个MemStores flush到文件中,MemStore flush 顺序是按照大小降序执行的,直到刷新到MemStore使用内存略小于lowerLimit