开启shell交互客户端
为了操作方便,建议将hbase配置到linux系统的环境变量中
配置好环境变量后,在任意位置,输入hbase shell 即可进入到shell客户端中
输入help指令,可查看shell客户端所有的操作指令列表
输入help “命令名” 可查看该命令所有的功能及用法
通用命令
status: 查看HBase的状态,例如,服务器的数量。
version: 提供正在使用HBase版本。
table_help: 表引用命令提供帮助。
whoami: 提供有关用户的信息。
namespace:操作名称空间的命令
hbase中没有数据库的概念 , 可以使用namespace来达到数据库分类别管理表的作用
alter_namespace 操作namespace的属性信息
create_namespace 创建名称空间
describe_namespace 查看名称空间的描述信息
drop_namespace 删除一个名称空间
list_namespace 查看系统中的名称空间
list_namespace_tables 列举出一个名称空间下所有的表
在创建名称空间时,可以给它赋予属性,属性中可以列出改名称空间的用途及创建人等信息
DDL(Data Definition Language):操作表的命令
list 列举出默认名称空间下所有的表
create 建表
alter 修改列族schema(表结构和属性) ,添加列,修改列
alter_async 这个不需要等所有region收到schema发生更改就返回
alter_status 可以查看alter进度,有几个region收到schema更改通知
describe/desc 查看表结构信息
disable 禁用表
disable_all 禁用多张表
is_disabled 查看是否是禁用
drop 删除表
drop_all 删除多张表
enable 启动一张表
enable_all 启动多张表
is_enabled 查看表是否启用
exists 查看表是否存在
get_table 获取表对象
list_regions 列出表所有region信息
locate_region 查看表的某行数据所在的region信息
show_filters 列举出系统可用的过滤器(用用条件筛选查询操作)
创建表时只需要创建表名和列族名即可,不需要创建属性,因为hbase的稀疏性,属性需要插入数据时再创建,创建列族时可以指定版本号VERSIONS和数据存留时间TTL
DML(Data Manipulation Language):操作表中数据的命令
append 向原始值上追加新的值,内部追加时,会先生成一个新的文件,过一段时间后新旧两个文件会自动合并,完成追加操作
count 获取一个表有多少行
delete 删除一个值
deleteall 可以删除一个值或一个列族或一行数据
get 获取值,可以获取整个一行,也可以获取一行中的一个列族或多个列族中的一个属性或多个属性值
get还可以获取某个属性的值被更新前的多个版本的数据,例如列族的VERSIONS属性设置为3时,则可以最多获取3个历史版本的数据.
get “tb_user2”,“r1”,{COLUMN=>“nf2:name”,VERSIONS=>3}
get_splits 获取切分点
incr 计数器,每次给他一个数字,然后自动叠加
get_counter 获取incr叠加后的结果
put 插入数据
scan 查看表中的所有数据
truncate 禁用、删除和重新创建指定的表。
truncate_preserve 禁用、删除和重新创建指定的表,同时仍然维护以前的区域边界。
put “表名”,“指定行键”,“列族名”,“属性”,“值”
put数据后可以使用scan查看数据,数据在hbase中看到,但在hdfs中还无法看到,因为数据会暂时存在内存中,如果想在hdfs中看见可以刷新一下
flush “表名” 将hbase存在内存中的数据刷到hdfs中
可以在linux中输入:
hbase hfile -p -f “储存路径” 查看存储在hdfs中的数据
hdfs储存路径如下:
扩展内容:
1.hbase实现删除和改动数据的方法
在大多数数据存储类型中都不支持随机写和随机改数据,那么在hbase中是如何实现删除和改动数据的呢?
当我们执行删除操作时,例如删除某一个行键:
deleteall “表名” “行键名”
执行此操作后,flush刷新一下该表,hbase会在hdfs中生成一个新的文件,储存着该行键已被删除的墓碑标记,然后过一段时间后,系统会自动将原文件和新生成的墓碑标记进行整合,整合后会生成一个该行键被删除后的新文件(改数据与此同理).
我们也可以使用major_compact "tb_name"命令手动合并一个表中所有的冗余文件
2.region的合并和拆分
region的合并:
hbase中的合并主要分为三种:region合并,列族合并,hfile文件合并(hfile文件默认大小为128M一个)
region合并主要是因为,当表中的数据被删除了很多或因时间过期,版本过期的时候,原始的多个region管理的数据大小就会缩小很多,这时为了节省内存空间,便可以合并region,region合并因为会涉及到行键/列族/属性等,合并时较为复杂,又称之为大合并,因此建议在业务低峰期时人为进行合并.
region的拆分:
1)自动按大小拆分拆分:
一个region达到256M时会自动拆分出第二个,
第二个达到2G会,分出第三个,
第三个达到6.75G时分出第四个,
从第四个开始每达到10G就会自动分出一个
2)预分region建表:
当我们用普通方式建表时,只会生成一个region,当后面有大量数据储存过来时,会导致只有一个regionserver在服务,这会导致插入热点问题.
为解决此问题,我们可以在创建表时,就多建几个region,region的分割方式是以行键进行分割的,例如我们建一个预分region表:create “doit:tb_user7”,“cf1”,SPLITS=>[“a4”,“a7”]
此时我们创建了两个分割点"a4",“a7” ,那么这个表就会被分成三个region
我们插入数据时设置行键后,因为设置的切分点是两位数的,所有系统就会去对比行键前两位比"a4","a7"大还是小,大的话就分到后面,小的就分到前面(按字典顺序进行比较),如果相同也分到后面,然后各个region文件就会均衡的分布到hdfs中,生成多个regionserver,从而避免了插入热点问题.3)一个表建好之后我们也可以手动设定切割点,进行手动拆分,例如:
split “tb_user2”,“r2” 将一个表的行键按r3进行切分
切分前
切分后
切分后可以手动的将region移动到其他regionserver上
move “region_name”,“regionserver_name”
移动后
负载均衡
当hbase集群中的某个regionserver管理的region太多或太少时,就得进行负载均衡得操作,这样主要是为了避免某个节点得工作压力太大,容易导致它宕机,在做负载均衡是会涉及到region的上线和下线的问题,当region下线时则它里面的数据无法访问.
行键的设计
在hbase中一个表的好坏,大多数时候都是由行键的设计直接决定的,设计行键时,我们需要注意数据的特点,根据数据查询的维度和热点进行考虑,且还要考虑数据插入时的特点,要做到即避免了查询热点问题,也避免了插入热点问题,避免某一台regionserver负载过大,导致宕机.
例1:某一部热门电影,引起大众的广泛关注,很多人都在查询它,那么此时就涉及查询热点问题,我们在设计它的行键时,就可以在电影id的前面加上插入时间或随机数,从而将此电影的多个信息分布到各个regionserver中去,就避免了查询热点的问题
例2:我们在以手机号为行键插入数据时,正常划分region的话,可能会出现大量的13或15开头的手机号同时插入造成插入热点的问题,那么我们此时可以将手机号进行反转之后再作为行键插入,这样就能保证前几位数相对比较随机,避免插入热点的问题.
在设计行键时基本要求如下:
1.等长
2.不要太长(行键和列族太长,都会导致在hbase表中生成大量的冗余数据,浪费存储资源)
3.考虑热点
4.考虑维度
二级索引表
在hbase中只有使用行键检索数据才会有很快的检索速度,但是在实际生活中,不能保证每个人都只会用行键来查询数据,那么我们如何保证查询的速度呢?
此时就可以用到二级索引表:
例如:我们的某张表中存了很多电影的评分,我们划分行键时一般都是会以电影id划分行将,不可能单纯的按电影名进行划分,但用户查询数据时一般都是输入电影名进行查询,那么此时为了提高查询效率,我们就可以使用二级索引表,将电影名和电影id这两条数据单独的做成一张表,当用户来查询某个电影名时,我们可以快速的检索出电影id,然后通过电影id快速的检索出该id下所有的评分信息,从而提高查询效率(在涉及多维度查询时,我们还可以涉及三级索引,甚至四级索引)
二级索引案例
在社交类应用中,经常需要快速检索各用户的关注列表,同时,又需要反向检索各种用户的粉丝列表,为了实现这个需求,最佳实践是建立两张互为反向的表:
一个表为正向索引关注表:“user_mingxing”:
Rowkey: a
f1:from b
另一个表为反向索引粉丝表:“mingxing_user”:
Rowkey: b
f1:from a
建表语句:
create ‘user_mingxing’,‘cf1’
create ‘mingxing_user’,‘cf1’
实现效果:往 user_mingxing 表插入一条数据,就会自动往 mingxing_user 表插入一条数据 put
‘user_mingxing’,‘a’,‘cf1:from’,‘b’
put ‘mingxing_user’,‘b’,‘cf1:from’,‘a’
创建maven工程
<dependencies>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-mapreduce</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-core</artifactId>
<version>5.0.0-HBase-2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<!-- get all project dependencies -->
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- MainClass in mainfest make a executable jar -->
<archive>
<manifest>
<!--<mainClass>util.Microseer</mainClass> -->
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- bind to the packaging phase -->
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
编写协处理器
public class SecondrayIndeximplements RegionCoprocessor, RegionObserver {
/**
* 可选择的协处理器的类型
*/
public Optional<RegionObserver> getRegionObserver() {
return Optional.of(this);
}
/**
* put之前操作
*/
@Override
public void prePut(ObserverContext<RegionCoprocessorEnvironment> c, Put put, WALEdit edit, Durability durability) throws IOException {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("ids_index"));
List<Cell> cells = put.get("f".getBytes(), "ids".getBytes());
for (Cell cell : cells) {
byte[] bytes = CellUtil.cloneValue(cell);
byte[] rowBytes = CellUtil.cloneRow(cell);
String ids = new String(bytes);
String[] split = ids.split(":");
ArrayList<Put> puts = new ArrayList<>();
for (String id : split) {
Put p = new Put(id.getBytes());
p.addColumn("f".getBytes(),"gid".getBytes(),rowBytes);
puts.add(p);
}
table.put(puts);
}
table.close();
conn.close();
}
/**
* 开启region
*/
@Override
public void start(CoprocessorEnvironment env) throws IOException {
}
/**
* 关闭region
*/
@Override
public void stop(CoprocessorEnvironment env) throws IOException {
}
}