google论文:big table
1. 导论
BigTable is a compressed, high performance, and proprietary data storage system built on Google File System, Chubby Lock Service, SSTable (log-structured storage like LevelDB) and a few other Google technologies.(这句是wikipedia摘抄的定义)
构成:
先通俗几个名词:
Google File System
2. 数据模型
BigTable不能支持完整的关系型数据模型,只提供一个简单的数据模型,可以支持针对数据部署和格式的动态控制,允许用户区推理底层存储所展现的数据的位置属性。这句话有些玄乎,其实就是nosql的典型存储方式,不管你需要存储的数据有多大,是什么样的格式——图片,音乐或者其他,bigtable都把它们当做字符串存储在GFS中。
这个数据模型世纪上市一个稀疏的、分布的、永久的多位排序图。采用row key,column key,timestamp对图进行索引。每个值都是未经解释的字节数组。
(row:string, column string, time:int64)→string
一个表中的行键,是任意的字符串(当前尺寸是64KB), 对每一个行键所包含数据的读或写都是一个原子操作,而不管这个行中所包含的的列的数量多少。在行键上根据字典顺序对数据进行维护。对一个表而言,行区间是动态划分的,因为列的大小数量不确定。每一个行区间是一个Tablet,是负载均衡和数据分发的基本单位。
列键被分组为一个称为“Column family”的集合,是基本的访问控制单元。存储在一个列家族当中的所有数据通常都属于同一个数据类型。因为通常是对同一个列家族中的数据一起压缩。存储上也是面向列进行的。列键的命名方式为Column family:qualifier。Family is heavyweight, qualifier lightweight,即为,列家族很少变化,基本上是固定的,但是修饰符可以是任意字符串。
这里给出一个实际的例子。假设我们想要拷贝一个可能被很多项目都是用的、很大的网页集合以及相关的信息,让我们把这个特定的表称为Webtable。在Webtable当中,我们使用URL作为行键,网页的不同方面作为列键,并把网页的内容存储在contents:column中,如图所示。通过对URL地址进行反转,属于同一个领域的网页都会被分组到连续的行中。例如,在键com.google.maps/index.html下面存储maps.google.com/index.html中包含的数据。把来自同一个领域的数据彼此临近存储,使得一些领域分析更加高效。
存储了网页数据的Webtable的一个片段。行名称是反转的URL,contents列家族包含了网页内容,anchor列家族包含了任何引用这个页面的anchor文本。CNN的主页被Sports Illustrated和MY-look主页同时引用,因此,我们的行包含了名称为”anchor:cnnsi.com”和”anchor:my.look.ca”的列。每个anchor单元格都只有一个版本,contents列有三个版本,分别对应于时间戳t3,t5和t6。
3. 实现
BigTable实现包括三个主要的功能组件:(1)库函数:链接到每个客户端,(2)一个主服务器,(3)许多Tablet服务器。
主服务器负责把Tablet分配到Tablet服务器,探测Tablet服务器的增加和过期,进行Table服务器的负载均衡,以及GFS文件系统中的垃圾收集。除此以外,它还处理模式变化,比如表和列家族创建。
每个Tablet服务器管理一个Tablet集合,通常,在每个Tablet服务器上,会放置10到1000个Tablet。Tablet服务器处理针对那些已经加载的Tablet而提出的读写请求,并且会对过大的Tablet进行划分。
客户端并不是直接从主服务器读取数据,而是直接从Tablet服务器上读取数据。因为BigTable客户端并不依赖于主服务器来获得Tablet的位置信息,所以,大多数客户端从来不和主服务器通信。从而使得在实际应用中,主服务器负载很小。
4. tablet查找
使用了一个类似于 B+树的三层架构,来存储Tablet位置信息。
METADATA表中存储了二级信息,包括一个日志,它记载了和每个tablet有关的所有事件,比如,一个服务器什么时候开始提供这个tablet服务。这些信息对于性能分析和程序调试是非常有用的。
客户端函数库会缓存Tablet位置信息。如果客户端不知道一个Tablet的位置信息,或者它发现,它所缓存的Tablet位置信息部正确,那么,它就会在Tablet位置层次结构中依次向上寻找。如果客户端缓存是空的,那么定位算法就需要进行三次轮询,其中就包括一次从Chubby中读取信息。如果客户端的缓存是过期的,定位算法就要进行六次轮询,因为,只有在访问无效的时候才会发现缓存中某个entry是过期的(这里假设METADATA Tablets不会频繁移动)。虽然,Tablets位置信息是保存在缓存中,从而不需要访问GFS,但是,仍然通过让客户端库函数预抓取tablet位置信息,来进一步减少代价,具体方法是:每次读取METADATA表时,都要读取至少两条以上的Tablet位置信息。
每个Tablet只能被分配到一个tablet服务器。主服务器跟踪tablet服务器的情况,掌握当前tablet被分配到tablet服务器的情况,其中包括哪个tablet还没有被分配。当一个tablet没有被分配,并且一个具有足够空间可以容纳该tablet的tablet服务器是可用时,主服务器就把当前这个tablet分配给这个tablet服务器,主服务器会向tablet服务器发送一个tablet负载请求。
BigTable使用Chubby来跟踪tablet服务器。当一个Tablet服务器启动的时候,它创建并且获得一个独占的排他锁,这个锁会锁住一个特定的Chubby目录中的一个唯一命名的文件。主服务器监视这个目录(服务器目录),来发现tablet服务器。如果一个tablet服务器停止服务,它就会丢失这个锁,比如,由于网络故障,导致这个tablet服务器丢失了这个Chubby会话。(Chubby提供了一个完善的机制,来允许一个tablet服务器检查自己是否已经丢失了这个独占排他锁)。如果丢失了锁,那么,只要目录中的这个文件还存在,那么一个tablet服务器就会努力去获得这个锁。如果文件不再存在,那么,这个tablet服务器就不再能够对外提供服务,因此,它就自杀。一旦一个tablet服务器终止了服务(比如,簇管理系统把这个tablet服务器从簇中移除),它就会努力释放锁,这样,主服务器就可以更快地重新分配这个tablet。
主服务器需要探测,什么时候tablet服务器不再提供tablet服务,并且要负责尽快对这些tablet进行重新分配。为了探测什么时候tablet服务器不再提供tablet服务,主服务器会周期性地询问每个tablet服务器,了解他们的锁的状态。如果一个tablet服务器报告,它已经丢失了锁;或者,在最近的几次尝试中,主服务器都无法与tablet服务器取得联系,主服务器就会努力获得一个针对这个服务器文件的独占排他锁。如果主服务器可以获得这个锁,那么,Chubby就是可用的,相应地,这个tablet服务器或者已经死亡,或者有些故障导致它无法到达Chubby。因此,主服务器就从Chubby中删除这个tablet服务器的文件,从而确保这个tablet服务器不再能够提供服务。一旦一个服务器文件被删除,主服务器就可以把所有以前分配给该服务器的tablet,都移动到“待分配”tablet集合。为了保证一个BigTable簇不会轻易受到主服务器和Chubby之间的网络故障的影响,如果一个主服务器的Chubby会话过期了,这个主服务器就会自杀。但是,正如上所述,主服务器失效,不会改变tablet到table的分配。
5. 读写方式
一个tablet的持久化存储是存在GFS当中,如图5所示。更新被提交到一个提交日志,日志中记录了redo记录。在这些更新当中,最近提交的更新被存放到内存当中的一个被称为memtable的排序缓冲区,比较老的更新被存储在一系列SSTable中。为了恢复一个tablet,tablet服务器从METADATA表当中读取这个tablet的元数据。这个元数据包含了SSTable列表,其中,每个SSTable都包括一个tablet和一个重做点(redo point)的集合,这些redo point是一些指针,它们指向那些可能包含tablet所需数据的重做日志。服务器把SSTable索引读入内存,并且重构memtable,方法是,执行重做点以后的所有已经提交的更新。
当一个写操作到达tablet服务器,服务器首先检查它是否是良好定义的,并且发送者是否被授权执行该操作。执行授权检查时,会从一个Chubby文件中读取具有访问权限的写入者的列表,这个Chubby文件通常总能够在Chubby客户端缓存中找到。一个有效的变化,会被写到提交日志中。分组提交是为了改进许多小更新[13,16]操作的吞吐量。在写操作已经被提交以后,它的内容就会被插入到memtable。
当一个读操作到达Tablet服务器,与写操作类似,服务器也会首先检查它是否是良好定义和得到授权的。一个有效地读操作是在以下二者的合并的基础上执行的,即一系列SSTable和memtable。由于SSTable和memtable是字典排序的数据结构,合并视图的执行是非常高效的。
当tablet发生合并或分解操作时,正在到达的读写操作仍然可以继续进行。
6. 压缩
压缩分为三种:
7. 完善措施
- locality group
- Compression
- Bloom filters
一个读操作必须从构成一个tablet的当前状态的所有SSTable中读取数据。如果这些SSTable不在内存中,我们就不得不需要很多磁盘访问。我们通过下面的方式来减少磁盘访问,即允许客户端来确定,为某个特定locality group中的SSTable创建Bloom filter。一个Bloom filter允许我们询问,一个SSTabble是否包含属于指定的“行-列队”的特定的数据。对于某个特定的应用,一个用来存储Bloom filter的很少量的tablet服务器内存空间,都可以极大减少读操作的磁盘访问次数。我们使用Bloom filter也意味着,许多针对目前不存在的行或列的查询,根本就不需要访问磁盘。