sqoop 总结
1. HBase 介绍
-
分布式、面向列开源数据库
-
Big Table开源实现
-
适合非结构化数据的存储
-
PB级别数据
-
可以支撑在线业务
-
分布式系统特点 :易于扩展,支持动态伸缩,并发数据处理
2. 面向列数据库
2.1 HBase 与 传统关系数据库的区别
HBase | 关系型数据库 | |
---|---|---|
数据库大小 | PB级别 | GB TB |
数据类型 | Bytes | 丰富的数据类型 |
事务支持 | ACID只支持单个Row级别 | 全面的ACID支持, 对Row和表 |
索引 | 只支持Row-key | 支持 |
吞吐量 | 百万写入/秒 | 数千写入/秒 |
- 关系型数据库中数据示例
ID | FILE NAME | FILE PATH | FILE TYPE | FILE SIZE | CREATOR |
---|---|---|---|---|---|
1 | file1.txt | /home | txt | 1024 | tom |
2 | file2.txt | /home/pics | jpg | 5032 | jerry |
- 同样数据保存到列式数据库中 列族:列标识符:值
RowKey | FILE INFO | SAVE INFO |
---|---|---|
1 | file_info:name:file1.txt file_info:type:txt file_info:size:1024 | path:/home/pics creator:Jerry |
2 | file_info:name:file2.jpg file_info:type:jpg file_info:size:5032 | path:/home creator:Tom |
- 行数据库&列数据库存储方式比较
-
关系型数据库:行式存储 每一行数据都是连续的 所有的记录都放到一个连续的存储空间中
-
列数据库: 列式存储 每一列对应一个文件 不同列并不对应连续的存储空间
-
结构化数据 V.S. 非结构化数据
- 结构化数据
- 预定义的数据模型 模型一旦确定不会经常变化(表结构不会频繁调整)
- 非结构化数据
- 没有预定义数据模型
- 模型不规则 不完整
- 文本 图片 视频 音频
- 结构化数据
2.2 Hive 和 Hbase区别
- hive hbase 共同点
- 都可以处理海量数据
- 文件都是保存到hdfs上
- hive 和 hbase不同
- hbase计算不是通过mapreduce实现的 自己实现的CRUD(增删改查)功能
- hive 通过mapreduce实现 数据查询的
- hbase 可以有集群 集群的管理是通过zookeeper实现
- hive 只能做离线计算
- hbase 提供对数据的随机实时读/写访问功能
- HBase 对事务的支持 只支持行级别的事务
- CAP定理
- C consistency 一致性 所有节点在同一时间具有相同的数据
- A availability 可用性 保证每个请求不管成功或失败都有响应,但不保证获取的数据的正确性
- P partition tolerance 分区容错性 系统中任意信息的丢失或失败不会影响系统的运行,
- 分区容错性 分布式系统都要有的特性,任何时候都要能提供服务 P保证
- HBase CP系统 强一致性
2.3 Hbase 和 传统关系型数据库区别
-
创建HBase表的时候只需要指定表名 和 列族
-
每一个行当中 只需要列族相同就可以了 至于每个列族中的 key:value key可以完全不同
3. Hbase 数据模型
- NameSpace 对应 关系型数据库 database
- 表(table):用于存储管理数据,具有稀疏的、面向列的特点。
- 行 (row): 每一行都对应一个row key 行键 Hbase有索引但是只是在行键 rowkey有索引
- 列 Column family 和 Column qualifier 组成
- 列族(Column Family)保存的就是 键值对集合 key:value
- 列修饰符(Column Qualifier) 就是key 对应关系型数据库的列
- 时间戳(TimeStamp):是列的一个属性
- 区域(Region):HBase自动把表水平划分成的多个区域,划分的区域随着数据的增大而增多。
- Hbase支持对行级别的 操作保证完全的 ACID
- A 原子性 整个事务中的所有操作,要么全部完成,要么全部不完成
- C 一致性 事物必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少
- I 隔离性 串行化或者序列化 隔离状态执行事务
- D 持久性 事务完成后,事务对数据库所做的更改持久保存在数据库中,不会回滚
4. HBase 基础架构
-
Client
- 与Zookeeper 通信
- Client与HMaster进行通信进行管理类操作;
- Client与HRegionServer进行数据读写类操作。
-
Zookeeper
- 保证HMaster有一个活着
- HRegionServer HMaster地址存储
- 监控Region Server状态 将Region Server信息通知HMaster
- 元数据存储
-
HMaster
- 为Region server分配region;
- 负责region server的负载均衡;
- 发现失效的region serve并重新分配其上的region;
- HDFS上的垃圾文件回收;
- 处理用户对表的增删改查操作。
-
HRegionServer
- HBase中最核心的模块,主要负责响应用户I/O请求,向HDFS文件系统中读写数据
- 维护Master分配给它的region,处理对这些region的IO请求
- HRegionServer管理一系列HRegion对象
-
HRegion
- 一个表最开始存储的时候,是一个region
- 一个Region中会有个多个store,每个store用来存储一个列簇。
- region会随着插入的数据越来越多,会进行拆分。默认大小是10G一个
-
HStore
- HBase存储的核心,由MemStore和StoreFile组成。
- 每一个column family 对应了一个HStore
- 用户写入数据的流程为:client访问ZK, ZK返回RegionServer地址-> client访问RegionServer写入数据 -> 数据存入MemStore,一直到MemStore满 -> Flush成StoreFile
-
HLog
在分布式系统环境中,无法避免系统出错或者宕机,一旦HRegionServer意外退出,MemStore中的内存数据就会丢失,引入HLog就是防止这种情况。
5. HBase的安装
-
下载安装包 http://archive.cloudera.com/cdh5/cdh/5/hbase-1.2.0-cdh5.7.0.tar.gz
-
配置伪分布式环境
-
环境变量配置
export HBASE_HOME=/usr/local/development/hbase-1.2.4 export PATH=$HBASE_HOME/bin:$PATH
-
配置hbase-env.sh
export JAVA_HOME=/usr/local/development/jdk1.7.0_15 export HBASE_MANAGES_ZK=false --如果你是使用hbase自带的zookeeper就是true,如果使用自己的zk就是false
-
配置hbase-site.xml
<property> <name>hbase.rootdir</name> --hbase持久保存的目录 <value>hdfs://hadoop001:8020/opt/hbase</value> </property> <property> <name>hbase.cluster.distributed</name> --是否是分布式 <value>true</value> </property> <property> <name>hbase.zookeeper.property.clientPort</name> --指定要连接zk的端口 <value>2181</value> </property> <property> <name>hbase.zookeeper.property.dataDir</name> <value>/home/hadoop/app/hbase/zkData</value> </property>
-
启动hbase(启动的hbase的时候要保证hadoop集群已经启动)
/hbase/bin/start-hbase.sh
-
输入hbase shell(进入shell命令行)
-
6. HBase shell
名称 | 命令表达式 |
---|---|
创建表 | create ‘表名’, ‘列族名1’,‘列族名2’,‘列族名n’ |
添加记录 | put ‘表名’,‘行名’,‘列名:’,'值 |
查看记录 | get ‘表名’,‘行名’ |
查看表中的记录总数 | count ‘表名’ |
删除记录 | delete ‘表名’, ‘行名’,‘列名’ |
删除一张表 | 第一步 disable ‘表名’ 第二步 drop ‘表名’ |
查看所有记录 | scan “表名称” |
查看指定表指定列所有数据 | scan ‘表名’ ,{COLUMNS=>‘列族名:列名’} |
更新记录 | 重写覆盖 |
- 创建表
create 'user','base_info'
- 删除表
disable 'user'
drop 'user'
- 创建名称空间
create_namespace 'test'
- 展示现有名称空间
list_namespace
- 创建表的时候添加namespace
create 'test:user','base_info'
- 显示某个名称空间下有哪些表
list_namespace_tables 'test'
-
插入数据
put ‘表名’,‘rowkey的值’,’列族:列标识符‘,’值‘
put 'user','rowkey_10','base_info:username','Tom'
put 'user','rowkey_10','base_info:birthday','2014-07-10'
put 'user','rowkey_10','base_info:sex','1'
put 'user','rowkey_10','base_info:address','Tokyo'
put 'user','rowkey_16','base_info:username','Mike'
put 'user','rowkey_16','base_info:birthday','2014-07-10'
put 'user','rowkey_16','base_info:sex','1'
put 'user','rowkey_16','base_info:address','beijing'
- 查询表中的所有数据
scan 'user'
- 查询某个rowkey的数据
get 'user','rowkey_16'
- 查询某个列簇的数据
get 'user','rowkey_16','base_info'
get 'user','rowkey_16','base_info:username'
get 'user', 'rowkey_16', {COLUMN => ['base_info:username','base_info:sex']}
- 删除表中的数据
delete 'user', 'rowkey_16', 'base_info:username'
- 清空数据
truncate 'user'
- 操作列簇
alter 'user', NAME => 'f2'
alter 'user', 'delete' => 'f2'
- HBase 追加型数据库 会保留多个版本数据
desc 'user'
Table user is ENABLED
user
COLUMN FAMILIES DESCRIPTION
{NAME => 'base_info', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_B
HE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MI
ER => 'NONE', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOM
se', COMPRESSION => 'NONE', BLOCKCACHE => 'false', BLOCKSIZE => '65536'}
- VERSIONS=>'1’说明最多可以显示一个版本 修改数据
put 'user','rowkey_10','base_info:username','Tom'
- 指定显示多个版本
get 'user','rowkey_10',{COLUMN=>'base_info:username',VERSIONS=>2}
- 修改可以显示的版本数量
alter 'user',NAME=>'base_info',VERSIONS=>10
可以通过HbaseUi界面查看表的信息
端口60010打不开的情况,是因为hbase 1.0 以后的版本,需要自己手动配置,在文件 hbase-site
<property>
<name>hbase.master.info.port</name>
<value>60010</value>
</property>
7. HappyBase操作HBase
import happybase
hostname = '192.168.19.188'
table_name = 'users'
column_family = 'cf'
row_key = 'row_1'
conn = happybase.Connection(hostname)
def show_tables():
print('show all tables now')
tables = conn.tables()
for t in tables:
print t
def create_table(table_name, column_family):
print('create table %s' % table_name)
conn.create_table(table_name, {column_family:dict()})
def show_rows(table, row_keys=None):
if row_keys:
print('show value of row named %s' % row_keys)
if len(row_keys) == 1:
print table.row(row_keys[0])
else:
print table.rows(row_keys)
else:
print('show all row values of table named %s' % table.name)
for key, value in table.scan():
print key, value
def put_row(table, column_family, row_key, value):
print('insert one row to hbase')
# column_family:qualifier:value
# column_qualifier = name
table.put(row_key, {'%s:name' % column_family:'name_%s' % value})
def put_rows(table, column_family, row_lines=30):
print('insert rows to hbase now')
for i in range(row_lines):
put_row(table, column_family, 'row_%s' % i, i)
def delete_row(table, row_key, column_family=None, keys=None):
if keys:
print('delete keys:%s from row_key:%s' % (keys, row_key))
key_list = ['%s:%s' % (column_family, key) for key in keys]
table.delete(row_key, key_list)
else:
print('delete row(column_family:) from hbase')
table.delete(row_key)
def delete_table(table_name):
pretty_print('delete table %s now.' % table_name)
conn.delete_table(table_name, True)
def main():
table = conn.table(table_name)
show_rows(table)
put_rows(table, column_family)
show_rows(table)
# 更新操作
# put_row(table, column_family, row_key, 'xiaoh.me')
# show_rows(table, [row_key])
# 删除数据
# delete_row(table, row_key)
# show_rows(table, [row_key])
# delete_row(table, row_key, column_family, ['name'])
# show_rows(table, [row_key])
# delete_table(table_name)
if __name__ == "__main__":
main()
- 建立连接 conn = happybase.Connection(hostname)
- 创建表 conn.create_table(table_name,{column_family,dict()})
- 查看所有表 table_list = conn.tables()
- 连接表 table = conn.table(table_name)
- 查看表中数据 table.row(column_qualifier) table.rows(column_qualifiers)
- 遍历表中数据 for key,value in table.scan(): print key,value
- 插入数据 table.put(row_key,{’’%s:%s:%s’ %column_family,%column_qualifier,%value})
- 删除表中数据 table.delete(row_key,column_qualifier)
- 删除表 conn.delete_table(table_name)
8. HBase表设计
-
DDI 目的是为了克服HBase架构上的缺陷(join繁琐 只有row key索引等)
- Denormalization (反规范化, 解决join麻烦的问题)
- Duplication (数据冗余)
- Intelligent keys(通过row key设计实现 索引 排序对读写优化)
-
设计HBase表时需要注意的特点
- HBase中表的索引是通过rowkey实现的
- 在表中是通过Row key的字典顺序来对数据进行排序的, 表中Region的划分通过起始Rowkey和结束Rowkey来决定的
- 所有存储在HBase中的数据都是二进制字节, 没有数据类型
- 原子性只在行内保证, HBase表中没有多行事务
- 列族(Column Family)在表创建之前就要定义好
- **列族中的列标识(Column Qualifier)**可以在表创建后动态插入数据的时候添加
- 不同的column family保存在不同的文件中。
9. HBase表设计案例:社交应用互粉信息表
-
设计表保存应用中用户互粉的信息
- 读场景:
- 某用户都关注了哪些用户
- 用户A有没有关注用户B
- 谁关注了用户A
- 写场景
- 用户关注了某个用户
- 用户取消关注了某个用户
- 读场景:
-
设计
- 列名 user_id
- 列名 user_id
-
最终设计(DDI)
- 解决谁关注了用户A问题
- ① 设计一张新表, 里面保存某个用户和他的粉丝
- ② 在同一张表中同时记录粉丝列表的和用户关注的列表, 并通过Rowkey来区分
- 01_userid: 用户关注列表
- 02_userid: 粉丝列表
- 上两种设计方案的问题(事务)
- 解决谁关注了用户A问题
-
案例总结
- Rowkey是HBase表结构设计中很重要的环节, 直接影响到HBase的效率和性能
- HBase的表结构比传统关系型数据库更灵活, 能存储任何二进制数据,无需考虑数据类型
- 利用列标识(Column Qualifier)来存储数据
- 衡量设计好坏的简单标准 是否会全表查询