一个region server里有多个region,每个region里有多个store(列族),store里有mem store和store file,region sever中所有mem store内值之和达到region server的阈值后,所有mem store同时flush
一个region server内的所有region共用一个hlog,用于写入mem store内的数据和操作日志,用于region server容灾
DDL之建表操作过程
客户端通过zk获得对外服务hmaster的位置,然后客户端向master发送建表请求,master拿到请求后向rs发送建表region请求
创建region(hbase数据存储的基本单位),rs向master发送创建成功的结果,master更新meta表信息
meta表
rowkey:表名+具体的id
保存的值分为三个列:
1.region info,保存region具体信息,如表名,start key/end key
2.server信息,这个region是被哪个server加载的(rs的域名和端口信息)
3.server start code,rs的启动时间,如果rs的start code和当前的start code不一样,说明该rs重启,此时region可能不在该rs上了,需要重新加载
所有region被创建完成之后,将该表标记为enable状态
修改表操作
disable命令发送给master,hmaster将zk里该表的状态为disabling
hmaster去meta表里获取相关region,向相关rs发送卸载region的请求(close region)
hmaster向zk标记该表已经被disabled
客户端向hmaster发送修改表的请求,hmaster拿到修改表请求,hmaster检查表是否被disabled了
hmaster去/hbase/data/namespace/default/表名/.tabledesc修改表描述,若涉及到列族的修改泽还会修改regioninfo文件
客户端向hmaster发送enable请求:在zk中把表标记成enable状态,hmaster读取表表各个region的描述文件
决定这些表的region分配到哪些rs上,向目标rs发送open region请求
rs加载对应的region,加载过程中先读取.regioninfo里的信息,创建hregion对象和store对象,创建store对象后,加载store file对象(文件信息)
region和store file的id是随机生成的不会重复的编码
region在流程处理过程中会被在zk中标记状态
当rs把所有region加载完后,hmaster修改meta表中的region信息,修改完成后将表在zk中的状态标记为enable
region数量可能成千上万数量,meta表无法在一个region中保存所有用户表的region信息,因此meta表会被分裂成多个region,zk中的root表用于保存meta表region信息
put操作
客户端去zk中拿root表region位置,去root表中查找请求范围,从而查到对应meta表信息,在meta表找到客户表region信息
root表和meta表可存于缓存中
客户端将put请求发送给具体的region
put在rs中的处理流程
put操作被保存在hlog中
region使用的有序存储底层数据结构:log structure merge tree,将操作作为日志存于内存当中,当达到一定阈值后dump成有序的存储文件,并适时的将小的存储文件合并成为大的存储文件
put请求保存到mem store
store file文件结构:多个数据块+多个元数据块+数据索引块+元数据索引块+布隆过滤器索引块+hfile文件尾
store file数量达到阈值后多个合并compaction,部分store file合并称作minor compaction,标记删除和多余版本不会被物理删除
所有store file合并成为major compaction,标记删除和多余版本会被物理删除
不同列族和compaction时刻不同,因此每个列族store file数量不一样
每次flush和compaction之后,region自查当前region是否达到阈值,若达到则需要split成为子region
若达到阈值则被分为两个子region,需要确定split key,确定后region下线,下线后生成两个子region目录,子region中的数据文件均为对父region中数据文件的引用(减少region不可用时间)
建立完引用后子region可以立刻上线,子region根据引用生成数据文件,引用文件消失,master中有个线程删除已经下线且不被引用的父region
store生成机制
每个key value会被加载到具体的data block当中
当地一个kv导致data block中的数据总长度大于等于block size时,data block生成完毕;在较新版本,hfile生成过程中,针对每一个data block生成对应的二级索引的index block和布隆过滤器block
生成meta block,在旧版本中会保留布隆过滤器block。新版本中布隆过滤器保存在data block之后。
生成data block和meta block的索引,data block按照key索引,指向每个data block后面index block的具体位置;meta block按照meta block value对应的key建立索引;
fileinfo保存文件中kv时间范围和最早的put时间,扫描文件过程中可帮助判断是否扫描该文件,若scan中的时间范围和文件中的时间范围不重合,则不扫描该文件
hlog id和mem store flush时间两个属性帮助判断hlog回收时间点,rs容灾过程中,region重启之后replay hlog的起始时间点
生成布隆过滤器索引
指向之前为每个block生成布隆过滤器的起始位置
文件结尾文件块
保存各类block数量、偏移量、长度、kv数量
scan操作
客户端调用scan函数向rs发送scan请求,创造result scanner
rs接到请求后为每一个列族storescanner对象,内保存有scanner id和lease;同时创建mem store和store file对应的scanner,根据scan的start key对这些数据存储对象进行sync操作,sync将文件读取指针指向首个大于等于start key的文件位置
sync操作过程:读取store file的文件尾,确定每一个block的起始位置和长度,读取文件信息,根据时间戳设置确定是否有必要扫描这个store file,若有必要扫描,在布隆过滤器索引中查找相关布隆过滤器位置,在布隆过滤器block中查找data block中是否有本次扫描操作中的row key,若存在,在data block index block进一步索引row key所在位置,在data block中进一步sync,查找到最终sync到的首个小于等于扫描的start key的位置
--store scanner创建结束
rs将scanner id返回客户端的scanner
当客户端调用next时,scanner将next发送给rs,rs将next请求发送给store scanner,store scanner更新scanner租期延长到期时间,每个scanner中找到对应row key的kv记录,所有记录放到filter过滤,过滤结果发送给rs,在rs中把所有的kv组装成result,result根据caching和batch的预设组装,batch设置的比较小result会被拆分,若caching设置的比较大则在进行一次内部的next拿到更多的result-----result返回给scanner
下次调用next不必进行rpc,直接将之前缓存的result结果返回给客户端