Hbase是一个分布式、可扩展、支持海量数据存储的NoSQL数据库,物理结构存储结构(K-V)。
如何在大数据场景中,做到上亿数据秒级返回。(有条件:单条数据,范围数据)
整张表会按照水平方向按照Row Key切割(Region)。再按垂直方向按ColumnFamily切割(Store),
Name Space:命名空间
Row:行
Column:列
Cell:单元
Row Key:行键
ColumnFamily:列族
TimeStamp:时间戳
下面从小到大解释上图中的各组件中的功能。
StoreFile
Store
Region
HLog
RegionServer
Master
hbase shell
help
help ‘命令‘
list_namespace
list_namespace_tables ‘命名空间名‘
create_namespace ‘命名空间名‘
drop_namespace ‘命名空间名‘
list
create ‘命名空间:表‘, ‘列族1‘, ‘列族2‘, ‘列族3‘,‘列族4‘...
如图发现有一串乱乱序文件夹,这串乱序就代表了Region号
describe ‘命名空间:表‘
可以看出VERSIONS为1,代表这个表只能存放一个版本的数据。
主要用于修改表的版本保存信息,也可以创建表的时候指定,但是shell命令复杂,故一般使用变更命令。
alter ‘命名空间:表‘,{NAME=>‘列族名‘,VERSIONS=>3}
disable ‘表‘
enable ‘表‘
delete ‘表‘
put ‘命名空间:表‘,‘RowKey‘,‘列族:列‘,‘值‘
put ‘命名空间:表‘,‘RowKey‘,‘列族:列‘,‘值‘,时间戳(版本控制)
如图发现并没有数据文件生成,因为数据在内存中,需要flush ‘表‘,而后就可以看见数据落地了。(flush一次就是生成一个StoreFile)
#全表扫描
scan ‘命名空间:表‘
#范围扫描(左闭右开)
scan ‘命名空间:表‘,{STARTROW => ‘RowKey‘,STOPROW=>‘RowKey‘}
#扫描N个版本的数据
scan ‘命名空间:表‘,{RAW=>true,VERSIONS=>10}
flush ‘命名空间:表‘
从上面知道flush一次就是生成一个StoreFile,那么数据就会根据建表保留版本个数来存储最近个数的数据。
比如:保留版本个数为2,那么如果插入v1,v2,v3三条数据,flush后,就只剩下v2,v3两条数据,这时再插入v4,v5,v6三条数据,flush后,剩下的为v2,v3,v5,v6四个版本的数据(此时是2个StoreFile文件),如果发生Region合并或者分裂,那么StoreFile文件会被合并后在放入对应的Region中,这时数据就又会根据保留版本个数删除,v2,v3,v5,v6,就变成了v5,v6。(如果没有手动flush,或者到设置的自动flush时间,那么数据不会根据版本个数删除)(默认超过3个StoreFile文件则会进行大合并)
get ‘命名空间:表‘,‘RowKey‘
get ‘命名空间:表‘,‘RowKey‘,‘列族‘
get ‘命名空间:表‘,‘RowKey‘,‘列族:列‘
#获取N个版本的数据
get ‘命名空间:表‘,‘RowKey‘,{COLUMN=>‘列族:列‘,VERSIONS=>10}
truncate ‘命名空间:表‘
#delete ‘命名空间:表‘,‘RowKey‘,‘列族‘(此命令行删除有问题,但是API可以)
delete ‘命名空间:表‘,‘RowKey‘,‘列族:列‘
deleteall ‘命名空间:表‘,‘RowKey‘
客户端缓存信息,方便下次使用
发送PUT请求到RegionServer,写操作日志(WAL),再写入内存,然后同步wal到HDFS,则结束。(此步骤由事务回滚保证日志、内存都写入成功)
在读取数据时候,MemStore和StoreFile一起读取,将StoreFile中的数据放入BlockCache,然后在将内存数据和BlockCache比较时间戳做Merge,取最新的数据返回。
由于Memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本和不同类型有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile合并。
Compaction分为Minor Compaction和Major Compaction。
Minor Compaction会将临近的若干个较小的HFile合并成一个较大的HFile,但不会清理过期和删除的数据。
Major Compaction会将一个Store下的所有HFile合并成一个大的HFile,并且会清理掉过期和删除的数据。
参数设置:
hbase.hregion.majorcompaction=0
hbase.hregion.majorcompaction.jitter=0
hbase.hstore.compactionThreshold=3
默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分,刚拆分时,两个子Region都位于当前Region Server,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的Region Server。
参数设置:
hbase.hregion.max.filesize=5G (如下公式中为Max1)(可以减小该值,提高并发)
hbase.hregion.memstore.flush.size=258M (如下公式中为Max2)
每次切分将会比较Max1和Max2的值,取小的。[min(Max1,Max2 * Region个数 * 2)],其中Region个数为当前Region Server中数据该Table的Region个数。
由于自动切分无法避免热点问题,所以在生产中我们常常使用预分区和设计RowKey避免出现热点问题
为了避免flush时产生多个小文件。
主要作用来缓存Table数据,但是flush时会GC,不要太大,根据集群资源,一般分配整个Hbase集群内存的70%,16->48G就可以了
dfs.support.append=true (hdfs-site.xml、hbase-site.xml)
dfs.datanode.max.transfer.threads=4096 (HDFS配置)
在Region Server级别的合并操作中,Region Server不可用,可以根据集群资源调整该值,增加并发。
hbase.regionserver.handler.count=30
根据集群情况,可以适当增加该值,主要决定是客户端的请求数。
hbase.client.write.buffer=100M (写缓存)
调高该值,可以减少RPC调用次数,单数会消耗更多内存,根据集群资源情况设定。
参考5合并切分
create ‘命名空间:表‘, ‘列族1‘, ‘列族2‘, ‘列族3‘,‘列族4‘...,SPLITS=>[‘分区号‘,‘分区号‘,‘分区号‘,‘分区号‘]
根据数据量预估半年到一年的数据量,和Region最大值来选择预分区数。
方案一:随机数,hash值,但是这种不能范围查询,没有数据的集中性。
方案二:字符串反转,比如时间戳反转后就达到了散列性,但是在查看的时候集中性只是优于第一种。
#设计预分区键(如比如200个区) | ASCLL码为124只有 } 和 ~ 比它大,那么不管以后的RowKey使用什么字符,都是小于这个字符的,所以可以有效的得到RowKey规律
000|
001|
......
199|
# 1 设计RowKey键_ASCLL码为95
000_
001_
......
199_
# 2 根据业务唯一标识(如用户ID,手机号,身份证)和时间维度(比如按月:202004)计算后根据分区数取余(13408657784^202004)%199=分区号
# 想以什么时间进行查询就把什么往前提,如下数据需要查1月数据范围就是 000_13408657784_2020-04 -> 000_13408657784_2020-04|
000_13408657784_2020-04-01 12:12:12
......
199_13408657784_2020-04-01 24:12:12
原文:https://www.cnblogs.com/ttzzyy/p/12685945.html