0%

HBase读数据过程

HBase 读数据流程:一条 RowKey 从客户端到磁盘,经历了什么?

HBase 里查一条数据,不是”直接去文件里找”这么简单。它要经过 ZooKeeper、元数据表、RegionServer,还要在内存、缓存、磁盘三层里搜一遍。

绕这么大一圈,是为了两个目标:

  1. 定位:数据在哪个 RegionServer 上?→ 靠 ZooKeeper + hbase:meta
  2. 读取:数据在内存还是磁盘?→ 靠 MemStore → BlockCache → StoreFile 三层查

整体流程:四步走

graph TD  
    A[客户端] --> B[ZooKeeper获取hbase:meta位置]  
    B --> C[访问hbase:meta表]  
    C --> D[定位目标Region及RegionServer]  
    D --> E[连接目标RegionServer]  
    E --> F{读取数据}  
    F -->|找到| G[MemStore]  
    F -->|未找到| H[BlockCache]  
    H -->|找到| I[返回数据]  
    H -->|未找到| J[读取StoreFile]  
    J --> K[写入BlockCache]  
    K --> I
1
2
3
4
1. 客户端 → ZooKeeper:问"元数据表在哪?"
2. 客户端 → 元数据表:问"我的数据在哪个 RegionServer?"
3. 客户端 → RegionServer:连上去,说"我要查这个 RowKey"
4. RegionServer → 客户端:从 MemStore/BlockCache/StoreFile 里找到数据,返回

前三步是”定位”,最后一步是”读取”。

第一步:找元数据表的位置——问 ZooKeeper

HBase 里所有表的 Region 分布信息都记录在 hbase:meta 表里。但 hbase:meta 表本身也是个表,它也存在某个 RegionServer 上。

问题来了:我怎么知道 hbase:meta 在哪?

ZooKeeper 存了这个信息。

客户端启动时,先连 ZooKeeper,找 /hbase/meta-region-server 这个节点,拿到 hbase:meta 表所在的 RegionServer 地址。

这一步的目的是:找到”目录”在哪。

第二步:查元数据表——定位目标 Region

拿到 hbase:meta 的位置后,客户端向那个 RegionServer 发请求,查 hbase:meta 表:

1
2
3
4
5
6
目标:namespace=default, 表名=user_info, RowKey=user_001

hbase:meta 表里有一条记录:
- 表名:user_info
- Region 范围:[user_001, user_200)
- RegionServer:rs1 (IP: 192.168.1.10)

匹配到了,返回 RegionServer 地址。

这一步的目的是:确定”数据在哪台机器上”。

元数据缓存优化: 客户端会把查到的 (Region → RegionServer) 映射缓存起来,下次再查同一个 Region 的数据,直接走缓存,不用再查 hbase:meta 表。

第三步:连 RegionServer——直接取数据

客户端拿到 RegionServer 地址后,直接建立 TCP 连接,发送读请求:

1
GET user_info, RowKey=user_001, 列族=info, 列=name

这一步开始,ZooKeeper 和元数据表就不再参与了。 数据读取完全在 RegionServer 内部完成。

第四步:RegionServer 三层查数据

RegionServer 收到请求后,按内存 → 缓存 → 磁盘的顺序查数据:

graph TD
    A[读请求] --> B{"MemStore 里有吗?"}
    B -->|有| F[返回数据]
    B -->|没有| C{"BlockCache 里有吗?"}
    C -->|有| F
    C -->|没有| D["读 StoreFile(磁盘)"]
    D --> E[写入 BlockCache]
    E --> F
层级 存什么 速度 命中率
MemStore 最近写入、还没刷盘的数据 极快(内存) 低(只含未刷盘的新数据)
BlockCache 最近读过的 HFile 数据块 极快(内存) 中(取决于访问模式)
StoreFile(HFile) 所有已持久化的数据 慢(磁盘 IO) 100%(最后一定能找到)

为什么是这个顺序?

  • MemStore 里是”热乎”的新数据,还没写到磁盘,不在这查就丢了
  • BlockCache 是”最近用过”的数据,用户可能重复查,缓存起来省磁盘 IO
  • StoreFile 是”全量数据”,磁盘上一定有,但速度最慢

三步查完,一定能找到数据(只要存在)。

读流程的两个关键优化

1. 元数据缓存(Client Cache)

每次请求都查 ZooKeeper + hbase:meta 表,开销太大。客户端把 Region 位置信息缓存起来,命中缓存就直接连 RegionServer。

缓存失效了怎么办? 如果 Region 因为分裂或负载均衡迁移到了别的 RegionServer,客户端请求会失败,然后重新去查 hbase:meta,更新缓存。

2. BlockCache(读缓存)

StoreFile 在磁盘上,每次读都走磁盘太慢。BlockCache 把最近读过的 HFile 数据块缓存在内存里,重复查询直接从内存返回。

BlockCache 的淘汰策略: LRU(最近最少使用)。内存满了就淘汰最久没用过的数据块。

欢迎关注我的其它发布渠道