我本想用MySQL来与HBase作比较,但发现他们两者毫无可比性,因为两者运用领域不同,各自有各自的优点,就好比爬山穿登山鞋,潜水穿脚蹼一般。
一门技术的兴起,一个优秀的开源项目的存在肯定是有它所存在的意义,正如大数据一样,正是因为随着时间的发展,随着技术的发展导致我们每天的数据增量达到一个非常庞大的状态,同时在数据之中又能挖掘到很多有用的信息。所以才有了大数据技术的飞速发展。
而学习HBase不仅仅是因为他属于Hadoop生态圈,而且他很特殊;
我想各位在接触HBase之前可能就没有看到过哪个数据库是面向列存储的,我也不知该如何简述他的与众不同,总之我们就沉浸下来,由笔者带各位从下文的学习中深刻体会一下吧。
目录
1. 海量数据存储:
2. 准实时查询:
Hbase在实际场景中的应用
1. 交通方面:
2. 金融方面:
3. 电商:
4. 移动:
1. 容量大:
2. 面向列:
3. 多版本:
4. 稀疏性:
5. 拓展性:
6. 高可靠性:
7.高性能:
总结:
面向列,容量大,写入比mysql快但是读取没有,超过五百万条数据的话建议读写用Hbase。


在HBase中有些术语需要提前了解一下:
HBase采用表来组织数据;

HBase架构有三个主要组成部分:



其实我们搭建了这么多集群总结起来无外乎三步:
注:在搭建HBase之前,请完成jdk、zookeeper、Hadoop等基础配置,详情可见我之前的文章
Hadoop-HDFS详解与HA,完全分布式集群搭建(细到令人发指的教程)
大数据学前准备--zookeeper详解与集群搭建(保姆级教程)
安装包下载:Index of /hbase
本文示例版本:Index of /hbase/2.4.14


或者通过wget命令下载
wget https://downloads.apache.org/hbase/1.7.2/hbase-1.7.2-bin.tar.gz # 红色是版本信息,依情景或公司要求自行选择

这里笔者为方便演示,直接上传已经下载好的安装包:hbase-2.4.14-bin.tar.gz
接下来以hbase-2.4.14-bin.tar.gz为例讲解hbase集群模式。

上传安装包并解压
上传后在安装包的目录执行:tar -zxvf hbase-2.4.14-bin.tar.gz -C /opt
| 节点/服务 | HMasterActive | HMasterStandby | HRegionServer | Zookeeper |
| master(node001) | √ | √ | √ | |
| slave1(node002) | √ | √ | √ | |
| slave2(node003) | √ | √ |
配置hbase环境变量
终端输入:vim /etc/profile
末行加入:
export HBASE_HOME=/opt/hbase-2.4.14
export PATH=$PATH:$HBASE_HOME/bin
重新加载配置文件:source /etc/profile
创建logs目录存放日志文件
[root@node001 ~]# mkdir -p /opt/hbase-2.4.14/logs
hbase-env.sh
终端输入:vim /opt/hbase-2.4.14/conf/hbase-env.sh
末行加入:
# hbase-env.sh
export HBASE_LOG_DIR=${HBASE_HOME}/logs
export JAVA_HOME=/usr/java/jdk1.8.0_231-amd64
export HADOOP_HOME=/opt/hadoop-3.1.2
export HBASE_HOME=/opt/hbase-2.4.14
export HBASE_MANAGES_ZK=false #不启动hbase内置的zookeeper集群,因为我们已经搭建了
hbase-site.xml
终端输入:vim /opt/hbase-2.4.14/conf/hbase-site.xml
将configuration中内容修改为:
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://bdp/hbase</value>
</property>
<!--配置WEB UI界面-->
<property>
<name>hbase.master.info.port</name>
<value>60010</value>
</property>
<!--超时时间-->
<property>
<name>zookeeper.session.timeout</name>
<value>120000</value>
</property>
<!--zookeeper集群配置,如果是集群,则添加其他主机地址-->
<property>
<name>hbase.zookeeper.quorum</name>
<value>node001:2181,node002:2181,node003:2181</value>
</property>
<!--hbase数据存放目录,tmp并不是临时文件目录-->
<property>
<name>hbase.tmp.dir</name>
<value>/var/bdp/hbase</value>
</property>
<!--集群或者单机模式,false是单机模式,true是分布式-->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<!--hbase在zookeeper上数据的根目录znode节点-->
<property>
<name>hbase.znode.parent</name>
<value>/hbase</value>
</property>
<!--使用本地文件系统设置为false,使用hdfs设置为true-->
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
</configuration>
regionservers
终端输入:vim /opt/hbase-2.4.14/conf/regionservers
去掉localhost加入:
node001
node002
node003
backup-masters(原本没有这个文件)
终端输入:vim /opt/hbase-2.4.14/conf/backup-masters
node002 # 将node002作为备用节点standby
拷贝Hadoop中core-site.xml文件到hbase中
终端输入:scp /opt/hadoop-3.1.2/etc/hadoop/core-site.xml /opt/hbase-2.4.14/conf/
拷贝Hadoop中hdfs-site.xml文件到hbase中
终端输入:scp /opt/hadoop-3.1.2/etc/hadoop/hdfs-site.xml /opt/hbase-2.4.14/conf/
拷贝hbase文件
发送hbase到node002节点
终端输入:scp -r /opt/hbase-2.4.14/ node002:/opt/
发送hbase到node003节点
终端输入:scp -r /opt/hbase-2.4.14/ node003:/opt/
拷贝profile文件
发送profile到node002节点
终端输入:scp /etc/profile node002:/etc/
发送profile到node003节点
终端输入:scp /etc/profile node003:/etc/
重新加载配置文件
在node001终端输入:
ssh root@node002 "source /etc/profile" # 重新加载node002 配置文件
ssh root@node003 "source /etc/profile" # 重新加载node0023配置文件
先启动zookeeper集群
三台节点都输入:zkServer.sh start

再启动Hadoop集群
node001输入:start-all.sh

启动HBase集群
node001终端输入:start-hbase.sh

访问web界面
通过hbase-env.sh配置文件中所配置的端口号(60010)访问web界面
<!--配置WEB UI界面-->
<property>
<name>hbase.master.info.port</name>
<value>60010</value>
</property>

查看日志文件
还记得我们在hbase-env.sh中配置的logs日志文件么
export HBASE_LOG_DIR=${HBASE_HOME}/logs
我们进入这个目录:cd /opt/hbase-2.4.14/logs/
输入:ls 展示一下自动生成的日志文件

在node002,node003节点也生成了他对应的日志文件

所以以后hbase集群有了什么问题可以在这些日志文件中查看。
到此HBase集群搭建完成!记得拍摄快照哟~
hbase的操作也类似于MySQL库、表的增删改查等操作
这里罗列一些常用的hbase操作

通过命令:hbase shell进入hbase(hbase集群启动的情况下)
通过help命令查看帮助命令
通过exit命令退出hbase客户端界面
查看服务器状态:status

查看hbase版本:version

创建命名空间
语法:create_namespace '命名空间名称'
create_namespace 'test'
查看命名空间
根据命名空间名称查询
describe_namespace 'test'
查询全部命名空间
list_namespace
在某命名空间中创建表
语法:create '命名空间名称:表名','列族','列族'
create 'test:tab_test','love','you'
创建表
# 语法:create 表名,列族1,列组2,...
# 例如:create 'tabname','column_family01','column_family02'
create 'student','info','grade'

现在先不用创建列,列名是后期插入数据时才定义的。
展示表
list:罗列出所有表
hbase:012:0> list
TABLE
student
tab_test
2 row(s)
Took 0.0286 seconds
=> ["student", "tab_test"]
describe:展示表的详细信息
hbase:013:0> describe 'tab_test'
Table tab_test is ENABLED
tab_test
COLUMN FAMILIES DESCRIPTION
{NAME => 'column_family01', BLOOMFILTER => 'ROW', IN_MEMORY => 'false', VERSION
S => '1', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', COMPRES
SION => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BL
OCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'column_family02', BLOOMFILTER => 'ROW', IN_MEMORY => 'false', VERSION
S => '1', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', COMPRES
SION => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BL
OCKSIZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s)
Quota is disabled
Took 0.1754 seconds
增加列族
语法:alter 'tablename','column_famaily03'
alter 'student','class'

删除列族
语法:alter 表名, 'delete' => 列族名
我们删除student表的class列族试试:
alter 'student','delete'=>'class'
alter 'student',{NAME=>'class',METHOD=>'delete'}
hbase:015:0> alter 'student','delete'=>'class'
Updating all regions with the new schema...
1/1 regions updated.
Done.
Took 2.8162 seconds
hbase:016:0> describe 'student' # 展示student的详细信息,发现class列族已经没有了
Table student is ENABLED
student
COLUMN FAMILIES DESCRIPTION
{NAME => 'grade', BLOOMFILTER => 'ROW', IN_MEMORY => 'false', VERSIONS => '1',
KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', COMPRESSION => 'N
ONE', TTL => 'FOREVER', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE =>
'65536', REPLICATION_SCOPE => '0'}
{NAME => 'info', BLOOMFILTER => 'ROW', IN_MEMORY => 'false', VERSIONS => '1', K
EEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', COMPRESSION => 'NO
NE', TTL => 'FOREVER', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE =>
'65536', REPLICATION_SCOPE => '0'}
2 row(s)
Quota is disabled
Took 0.1113 seconds
删除表
表创建成功后,默认状态是enable,即“使用中”的状态,删除表之前需先设置表为“关闭中”。
disable 'student'
再使用关键字drop删除表
drop 'student'
插入(跟新)数据
由于hbase有时间戳版本这一概念,所以跟新操作跟插入操作一样,但是旧数据不会就消失了,旧数据会被当做老版本依旧存放于表中。
语法:put '表名','行键','列族:列名','值'
put 'student','student_01','grade:math','82'
put 'student','student_01','grade:english','96'
put 'student','student_01','info:name','lisi'
put 'student','student_01','info:addr','chongqing'
查看数据(get|scan)
语法:
get: 只查看某个行键的数据 get '表名' ,'行键'

scan:查看表的所有数据 scan '表名'

说明:scan全表扫描与get获取到的数据都是目前时间戳最新的数据。
我们如何查看老版本的信息呢:scan时可以设置是否开启RAW模式,开启RAW模式会返回已添加删除标记但是未实际进行删除的数据
语法:scan '表名',{RAW=>true,VERSIONS=>你想展示多少个版本的信息就写几}
scan 'student',{RAW=>true,VERSIONS=>2}

删除一行数据中的列值
delete '表名','行键','列族:列名' # 不指定时间戳的话,默认删除当前最新版本的记录
或deleteall '表名','行键','列族:列名' # 删除指定单元格所有版本的记录
delete 'student','student_01','info:addr'
hbase:036:0> get 'student','student_01' # 第一次获取数据,zhangsan的地址是beijing
COLUMN CELL
grade:english timestamp=2022-09-22T11:32:38.926, value=45
grade:math timestamp=2022-09-22T11:32:38.540, value=99
info:addr timestamp=2022-09-22T11:32:40.774, value=beijing
info:name timestamp=2022-09-22T11:32:39.091, value=zhangsan
1 row(s)
Took 0.0510 seconds
hbase:039:0> delete 'student','student_01','info:addr' # 删除掉了新版本的addr记录
Took 0.1579 seconds
hbase:040:0> get 'student','student_01' # 第二次获取数据,zhangsan的地址是chongqing(旧版本)
COLUMN CELL
grade:english timestamp=2022-09-22T11:32:38.926, value=45
grade:math timestamp=2022-09-22T11:32:38.540, value=99
info:addr timestamp=2022-09-22T11:16:53.171, value=chongqing
info:name timestamp=2022-09-22T11:32:39.091, value=zhangsan
1 row(s)
Took 0.0583 seconds
hbase:041:0> delete 'student','student_01','info:addr' # 再次删除掉当前最新版本也就是之前的旧版本chongqing
Took 0.0370 seconds
hbase:042:0> get 'student','student_01' # 由于只存入了两个版本的信息,两条addr的信息都被删除后就,没有数据展示了
COLUMN CELL
grade:english timestamp=2022-09-22T11:32:38.926, value=45
grade:math timestamp=2022-09-22T11:32:38.540, value=99
info:name timestamp=2022-09-22T11:32:39.091, value=zhangsan
1 row(s)
Took 0.0424 seconds
deleteall 'student','student_01','grade:math'
hbase:048:0> get 'student','student_01'
COLUMN CELL
grade:english timestamp=2022-09-22T11:32:38.926, value=45
grade:math timestamp=2022-09-22T11:32:38.540, value=99
info:name timestamp=2022-09-22T11:32:39.091, value=zhangsan
1 row(s)
Took 0.0599 seconds
hbase:049:0> deleteall 'student','student_01','grade:math' # 一次性删除所有版本的记录
Took 0.0256 seconds
hbase:050:0> get 'student','student_01'
COLUMN CELL
grade:english timestamp=2022-09-22T11:32:38.926, value=45
info:name timestamp=2022-09-22T11:32:39.091, value=zhangsan
1 row(s)
Took 0.0303 seconds
删除一行数据(deleteall)
deleteall '表名','行键'
deleteall 'student','student_01'
先回顾一下我们的节点规划:
| 节点/服务 | HMasterActive | HMasterStandby | HRegionServer | Zookeeper |
| master(node001) | √ | √ | √ | |
| slave1(node002) | √ | √ | √ | |
| slave2(node003) | √ | √ |
接下来以我们搭建好的hbase集群与我们刚才上文对表的操作来讲讲当我们提交了put 'student','student_01','grade:math','82'命令后hbase到底做了什么(建议初学者将下图着重掌握):


在操作之前确保hbase集群正常运行!
使用的是IDEA+Maven来进行测试
Maven的pom.xml中hbase依赖如下:
<dependencies>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-protocol</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
获取所有表
package com.libing.hbase;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import java.io.IOException;
/**
* @author liar
* @version 1.0
* @date 2022/9/24 13:48
*/
public class GetAllTableTest {
public static Configuration cfg = HBaseConfiguration.create();
public static Connection conn;
public static void main(String[] args) throws IOException {
cfg.set("hbase.zookeeper.quorum","192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181");
//cfg.set("hbase.zookeeper.quorum","node001:2181,node002:2181,node003:2181");
//创建数据库连接
conn = ConnectionFactory.createConnection(cfg);
/**
* Admin 用于管理HBase数据库的表信息
* org.apache.hadoop.hbase.client.Admin是为管理HBase而提供的接口,在Connection
* 实例调用getAdmin()和close()方法期间有效。
*/
Admin admin = conn.getAdmin();
for(TableName name : admin.listTableNames())
{
System.out.println(name);
}
//关闭连接
conn.close();
}
}

注:这里运行报错Caused by: java.net.UnknownHostException: can not resolve node001,16000,1663...的需要在Windows的C:\Windows\System32\drivers\etc\hosts文件中添加对应的域名解析(我也不知道为啥,反正我的加了解决了报错):192.168.1.101 node001

言归正传:
org.apache.hadoop.hbase.client.Admin是为管理HBase而提供的接口,在Connection
实例调用getAdmin()和close()方法期间有效。使用Admin接口可以实现的主要
HBase Shell命令包括create, list, drop, enable, disable, alter,相应java方法如下表:
| 描述 | 方法 | 返回值 |
| 创建一个新表 | admin.createTable(HTableDescriptor desc); | void |
| 列出所有表名 | admin.listTableNames(); | tableName |
| 删除一个已经存在的表 | admin.deleteTable(TableName tableName); | void |
| 使表有效 | admin.enableTable(TableName tableName); | void |
| 使表无效 | admin.disableTable(TableName tableName); | void |
| 修改一个已经存在的表 | admin.modifyTable(TableDescriptor td); | void |
| 检查表是否存在 | admin.tableExists(TableName tableName); | boolean |
package com.libing.hbase;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import java.io.IOException;
/**
* @author liar
* @version 1.0
* @date 2022/9/24 15:16
*/
public class CreateTableTest {
public static Configuration cfg = HBaseConfiguration.create();
public static Connection conn;
public static void main(String[] args) throws IOException {
cfg.set("hbase.zookeeper.quorum","192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181");
//创建数据库连接
conn = ConnectionFactory.createConnection(cfg);
/**
* Admin 用于管理HBase数据库的表信息
* org.apache.hadoop.hbase.client.Admin是为管理HBase而提供的接口,在Connection
* 实例调用getAdmin()和close()方法期间有效。
*/
Admin admin = conn.getAdmin();
String tableName = "create_test";
String columFamily1 = "create_test_family1";
String columFamily2 = "create_test_family2";
HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableName));
HColumnDescriptor hColumnDescriptor1 = new HColumnDescriptor(columFamily1);
HColumnDescriptor hColumnDescriptor2 = new HColumnDescriptor(columFamily2);
tableDescriptor.addFamily(hColumnDescriptor1).addFamily(hColumnDescriptor2);
admin.createTable(tableDescriptor);
for (TableName tables :admin.listTableNames()) {
System.out.println(tables);
}
//关闭连接
conn.close();
}
}

通过hbase客户端也发现这张表的列族也是按照要求创建好了的。
package com.libing.hbase;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
/**
* @author liar
* @version 1.0
* @date 2022/9/24 16:12
*/
public class AddTest {
public static Configuration cfg = HBaseConfiguration.create();
public static Connection conn;
public static void main(String[] args) throws IOException {
cfg.set("hbase.zookeeper.quorum","192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181");
//创建数据库连接
conn = ConnectionFactory.createConnection(cfg);
//获取名字为create_test的表
Table table = conn.getTable(TableName.valueOf("create_test"));
//行键001
Put p = new Put(Bytes.toBytes("001"));
//给001行键与列族为create_test_family1创建一个id列存入数据123456
p.addColumn(Bytes.toBytes("create_test_family1"),Bytes.toBytes("id"),Bytes.toBytes("123456"));
//给001行键与列族为create_test_family2创建一个addr列存入数据chongqing
p.addColumn(Bytes.toBytes("create_test_family2"),Bytes.toBytes("addr"),Bytes.toBytes("chongqing"));
//给001行键与列族为create_test_family2创建一个age列存入数据25
p.addColumn(Bytes.toBytes("create_test_family2"),Bytes.toBytes("age"),Bytes.toBytes("25"));
//提交,相当于hbase shell中的put指令
table.put(p);
//关闭连接
conn.close();
}
}
通过hbase客户端看到数据已经按要求成功提交了

Table接口用于和HBase中的表进行通信,代表了该表的实例,使用Connection的getTable(TableName tableName)方法可以获取该接口的实例,用于获取、添加、删除、扫描HBase表中的数据。
Table接口包含的主要方法如下:
| 描述 | 方法 | 返回值 |
| 向表添加值 | put(Put put) | void |
| 获取表中的值 | get(Get get) | Result |
| 删除指定单元/行的值 | delete(Delete delete) | void |
| 获取当前表给定列族的scanner实例, ResultScanner代表结果列表 | getScanner() | ResultScanner |
| 测试Get实例所指定的值是否存于table中 | exists(Get get) | boolean |
| 获取表的HTableDescriptor实例 | getTableDescriptor() | HTableDescriptor |
| 获取表名 | getName() | TableName |
这里不对每一个方法进行展示,不然文章就太臃肿了,读者视情况可以自行测试。
预创建HRegion
默认情况下,在创建HBase表的时候会自动创建一个region分区,当导入数据的时候,所有的HBase客户端都向这一个region写数据,直到这个region足够大了才进行切分。一种可以加快批量写入速度的方法是通过预先创建一些空的regions,这样当数据写入HBase时,会按照region分区情况,在集群内做数据的负载均衡。
手动设定预分区
Hbase> create'staff1','info','partition1',SPLITS =>['1000','2000','3000','4000']
生成 16 进制序列预分区
create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO =>'HexStringSplit'}
按照文件中设置的规则预分区
创建 splits.txt 文件内容如下:
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);
Row Key优化
在HBase中,Row Key可以是任意字符串,最大长度为64KB,实际应用中一般为10~100Bytes,存为byte[]字节数组,一般设计成定长的。Row Key是按照字典顺序存储的,也就是说行键在顺序上接近的数据大概率在物理上是存储在一起的。充分利用这个特性可提高数据查询效率。
列族优化
不要在一张表里定义太多的列族Column Family。目前 HBase并不能很好地处理超过3个列族的表。因为某个列族在刷新缓冲区的时候,它邻近的列族也会因关联效应被触发刷新缓冲区,最终导致系统产生更多的1/O。
版本优化
通过HColumnDescriptor.sctMaxVersions(int maxVersions)设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置 setMax Versions( 1)。
HBase支持并发读取,为了加快读取数据速度,可以创建多个HTable客户端同时进行读操作,提高吞吐量
Scanner 缓存
调用HTable.setScannerCaching(int scannerCaching)可以设置Hbase扫描一次从服务端抓取的数条数。通过将此值设置成一个合理的值,可以减少扫描过程next()的时间花销,代价是扫描需要通过客户端的内存来维持这些被缓存的行记录。扫描时指定需安的 Coumn Family,可以减少网络传输数据量,否则默认扫描操作会返回整行所有Column family 数据。通过扫描取完数据后,要及时关闭 ResultScanner,否则HRegionServer可能会出现回题(对应的Server资源无法释放)
批量读取
通过调用 HTable.get(Get)方法,可以根据一个指定的Row Key获取一行记录。同样地,HBase 提供了另一个方法:通过调用 HTable.get(List)方法,可以根据指定的Row Key 列表批量获取多行记录。这样做的好处是批量执行,只需要一次网络IO开销,这可能带来明显的性能提升
多线程并发读取
在客户端开启多个 HTable读线程,每个读线程都通过HTable对象进行get 操作
缓存结果查询
对于频繁查询HBase的应用场景,可以考虑在应用程序中进行缓存,当有新的查询请求时首先在缓存中查找,如果存在则直接返回,不再查询HBase;否则对HBase发起读请求查询然后在应用程序中将查询结果缓存起来。至于缓存的替换策略,可以考虑LRU等常用的策略
块缓存
HBase上 HRegionServer 的内存分为两个部分:一部分作为MemStore,主要用来写;另外一部分作为BlockCache,主要用于读。写请求会先写入MemStore,HRegionServer 会给每个HRegion提供一个 MemStore,当MmStore满64MB以后,会清空MemStore并把数据写
允许在 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
一分为二。
这篇博客我也是花了很大精力写的,但是难免有错误,希望对文章有意见或建议的朋友可以联系我,我也希望能够听取读者的意见完善自己的文章。
最后,附上一张我在写博客时画的一些图示:

有需要这些图示或者需要源码(配置文档,java代码)的可以通过我的邮箱联系到我。
邮箱:719167291@qq.com
1.1.1 YARN的介绍 为克服Hadoop1.0中HDFS和MapReduce存在的各种问题⽽提出的,针对Hadoop1.0中的MapReduce在扩展性和多框架⽀持⽅⾯的不⾜,提出了全新的资源管理框架YARN. ApacheYARN(YetanotherResourceNegotiator的缩写)是Hadoop集群的资源管理系统,负责为计算程序提供服务器计算资源,相当于⼀个分布式的操作系统平台,⽽MapReduce等计算程序则相当于运⾏于操作系统之上的应⽤程序。 YARN被引⼊Hadoop2,最初是为了改善MapReduce的实现,但是因为具有⾜够的通⽤性,同样可以⽀持其他的分布式计算模
Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile
一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是
开门见山|拉取镜像dockerpullelasticsearch:7.16.1|配置存放的目录#存放配置文件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/config#存放数据的文件夹mkdir-p/opt/docker/elasticsearch/node-1/data#存放运行日志的文件夹mkdir-p/opt/docker/elasticsearch/node-1/log#存放IK分词插件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/plugins若你使用了moba,直接右键新建即可如上图所示依次类推创建
文章目录概念索引相关操作创建索引更新副本查看索引删除索引索引的打开与关闭收缩索引索引别名查询索引别名文档相关操作新建文档查询文档更新文档删除文档映射相关操作查询文档映射创建静态映射创建索引并添加映射概念es中有三个概念要清楚,分别为索引、映射和文档(不用死记硬背,大概有个印象就可以)索引可理解为MySQL数据库;映射可理解为MySQL的表结构;文档可理解为MySQL表中的每行数据静态映射和动态映射上面已经介绍了,映射可理解为MySQL的表结构,在MySQL中,向表中插入数据是需要先创建表结构的;但在es中不必这样,可以直接插入文档,es可以根据插入的文档(数据),动态的创建映射(表结构),这就
HTTP缓存是指浏览器或者代理服务器将已经请求过的资源保存到本地,以便下次请求时能够直接从缓存中获取资源,从而减少网络请求次数,提高网页的加载速度和用户体验。缓存分为强缓存和协商缓存两种模式。一.强缓存强缓存是指浏览器直接从本地缓存中获取资源,而不需要向web服务器发出网络请求。这是因为浏览器在第一次请求资源时,服务器会在响应头中添加相关缓存的响应头,以表明该资源的缓存策略。常见的强缓存响应头如下所述:Cache-ControlCache-Control响应头是用于控制强制缓存和协商缓存的缓存策略。该响应头中的指令如下:max-age:指定该资源在本地缓存的最长有效时间,以秒为单位。例如:Ca
如何用IDEA2022创建并初始化一个SpringBoot项目?目录如何用IDEA2022创建并初始化一个SpringBoot项目?0. 环境说明1. 创建SpringBoot项目 2.编写初始化代码0. 环境说明IDEA2022.3.1JDK1.8SpringBoot1. 创建SpringBoot项目 打开IDEA,选择NewProject创建项目。 填写项目名称、项目构建方式、jdk版本,按需要修改项目文件路径等信息。 选择springboot版本以及需要的包,此处只选择了springweb。 此处需特别注意,若你使用的是jdk1
前言上一篇我们简要讲述了粒子系统是什么,如何添加,以及基本模块的介绍,以及对于曲线和颜色编辑器的讲解。从本篇开始,我们将按照模块结构讲解下去,本篇主要讲粒子系统的主模块,该模块主要是控制粒子的初始状态和全局属性的,以下是关于该模块的介绍,请大家指正。目录前言本系列提要一、粒子系统主模块1.阅读前注意事项2.参考图3.参数讲解DurationLoopingPrewarmStartDelayStartLifetimeStartSpeed3DStartSizeStartSize3DStartRotationStartRotationFlipRotationStartColorGravityModif
VMware虚拟机与本地主机进行磁盘共享前提虚拟机版本为Windows10(专业版,不是可能有问题)本地主机为家庭版或学生版(此版本会有问题,但有替代方式)最好是专业版VMware操作1.关闭防火墙,全部关闭。2.打开电脑属性3.点击共享-》高级共享-》权限4.如果没有everyone,就添加权限选择完全控制,然后应用确定。5.打开cmd输入lusrmgr.msc(只有专业版可以打开)如果不是专业版,可以跳过这一步。点击用户-》administrator密码要复杂密码,否则不行。推荐admaiN@1234类型的密码。设置完密码,点击属性,将禁用解开。6.如果虚拟机的windows不是专业版,可