Big Table
Bigtable
Bigtable 是一个用于管理结构化数据的分布式存储系统,它有非常优秀的扩展性,可以同时处理上千台机器中的 PB 级别的数据;Google 中的很多项目,包括 Web 索引都使用 Bigtable 来存储海量的数据;Bigtable 的论文中声称它实现了四个目标:
数据模型
Bigtable 与数据库在很多方面都非常相似,但是它提供了与数据库不同的接口,它并没有支持全部的关系型数据模型,反而使用了简单的数据模型,使数据可以被更灵活的控制和管理。
在实现中,Bigtable 其实就是一个稀疏的、分布式的、多维持久有序哈希。
A Bigtable is a sparse, distributed, persistent multi-dimensional sorted map.
它的定义其实也就决定了其数据模型非常简单并且易于实现,我们使用 row、column 和 timestamp 三个字段作为这个哈希的键,值就是一个字节数组,也可以理解为字符串。
这里最重要的就是 row 的值,它的长度最大可以为 64KB,对于同一 row 下数据的读写都可以看做是原子的;因为 Bigtable 是按照 row 的值使用字典顺序进行排序的,每一段 row 的范围都会被 Bigtable 进行分区,并交给一个 tablet 进行处理。
tablet 的组织形式
我们使用类似 B+ 树的三层结构来存储 tablet 的位置信息,第一层是一个单独的 Chubby 文件,其中保存了根 tablet 的位置。
每一个 METADATA tablet 包括根节点上的 tablet 都存储了 tablet 的位置和该 tablet 中 key 的最小值和最大值;每一个 METADATA 行大约在内存中存储了 1KB 的数据,如果每一个 METADATA tablet 的大小都为 128MB,那么整个三层结构可以存储 2^61 字节的数据。
tablet 的管理
既然在整个 Bigtable 中有着海量的 tablet 服务器以及数据的分片 tablet,那么 Bigtable 是如何管理海量的数据呢?Bigtable 与很多的分布式系统一样,使用一个主服务器将 tablet 分派给不同的服务器节点。
为了减轻主服务器的负载,所有的客户端仅仅通过 Master 获取 tablet 服务器的位置信息,它并不会在每次读写时都请求 Master 节点,而是直接与 tablet 服务器相连,同时客户端本身也会保存一份 tablet 服务器位置的缓存以减少与 Master 通信的次数和频率。
读写请求的处理
从读写请求的处理,我们其实可以看出整个 Bigtable 中的各个部分是如何协作的,包括日志、memtable 以及 SSTable 文件。
当有客户端向 tablet 服务器发送写操作时,它会先向 tablet 服务器中的日志追加一条记录,在日志成功追加之后再向 memtable 中插入该条记录;这与现在大多的数据库的实现完全相同,通过顺序写向日志追加记录,然后再向数据库随机写,因为随机写的耗时远远大于追加内容,如果直接进行随机写,可能由于发生设备故障造成数据丢失。
当 tablet 服务器接收到读操作时,它会在 memtable 和 SSTable 上进行合并查找,因为 memtable 和 SSTable 中对于键值的存储都是字典顺序的,所以整个读操作的执行会非常快。
表的压缩
随着写操作的进行,memtable 会随着事件的推移逐渐增大,当 memtable 的大小超过一定的阈值时,就会将当前的 memtable 冻结,并且创建一个新的 memtable,被冻结的 memtable 会被转换为一个 SSTable 并且写入到 GFS 系统中,这种压缩方式也被称作 Minor Compaction。
每一个 Minor Compaction 都能够创建一个新的 SSTable,它能够有效地降低内存的占用并且降低服务进程异常退出后,过大的日志导致的过长的恢复时间。既然有用于压缩 memtable 中数据的 Minor Compaction,那么就一定有一个对应的 Major Compaction 操作。
Bigtable 会在后台周期性地进行 Major Compaction,将 memtable 中的数据和一部分的 SSTable 作为输入,将其中的键值进行归并排序,生成新的 SSTable 并移除原有的 memtable 和 SSTable,新生成的 SSTable 中包含前两者的全部数据和信息,并且将其中一部分标记未删除的信息彻底清除。