Hbase
Hbase 基本概念
常用术语
namespace:类似于关系型数据库的databases的概念(默认两个空间hbase default)
region:按行切分的数据(根据 row_key )
Row:一个rowkey(字典顺序)和多个column组成 全表扫描、
column:列簇+列限定符(列名)
时间戳:除了版本和value,其他东西必须相同(列簇,列名)
cell:row_key,列簇,列名,时间戳就能确定唯一的单元
ZK:作为读写数据交互
Hlog 记录操作的日志,类似于hdfs的edits文件,实时落盘
Mem Store : 内存存储(内存到磁盘 flush)
StoreFile:Hfile(存储格式类似 parquet) 磁盘存储
hbase节点功能
Region Server(管理数据) Region Server(region(store))
1.splitRegion compactRegion 切分和合并
2.get put delete
master (管理表)
1.create delete alter list desc
2.Region Server (负载均衡)管理
hbase 自带高可用(可以起来多master,争抢ZK中的资源,谁拿到谁是主节点)
hbase存储的稀疏性:
物理存储的时候:一列一列存储
row_key,列簇,列,时间戳(版本的概念,时间戳最大的版本),type(put delete 数据是否删除),value
KeyValue内容:rowlength(key长度)row(key值)columnfamilylength(列簇长度)
columnfamily(列簇值)columnqualifier(列名)timestamp(时间戳)keytype(类型)
列簇:将数据分为不同的文件夹,建表的时候只要列簇,不需要列类型,字节数组
hbase shell -m -f /hbase/data/bigdata/student/info/hfile名
常用命令
备份命令
hbase shell hbase.sql
flush 'student' //内存文件刷到磁盘,当前内存相同row_key的数据会删除,
删除标记会在(不确定这个标记作用于其他文件),保存到大合并
compact 'student' //手动触发合并文件
数据存储路径:/Hbase/data/命名空间/表名/region名称/列簇/
表操作
list 显示所有用户表
create 'student','info','info1' 创建表
create 'test2', { NAME => 'cf2', COMPRESSION => 'SNAPPY' }
create 'mytable',{NAME=>'cf',BLOCKCACHE=>'false'}
desc 'student' 描述用户表
alter 'student','{name=>'info',VERSION=>3}' 更改表的结构
disable 'student';drop 'student' 删除表
truncate 'bigdata.student' //清空表
count '<tablename>', CACHE => 1000
hbase org.apache.hadoop.hbase.mapreduce.RowCounter 'table' /var/log/hbase/hbase.log
命名空间操作
list_namespace //显示命名空间
create_namespace 'bigdata' //创建命名空间
create 'bigdata.student','info' //在固定命名空间下创建表
drop_namespace 'bigdata' //表必须是空的才能删除命名空间
数据操作
put 'bigdata.student','row_key','info:name','zhangsan' //数据增加,修改
get 'bigdata.student','row_key' //数据查询
get 'bigdata.student','row_key','info' //数据查询
get 'bigdata.student','row_key','info:name' //数据查询
get 'student','row_key',{COLUMN=>'info:name',VERSION=3} //多版本
scan 'bigdata.student',{LIMIT=>10} //扫描全表 limit扫描
scan 'bigdata.student',{STARTROW=>'1003',STOPROW=>'1003'} //规则扫描
scan 'bigdata.student',{RAW=true,VERSION=10} //删除的数据也能看到
delete 'bigdata.student','row_key','info:name' //数据删除
deleteall 'bigdata.student','row_key' //删除row_key
列簇操作
删除的时候,传递大的时间戳,就可以删除当前时间
alter 'bigdata.student',{NAME=>'f1',VERSION=>3} //修改列簇
alter 'bigdata.student',{NAME=>'f1',METHOD=>'delete'} //删除列簇
alter 'bigdata.student','delete'=>'f1' //删除列簇
alter 'student',{NAME=>'info',VERSION=3}//更改多版本 三个版本
hbase 流程解释
写流程(读比写慢)(meta表可以切分)
1.客户端连接ZK,找到meta表所在的RegionServer(表的元数据信息) (2.3更新了一种方式连接master)
2.连接返回的RegionServer,请求meta表,找到student对应的RegionServer。(缓存元数据)
3.请求2返回的 RegionServer 。先写WAL,在写Mem Store(自动排序)。
源码:构建wal,添加到上一次wal但是不同步,写内存。在同步wal。如果同步失败,就删除内存中数据。
scan 'hbase:meta' //hbase元数据存储
读流程
1.客户端连接ZK,找到meta表所在的RegionServer(表的元数据信息) (2.3更新了一种方式连接master)
2.连接返回的RegionServer,请求meta表,找到student对应的RegionServer。(缓存元数据)
3.请求2返回的 RegionServer ,BlockCache(内部存在文件信息),写内存和磁盘同时读取,最后merge,看时间戳。
BlockCache缓存磁盘读取的数据。只是缓存了一个文件的数据。别的文件没有缓存。
BlockCache中优先缓存索引文件,布隆过滤器,key值(元数据)。剩余内存按照64K块进行缓存,清理的时候清理块数据
region 拆分
1.将需要拆分的 Region下线,阻止所有对该 Region 的客户端请求,Master 会检测到 Region 的状态为 SPLITTING。(ZK)
2.将一个 Region 拆分成两个子 Region,先在父 Region下建立两个引用文件,分别指向 Region 的首行和末行,
这时两个引用文件并不会从父 Region 中复制数据。
3.之后在 HDFS 上建立两个子 Region 的目录,分别复制上一步建立的引用文件,
每个子 Region 分别占父 Region 的一半数据。复制登录完成后删除两个引用文件。
4.完成子 Region 创建后,向 Meta 表发送新产生的 Region 的元数据信息。
5.将 Region 的拆分信息更新到 HMaster,并且每个 Region 进入可用状态。
hbase 可配参数
Mem Store 参数
1.hbase.regionserver.global.memstore.size(所有memstore相加)//会阻塞读写 最大内存0.4 +hfile.block.cache.size <0.8
2.hbase.regionserver.global.memstore.size.lower.limit //不阻塞读写 1结果*0.95
3.hbase.regionserver.optionalcacheflushinterval(一小时刷新一次)//当前内存最后一次更改时间
4.hbase.hregion.memstore.flush.size(128M) 单个region 达到128M
hbase.hregion.memstore.block.multiplier=4*128的时候 阻止继续写数据
数据合并参数
Mintor Compactior:小的文件进行合并,删除部分过期和删除的数据
Major Compactior:不管大文件还是小文件,都合并成一个。删除数据
小合并参数:
hbase.hstore.compaction.ration=1.2合并文件选择算法中使用的比率
hbase.hstore.compaction.min=3 至少需要三个满足条件的 store file 时,minor compaction 才会启动
hbase.hstore.compaction.max=10 一次 minor compaction 中最多选取 10 个 store file
hbase.hstore.compaction.min.size=128M 文件大小小于该值的 store file 一定会加入到 minor compaction
hbase.hstore.compaction.max.size=LONG.max 文件大于该值 不会加入到 minor compaction
1.过小合并,过大不合并。文件大小/比例<剩余文件大小 则合并。每3-10个合并一次
大合并:
hbase.hregion.majorcompaction=0 大合并
hbase.hstore.compactionThreshold=3 文件超过3个,文件合并
切分数据 参数
只有一个region:2*hbase.hregion.memstore.flush.size
否则按照 hbase.hregion.max.filesize=10G//文件大小 切分
hbase 优化
优化参数
预分区:create 'student','info',SPLITS=>['1000','2000','3000','4000'] //四刀 五个分区
row_key设计:散列,唯一,长度限制 散列:随机数,hash,字符串反转(9999-当前值)、字符串拼接
alter 'table',{NAME =>'info',TTL => '86400'} //设置过期时间,默认永久存储
major_compact 'table' //数据进行合并
电话号码row_key设计:
(手机*年月)%299 确定分区节点机器 分区机器节点_手机号码_年月_
dfs.support.append=true //允许hdfs append 数据删除
dfs.datanode.max.transfer.threads=4096 //hbase刷写的时候 打开大量的文件
dfs.image.max.transfer.timeout=60*1000 //增加等待时长
mapreduce.map.output.compress mapreduce.map.output.compress.codec //压缩相关数据
hbase.regionserver.handler.count=30 //读写请求多的时候增加这个参数
(0单个共享队列,1表示每个处理程序一个队列,队列的数量与处理程序的数量成比例地分配)
hbase.ipc.server.num.callqueue 队列的数量
hbase.ipc.server.callqueue.read.ratio 调用队列拆分为读取和写入队列 <0.5读多于写 >0.5写多于读
hbase.ipc.server.callqueue.scan.ratio 将读取调用队列拆分为小读取和长读取队列 <0.5更多短读 >0.5更多长读
禁用 Nagle 算法。延迟的 ACK 最多可以使 RPC 往返时间增加约 200 毫秒:
ipc.server.tcpnodelay = true;ipc.client.tcpnodelay = true;
hbase.ipc.client.tcpnodelay = true;hbase.ipc.server.tcpnodelay = true;
路径校验:
dfs.client.read.shortcircuit = true;dfs.client.read.shortcircuit.skip.checksum = true;
数据本地性:hbase.hstore.min.locality.to.skip.major.compact = 0.7 意味着 0.7 <= n <= 1
DataNode 有足够的处理程序用于块传输:
dfs.datanode.max.xcievers >= 8192
dfs.datanode.handler.count =锭数
hbase.regionserver.max.filesize=30 //切分的最大的大小,一个region是一个map
hbase.client.write.buffer=2M //写数据的缓存大小
hbase.client.scanner.caching //读缓存 一次拉取的数据大小行数
hfile.block.cache.size=0.4 读取请求比较多,可以适当调大 +hbase.regionserver.global.memstore.size<0.8
hfile.regionserver.global.memstore.size=0.4 写取请求比较多,可以适当调大 //两个值相加<80
WAL 文件的大小和数量
HDFS64M=>WAL60M,数量:16Gb*0.4/60M=109个
region拆分:
hbase.hregion.max.filesize 大小就进行拆分
org.apache.hadoop.hbase.regionserver.DisabledRegionSplitPolicy 禁用自动拆分
每台服务器的 10 个预分割区域
任务推测:最好关闭:mapreduce.map.speculative、mapreduce.reduce.speculative为 false
开启缓存:hfile.block.cache.size
JVM监控:
<property><name>hbase.coprocessor.regionserver.classes</name>
<value>org.apache.hadoop.hbase.JMXListener</value></property>
使用经验
(1)Region 大小控制在10-50G
(2)cell不能超过10M(对于小于100K的数据有优化),mob(Medium-sized Objects对象存储)不超过50M
(3)1-3个列簇,最好就是一个。最好保证不同时读取多个列簇
(4)50-100 Region (memstore 相应的增多)
(5)列簇,列名 尽量短 不要参考mysql
(6)不进行预分区的话,尽量增多Region数量
(7)写内存不会占用太多的内存,分配资源的时候可以适当缩减
尽量保持 ColumnFamily 名称尽可能小,最好是一个字符(例如,“d”代表数据/默认值)。
例如,对于 16Gb RS 堆、默认 memstore 设置 (0.4) 和默认 WAL 文件大小 (~60Mb),16Gb*0.4/60M,WAL 文件计数的起点是~109。
hbase-site.xml hbase.block.data.cachecompressed=true
hbase.ipc.server.callqueue.read.ratio 0.3 读多于写
hbase.ipc.server.callqueue.scan.ratio 0.3 更多短读操作
hbase.regionserver.global.memstore.size 0.3 分配资源的0.3用于写
hbase.regionserver.handler.count=60 hbase链接
hfile.block.cache.size 0.6 分配资源的0.6用于读
HBASE_HEAPSIZE=机器的一半资源
Phoenix
!table 显示所有的表 (表名和列名默认大写 小写的话 "aa" 大小写区分)
可以创建组合的key(联合主键)。
列族和列名最后默认会被转换成数字(数字对应关系)
upsert into table values()
Phoenix里面不能看到hbase
可以通过映射关系映射过去 表名列名一致 create view "aa"(id varchar primary key) 只读
表映射 create table "aa"(id varchar primary key) column_rncoded_bytes=0; 可读写
hbase底层补码,Bytes.toBytes(1000)//hbase 存储的时候这样存储
数字存储有问题,create view "aa"(id varchar primary key,info number unsigned_long)
索引:全局索引、包含索引、本地索引
全局索引(新建一张表,索引数据和表存储在不同的表中,多读少写,修改数据的时候写两张表)
create index my_index on student(age) 。使用的时候必须全部字段都在select后面
包含索引(携带其他字段的全局索引,本质还是全局索引,存储了一条记录)
create index my_index on student(age) include(address)
本地索引(创建的索引和数据在一张表里面,同一个region,写多读少)
create local index my_index on student(age,address)
hbase spark集成
集成命令
spark-shell --jars "/usr/lib/hbase/lib/activation-1.1.jar,*.jar" --conf spark.serializer=org.apache.spark.serializer.KryoSerializer
nohup hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /data/hbase student 2>&1 &
spark代码
import org.apache.hadoop.hbase.KeyValue
import org.apache.hadoop.hbase.util.Bytes
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2
val cf: Array[Byte] = "info".getBytes //列族
val sex: Array[Byte] = "sex".getBytes //列
val age: Array[Byte] = "age".getBytes //列
val vip: Array[Byte] = "vip".getBytes //列
val namedf = spark.sql("select 1 as name,1 as sex,1 as age,1 as vip union all"
+" select 2 as name,2 as sex,2 as age,2 as vip").
select("name","sex","age","vip").rdd.map(x=>{
val data = Array(
new KeyValue(Bytes.toBytes(x.apply(0).toString), cf, sex,Bytes.toBytes(x.apply(1).toString)),
new KeyValue(Bytes.toBytes(x.apply(0).toString), cf, age,Bytes.toBytes(x.apply(2).toString)),
new KeyValue(Bytes.toBytes(x.apply(0).toString), cf, vip,Bytes.toBytes(x.apply(3).toString))
)
(new ImmutableBytesWritable(Bytes.toBytes(x.apply(0).toString)),data)
}).flatMapValues(x => x.iterator).sortBy(x => (x._1), true).saveAsNewAPIHadoopFile("/data/hbase",
classOf[ImmutableBytesWritable],
classOf[KeyValue],
classOf[HFileOutputFormat2])
最终使用进行调解的参数:
hbase.regionserver.global.memstore.size+hfile.block.cache.size <0.8
hbase.ipc.server.callqueue.read.ratio 0.3
hbase.ipc.server.callqueue.scan.ratio 0.3
hbase.regionserver.global.memstore.size 0.3
hbase.regionserver.handler.count=60
hfile.block.cache.size 0.5
搬砖多年终不得要领,遂载源码看之望得真经。