1、设计动机与目标

(1)设计动机

需要存储的数据种类繁多Google目前向公众开放的服务很多,需要处理的数据类型也非常多。包括URL、网页内容、用户的个性化设置在内的数据都是Google需要经常处理的 

海量的服务请求Google运行着目前世界上最繁忙的系统,它每时每刻处理的客户服务请求数量是普通的系统根本无法承受的 

商用数据库无法满足Google的需求:一方面现有商用数据库设计着眼点在于通用性,根本无法满足Google的苛刻服务要求;另一方面对于底层系统的完全掌控会给后期的系统维护、升级带来极大的便利 

(2)基本目标

2、数据模型

Bigtable是一个分布式多维映射表,表中的数据通过一个行关键字(Row Key)、一个列关键字(Column Key)以及一个时间戳(Time Stamp)进行索引

Bigtable对存储在其中的数据不做任何解析,一律看做字符串

Bigtable的存储逻辑可以表示为:

( row:string , column:string , time:int64)→string


Ø

   ˜Bigtable的行关键字可以是任意的字符串,但是大小不能超过64KB。Bigtable和传统的关系型数据库有很大不同,它不支持一般意义上的事务,但能保证对于行的读写操作具有原子性(Atomic

   ˜表中数据都是根据行关键字进行排序的,排序使用的是词典序。

     ˜一个典型实例,其中com.cnn.www就是一个行关键字。不直接存储网页地址而将其倒排是Bigtable的一个巧妙设计。这样做至少会带来以下两个好处

       同一地址域的网页会被存储在表中的连续位置,有利于用户查找和分析

       倒排便于数据压缩,可以大幅提高压缩率

Ø

  ˜Bigtable并不是简单地存储所有的列关键字,而是将其组织成所谓的列族(Column Family),每个族中的数据都属于同一个类型,并且同族的数据会被压缩在一起保存。引入了列族的概念之后,列关键字就采用下述的语法规则来定义:

  ˜族名:限定词(family:qualifier)

      族名必须有意义,限定词则可以任意选定

      图中,内容(Contents)、锚点(Anchor)都是不同的族。而cnnsi.com和my.look.ca则是锚点族中不同的限定词

      族同时也是Bigtable中访问控制(Access Control)基本单元,也就是说访问权限的设置是在族这一级别上进行的

Ø时间戳

˜Google的很多服务比如网页检索和用户的个性化设置等都需要保存不同时间的数据,这些不同的数据版本必须通过时间戳来区分。图2中内容列的t3、t5和t6表明其中保存了在t3、t5和t6这三个时间获取的网页。Bigtable中的时间戳是64位整型数,具体的赋值方式可以采取系统默认的方式,也可以用户自行定义

为了简化不同版本的数据管理,Bigtable目前提供了两种设置:一种是 保留最近的 N 个不同版本,图中数据模型采取的就是这种方法,它保存最新的三个版本数据。另一种就是 保留限定时间内的所有不同版本,比如可以保存最近10天的所有不同版本数据。失效的版本将会由Bigtable的垃圾回收机制自动处理

3、系统架构

Ø在Bigtable中Chubby主要有以下几个作用:

1选取并保证同一时间内只有一个主服务器(MasterServer)

2获取子表的位置信息

3保存Bigtable的模式信息及访问控制列表

Ø另外在Bigtable的实际执行过程中,Google的MapReduce

和Sawzall也被用来改善其性能

4、主服务器

Ø当一个新子表产生时,主服务器通过一个加载命令将其分配给一个空间足够的子表服务器。创建新表、表合并以及较大子表的分裂都会产生一个或多个新子表。对于前面两种,主服务器会自动检测到,而较大子表的分裂是由子服务发起并完成的,所以主服务器并不能自动检测到,因此在分割完成之后子服务器需要向主服务发出一个通知 

Ø由于系统设计之初就要求能达到良好的扩展性(既然要求有扩展性,那么,当有新的服务器加进来时,必须得及时知道),所以主服务器必须对子表服务器的状态进行监控,以便及时检测到服务器的加入或撤销

   Bigtable中主服务器对子表服务器的监控是通过Chubby完成的——子表服务器在初始化时都会从Chubby中得到一个 独占锁。通过这种方式所有 子表服务器基本信息被保存在Chubby中一个称为 服务器目录(ServerDirectory)的特殊目录之中

Ø主服务器会定期向其询问独占锁的状态。如果子表服务器的锁丢失或没有回应,则此时可能有两种情况

   要么是Chubby出现了问题(虽然这种概率很小,但的确存在,Google自己也做过相关测试)

   要么是子表服务器自身出现了问题。对此主服务器首先自己尝试获取这个独占锁,如果失败说明Chubby服务出现问题,需等待恢复;如果成功则说明Chubby服务良好而子表服务器本身出现了问题

Ø当在状态监测时发现某个子表服务器上负载过重时,主服务器会自动对其进行 负载均衡操作

  基于系统出现故障是一种常态的设计理念,每个主服务器被设定了一个会话时间的限制。当某个主服务器到时退出后,管理系统就会指定一个新的主服务器,这个主服务器的启动需要经历以下四个步骤:

   (1)从Chubby中获取一个独占锁,确保同一时间只有一个主服务器

   (2)扫描服务器目录,发现目前活跃的子表服务器

   (3)与所有的活跃子表服务器取得联系以便了解所有子表的分配情况

   (4)扫描元数据表,发现未分配的子表并将其分配到合适子表服务器

如果元数据表未分配,则首先需要将根子表(Root Tablet)加入未分配的子表中。由于根子表保存了其他所有元数据子表的信息,确保了扫描能够发现所有未分配的子表 

5子表服务器

由于一个BigTable需要存储海量数据,所以它不得不被分成多个Tablet,而每个Tablet都会负责一定范围的列。并且存储在多个服务器上。

SSTable及子表基本结构

SSTable是Sorted String Table的缩写,按照键排序后存储键/值对(Key——Value)字符串,并且它是不可变动的,也就是写子之后,只能将其更新附加至其后,而不能直接对其进行修改,这样是为了让系统能执行磁盘所擅长的顺序访问,而不是随机访问。

SSTable及子表基本结构

子表实际组成 

Bigtable中的日志文件是一种共享日志,每个子表服务器上仅保存一个日志文件,某个子表日志只是这个共享日志的一个片段。这样会节省大量的空间,但在恢复时却有一定的难度

Google为了避免这种情况出现,对日志做了一些改进。Bigtable规定将日志的内容 按照键值进行排序,这样不同的子表服务器都可以连续读取日志文件了
一般来说每个子表的大小在 100MB到200MB之间。每个子表服务器上保存的子表数量可以从几十到上千不等,通常情况下是100个左右

个人理解:由此,一个子表服务器上有一个日志文件,而同时,每个子表中也有自己的日志,它是其所在服务器上日志文件中的一个片段)

SSTable表的结构

SSTable中数据被划分成一个个的(Block),每个块的大小是可以设置的,一般为64KB

在SSTable的结尾有一个索引(Index),这个索引保存了块的位置信息,在SSTable打开时这个索引会被加载进内存,用户在查找某个块时首先在内存中查找块的位置信息,然后在硬盘上直接找到这个块

由于每个SSTable一般都不是很大,用户还可以选择将其 整体加载进内存,这样查找起来会更快

²所有子表地址都被记录在元数据表中,元数据表也是由一个个的元数据子表Metadata tablet)组成

²根子表是元数据表中一个比较特殊的子表,它既是元数据表的第一条记录,也包含了其他元数据子表的地址,同时Chubby中的一个文件也存储了这个根子表的信息。

²查询时,首先Chubby中提取这个根子表的地址,进而读取所需的元数据子表的位置,最后就可以从元数据子表中找到待查询的子表。除了这些子表的元数据之外,元数据表中还保存了其他一些有利于调试和分析的信息,比如事件日志

为了减少访问开销,提高客户访问效率,Bigtable使用了缓存(Cache预取(Prefetch技术

子表的地址信息被缓存在客户端,客户在寻址时直接根据缓存信息进行查找。一旦出现缓存为空或缓存信息过时的情况,客户端就需要按照图示方式进行网络的来回通信(Network Round-trips)进行寻址,在缓存为空的情况下需要三个网络来回通信。如果缓存的信息是过时的,则需要六个网络来回通信。其中三个用来确定信息是过时的,另外三个获取新的地址 

   预取则是在每次访问元数据表时不仅仅读取所需的子表元数据,而是读取多个子表的元数据,这样下次需要时就不用再次访问元数据表

子表数据存储及元数据

ØBigtable将数据存储划分成两块:较新的数据存储在内存中一个称为内存表(Memtable)的有序缓冲里,较早的数据则以SSTable格式保存GFS

Ø写操作(Write Op——先查询Chubby中保存的访问控制列表确定用户具相应写权限,通过认证之后写入的数据首先被保存在提交日志(Commit Log)中。提交日志中以重做记录(RedoRecord)的形式保存着最近的一系列数据更改,这些重做记录在子表进行恢复时可以向系统提供已完成的更改信息。

Ø 读操作( Read Op ——先通过认证,之后读操作就要结合内存表和SSTable文件来进行,因为内存表和SSTable中都保存了数据

每一次旧的内存表停止使用时都会进行一个次压缩操作,这会产生一个SSTable。但如果系统中只有这种压缩的话,SSTable的数量就会无限制地增加下去 

而在Bigtable中,读操作实际上比写操作更重要,因此Bigtable会定期地执行一次合并压缩的操作,将一些已有的SSTable和现有的内存表一并进行一次压缩 

主压缩其实是合并压缩的一种,只不过它将所有的SSTable一次性压缩成一个大的SSTable文件。主压缩也是定期执行,执行一次主压缩之后可以保证将所有的被压缩数据彻底删除

Ø压缩

 

˜压缩可以有效地节省空间,Bigtable中的压缩被应用于很多场合

 F首先压缩可以被用在构成局部性群组的SSTable中,可以选择是否对个人的局部性群组的SSTable进行压缩。这种压缩是对每个局部性群组独立进行,虽然会浪费一些空间,但是在需要读时解压速度非常快

˜通常情况下,用户可以采用两步压缩的方式:

 F第一步利用Bentley & McIlroy方式(BMDiff)在大的扫描窗口将常见的长串进行压缩;第二步采取Zippy技术进行快速压缩,它在一个16KB大小的扫描窗口内寻找重复数据,这个过程非常快

˜压缩技术还可以 提高子表的恢复速度,当某个子表服务器停止使用后,需要将上面所有的子表移至另一个子表服务器。转移前两次压缩: 第一次压缩减少了提交日志中未压缩状态;文件正式转移前还要进行一次压缩,主要是 将第一次压缩后遗留的未压缩空间进行压缩

Ø布隆过滤器(Bloom Filter)

 

˜巴顿·布隆在1970年提出的,实际上它是一个很长的二进制向量和一系列随机映射函数,在读操作中确定子表的位置时非常有用

 F优势:速度快,省空间。而且它有一个最大的好处是它绝不会将一个存在的子表判定为不存在

 F缺点:在某些情况下它会将不存在的子表判断为存在。不过这种情况出现的概率非常小,跟它带来的巨大好处相比这个缺点是可以忍受的

      目前包括Google Analytics、Google Earth、个性化搜索、Orkut和RRS阅读器在内几十个项目都使用Bigtable。这些应用对Bigtable的要求以及使用的集群机器数量都各不相同,但从实际运行来看,Bigtable完全可以满足这些不同需求的应用,而这一切都得益于其优良的构架以及恰当的技术选择
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐