HBase 读数据流程:一条 RowKey 从客户端到磁盘,经历了什么?
HBase 里查一条数据,不是”直接去文件里找”这么简单。它要经过 ZooKeeper、元数据表、RegionServer,还要在内存、缓存、磁盘三层里搜一遍。
绕这么大一圈,是为了两个目标:
- 定位:数据在哪个 RegionServer 上?→ 靠 ZooKeeper + hbase:meta
- 读取:数据在内存还是磁盘?→ 靠 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 | 1. 客户端 → ZooKeeper:问"元数据表在哪?" |
前三步是”定位”,最后一步是”读取”。
第一步:找元数据表的位置——问 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 | 目标:namespace=default, 表名=user_info, RowKey=user_001 |
匹配到了,返回 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(最近最少使用)。内存满了就淘汰最久没用过的数据块。