背景
冷热分离需要用到hbase,冷数据较多,需求:
- 存放上亿数据
- 支持简单的组合关键字查询
- 存放数据不需要变更
基本存储数据结构
HBase可以被看作是一个稀疏的多维度Map(映射),稀疏的、分布式、多维的Map,将行键(Row Key)、列族(Column Family)、列限定符(Column Qualifier)和时间戳(Timestamp)映射到一个值(Value)
数据模型
如下数据如何存储?表users
,包含两个列族personal_info
和contact_info
。
![[Pasted image 20240612235231.png]]
实际存储结构:
Row Key: user1
Column Family: personal_info
Column Qualifier: name -> Value: Alice
Column Qualifier: age -> Value: 30
Column Family: contact_info
Column Qualifier: email -> Value: alice@example.com
Column Qualifier: phone -> Value: 123-456-7890
Row Key: user2
Column Family: personal_info
Column Qualifier: name -> Value: Bob
Column Qualifier: age -> Value: 25
Column Family: contact_info
Column Qualifier: email -> Value: bob@example.com
Column Qualifier: phone -> Value: 987-654-3210
每一个RowKey、TimeStamp以及Key-Value值就是一个Cell
- 行键 (Row Key) : 唯一标识每一行数据,例如
user1
和user2
。 - 列族 (Column Family) : 数据按列族进行物理存储,例如
personal_info
和contact_info
。 - 列限定符 (Column Qualifier) : 列族下的具体列,例如
name
、age
、email
、phone
。 - 时间戳 (Timestamp): 记录数据的版本,HBase支持多个版本的值,默认为服务器写入数据的时间。
- 值 (Value) : 存储的实际数据,例如
Alice
、30
、alice@example.com
等
ColumnFamily一开始就要定义好,类似于关系型数据库里面的列,属于schema,每个ColumnFamily可以灵活增加ColumnQualifier,ColumnQualifier不需要在创建表的时候定义
物理存储模型
根据RowKey的范围划分成多个Region
- 一个表会被水平切割成多个Region
- 一个Region会包含多个Row,包含startkey和endkey之间所有连续的行。每个Region的大小默认会控制在1GB内。每个表一开始只有二个 Region,随着数据不断插入到表中,Region 不断增大,当增大到一个阈值的时候,Region 就会等分为两个新的 Region
- 每个Region包含着多个Store对象。每个Store包含一个MemStore或若干StoreFile,StoreFile包含一个或多个HFile。MemStore存放在内存中,StoreFile存储在HDFS上
- 一个MemStore会存储一个ColumnFamily,一个MemStore会把数据写入多个HFile
- 一个RegionServer会服务多个Region
![[Pasted image 20240613081011.png]]
Table: users
Region 1 (RowKey: user1 - user1000)
|-- Store (Column Family: personal_info)
| |-- MemStore
| |-- HFile
|
|-- Store (Column Family: contact_info)
|-- MemStore
|-- HFile
Region 2 (RowKey: user1001 - user2000)
|-- Store (Column Family: personal_info)
| |-- MemStore
| |-- HFile
|
|-- Store (Column Family: contact_info)
|-- MemStore
|-- HFile
分布式环境
Master 主要负责表 Region 的管理工作,包括分配 Region 给 Region Server,协调多个 Region Server,检测各个 Region Server 的状态,并平衡 Region Server 之间的负载。
Region Server 是 HBase 最核心的模块,包含多个 Region,负责维护 Master 分配给它的 Region 集合,并处理对这些 Region 的读写操作,Client 直接与 Region Server 连接,并经过通信获取 HBase 中的数据。Region Server 需要向 HDFS 写入数据。
Zookeeper 作用:
- 是 HBase Master 的高可用性(High Available,HA)解决方案,保证了至少有一个 HBase Master 处于运行状态。
- 负责 Region 和 Region Server 的注册,Master 就可以通过 Zookeeper 随时感知各个 Region Server 的工作状态
![[Pasted image 20240613081021.png]]
数据写入流程
- 写请求:客户端向HBase发送写请求。
- 具体client访问zk读取元数据,根据namespace、表名、rowkey找到数据对应region,访问region对应regionServer
- 写入WAL:数据首先写入WAL(WriteAheadLog),以确保数据不会因为RegionServer故障而丢失,每个regionServer都会维护一个WAL文件(也是基于HDFS),所有写操作现将变动添加到WAL文件末尾。
- 写入MemStore:数据被写入MemStore,当MemStore达到一定大小时,会触发一次flush操作。
- Flush到HFile:MemStore的数据被写入HFile,存储在HDFS上。
- Compaction:随着时间推移,HBase会执行合并操作(Compaction),将多个小的HFile合并成一个大的HFile,以提高读性能。
数据读取流程
- 查找MemStore:首先在MemStore中查找数据。
- 查找BlockCache:如果数据不在MemStore中,接下来在BlockCache中查找。
- 查找HFile:如果数据既不在MemStore也不在BlockCache中,则查找HFile。
- 返回数据:找到数据后,返回给客户端。如果在HFile中找到数据,则将数据块缓存到BlockCache中,以加快后续的读取操作
HFile的结构
数据块(Data Block):
- 存储实际的数据,包含多个KeyValue对。
- 每个数据块都可以进行压缩,以减少存储空间和提高读写效率。
-
索引块(Index Block):
- 存储数据块的索引信息,用于加快数据查找。
- HFile包含一个元索引块(Meta Index Block),指向索引块的位置。
-
元数据块(Meta Block):
-
存储额外的元数据信息,例如文件信息、统计信息等
HDFS
├── DataNode 1
│ ├── /hbase/data/default/users/region1/store1/hfile1
│ ├── /hbase/data/default/users/region1/store2/hfile2
│ └── ...
├── DataNode 2
│ ├── /hbase/data/default/users/region2/store1/hfile3
│ ├── /hbase/data/default/users/region2/store2/hfile4
│ └── ...
├── DataNode 3
│ ├── /hbase/data/default/users/region3/store1/hfile5
│ ├── /hbase/data/default/users/region3/store2/hfile6
│ └── ...
└── ...HFile:
├── Data Block 1
│ ├── KeyValue1
│ ├── KeyValue2
│ └── ...
├── Data Block 2
│ ├── KeyValue3
│ ├── KeyValue4
│ └── ...
├── ...
├── Index Block
│ ├── Index Entry 1
│ ├── Index Entry 2
│ └── ...
└── Meta Block
├── Meta Entry 1
├── Meta Entry 2
└── ...
-
表结构的设计
rowkey设计:
md5[cumstomeremail]+ticketId
columnFamily: ColumnFamily:i
为什么只整一个?
因为官方不推荐两个以上的columnFamily,原因:memstore刷新到HFile的动作叫flushing,flushing的操作是region级别,也就是只要有一个columnFamily满了就需要刷新,可能另外一个还很空,增加不必要的IO操作
ColumnKey: 剩余字段都设为i列簇下的Key
![[Pasted image 20240614080719.png]]
工单处理记录表,将处理记录转为json,保存在一个columnKey中