Bigtable: A Distributed Storage System for Structured Data

2003年USENIX,出自谷歌,开启分布式大数据时代的三篇论文之一,底层依赖 GFS 存储,上层供 MapReduce 查询使用

Abstract

是一种分布式结构化数据存储管理系统,存储量级是PB级别。存储的数据类型和延时要求差异都很大。论文介绍数 bigtable 的数据模型。

Introduction

BigTable 达成了几个目标:适用面广、伸缩性好、高性能、高可用。即可以满足吞吐导向的批处理的需求,也满足延迟敏感服务的需求。很多时候 BigTable 看起来像数据库,但又有不同的接口层。不支持全部关系数据模型、支持动态控制数据布局和格式。支持数据再底层存储时候的属性推断。数据用字符串作为行列名建索引。BigTable 把数据当字符串。

Data Model

BigTable 是一个稀疏、分布式、持久化、多维存储的字典(map)。map 由一个 row key、column key、timestamp 组合建索引,map 的值是字节流(array of bytes)。(row:string, column:string, time:int64) → string,以下是一个具体的例子:
在这里插入图片描述
这个 Webtable 表存储了网页内容,和引用该网页的网页地址。

Rows

对一个 row key 的读写都是原子的,不管里面包含了多少列。这个设计使得客户端使用的时候更好做并发控制。

BigTable按照字典序存储 row key。行范围动态划分,一个范围称为一个 tablet,其作为分布式存储平衡的单元。这个性质帮助客户端探索数据的局部性存储,得到更高的效率。比如对于 webtable 来说,同一个网站的页面因为 url 的倒序排列而聚集到一起。

Column Families

column keys 聚集到 column families 里面,column families 作为访问控制的基本单元。同一个 column families 的数据通常来说有相同的数据类型,并且系统会把数据放一起压缩。column family 先创建,再使用。系统的用意就是 column family 的数量比较少,并且不经常变动。相反,column 的数量不做限制。

一个 column key 的格式 family:qualifier,例如对于 webtable 来说,一个 column family是 language family。里面只有一个 column key,存储网页的 language ID。另一个 column family 是 anchor,如图一所示。

Timestamps

每个 BigTable 的单元格可以存储同一份数据的多个版本,版本号就是 timestamp。并且从大到小倒序排列。为了高效管理,系统支持设置保留最近几个版本,或者回收多久以前的旧版本。

API

提供了基本的API来控制 BigTable,比如创建表,改变列,访问控制等。一个简单的例子:

// Open the table
Table *T = OpenOrDie("/bigtable/web/webtable");
// Write a new anchor and delete an old anchor
RowMutation r1(T, "com.cnn.www");
r1.Set("anchor:www.c-span.org", "CNN");
r1.Delete("anchor:www.abc.com");
Operation op;        // 原子的将这些改变落地
Apply(&op, &r1)

还有一个用 Scanner 来扫描特定行列的例子:

Scanner scanner(T);
ScanStream *stream;
stream = scanner.FetchColumnFamily("anchor");
stream->SetReturnAllVersions();
scanner.Lookup("com.cnn.www");
for (; !stream->Done(); stream->Next()) {printf("%s %s %lld %s\n",scanner.RowName(),stream->ColumnName(),stream->MicroTimestamp(),stream->Value());
}

BigTable 支持单行的事务,用 read-modify-write 模式保证原子性。支持单元格计数。支持服务器上执行客户端提供的脚本,脚本功能是对数据进行转化,过滤,统计等操作。

Building Blocks

BigTable 依赖几个谷歌内部的基础服务,第一个就是GFS。

存储文件格式是 Google SSTable 文件格式。这个格式是一种持久化,有序、不可变的 key -> value 映射格式,key 和 value 都是字符串的二进制数组形式。每一个 SSTable 包括连续的 blocks,一个 block 64KB。block index 用于查找 block。当 SSTable 打开的时候,block index 载入内存,通过二分查找找到合适的索引。然后从磁盘读取合适的 block。此外 SSTable 还可以映射到内存中,这样可以完全避免磁盘操作。

BigTable 还依赖一个高可用的分布式锁服务 Chubby。Chubby 有5个服务组成,其中一个是 master,用来处理请求。当超过一半副本存活的时候,集群可用。Chubby 使用 Paxos 算法来保持副本间的一致性。Chubby 基本可以看作是 zookeeper 的谷歌版。客户端和 Chubby 保持session,能一致性的读写小文件,文件带锁,Chubby 支持对保存文件注册回调函数。

BigTable 用 Chubby 有几个不同用处:确保任何时刻只有最多一个 master;存储 bootstrap 文件地址;tablet 服务发现和死亡摘除;存储表的 schema 信息(每张表的 column family);保存存储权限列表。Chubby 不可用了,BigTable 也就不可用了。

5 Implementation

整体有三大组件:客户端需要链接的依赖库,一个 master Server,一堆 tablet Servers。tablet server 可以动态加入或者移除集群。

master 的职责是分配 tablets 给 tablet servers;发现并加入 tablet server,删除过期的 tablet server,平衡 tablet servers 之间的负载,垃圾回收无效的文件,表格 schema 的变化。

tablet Server 负责一系列的 tablet,包括读写请求,对于增长过大的 tablet 负责分裂。

client 也是直接和 tablet Server 进行读写数据通信。client 不依赖 master 获取 tablet 的定位信息,绝大多数 client 不会和 master进行通讯。

一个 BigTable 集群储存多张 table,每个 table 由多个 tablet 组成,每个 tablet 里面存储 row range 里面的全部数据。一开始,一张 table 只有一个 tablet,随着 table 数据增长,会自动分裂成多个 tablet,每一个 tablet 大约100~200M

5.1 Tablet Location

三层结构存储 tablet 位置信息的 B+ 树
在这里插入图片描述
Chubby 里面保存 root tablet 的地址,root tablet 不会分裂,里面保存其他所有 MetaData 里的 tablet,而MetaData 里面的 tablet 里保存 user tablet 的位置信息。

MetaData table 保存一个 row key 存储在 tablet 的位置信息,这个位置信息是 tablet 对其所属 table 标识符和row key的开始行和结束行的 encoding。其中存储的是以开始和结尾的Row Key作为键,tablet位置作为值的映射。每一个 MetaData row 差不多1KB,通常128MB的大小的 MetaData tablet 限制,三层的 location schema 能存储2^34 个 tablets。

client 会 cache tablet 的位置信息,如果 cache 中没有或者不正确,就递归的向上查找。这个位置信息存储在内存中,客户端在读取时也会采取“预取”策略,一次读取多个 tablet 位置信息。

MetaData 里面还存储一些二级信息,例如事件日志,用于调试。

5.2 Tablet Assignment

master 追踪所有 tablet Server,一个 tablet 一个时刻也只能分配给一个 tablet Server。
当一个 tablet 没有被分配,如果出现足够资源的 tablet Server,master 就会将其分配给这个 tablet Server。

BigTable 用 Chubby 来追踪 tablet Server。当 tablet Server 启动的时候,在 Chubby 的一个特定目录下申请一个排它锁(一个唯一文件名的文件)。master 会一直监控这个目录以感知 tablet Server 的变化。当 tablet Server 不服务的时候,就会释放 Chubby 上的锁。

master 会周期性的询问 tablet Server 是否还持有 Chubby 上的锁。如果 tablet 不持有或者无法应答 master 的请求,master 会尝试获取这个 tablet Server 的锁,并删除这个文件对应的锁。之后 master 会标记 tablets 为不可用。当 master 和 Chubby 断链,master 会自动退出,并不改变 tablet 的分配。

当 master 启动时,执行一下操作(1)获取 Chubby 上的 mater 锁,确保只有一个 master(2)master 扫描 Chubby 上的 server 目录,发现活着的 tablet Server。(3)和每个 tablet Server 通讯,查询被分配的 tablet(4)扫描 MetaData 表,如果遇到 tablet 没有被分配,标记为未分配。后续会对未分配的 tablet 做分配。

一个复杂的情况是扫描 MetaData 表的时候,MetaData tablet 本身就还未分配。因此在执行步骤(4)之前,如果 root table 没有 分配,master 把 root tablet 标记为未分配。因为 root table 包含所有 MetaData 的 tablets,所以 master 扫描 root table 之后就能扫描全部的 MetaData。

一个已有的 tablet 只有创建/删除、合并、分裂的时候才会改变。当 tablet 分裂时,tablet Server 往 MetaData 中记录新的 tablet,之后会通知 master。

5.3 Tablet Serving在这里插入图片描述

更新操作提交到 commit log 中,作为重做记录(redo log)。整体这块的顺序是WAL(write after log)。最近的一些更新提交存储在内存中,有序存储,这块儿叫做 memtable;老一些的更新提交存储在磁盘上的 sequence SSTable 上。所以可以看出来,一个 tablet 由三部分组成,磁盘上的 tablet log,一系列的 SSTable 文件,以及内存上的 memtable。这种操作在后续的 ElasticSearch 上也有体现。

为了恢复一个 tablet Server,tablet Server 会先读取其 MetaData 知道包含哪些 SSTable,并且 MetaData 里有一系列的重做指针,指向 commit log。tablet Server 读取 SSTable 索引,并通过重做指针指向的更新提交,重建 memtable。

新来一个写操作的时候,先校验格式、鉴权。通过之后先写都 commit log 里。多个 commit 聚合起来写,提升吞吐,写完之后,再把内容写入到 memtable。

读操作也是先校验,鉴权,然后在 memtable 和 SSTable 里面查询,并将结果合并。

5.4 Compactions

随着 memtable 越来越大,达到阈值之后冻结转化成 SSTable,写入GFS,同时创建一个新的 memtable。这个操作叫 minor compaction,能较少内存使用,也能较少 commit log 的大小。

minor compaction 每次都会创建一个 SSTable,放任不管小文件会越来越多。因此还需要控制文件数量, BigTable 通过一个默认的线程执行 major compaction 来达成。这个操作读取新生成的小碎 SSTable,然后合并写入一个新的大的 SSTable 里。

在 major compaction 会删除之前 SSTable 里面标记软删除的数据。

6 Refinements

Locality groups(存储位置分组)

Compression(数据压缩)

Caching for read performance(读时缓存)

Bloom filters(布隆过滤器)

例如5.3节里的图例表示,需要读取 tablet Server 下所有的 tablet 来获取最新的数据,这会有比较多的磁盘读取操作。在 tablet Server 上建立 bloom filter,验真查找的 row-cloumn 对是否在某个 SSTable 上,减少磁盘操作。

Speeding up tablet recovery(恢复加速)

master 移动一个 tablet 的时候,原来的 tablet Server 对这个 tablet 先做一次 minor compaction,这样能减少 commit log,从而加速恢复。然后该 tablet Server 停止对这个 tablet 服务。在确保卸载完全之前,还会在做一次 minor compaction,彻底干掉内存里的 commit log。

Exploiting immutability(不可变性)

除了SSTable缓存之外,Bigtable 系统的其他各个部分都被简化了,因为我们生成的所有 SSTable 都是不可变的。例如,当从SSTables 读取时,我们不需要同步访问文件系统。因此可以非常有效地实现对行的并发控制。读写都可以访问的唯一可变数据结构是 memtable。为了减少读取 memtable 时的争用,我们在写时复制每个memtable 行,并允许读和写并行进行。

由于 SSTables 是不可变的,永久删除已删除数据的问题转化为垃圾收集过时的 SSTables。每个 tablet Server 的 SSTable 都注册在 MetaData 中。主进程删除过时的 SSTables,作为对 SSTables 集的标记和清除垃圾回收,其中元数据表包含根集。

最后,SSTables 的不变性使得能够快速分割 tablet。我们不为每个子 tablet 生成一组新的 SSTable,而是让子 tablet 共享父tablet 的 SSTables。

9 Lessons

作者总结了大型分布式系统的一些经验

第一条经验:大型分布式系统容易受到多种失败类型的困扰,不仅仅是标准的网络不通,故障停止(fail-stop)等。例如内存和网络崩溃、锁倾斜、机器宕机、非对称的网络分裂、依赖系统的 bug、GFS配额超限、硬件过保等等。作者通过修改协议来缓解。例如在 RPC 里面增加校验和,去掉对依赖系统的一些假设。

第二大经验:除非清楚新功能有什么用,否则延迟增加新需求很重要。例如作者想实现【事务】的时候,等实际使用了来,才发现只需要实现单行级别的事务就可以了。

第三大经验:系统级的监控非常重要(例如监控 BigTable 本身和使用 BigTable 的客户端)。例如扩展了RPC系统,用于追踪系统通过RPC做的重要动作。这个特性帮助排查解决了很多问题。

最重要的经验:设计简单的价值。考虑到我们系统的规模,以及代码随着时间的推移以意想不到的方式演变的事实,我们发现代码和设计的清晰性对代码维护和调试有着巨大的帮助。其中一个例子就是我们的tablet服务器成员协议。我们的第一个协议很简单:主机定期向tablet服务器发出租约,如果租约到期,tablet服务器就会自杀。不幸的是,这种协议在出现网络问题时会大大降低可用性,而且对主恢复时间也很敏感。我们重新设计了几次协议,直到我们有了一个性能良好的协议。但是,生成的协议太复杂,并且依赖于其他应用程序很少使用的Chubby功能的行为。 我们发现,不仅在Bigtable代码中,而且在Chubby代码中,我们花费大量时间调试晦涩难解的案例。 最终,我们放弃了该协议,转而使用仅依赖于广泛使用的Chubby功能的更新的更简单协议。

参考链接:
https://zhuanlan.zhihu.com/p/338566270
https://zhuanlan.zhihu.com/p/164926186
https://zhuanlan.zhihu.com/p/158607288

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/350222.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

植物ATAC-seq文献集锦(三)——果实发育篇

ATAC-seq在植物研究领域的应用我们已经介绍2期了,本期我们聚焦ATAC-seq技术在果实发育方向的应用案例。 植物ATAC-seq文献集锦(一)——基因组篇 植物ATAC-seq文献集锦(二)——生长发育篇 文献一:Ident…

electron基础使用

安装以及运行 当前node版本18,按照官网提供操作,npm init进行初始化操作,将index.js修改为main.js,执行npm install --save-dev electron。(这里我挂梯子下载成功了。),添加如下代码至package.…

【AI绘画】教你一个完美的文生图方法,简单易学好上手,新手也能轻松掌握Stable Diffusion使用!

当我们还在思索, AI(人工智能)是否能替代人类的地位, 它已悄然无声, 融入我们生活的点滴细节。 在艺术创作领域, AI技术作为核心力量,展现其无尽的魅力。 AI换脸、AI影像,AI角色、A…

Nas实现软路由OpenWrt安装

文章目录 基本配置步骤 基本配置 NAS:TS-264C 宇宙魔方 步骤 1.下载软路由OpenWrt 下载地址:https://openwrt.org/ 2.下载好以后,需要下载虚拟盘转换工具(StarWind V2V Convert) 下载地址:https://…

sprintboot容器功能

容器 容器功能Spring注入组件的注解Component,Controller,Service,Repository案例演示 Configuration应用实例传统方式使用Configuration 注意事项和细节 Import应用实例 ConditionalConditional介绍应用实例 ImportResource应用实例 配置绑定…

10 SpringBoot 静态资源访问

我们在开发Web项目的时候,往往会有很多静态资源,如html、图片、css等。那如何向前端返回静态资源呢? 以前做过web开发的同学应该知道,我们以前创建的web工程下面会有一个webapp的目录,我们只要把静态资源放在该目录下…

C#——正则表达式详情

正则表达式 正则表达式: 列如判断一个字符串是不是手机号,或者密码是否包含大小写数字等这些要求,可以把这些条件写成一个表达式 创建正则表达式 string s1 "1234adsab1KHGFJD"; // 创建正则时需要在字符串前面加上 Regex r new Regex(&q…

【安卓】在安卓中使用HTTP协议的最佳实践

人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…

btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具

一、简介: 在进行Android恶意APP检测时,需要进行自动化的行为分析,一般至少包括行为采集和行为分析两个模块。其中,行为分析有基于规则、基于机器学习、基于深度学习甚至基于大模型的方案,各有各的优缺点,不…

从零开始开发知识付费APP:在线教育系统源码详解

今天,小编将从零开始,详细讲解在线教育系统的源码开发过程,帮助你打造一款功能完善的知识付费APP。 一、需求分析与规划 1.1 市场调研 在开始开发之前,首先要进行市场调研,了解当前市场上的主要竞争对手和用户需求。…

SpringBoot使用jasypt实现数据库信息的脱敏,以此来保护数据库的用户名username和密码password(容易上手,详细)

1.为什么要有这个需求? 一般当我们自己练习的时候,username和password直接是爆露出来的 假如别人路过你旁边时看到了你的数据库账号密码,他跑到他的电脑打开navicat直接就是一顿连接,直接疯狂删除你的数据库,那可就废…

Redis数据结构学习

Redis 关于redis相关的技术文章我一直没什么思路 直到最近的端午节,我偶然和一个程序员朋友聊到了关于redis数据结构相关的知识点, 所以我决定写一篇文章记录一下 首先我们需要知道redis支持哪些数据类型 Strings (字符串)Lists(列表)Hashes(哈希)Sets(集合)Sorted Sets(有序…

通过语言大模型来学习LLM和LMM(四)

一、大模型学习 新的东西,学习的东西就是多,而且最简单最基础的都需要学习,仿佛一点基础知识都要细嚼慢咽,刨根问底,再加上一顿云里雾里的吹嘘,迷迷糊糊的感觉高大上。其实就是那么一回事。再过一段时日&a…

Java课程设计:基于swing的学生信息管理系统

文章目录 一、项目介绍二、项目展示三、源码展示四、源码获取 一、项目介绍 这款Java swing实现的学生信息管理系统和jsp版本的功能很相似,简单的实现了班级信息的增删改查,学生信息的增删改查,数据库采用的是mysql,jdk版本不限&…

Django+Vue.js怎么实现搜索功能

一.前言 类似这样的搜索功能 二.前端代码 <div class"form-container"><div class"form-group"><label for"departure-city">出发城市</label><select v-model"departureCity" id"departure-city&q…

C# Winform 用户控件,扩展控件,自定义控件综合实例

Control类是Windows窗体控件的基类&#xff0c;它提供了在 Windows 窗体应用程序中进行可视显示所需的基础结构&#xff0c;可以通过继承来扩展熟悉的用户控件和现有控件的功能。本列介绍三种不同自定义控件以及怎么创建他们。 自定义控件分类 用户控件&#xff1a;基本控件的…

Python 中国象棋游戏【含Python源码 MX_011期】

简介&#xff1a; 中国象棋是一种古老而深受喜爱的策略棋类游戏&#xff0c;也被称为中国的国粹之一。它在中国有着悠久的历史&#xff0c;起源可以追溯到几个世纪以前。Python 中国象棋游戏是一个用Python编程语言编写的软件程序&#xff0c;旨在模拟和提供中国象棋的游戏体验…

性能测试包括哪些方面?

性能测试、通过自动化测试工具模拟多种正常&#xff0c;峰值&#xff0c;以及异常的负载情况下对系统各项性能指标进行的测试。 负载测试、压力测试、容量测试都属于性能测试。 性能测试指标是衡量系统性能的评价标准 主要关注一些响应时间、并发用户/并发、点击率、吞吐量、…

【ARMv8/ARMv9 硬件加速系列 3.2 -- SVE 读写内存指令 st1b | st1w | st1w | st1d 使用介绍】

文章目录 SVE Load 和 Store 指令使用介绍LD1 加载指令ST1 存储指令PFR 预取指令参考示例LD1 加载示例ST1 存储示例 代码实例 SVE Load 和 Store 指令使用介绍 ARMv9架构中的SVE&#xff08;Scalable Vector Extension&#xff09;指令集为向量计算提供了强大支持&#xff0c;…

10W大奖等你瓜分,OpenTiny CCF开源创新大赛报名火热启动!

OpenTiny CCF开源创新大赛正式启幕&#xff01; &#x1f31f;10万奖金&#xff0c;等你来战&#xff01; &#x1f31f; &#x1f465;无论你是独行侠还是团队英雄&#x1f465; 只要你对前端技术充满热情&#xff0c; 渴望在实战中磨砺技能&#xff0c; 那么&#xff0c…