开发者学堂课程【高校精品课-上海交通大学-企业级应用体系架构: HBase&HIve 1】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/75/detail/15846
HBase&HIve 1
内容介绍
一.HBase
二.代码
三.HBase 与关系型数据库差异
一.HBase
1.概念
HBase 是数据仓库是一个面向列的分布式存储 HBase 之上,如果把它想象成一个数据库,数据库肯定都是有一些文件,无论用哪一种数据库系统,最终存存取数据的时候都会是文件,这些文件是存储在 HBase 之上,这是一个关系。
在 HBase 中,是 hadoop 里面的一部分,可以做所谓的随机访问,在一个非常大的数据里面做随机访问,描述属性是怎么做到的?总的来说,及时随机实时的随机的读写,解决可扩展性的问题,不是像关系型数据库的做法。
2.展开关系型数据库的表,存在几个问题
考虑在一个集群内部把数据分开存储要如何做。强调的是关系型不支持 SQL,SQL 中 S 最为重要考虑的是结构化。表内所有数据具有相同的列是特点,表与表通过外键关系存储关联,关系型数据库最重要的是结构化的数据和表中的关联。此时存在一个问题该数据库无法存放大量数据(hadoop 思想是大量的,廉价的构建一个集群模拟超级计算机,关系型数据库很难在此机群进行展开)如果想要展开关系型数据库的表,存在几个问题:
(1)索引的建立
在不同的机器上索引如何建立?所以能按照某一值进行吗?如何保证索引的读取效率高?是在索引的基础上加上位置信息吗?在集群中如何建立。
(2)在关系型数据库内,表与表之间存在数据关联。若想从表一中寻找李明这个人在另外一个表内有好几列信息,应该将两个表存放在同一台机器上。若数据量过大,要存在同一个集群内。分别为 ab 机器但是两个机器之间进行关联比较复杂。
如果分上下部进行储存,如何保证两个表之间上半部分一定彼此关联?
所以以上的关系导致分布式存储比较困难.
3.解决
(1)特点
首先建立一张大表,此表与其他数据没有关联。表的组件可以从哈奇方式进行获得哈奇组建包括表的位置。数据放入表内,表有行和列,行列交叉。听起来与二维表没什么区别,但其实存在区别,cell 有版本号,当对 cell 中的数据进行改写时,会加入时间戳进去,比如当 cell 是1加入时间戳版本将其改变成二的时候,不是说1不存在,1还可以存在,会打一个不同的版本上去,有一个 timestamp 时间戳上去,可以存若干个版本。听起来与关系数据库有点不一样,它里面存的就是字节数组,无论是一个整数还是一个字符串,还是一张图片的一部分,在其眼里看到的全都是字节,存字节数组,每一行都有一个 key, key 是字节数组.
(2)基本想法
整个表内的所有行可以进行排序,按照 key 来进行。整个表里的组件是按什么排序呢?因为存的都是字节,所以按字节的内容进行排序。这些表在被访问的时候就要靠行的 key,也就是组件来访问,所以听起来同 key value 很像,只是value 通过若干个组件组成。可以通过访问后面的数据。
4.synopsis
每一行的列与关系数据库不同,产生了一个层次如果刚个列可以汇聚起来,叫一个列的 family 即一个列族,表明每一个列属于哪一个族,所以在引用到每一个列的时候,都有一个前缀,这个前缀就是它的列族。比如在某一列来自于这一列的列族,具体的列的名字叫 Temperature air,合起来才是完整的这一列有关就会测出来的空气值,空气污染指数,冰点等与温度相关的值的一个表,一行里面有一些是跟温度相关的,有一些是跟观测站的信息相关的,比如说观众站的 id,所以这张表的结构是这样的:画出一个表,有 ID 有 temperature,有 station 相关存在各列内容有air,可以看到在关系库数据组内的概念。
列与列进行管理时,可以动态加入列族或者动态在某一个列族里面加一列,一旦加入就意味着现在已经写进去了一些数据,在这里加一列之前写进去数据在这一点上是没有值的。此时所有列看起来与其他列相比多了一列或者少了一些列,每一行数据看起来都不太一样。等于没有严格要求你,这里面所有的行都必须要相同的点,也就是说结构化要求不严格,在讲课时,数据库的 schema 要求不是那么固定,比较灵活。加上每个数据可以存储若干个版本看到了这张表,虽然它只有表,没有表和表之间的关联,但是表比关系型数据库里的表要灵活。新的列族需要动态的添加列族。
所以 synopsis 与关系型数据库相比 Cell是有版本号和版本管理的,是可以排序的列可以在动态的去添加,根据用户的需要动态添加,而不是一张表,在定义好之后除非进到关系数据库的管理工具里面去改这张表,否则的话是改完之后,之前的基本还要考虑这一类,如果加一列,这一列必须要与为空,之前没有值,但这些在 synopsis 就很容易实现。
5. 优点
由此以后产生了一个巨大的优点。 里面是只有一张非常大的一张表是线性表,张表里有很多的行,没有说要和另外一张表建立关联,世界里没有这样的东西,意味着这张表看起来就是线性的,一行一行堆积的局势不存在不好去切分的问题,所以可以自动将其切成若干块。可以做水平方向的划分,也就是把一个 HBase 切分成若干块,每一块都包含这表里面的所有的行的子集,每一块可以用把信息记录到类似于文件分区表的地方,此张表分了多少个 region,哪一个region 的起始行是在哪里,终止行在哪里。用 key 切分切分完成后得到发这样的信息,把这些信息记录到原数据里面,未来别人在查找数据库的时候,就可以根据元数据快速的定位到包含这一条要找的数据的 region 在哪一个机器上,一开始创建的一张表默认是由一个 region 构成。不断的插入尺寸变大之后会自动的做水平划分会产生新的region,但是尺寸的真正大小只要超过了配置的法制,就自动的去产生新的 region。划分 Region 有类似相等的尺寸,一个 region 放不下了,切两半,两半大体上一样多,数据一样多,继续往下存发。如果说切开多个,region可以分布到一个集群里面去存储。所以一个表可以存在很多数据。可以存放在集群,分布在若干进行存储。因为没有关系存在,所以比较容易切分开。只能按照 key 去进行查找,所以记住 key 的范围便可。Key 类型是什么,id 能达到效果吗?
6.Locking
切分完之后存储,存储完成之后一般来说建议在 hadoop 使用数据的时候,数据应该是一次写入多次读取,但是不排斥这个行,可以更新。
更新的时候会告诉更新是原子性的,这里面包含很多列,列组,每一个列组里面有若干列,更新的时候一定是把整个一行的内容全写,不会把前三个列更新下,后两个还没更新就被提交,要么全部更新,要么都更新。不行就不管。这一行是有多少个列构成,在更新的时候,是原子性要把整个的全部都写进去,这样做可以让这个加锁的机制变得简单,在更新这一行的时候就锁住整个这一行,其他行不动,此时可以看出,若深究。比关联性数据库管理弱,为了解决此问题,提出一个名字叫 perwlator 的机制做一个类似于在 HBase 上的管理。从前讲过,若想了解可以自行查看。
7.Get Started with HBase
需要单独下载修改环境。支持的 jk 版本是1.8.0_112版本过高或许会不支持,在配置文件内需要写入下面的信息:
使用命令:The bin/start-hbase.sh script is provied as a convenient way to start HBase
跑起来后就会看到下面的内容:
需要注意的是在下载时 hBase 有专门的包没有进入 hadoop 内,需要专门进行下载,部署跑起来,跑起来之后在控制台里就能看到内容,演示的跑起来只有一台服务器能在里面看到状态,现在是让只对着的数据分多少块,只有一个写进去的一个文件。
查看代码操作:
Create 创建一个表内列组,含一个表的信息.
查看表的原数据输出下面的内容。插入时只含有一行1 row:
向表中插入内容已有 test 用 put 来插入写入一行 row1,这行有一个 cf 列,值是 value1。以此类推。在此例子可以看到,虽然都像 test 内部插入,但三列的内容是不同的。并不要求所有的行具有相同列,列是可以不同的。
此时正在扫描全表,上一步插入三行会产生这样的结果三列是什么样的,时间戳。Timestamp,值 value,按顺序插入时间戳在增加。
获取里面的某一行。在获取第一行的主键,将第一行的内容获取.
Disable 的意思是将词表禁用表。不是删除,是禁用,暂时没有办法从里面获取值,打开后可以再次操作。
Drop:删除
跑起来后与hdfs操作很相像,有 master,有若干个 regionserver 储存,如果将 region 类比于 HDFS 内的 black, 类比于datanode,master 类比于 namenode,在。
Master 内存取原数据会存在比如 region1,起始行号是多少,最终行号是多少?test2其实行号中的行号是多少?以此类推,将所有表中信息存入深究,会发现表内容多,此表叫做 metadata。还有一个关于 metadata 的表,表较长,有1 gb,metadata 将切成10个 region,记录10条记录,Meta data 第一块起始行号与终止行号存在哪一个机器上,1~10块储存位置,每次用户来访问寻找 test 信息,从此信息找元数据在哪,寻找存储数据在哪一排。此表可以理解为原数据的元数据。显然此文件是所有用户进入入口都需要访问的。有可能成为系统的瓶颈。所以此文件不允许上锁,用户大部分在此进行操作。当用户发生变化,master 进行处理重排序或其他处理速度较快,所以应避免成为瓶颈。
透过这两方可以看出,分布式系统作词文件都有相同思路,有一个唯一路口做管理,其他实际上进行承载业务节点。会对业务接点进行管理真正储存数据,分层,上面是 hbase,当文件需要被管理时 hbase 也是在做这样一套管理。
8.代码
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class HBaseTest
/获取配置信息
public static Configuration conf;
static{
conf HBaseConfiguration.create();
每一个方法都有相应的动作,判断一张表是否存在创建表?在创建表里面分别有创建列族,判断表是否存在,创建表的动作,删除多行数据。删除所有扫描表的数据,扫描全表。遍历数据。获取一行,创建删除等。每次不能执行相同代码,否则会报错。注释掉便不会报错。
删除行和所有动作完成:
扫描出现表内容:一行已经被获取完成
拿出表时发现抛出异常,只需要注释掉一些行即可,可以每次只打开一行查看运行效果。
二.代码
1.判断一张表是否存在
public static boolean isExist(String tableName){
/对表操作需要使用 HbaseAdmin
try
Connection connection ConnectionFactory.createConnection(conf)
/管理表
HBaseAdmin admin =(HBaseAdmin)connection.getAdmin()
return admin.tableExists(TableName.valueOf(tableName))
catch(IOException e){
e.printStackTrace();
}
return false;
产生一个配置,利用配置到表的连接,与用 jdbc 访问数据库很相像。判断一个表是否存在先创建文件获取 admin拿到 admin 后才能对表进行管理检查表是否存在,获取表的名字填入括号内,此例子中是将它转成 tablename。这个值会返回一个布尔值,会告诉你此表是否存在。
2. 在 hbase 创建表
获取一个连接,就像在 jdbc 上获取 session。调用刚才的判断表是否存在若存在输入表明若不存在告诉表的具体名称生成表的描述器,表的描述器中存在表的名称列族,将描述服添加进入表的描述增加列足注意到此中使用的是可变长类型放进列足时可以用逗号风格任意长度,任意多个元素可以表示传进去的 column family 数量可以有任意多个无论如何做 column family 中所有内容全部丢掉遍历 column family 中元素循环从此开始。可变长逻辑遍历器中的每一个,每一个都放入拿描述信息创建一个表包含了指定的列族。
public static void createTable(String tableName,String...columnfamily)(
try{
/对表操作需要使用 HbaseAdmin
Connection connection ConnectionFactory.createConnection(con)
/管理表
HBaseAdmin admin =(HBaseAdmin)connection.getAdmin()
//.表如果存在,请输入其他表名
if(isExist(tableName)){
System.out.printin("表存在,请输入其他表名")
}elsef
//.注意:创建表的话,需要创建一个描述器
HTableDescriptor htd new HTableDescriptor(TableName.valueOf(tableName));
//3.创建列族
for(String cf:columnfamily){
htd.addFamily(new HColumnDescriptor(cf))
//4.创建表
admin.createTable(htd)
System.out.printin("表已经创建成功!")}
catch (IOException e){
e.printStackTrace();}
}
3. 删除 hbase 的表
删除一个表其他的代码相同先进行 disable,然后进行 delete 删除比较简单。
public static void deleteTable(String tableName){
try{
/对表操作需要使用 HbaseAdmin
Connection connection ConnectionFactory.createConnection(conf)
/管理表
HBaseAdmin admin =(HBaseAdmin)connection.getAdmin();
/1.表如果存在,请输入其他表名
if (lisExist(tableName)){
System.out.println("表不存在")
}else
/2.如果表存在,删除
admin.disableTable(TableName.valueOf(tableName))
admin.deleteTable(TableName.valueOf(tableName))
System.out.println("表删除了")
}catch (IOException e){
e.printStackTrace();}
}
4. 添加数据 put'user,'rowkey','info:name',tony'
插入数据需要获取一个链接需要往表里进行插入,所以现在连接内获取表获取表时,若表不存在若存在开始put放入数据 Put 先把第一个行的主键放入之后加入后续指定的各个列的数据某一列族的某一列的指定数据在此列读内对此列进行操作的值此时就将表中插入一行列族列云菊全部清楚相当于一次性插入表的一列.
public static void addRow(String tableName,String rowkey,String cf,String column,String value){
try{
/对表操作需要使用 HbaseAdmin
--Connection connection ConnectionFactory.createConnection(con/);
Table t=connection.getTable(TableName.valueOf(tableName));
/1.表如果存在,请输入其他表名
if(!isExist(tableName)){
System.out.println("表不存在")月
}else
/2.用 put 方式加入数据
Put p new Put(Bytes.toBytes(rowkey))
/3.加入数据
p.addColumn(Bytes.toBytes(cf),Bytes.toBytes(column),Bytes.toBytes(value))
t.put(p);
}
catch (IOException e){
e.printStackTrace();
}
}
5.删除表中一行数据
public static void deleteRow(String tableName String rowkey,String cf){
try{
/对表操作需要使用 HbaseAdmin
Connection connection=ConnectionFactory.createConnection(conf);
Table t=connection.getTable(TableName.valueOf(tableName));
//.表如果存在,请输入其他表名
if (!isExist(tableName)){
System.out.println("表不存在")
}else{
//.根据 rowkeyl 删除数据
Delete delete new Delete(Bytes.toBytes(rowkey));
/2.删除
t.delete(delete);
System.out.println("删除成功");
catch (IOException e){
e.printStackTrace();}
}
删除一行是指将 table 中指定的一行进行删除前面是相同的获取表,对表进行操作下面进行 delete 创建 delete对象,表示把某一行进行删除在 t 表中的 delete 定义 delete 将内容删掉删掉时是删掉的指定的参数最后将指定的一行全部删掉。
6.删除多行数据
public static void deleteAl(String tableName,String...rowkeys){
try{
/对表操作需要使用 HbaseAdmin
Connection connection ConnectionFactory.createConnection(conf)
Table t=connection.getTable(TableName.valueOf(tableName))
/1.表如果存在,请输入其他表名
if (!isExist(tableName)){
System.out.println("表不存在"):
}else{
/1.把 delete 封装到集合
List<Delete>list new ArrayList<Delete>();
/2.遍历
for(String row:rowkeys)
Delete d=new Delete(Bytes.toBytes(row))
list.add(d)
}
t.delete(list)
System.out.println("删除成功")
catch (IOException e){
e.printStackTrace()
Delete all 稍微复杂一些,是在遍历表中的所有内容,遍历表中所有的 key,每得到一个表新创建一个 delete对象,将其融入数组里整个 delete 掉删除.
7.扫描表数据 scan 全表扫描
public static void scanA(String tableName)(
try{
/对表操作需要使用 HbaseAdmin
Connection connection ConnectionFactory.createConnection(conA);
Table t=connection.getTable(TableName.valueOf(tableName))
/1.实例 scan
Scan s=new Scan();
/2.拿到 Scanner 对象
ResultScanner rs =t.getScanner(s)
//3.遍历
for (Result r:rs)(
Cell[]cells=r.rawCells();
/遍历具体数据
for (Cell c:cells){
System.out.print("行键为:"+Bytes..toString(CellUtil.cloneRow(c))+""):
System.out.print("列族为:"+Bytes..toString(CellUtil..cloneFamily(c)+""):
System.out.print('列名为:"+Bytes.toString(CellUtil.cloneQualifier(c))+""):
System.out.printIn(":"+Bytes.toString(CellUtil.cloneValue(c)))
catch (IOException e){
e.printStackTrace();
扫描全表是将表中内容全部拿出,前面内容不再赘述,下面需要得到一个扫描器西安创建一个 scan 的实例,用scan的在此表上拿到扫描器对扫描器进行遍历,每一次遍历出来一个结果对应一个 cell 遍历出来一行一行,每一列是一个cell,对 cell 列表内的每一个 cell 进行输出获取行的键列族列名和值将此表的行进行扫描一遍,完成
8.获取一行表数据
public static void getRow(String tableName,String rowkey)throws IOException
Connection connection ConnectionFactory.createConnection(conf);
/拿到表对象
Table t=connection.getTable(TableName.valueOf(tableName));
/1.扫描指定数据需要实例对象 Get
Get get new Get(Bytes.toBytes(rowkey))
/2.可加过滤条件
get.addFamily(Bytes.toBytes("info"));
Result rs =t.get(get);
/3.遍历
Cell[]cells=rs.rawCells();
for (Cell c:cells){
System.out.print("行键为:"+Bytes.toString(CellUtil..cloneRow(cl)+"")月
System.out.print("列族为:"+Bytes.toString(CelIUtil..cloneFamily(cl)+"")
System.out.print(":"+Bytes.toString(CellUtil.cloneQualifier(c))+"");
System.out.println(":"+Bytes.toString(CellUtil.cloneRow(c))+"");}
}
可以获取一列,自然也可以获取一行数据使用 get 类似于按照主键进行查找得到了获取 info 的列族内容,一旦执行完成就返回一个 cell 集合与前面类似。
public static void main(String[]args)throws IOException
System.out.println(isExist("test"));
createTable("test","info");
deleteTable("test");
addRow("test","101","info","age","20");
deleteRow("test","101","info");
deleteAll("test","1001,"1002");
scanAll("test");
getRow("test","101");
}
}
从此可以看出,即使 hbase 与 sql 操作差距较大。总结出他的系统里有一张大表不存在表与表之间的概念不要求表中所有行的列完全相同完全可以不同每一个 cell 都有版本,123不同的版本与关系表不同,因为是线性表,从中间任意切开都很容易实现这就是 hbase 的一个作用。
三.HBase 与关系型数据库差异
1.差异
Hbase 的 schema 不要求完全相同,关系型数据库里的 scheme 是固定的,所有数据全部一样。
其次,关系型数据库按照行存储。Hbase 按照列进行存储。上节课在讲解 spark 时提到列式存储的含义。列式存储优点是强调对一列全部进行扫描快速,列式扫描对 scan 操作非常适合。想要获取一列或者一列族内容比较快速,因为是列式存储。行式存储是对关系型数据库操作支持较好,所以非常适合 OLtp。hbase 适合 olap 是在处理事务型数据,在做统计订单总量的分析,这是他们两个的差异.关系型数据库是固定模式,按行存储。hbase 是 spark 灵活的,按列存储这是不同适应的场景不同。
2. 为什么 hbase 较好
是因为关系型数据库随着业务的增长,可扩展性所面临的问题变大。查看下面的例子。写电子书店刚开始发布。使用本地工作证。可以跑。复杂时迁移到远程机器。跑入实力。里面的数据全部是定义完成的,可以更改。业务变得流行时有很多读进行操作,因为用户增多,加入 memcached 缓存,增加内存命中率减少 lo。加入缓存可以个观察到一部分缓存,一部分在数据库内事务管理的麻烦及到数据同步的问题,缓存内容与数据库内容需要完全一致。若不一致比较麻烦。为了支持高并发的事务,便不再严格要求一致。但是缓存的需要有一定的过期,允许不一致。但程度不能特别高。在数据库中加入过期会告知数据过期的时长,数据差异较大必须同步,会发现此时如何写操作都存在比较多,解决方法是将机器的性能变高,内存增加比较费钱。继续执行会发现用户的操作会变得复杂。涉及到很多连接操作。只能按照在数据库课程上学到的,按照一定范围,按照范式。范式化程度过高,没有溶于。降低范式化程度数据库中带入大量溶于缺点是有溶于要减少溶于同步。
优点:减少连接操作,直接在一张表里就包含了需要的所有数据,所以连接操作不再需要。
接下来会发现所有请求到达服务器端时很慢。大量请求到达服务器端,需要通过大量工具将数据推到客户服务器减少压力,到达这一步时,系统还是过慢的,原因是有很多查询请求需要去扫描全表,将复杂查询进行周期性处理,用户访问时将处理结果直接返回。每次做现场动作,读操作可以进行写操作变得缓慢。因为写操作需要加锁,与数据量有关。写进去后还要重新整理索引,索引还需调整。如何解决将所有无用的索引全部丢掉或者不启用索引,会发现在关系型数据库内所碰到的问题,随着系统会变得复杂,很难处理,使用 hbase 这些问题是否还会存在。
3. hbase 是否存在问题
(1)在 hbase 内没有索引,证明影响是在写入数据时,速度不会像上面所述到达一定程度变得缓慢.
(2)当尺寸到达预设尺寸时,自动被分成两块。不断的自动进行分区
(3)没有表与表之间的关联可以自动分离,几乎接近于线性的。只要增加新的节点进入就可以马上利用将数据存入新的节点,所有节点基本一样多。一个 region 写满后会一分为二,分别放入不同的服务器内
(4)构建于 hdfs 上不需要过强的服务器,数据存储在大堆的廉价机器上,在一个集群里可以通过并行的方式提高数据处理速度不需要很大的服务器。
(5)有容错。自身可以依靠到 hdfs 的容错机制,让数据存储多个部分,提高存储效率。容错能力变强
(6)批处理如果数据在多个机器上操作,可以开启并行。可以利用 mr 框架在机器上并行操作。
这就是 hbase,会学到 mysql,morgodb(nosql代表),hbase 都来源于 b.gtable,基本想法单个表做线性存储