您现在的位置是:首页 > 正文

YunTable开发日记(6)- BigTable的分布式模型

2024-04-01 00:42:52阅读 4

 

在介绍了BigTable的存储模型之后,本篇将重点给大家介绍其分布式模型。由于本文大多数内容参考BigTable的论文,如果有些博友已经熟读这篇论文,可以跳过本文。

综述

从分布式的角度而言,BigTable会涉及总共五种独立的构件:

    1. Client端的库:一个基于BigTable的应用会根据其所使用语言的不同,而选择不同的Client端库来访问一个BigTable系统。
    2. Chubby服务:一个高可用、分布式的锁服务,用于协调整个BigTable的运作。
    3. Master节点:分配Tablets给Tablet服务器、检测新加入的或者过期失效的Table服务器、并对Tablet服务器进行负载均衡、以及对保存在GFS上的文件进行垃圾收集。除此之外,它还处理与数据库Schema相关的修改操作,例如建立Table和Column Family。
    4. Tablet节点: 每个Tablet服务器都管理一个Tablet的集合(通常每个服务器有大约数十个至上千个Tablet)。每个Tablet服务器负责处理它所加载的Tablet的读写操作,以及在Tablets过大时,对其进行分割。
    5. GFS系统:GFS是一个分布式文件系统,其主要用于管理和备份那些用于存储Tablet的SSTable文件,但是其执行对于BigTable而言是透明的。

 

虽然Chubby并不是BigTable的一个组成部分,但由于其对BigTable整个分布式的运作非常关键,所以下面将首先介绍Chubby。

 

Chubby的介绍

Chubby的机制

主要可以分为下面这四个方面:

    1. 在运行机制方面:一个Chubby服务包括5个活动的副本,也就是replica,其中的一个副本被选为Master,让其来处理请求。只有在大多数副本都是正常运行的,并且彼此之间能够互相通信的情况下,Chubby服务才被认为是可用的,而当有一个副本失效的时候,Chubby使用Paxos算法来保证副本的一致性。
    2. 在实现机制方面:Chubby主要提供了一个名字空间,里面包括了目录和小文件。每个目录或者文件都可被视为一个锁,而读写这些文件的操作都是原子的。
    3. 在与Client端交流方面:Chubby提供对Chubby文件的一致性缓存。每个Chubby客户程序都维护一个与Chubby服务的会话。如果客户程序不能在租约(Lease)到期的时间内重新签订会话的租约,这个会话就过期失效了。当一个会话失效时,它拥有的锁和打开的文件句柄都失效了。

 

Chubby在BigTable的作用

在BigTable中Chubby主要完成下面的几个任务:

    1. 确保在任何给定的时间内最多只有一个活动的Master节点。
    2. 存储BigTable数据库的初始Root Tablet的位置(具体请看下面“如何定位Tablet”这段)
    3. 为Tablet服务器提高锁服务,以及在Tablet服务器失效时进行善后(具体请看下面“如何分配Tablet”这段)
    4. 存储BigTable的schema信息(和column family相关的)和ACL(访问控制列表)。

 

假设Chubby服务在长时间内无法被访问,这将导致BigTable无法正常工作。还有,Chubby也有相关的开源版本,比如Hadoop系列的zookeeper,但两者在实现机制上面有一定的差别。

 

如何定位Tablet?

首先,在Master和Tablet节点之间的关系上面,采用了很多Single-Master类型的分布式存储系统类似的设计,也就是客户端读取的数据都不经过Master服务器,客户程序直接和Tablet服务器通信进行读写操作。由于BigTable的客户端程序不必通过Master服务器来获取Tablet的位置信息,因此,大多数客户端程序甚至完全不需要和Master服务器通信。在实际应用中,Master服务器的负载是很轻的,所以一个Master节点能支持上千的Tablet节点。还有,一个BigTable集群会存储了很多表,每个表都可以被认为是一个Tablet的集合,而且每个Tablet包含属于某个Range的行的所有相关数据,在初始状态下,一个表只有一个Tablet,但随着表中数据的增长,它会被自动分割成多个Tablet,在缺省情况下,每个Tablet的大小在100MB左右。下图为Tablet的层次图:Bigtable distributed

图1. Tablet的层次图

总体而言,Tablet的层次是一个三层,类似于B+树的结构。最上面是一个存储在Chubby中的文件,它包含了Root Tablet的位置信息。Root Tablet包含了一个特殊的METADATA表里所有的Tablet的位置信息。METADATA表的每个Tablet包含了一个UserTablet的集合。Root Tablet实际上是METADATA表的第一个Tablet,只不过对它的处理比较特殊,比如,Root Tablet永远不会被分割,这样将保证了Tablet的结构最多有三层。在METADATA表里面,每个Tablet的位置信息都存放在一个行关键字下面,而这个行关键字是由Tablet所在的表的标识符和Tablet的最后一行编码而成的。METADATA的每一行都存储了大约1KB的内存数据。在客户端使用的BigTable库会缓存Tablet的位置信息。如果客户端程序没有缓存某个Tablet的地址信息,或者发现它缓存的地址信息不正确,客户端程序就在上面那个树状的存储结构中递归的查询Tablet位置信息。在支撑的容量方面,一个大小适中的、容量限制为128MB的METADATA Tablet中,假如采用这种三层结构的存储模式,可以标识2^34个Tablet的地址(如果每个Tablet存储128MB数据,那么一共可以存储 2^61字节数据)。

 

如何分配Tablet?

Masater会跟踪当前有那些活跃的Tablet服务器和跟踪Tablet的存储地方,并将Tablet分配给有空闲空间的Tablet服务器。BigTable系统使用Chubby服务来记录Tablet服务器的状态。当一个Tablet服务器启动时,这个Tablet服务器会在Chubby的一个指定目录下建立一个有唯一性名字的文件,并且获取该文件的独占锁。Master服务器实时监控着这个目录,而且通过这个手段,Master服务器因此能够获知有那些新的Tablet服务器加入整个集群。如果这个Tablet服务器丢失了Chubby上的独占锁,只要那个文件还存在,这个服务器就会试图重新获得对该文件的独占锁;如果文件不存在了,那么Tablet服务器就不能再提供服务了,它会自行退出。当Tablet服务器终止时,它会尝试释放它持有的文件锁,这样一来,Master服务器就能尽快把Tablet分配到其它的Tablet服务器。

Master服务器会检查一个Tablet服务器是否已经不再为它的Tablet提供服务了,并且要尽快重新分配它加载的Tablet。 Master服务器通过轮询Tablet服务器文件锁的状态来检测。如果一个Tablet服务器报告它丢失了文件锁,或者Master服务器最近几次尝试和它通信都没有得到响应,Master服务器就会尝试获取该Tablet服务器文件的独占锁;如果Master服务器成功获取了独占锁,那么就说明Chubby是正常运行的,而Tablet服务器要么是宕机了、要么是不能和Chubby通信了,因此,Master服务器就删除该Tablet服务器在Chubby上的服务器文件以确保它不再给Tablet提供服务。一旦Tablet服务器在Chubby上的服务器文件被删除了,Master服务器就把之前分配给它的所有的Tablet放入未分配的Tablet集合中。为了确保Bigtable集群在Master服务器和Chubby之间网络出现故障的时候仍然可以使用,Master服务器在它的Chubby会话过期后主动退出。总体的来说,Chubby提供了一种高效的机制,利用这种机制,Tablet服务器能够在不增加网络负担的情况下知道它是否还持有锁。

当BigTable系统启动了一个Master服务器之后,Master服务器首先要了解当前Tablet的分配状态,之后才能够修改分配状态。 Master服务器在启动的时候执行以下步骤:

    1. Master服务器从Chubby获取一个唯一的Master锁,用来阻止创建其它的Master服务器的实例。
    2. Master服务器扫描Chubby的服务器文件锁存储目录,获取当前正在运行的服务器列表。
    3. Master服务器和所有的正在运行的Tablet表服务器通信,获取每个Tablet服务器上Tablet的分配信息,如果发现发现Root Tablet还没有分配,Master服务器就把Root Tablet加入到未分配的Tablet集合。这个附加操作确保了Root Tablet会被分配。
    4. Master服务器扫描METADATA表获取所有的Tablet的集合。在扫描的过程中,当Master服务器发现了一个还没有分配的Tablet,Master服务器就将这个Tablet加入未分配的Tablet集合等待合适的时机分配。

 

由于Root Tablet包括了所有METADATA的Tablet的名字,因此Master服务器扫描完Root Tablet以后,就得到了所有的METADATA表的Tablet的名字了。

保存现有Tablet的集合只有在以下事件发生时才会改变,建立了一个新表或者删除了一个旧表、两个Tablet被合并了、或者一个Tablet被分割成两个小的Tablet。Master服务器可以跟踪记录所有这些事件,因为除了最后一个事件外的两个事件都是由它启动的。Tablet分割事件需要特殊处理,因为它是由Tablet服务器启动。在分割操作完成之后,Tablet服务器通过在METADATA表中记录新的Tablet的信息来提交这个操作;当分割操作提交之后,Tablet服务器会通知Master服务器。如果分割操作已提交的信息没有通知到Master服务器(可能两个服务器中有一个宕机了),Master服务器在要求Tablet服务器装载已经被分割的子表的时候会发现一个新的Tablet。通过对比METADATA表中Tablet的信息,Tablet服务器会发现Master服务器要求其装载的Tablet并不完整,因此,Tablet服务器会重新向Master服务器发送通知信息。

 

本文结束,下篇将关注BigTable的功能集。

参考资料:

    1. BigTable的论文
    2. Chubby的论文

网站文章

  • 红绿灯倒计时

    红绿灯倒计时

    这里写自定义目录标题新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 红绿灯倒计时 ...

    2024-04-01 00:42:26
  • 2023最新在线生成支付宝自定义支付收款二维码源码+UI轻量级的

    2023最新在线生成支付宝自定义支付收款二维码源码+UI轻量级的

    ​在线生成支付宝自定义支付二维码,是一种非常方便的工具。通过这个工具,您可以快速生成支付宝自定义金额和备注的二维码,不受限制生成次数。只需要填写收款方的支付宝商户号、金额和转账备注,然后点击生成二维码即可。商户号获取:1.登录支付宝商户官网。

    2024-04-01 00:42:20
  • chatgpt赋能python:Python从后往前查找字符串:最实用的字符串操作技巧

    chatgpt赋能python:Python从后往前查找字符串:最实用的字符串操作技巧

    从后往前查找字符串指的是在一个字符串中从后往前查找匹配的子字符串。在 Python 中,我们可以使用rfind()方法来实现从后往前查找。例如,我们有一个字符串 “Hello World”,我们想要查...

    2024-04-01 00:42:14
  • hutool——解析csv文件

    hutool——解析csv文件

    【代码】hutool——解析csv文件。

    2024-04-01 00:42:08
  • 利用阿里云OSS Browser图形工具管理OSS对象存储文件

    利用阿里云OSS Browser图形工具管理OSS对象存储文件

    之前老左有分享过利用阿里云OSS对象存储自建图床,以及可以将WordPress网站中的图片、附件单独存储与网站文件分离,其中可以用到WPOSS插件工具(WPOSS插件实现WordPress图片分离至阿...

    2024-04-01 00:41:43
  • 如何检测照片中共有多少张人脸,机器学习

    如何检测照片中共有多少张人脸,机器学习

    后面的学习中,我会慢慢训练出自己的模型来使用,其实不用自己训练数据模型的话代码量还是比较少的。下面是github的训练模型的下载地址,目前已经2100多的star了。今天实践的是python中的opencv这个库,至于这个库官方肯定比我解释的更加准确,下面是官方的解释。python解释器使用的版本是3.8.6,我这里测试使用的是这两个版本是没有问题的。对读取的pic.jpg图片做灰度处理。...

    2024-04-01 00:41:35
  • 计算机网络搜索引擎的分类和技术,搜索引擎-及计算机网络信息资源分类组织.pdf...

    图书情报工作 2000年第4期LIBHAPLYANDINFDRMA.110NSERVICENO.4,2000搜索引擎及网络信息资源的分类组织陈树年(华东理工大学石油化工学院上海200540)[...

    2024-04-01 00:41:29
  • 函数指针的读法

    指针的概念在C里面非常重要,而对于函数指针的理解更有利于掌握程序执行的过程。对于以下声明 (char*)(*f)(int*,float)正确的阅读顺序为:要从(*f)开始读,*f表明f为一个指针,而(*f)(int*,float*)表明f是一个函数指针,这个函数有2个参数,分别位int*和float。最后我们知道它是一个返回值为char*和参数为int*和float的函数。另外

    2024-04-01 00:41:05
  • cafee matlab可视化,12个写论文必备的神经网络可视化工具

    cafee matlab可视化,12个写论文必备的神经网络可视化工具

    本文介绍了了12个将神经网络画地更好看的工具。1. draw_convnet一个用于画卷积神经网络的Python脚本链接:https://github.com/gwding/draw_convnet2...

    2024-04-01 00:40:57
  • 二叉树的二叉链表存储及基本操作

    第1关:先序遍历创建二叉链表存储的二叉树及遍历操作 本关任务:以二叉链表作存储结构存储二叉树,利用先序递归遍历创建二叉树,并依次进行二叉树的前序、中序、后序递归遍历。 #include #includ...

    2024-04-01 00:40:51