day28

本文详细介绍了HBase的存储模型,包括rowkey、regionserver、region的概念和工作原理,以及HBase的读写流程。讨论了热点问题和解决策略,并探讨了表设计和应用场景。同时,提到了HBase的Java API使用和运维相关知识。
摘要由CSDN通过智能技术生成

一、Hbase存储模型

-》hbase所有数据读写都依赖于rowkey
-》regionserver:负责存储hbase表数据
	 -》每个region唯一被一台regionserver管理(不考虑副本)
     -》一台regionserver可以管理多个region

region:分区rowkey

region:分区,用于存储每张表中的所有数据
		默认情况下,每一张表一开始只有一个region
		region分割阈值:20
		min-max:region1
		00-20:region1 >>达到阈值分割,一般会从中间位置分割
			min-10:region1-1		10
			10-max:region1-2
			10-30:region1-2	>>达到阈值准备分割		
				10-20:region1-2-1	10
				20-max:region1-2-2
注意:region1-1	和region1-2-1还是有空余的空间了,但是不会再有数据往里面插入了
-》每一个region都有一个范围,起始rowkey值,终止rowkey的值
-》当数据进行插入时:
-》判断当前rowkey属于哪个region:rowkey的前缀匹配
-》将rowkey插入到对应region中
				min-10:	   region1		
				10-20:		region2		
				20-max:		region3		
				
				012344_lkjdfldjklfdlkfkl:	region1	
				122434_fkjdlkjflkfjlkddf:	region2
				503344_dkjfhdlkfkdfdkdfd:	region3
				
原因:
	1-rowkey设计不合理
       region1、region2存储一半数据就不能再存储了
	2-默认只有一个region
	   如果又多个region就可以在插入数据时候进行并发操作
       接下来就围绕这两个问题进行探讨,解决热点问题.

启动hadoop:

启动zookeeper:

创建表时的第一个region是没有范围
    region是hbase负载均衡和分布式存储的最小单元
			regionserver:region
			regionserver1:10			8个属于tab1 ,2 个属于tab2
										80%
			regionserver2:4			2个region属于tab1,2个region属于tab2
										20%
										
			将regionserver1上的region分配3个给regionserver2

Hbase的物理存储

put 'tbname','rowkey','cf1:name','laoda'
put 'tbname','rowkey','cf1:age','18'
put 'tbname','rowkey','cf2:phone','110'
好处:相同列簇时候读取非常快
regionserver:
-》region
-》1至多个store(一个列簇):将不同列簇的列分开存储
   相同rowkey,不同列簇会分开存储;因为数据是在同一rowkey中的,所以放在同一个region
   中。 
	    1个store存储的是一个列簇
		store1:cf1
		store2:cf2
		-》Store
		   -》memstore
		   -》storefile(0-多个)
						-》HFILE
			1-根据rowkey判读属于哪个region
			2-根据列簇名称判断属于哪个store
			3-将该条记录写入对应store的memstore
			4-当memstore达到一定阈值时,memstore中的数据会开始溢写为storefile
           (一次性写入)

hdfs上的存储结构
	   namespace:
	   default:默认创建表是时不加ns,就在默认的namespace下
	   hbase:系统表
			meta:元数据
			namespace:存储了hbase中所有的namespace的信息
	

        

Hbase在HDFS上的存储结构  

ns1:order02,,1528188707239.b48cd2efa405a1f56f9864f345e79700.
		表名,起始位置,region时间,region的唯一id
		
		hive:database/table/partition/file
		hbase:namespace/table/region/store/storefile+memstore

WALS:Hlog,write ahead log 预写日志
		-》在hbase中写入数据的第一步就是将数据写入wals
		-》第二步写入memstore

二、Hbase读写流程及集群架构

-》client:用户提交用户请求
	-》Hmaster:负责管理
	-》Hregionserver:负责存储数据
	-》zookeeper:
		-》存储元数据表对应的regionserver的地址
	
	-》hbase自带的两张系统表:	
		hbase:namespace:存储了hbase中所有的namespace的信息
		hbase:meta:元数据
			rowkey:hbase中所有region的名称
			column=info:regioninfo
			column=info:seqnumDuringOpen
			column=info:server
			column=info:serverstartcode
			
		-》记录了每个region的名称、起始范围与结束范围
		-》每个region对的regionserver的地址
		-》meta表只有一个region,该region的存放地址存储在zookeeper中

 

-》写:
		put 'ns:tbname','rowkey','cf1:name','laoda'
		-》客户端连接zookeeper,获取meta表所在的regionsever的地址
		-》根据地址读取meta表
		-》根据表名到meta表中进行前缀匹配,得到每张表的所有region信息
		-》先读取元数据查询表所对应的region有哪些,以及每个region对应的范围
		-》根据rowkey判断当前记录应该写入哪个region
		-》根据元数据中的region信息找到region对应的regionsever
		-》访问对应的regionserver,找到对应的region,将写入操作写入wals
		-》根据列簇判断当前记录写入哪个store
		-》将数据写入memstore
			-》当内存达到阈值,开始flush,变成storefile
			-》当满足一定条件时,多个storefile会进行合并:compaction
			-》当大文件满足一定条件时,会触发split,当前region会等分为两个新的region
				老的region下线,两个新的region会由master分配到不同的regionserver上
-》读取数据:
		get 'tbname','rowkey'
		get 'tbname','rowkey','info:id'
		scan 'tbname'
		
		-》客户端连接zookeeper,获取meta表所在的regionsever的地址
		-》根据地址读取meta表
		-》根据表名到meta表中进行前缀匹配,得到每张表的所有region信息
		-》先读取元数据查询表所对应的region有哪些,以及每个region对应的范围
		-》根据rowkey判断当前记录应该从哪个region中读
		-》连接对应的regionsever,找到对应的region
		-》判断需要的读取的列在哪些store中
		-》从store中读取数据
		-》先读memstore,如果内存中没有,从storefile中读

三、Hase的应用场景

-》hbase只负责读写执行,不负责删改的执行
		-》删改:打标签
						110		info:name		laoda		
			  put		110		info:name		laoer
				-》flush:
					110		info:name		laoda	(delete)	
					110		info:name		laoer
				->compaction:合并多个storefile时,将所有标记为删除的数据进行删除
-》Hbase运维案例
	 https://mp.weixin.qq.com/s/vNqUqhasUvtEBhV5DWyi_w
     如果文件都存在,但是元数据没有了
 	 Bin/hbase –fsck  –fixMate 进行修复
  修改元数据的前提是regioninfo中的数据都是存在的
  regioninfo:rigion中的所有信息,这也是获取元数据的重要文件

-》应用
		1-统计结果、报表类数据:要求实时性比较高的业务场景
		2-原始事实类数据:统一归档存储、提供搜索查询业务场景
			短期数据:RDBMS
			归档数据:NOSQL
		3-中间结果数据:
			-》原始数据在hbase,中间处理结果数据较大
			-》符合hbase特点的数据
		4-线上系统的备份数据:
			归档
常见运维:
		-》集群规划
		-》性能调优
		-》数据管理
##bin/hbase hbck 修复丢失的文件
修复HBASE丢失的数据,丢失元数据(元数据也是放到HBASE中)
内存中的数据修复不了,所以高频率的数据内存中放到HBASE中(变成storefile)

四、Hbase表的设计及其应用架构

HBase表设计的两个问题
        1、每个表刚开始只有一个分区,所有读写请求全部集中在同一个region中
	   		没有分区没有上限和下限,所有数据都存放在一台机器上
		热点问题:大部分的读写请求全部集中在某台或者某几台regionserver中
		2、rowkey为递增序列,不符合实际业务需求
        虽然有上限,有阀值能产生分区。但是这样一很多region只能存储未满,后期也不会在
        存储数据了,造成资源浪费.
			region1:min		max
					00			20
				region1-1:	min		10
				region1-2:	10		max
			21		region1-2
			22		region1-2
			……
			

rowkey的设计

必须严格按照页面构建rowkey
所有读写依赖于rowkey的前缀匹配

组合字段

  组合字段:由多个字段构成:经常作为查询条件的字段
			userId_timestamp_orderId
			>>这样设计不会产生递增序列:userId_timestamp_orderId
			-》需求:用户进入订单查询页面>>根据业务场景设计rowkey
				-》根据用户id在hbase进行前缀匹配
					得到该用户的所有的订单
				-》用户根据日期自己选择
					使用userId+用户勾选的时间范围,查询信息
scan 'order',{STARTROW=>'userId_20180301',STOPROW=>'userId_20180401'}
			示例:
			timestamp_orderId:适合于小数据量
rowkey是递增的,还是会出现上面的两个问题.
			110_timestamp:这种设计适用于手机营业厅查询时间间断的花费
			
-》极少部分需求没办法满足
比如:如上的rowkey设计,只能满足用户的查询;如果查询一个时间段的所有订单数,这时候就不好查询了。这时候需要用timestamp作为rowkey开头构建二级索引解决问题。
				-》解决:构建二级索引
				tb1:用户按照时间查询自己所有的订单
					rowkey:userId+timestamp+orderId
							110_20180609180000_000001
				-》需求:按照时间查询所有订单
				tb2:索引表
					rowkey:
						timestamp_orderId_userId
						20180609180000_000001_110
					info:tb1_id
						userId+timestamp+orderId
						110_20180609180000_000001
创建索引表:tb2   tb1中的rowkey对应tb2中列簇info:tb1_id,tb2中的rowKey就是二级索引
需求:查询某一时间段订单数
操作过程:1、通过时间(20180609180000)查询出tb2中所有info:tb1_id
			  2、将tb2中所有info:tb1_id作为rowkey交给tb1查询


-》问题:源表与索引表如何同步?	
-》1、当往源表中插入数据时,同是也往索引表插入一份
>>缺点:性能低下
 客户端向server端insert一条命令就变成两条命令,服务端需要处理两次;
中间消耗服务端的资源,还有并发量变大;这都会影响性能.
-》2、通过协处理器(Day30中会提到)
	>> 往源数据表中插入一条数据时候会自动往索引表中插入数据
-》3、第三方框架
	>> 公司做的最多,协处理器代码不好编写。第三方框架即结合了协处理器又不用自己编写代码.
	-》Phoenix
-》solr
			
-》唯一性:rowkey唯一标识一条记录

散列原则

散列:将不连续的rowkey写入不同的region,避免热点(不连续必然随机)
方法一:添加随机数
-》在rowkey前面添加随机数:00-99
				region1:	min			20
				region2:	20			40
				region3:	40			60
				……
				regionN:	80			max
			
				45_timestamp1_orderId1
				11_timestamp2_orderId1
				34_timestamp3_orderId2

		查:00-99_timestamp_orderId1
查询:比如这里有0-99个随机数,我查询时候要遍历0-99查询100次才能查询到这条数据。
		缺点:查询不方便,虽然解决了上述的两个问题,但是查询付出一定代价.
			  效率会受到影响,但是影响不大,属于常见的解决热点问题的方法.
方法二:反转
	20180609180000 dlfkjdlkjfklds dfjlkdjflkdjkfl
				20180609180001 dfdfdfdfeeewws dfjlkdjflkdjkf2
				
				rowkey:timestamp_userid_orderid
					00008190608102_dlfkjdlkjfklds_dfjlkdjflkdjkfl
					10008190608102
					20008190608102
方法三:固定编码
				MD5、CRC32

RowKey的长度:
		-》官方建议:rowkey长度不超过64字节
		   实际开发:不超过100
		   满足查询条件:越短越好
				-》匹配越快
				-》减少冗余
散列的好处:
1、散列后就不是连续数据,预分区后可以分布式存储
2、查询时候读取某段时间数据也不是基于某一个region,而是基于多个region分布式查询
列簇设计
		-》长度原则:越短越好,具体叫什么无所谓<<也有冗余
		-》个数原则:3个以内
		   一般给两个,一个是经常读写,一个是不经常读写
列标签设计
		-》符合列名
		-》使用列标签代替多版本
			使用列簇代替列
		 	将版本号写入到列标签中
			-》使用多版本来存储
			    没有添加列标签时候,需要比较rowkey,cf,col,timestamp
			    添加了列标签后,需要比较rowkey,cf,col
				原因:列标签中添加了版本号,不需要再比较timestamp
			    虽然这种方式不对timstamp进行比较,但是会对store进行比较。
				但是相对于比较timestamp性能会提高很多

预分区 

上面只解决散列问题,但是如果只有一个region还是会有热点问题
这时候我们就需要预分区
预分区是在创建表之前进行的
在创建表时,根据rowkey(的前缀)创建多个region
第一种方式:
create 'ts2', 'info', SPLITS => ['10', '20', '30', '40']

put 'ts2','000111','info:name','laoda'
put 'ts2','600111','info:name','laoda'
第二种方式:
create 'ts3', 'f1', SPLITS_FILE => 'splits.txt'
create 'ts4', 'f1', {NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

sqoop将订单详情表导入hbase

create 'ns1:order03','info',SPLITS => ['20', '40', '60', '80']

bin/sqoop import \
--connect jdbc:mysql://bigdata-training01.erongda.com:3306/dingdan \
--username root \
--password 123456 \
--table so_detail \
--split-by rk \
--hbase-table ns1:order03 \
--hbase-row-key rk \
--column-family info \
-m 2
sqoop只能往HBase中写入数据,读数据的话还是要自己写MapReduce程序(Day30会说)

HBase数据存储

StoreFile不仅仅是HFile,还有索引文件

region是对rowkey(行)进行分区
region Server 是对列簇(列)进行分

面试题:HBase调优、 如何进行运维、出现故障如何处理?
重点内容:索引,HBase二级索引(二级索引的类型,二级索引的原理),Phoenix使用

四、Hbase Java API

引入Hbase的依赖

<repositories>
	<!-- 指定该项目可以从哪些地方下载依赖包 --> 
	<repository>
		<id>aliyun</id>
		<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
	</repository>
	<repository>
		<id>cloudera</id>
		<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
	</repository>
	<repository>
		<id>jboss</id>
		<url>http://repository.jboss.org/nexus/content/groups/public</url>
	</repository>
</repositories>
<dependency>
   <groupId>org.apache.hbase</groupId>
		<artifactId>hbase-client</artifactId>
		<version>1.2.0-cdh5.7.6</version>
   </dependency>

   <dependency>
		<groupId>org.apache.hbase</groupId>
		<artifactId>hbase-server</artifactId>
   <version>1.2.0-cdh5.7.6</version>
</dependency>

配置访问路径:zookeeper

原因:客户端都需要经过zookeeper才能对HBASE数据进行读取和写入

                 数据都要经过zookeeper,zookeeper在转交数据给hbase

                  -》将hbase-site放入resource目录

                  -》在conf对象中配置

编写API:GET、PUT、DELETE、SCAN+FILTER

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值