0%

Bigtable

Google Bigtable:分布式结构化存储的开山之作,HBase 就是照着它做的

关系型数据库在数据量到 PB 级的时候撑不住了——单机存不下、分库分表太复杂、高并发读写扛不住。

Google 的 Bigtable 就是在这个背景下诞生的:一个专门为”海量结构化数据”设计的分布式存储系统。

它影响了后来几乎所有 NoSQL 数据库的设计思路。HBase 就是 Bigtable 的开源实现——数据模型一样、架构一样、连组件名字都是对应的。

Bigtable 的数据模型:一张三维的稀疏大表

Bigtable 的数据模型可以用一句话概括:

一个稀疏的、分布式的、多版本的三维映射表。

1
(row, column, timestamp) → value

拆开看四个概念:

1. 行(Row)

每行有一个唯一的 Row Key,按字典序排序。

排序这个设计很关键: 相近的 Row Key 会存到一起,范围查询效率极高。比如你要查 user_001user_100 的数据,它们物理上连续,一次扫描就能拿到。

2. 列(Column)

列分两级:列族(Column Family)+ 限定符(Qualifier)

格式是 family:qualifier,比如 user:nameuser:agelog:timestamp

  • 列族 必须预先定义,是存储和权限控制的基本单位
  • 限定符 不用预先定义,随时可以加

这个设计让 Bigtable 非常灵活: 你可以在同一个列族下动态添加新列,不用改表结构。

3. 时间戳(Timestamp)

每个单元格可以存多个版本,用时间戳区分:

1
2
3
4
Row Key: user_001
Column: log:login
t1: "2023-10-01 08:00"
t2: "2023-10-02 09:30"

可以配置保留最近 N 个版本,或者保留某个时间范围内的版本。

4. 单元格(Cell)

(Row Key, Column, Timestamp) 三者唯一确定一个值。值就是普通的字符串(二进制安全,可以存任意数据)。

Bigtable 的数据模型 vs 关系型数据库

关系型数据库 Bigtable
表结构 预定义 schema,列固定 列族预定义,限定符动态添加
数据行 有主键,但无排序保证 按 Row Key 字典序排序
多版本 不支持(需自己实现) 原生支持多版本时间戳
稀疏性 每行都有所有列 空的单元格不占存储

Bigtable 适合”半结构化”数据——每行字段不完全一样,比如用户行为日志、爬虫抓取的数据。

系统架构:Master 管调度,Tablet Server 存数据

Bigtable 是典型的”管理 + 执行”分离架构:

graph TD  
    A[客户端 Client] -->|RPC| B[主控服务器 Master]  
    A -->|直接 RPC| C[子表服务器 Tablet Server1] & D[Tablet Server2]  
    B -->|管理/监控| C & D  
    C -->|存储数据| E[GFS
SSTable + 操作日志] D -->|存储数据| E B -->|依赖| F[Chubby
分布式锁/选举] C -->|依赖| F note[核心依赖 GFS 提供持久化,Chubby 提供分布式协调]

三个核心组件:

组件 管什么 类比
Master 子表分配、负载均衡、故障恢复、元数据管理 指挥官,不下场干活
Tablet Server 实际存数据、处理读写请求 一线执行者
Client 应用程序接口,缓存子表位置 用户的门面

底层依赖两个基础设施:

  • GFS:存数据文件的”硬盘”(SSTable + 操作日志)
  • Chubby:分布式锁服务,选 Master、存根表位置

子表(Tablet):数据分片的基本单位

Bigtable 把一张大表按 Row Key 范围切成多个连续的子表(Tablet)。

  • 初始时一张表只有一个 Tablet
  • 数据量超过阈值(100-200MB)自动分裂成两个
  • Tablet 可以在 Tablet Server 之间迁移,实现负载均衡

定位一个 Tablet 的流程(三级元数据):

1
Client → 根表(Root Tablet)→ 元数据表 → 目标 Tablet → Tablet Server
  • 根表:只有一张,存元数据表的位置,永不分裂,存储在 Chubby 里
  • 元数据表:存所有用户表的 Tablet 位置信息
  • 用户表:实际业务数据

HBase 的 .META. 表就是照搬这个设计的。

读写流程:内存 + 日志 + SSTable

写操作:

  1. Client 定位到目标 Tablet Server
  2. 写操作先记到 操作日志(WAL)(GFS 上,确保不丢)
  3. 更新内存中的 MemTable(有序结构)
  4. MemTable 满了之后,异步刷到 GFS 生成 SSTable 文件

读操作:

  1. Client 定位到目标 Tablet Server
  2. 合并读取 MemTable(内存中最新数据)+ SSTable(磁盘上已持久化的数据)
  3. 按时间戳返回最新版本

为什么写快? 写只涉及内存 + 追加日志,不涉及随机磁盘 IO。为什么读不慢? SSTable 是按 Row Key 排序的,查询是二分查找。

Bigtable 的核心设计思想

设计决策 为什么这么设计
Row Key 排序 范围查询高效,数据局部性好
列族 + 动态限定符 灵活的数据模型,不用预先定义所有列
多版本时间戳 支持历史数据追溯,不用自己维护版本
子表自动分裂 数据量增长时自动扩展,不用人工干预
操作日志 + MemTable 写入快 + 数据不丢
Master 不参与读写 Master 压力小,集群规模可以很大

Bigtable 与 HBase 的对照

HBase 就是 Bigtable 的开源实现,几乎照搬了设计:

Bigtable HBase
GFS HDFS
Chubby ZooKeeper
Master HMaster
Tablet Server RegionServer
Tablet Region
SSTable HFile
MemTable MemStore
操作日志(WAL) WAL(Write-Ahead Log)

理解了 Bigtable,就理解了 HBase。模型一样、架构一样、读写流程一样,只是名字换了。

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