如何解决kv存储:Google Bigtable 浅析


1.什么是BigTable

       BigTable是一个分布式的存储系统,可以支持PB级别的数据。对于不同数据量和延迟需求的应用都有灵活、高性能的解决方案。
       BigTable和数据库有很多相似之处。Bigtable不支持完整的关系数据模型,而是提供了可以对数据部署和格式动态控制的数据模型。
       BigTable使用行和列索引,行名和列名可以是任意字符串。
       BigTable用灵活的模式参数,允许用户选择从磁盘还是内存获取数据。

2.数据模型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2vMdNizg-1646977304526)(C:\Users\LXC\AppData\Roaming\Typora\typora-user-images\image-20220311133542064.png)]

       一个BigTable是一个**稀疏的、分布式的、永久的多维排序图。**有行健、列键、时间戳三层图索引。

row:string,column:string,time:int64    推出string

       Webtable:很多项目使用的,庞大的网页集合和网页相关信息。
       在Webtabe中,使用URL作为行健,网页元素的类别作为列键,例如网页内容存在contents:column中。

2.1 行

       任意字符串,**每行的数据读写都是原子操作,无论有多少列。**这样便于用户知道同一行的并发更新的发生。
       按字典序维护,表的航区间是动态划分的,没有固定大小限制,每一行叫一个Tablet,是负载均衡和数据分配(一个tablet一条数据)的基本单位。
       对URL进行反转可以提高存储效率、压缩效率(后面会讲),可以把同一领域(类型)的数据临近存储。

2.2 列

       列键又叫做家族,是基本的**访问控制单元。**同一家族的数据属于同一数据类型,也就意味着同一家族的数据可以压缩存储。
       列在操作作中很少发生变化。
       列名:family:qualifier。例如网页的language列存储了网页所用语言的信息。网页的另一个列家族anchor,每一个元素qualifier是引用网站的名称。

2.3 时间戳

       每个单元格会有相同数据的多个版本,版本按时间降序存储,保证获取的第一个是传新版本。
       以列为单位,可以选择保存每个单元格最近的n各版本或最近n天的版本。
例如,为contents列设置时间戳,数值就是这个网页被抓取的时间,只保留网页最新的三个版本的内容。

3. API

       删除创建表、列;改变簇、列家族的元数据,例如访问控制权限。
       增删表中的值,按行查询,,对表的子集遍历(游标)。

//Apply函数调用
//open the table
Table *T = OpenOrDie("/bigtable/web/webtable");
//write a new anchor and delete an old anchor
RowMultitation ri(T,"com.cnn.www");
ri.Set("anchor:www.c-span.org","CNN");
ri.Delete("anchor:www.abc.com");
Operation op;
Apply(&op,&r1);
//apply操作会执行原子更新操作:向www.cnn.com添加一个anchor并删除一个

       利用Scanner遍历某行的所有anchor,可以限制扫描到的anchor符合正则表达式anchor:*.cnn.com或十天内的。

Scanner scanner(T);
ScanStream *stream;
stream = scanner.FetchColumnFamily("anchor");
stream->SetReturnAllVersions();
scanner.LookUp("com.cnn.www");
for(;!stream.Done();stream.next()){
print(%s%s%lld%sn),
scanner.Rowname(),stream->ColumnName(),stream->MicroTimeStamp(),stream.value();}

*其他功能

1.支持单行事务

       允许某一行数据进行原子的读写改。

2.单元格可以作为整数计数器

3.支持服务器在地址空间内执行客户端的脚本

4.建立块结构

       1.BigTable的一个会在一个共享机器池内工作,与其他分布式应用同时运行。所有应用共享共同的硬件机器
       2.**BigTable的内部文件格式:SSTabel。**每一个SSTable是一个持续的,有序的,不可变的,从键到值的映射。
       3.BigTable提供了查找指定键和在一个键区间内查找所有键值对的操作。
       4.每个SSTable内部包换一个块序列。每个块64KB,但块大小是可配置的。
       5.SSTable末尾存储自己内部的块索引,用于快速定位块的位置。
       6.每当SSTable被打开,其内部的块索引就会被装入内存用于快速读取。
       7.一次查询操作只需要进行一次磁盘扫描(二分查找)。
       8.完全读入一个SSTable到内存,就可以在执行查找操作时不需要在访问磁盘。
       9.每个SSTable有一个块序列,也就是一些块,末尾是这些块的索引。

4.1 高可用性和持久性的分布式锁:Chubby

       一个chubby服务有五个副本,主副本对外提供服务,当大部分副本可用(能相互通信时),才对外提供服务。
       chubby有一个命名空间,内部有目录和小文件,每个目录和文件都可以视作一个锁。文件的读写操作都是原子性的。
       所以命名空间就是以他名字命名的一块地址空间。
       chubby客户端函数库提供了对chubby文件的持久性缓存。每个chubby客户啊短同时维护一个session,是chubby提供服务的证明。如果session在规定时间内得不到更新(心跳消息),这个客户端session就会过期。
       此时这个客户端的所有锁都会丢失,同时放弃句柄
       chubby客户端也可以注册/申请对chubby文件的回调服务,用来通知session过期或延长服务。

4.2 Chubby的功能

       (1)每个时刻,只有一个chubby副本是活跃的。
       (2)存储数据boostrap的位置。
       (3)发现tablet服务器和宣告他的死亡。
       (4)存储BigTable的模式信息(每个表的列家族信息。
       (5)存储访问控制列表。

4.3 BigTable实现功能的三个主要组件

       库函数:链接每一个客户端和服务器。
       主服务器:唯一
       很多Tablet服务器
       Tablet服务器(行数据服务器)可以根据负载变化对族中数据进行删除。每个tablet服务器管理一个tablet集合,可以对已经加载的tablet发出读写请求,对大的tablet进行划分。
       主服务器把tablet分配到tablet服务器,同时监听tablet服务器的增加和过期,进行负载均衡。主服务器还可以进行模式修改,比如表、列家族的创建。
       BigTable包含很多表,每个表又包含很多Tablet,每个tablet包含了某个区域的所有数据。
       表会根据情况增加tablet数量。

*单服务器分布式系统的特点

       客户端不从主服务器上拿数据,而是从tablet服务器上拿。也不依赖主服务器获取tablet的位置信息。以此减小主服务器的负载。

5.实现

5.1 TabLet的位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M6b8aRQ8-1646977304529)(C:\Users\LXC\AppData\Roaming\Typora\typora-user-images\image-20220311133622455.png)]

       一个类似B+树的三层结构。

第一层次:文件

       一个存储在chubby中的文件,包含Tool Table的位置信息。

第二层次:Root Table

       存储所有的tablet位置信息,存在一个metadata中。每个metadata表包含很多user tablet的位置信息。

第三层次:METADATA

       存储某一行的tablet的位置信息,行健表示的就是tablet表的标识符和最后一行的位置。

第四层次:User Table

       客户端函数库负责缓存tablet位置。客户端每次获取tablet位置信息(丢失,错误时),需要向上逐层访问(类似于DNS寻找域名需要到根服务器)进行3/6次查询。

5.2 Tablet 分配

       当一个tablet被分配到tablet服务器时,主服务器通过发送tablet负载请求到tablet服务器,主服务器负责调度。
       Bigtable通过chubby追踪tablet服务器。每个tablet服务器启动时获得一个排它锁,这个锁用于锁住特定的chubby目录下的唯一文件。主服务器通过监视这个目录来发现tablet服务器。tablet服务器停机时丢失这个锁。
       Tablet允许tablet服务器检查锁:如果文件还在,tablet服务器会尽力重新获得锁,否则会立刻自杀(因为不能在提供服务),同时释放锁。
       主服务器在tablet服务器失联或反映丢失锁时,会去获得针对这个服务器文件的排他锁。来判断tablet服务器到底是否可用。

5.3 主服务器启动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZeAsRcB-1646977304530)(C:\Users\LXC\AppData\Roaming\Typora\typora-user-images\image-20220311133641834.png)]

       (1)获取master lock,保证只有一个主服务器。
       (2)扫描chubby的服务器目录,了解当前的可用tablet服务器。
       (3)和每一个tablet服务器联系,了解tablet服务器上tablet的分布。,没有分配的tablet加入未分配集合。
       (4)因为meta table不分配空间是无法扫描的,所以需要先分配root table,再逐层向下扫描,获得所有meta table 和user table的名字和分配情况。
       分配完后,只有tablet被创建/删除/合并/分解才会改变tablet集合
       tablet分裂会记录在日志中,读取分裂的tablet时,会调用日志找到所有文件碎片,读取合并。

5.3.1 Tablet服务

       一个tablet通过GFS的持久性存储。
       最近的更新存放在内存一个叫memtable的排队缓冲区,老的更新存放在一系列SSTable中。

5.3.2 Tablet恢复过程

       tablet服务器从metadata级别的表中读取这个tablet的元数据,**元数据包含了一个SSTabel列表,每一项是sstable和redo指针域的集合。(redo指针指向可能包含sstable需要数据的重做日志)。**服务器读入sstable索引到内存,执行这个sstable对应的redo指针后面的更新,重构mentable。
       SSTable有重做点日志,通过redo指针指向。
       通过执行重做点以后的更新,重构mentable。

5.3.3 Tablet服务器处理读、写请求

5.3.3.1 写操作

       先检查写操作是不是完整的,操作者权限是不是符合(从chubby客户端的缓存中的一个chubby文件,里面有写入权限的访问者列表)。写操作提交后,内容插入memtable。

5.3.3.2读操作

       类似于读,可以在读操作的时候可以合并一系列SSTable(老的提交的读操作)和memtable(新的读操作)。二者都是字典序的数据结构,便于排序。
       合并时不影响正在进行的读写操作。
       读操作必须从当前tablet的所有sstable中读数据

5.4 块压缩

5.4.1 次压缩

       mentable尺寸会随着写操作不断增加,当一个memtable达到上限时,会创建新的原来的memtable转化成一个SSTable。
       次压缩有两个目标:1、减少tablet服务器的内存使用率,把老的请求保存到硬盘上。2、服务器需要从死亡中恢复时,减少了从重做日志中读取的数据量。
       后台还会运行一个合并压缩程序,将一些sstable和memtable合并成一个sstable,删除源文件。

5.4.2 主压缩

       把所有的sstable写成一个sstable。**非主压缩产生的sstable可以包含一个删除入口,把被删的数据保存在其他的老的sstable中。主压缩不会保留删除信息和被删除的数据。**BigTable会周期性执行主压缩,这对于存储敏感的服务很重要。

6.改进、完善措施(refinements)

6.1 家族组(locatity groups)

       把多个列家族放到一个组内,为每个组单独创建一个sstable,可以实现高效读(利用程序的空间局部性)。例如,WebTable的页元数据(语言,校验码)放在一个组中,网页内容放在一个组中。
       通过修改参数,一个组可以直接存放在内存中。
       常驻内存(非调入)的家族组的sstable通过被动加载,被加载到tablet服务器的内存中’即应用请求sstabel的数据而数据不在服务器内存中,才会把sstable调入内存。只要sstable被调入内存,这个组的所有家族都可以直接访问而不必访问磁盘。适用于被频繁调用的小量数据。(不占太多内存空间)

6.2 压缩

       之前提到了对于多个sstable进行压缩,现在进一步分析。
       客户端可以决定要不要对**家族组对应的的一系列sstable进行压缩。**用户可以设定家族组的参数来控制sstable的块大小,以块为单位进行压缩。
       以块为单位进行压缩会损失一些空间,但是解压缩时不必对所有文件进行解压。
       压缩算法的性能取决于压缩文件的组织格式。例如,WebTable的行存储方式是DNS的倒序,这使得来自同一站点的网页存在相邻的位置,便于压缩算法从一个站点的网页获取相似的内容。好的行组织方式可以取得很好的压缩率。

6.3 缓存

       tablet服务器使用两个层次的缓存:scan和block。

6.3.1 scan缓存

       高层次缓存,缓存键值对,值是sstable接口,适用于频繁读取相同数据的应用。

6.3.2 block缓存

       低层次缓存,缓存了GFS中读取的sstable块,适用于倾向读取与最近读取数据相邻数据的应用(顺序读取/读取一个locatity group中随机列)。

6.4 bloom filter

       一种牺牲了准确性,换取时间空间效率的,判断包含关系的数据结构。
       不同于链表和树,先把所有元素保存下来,然后检索查找的数据是否在数据结构内,bloom filter采用哈希函数,把一个元素映射到长为m的向量的一个属性上。如果这一位为1,说明在,否则不在。为了减少哈希冲突,对每个元素使用k各哈希函数,只有这些函数对应的位都是1,才说明集合包含这个元素。
       优点:只查询不保存元素有很好的安全性(防止肆意修改数据),但是元素越多,误差越大,而且不可删除任一个元素,因为每一位代表的可能不止一个元素,删除一个会对其他数据产生影响。
在这里插入图片描述
       言归正传,因为读操作需要tablet的所有sstable,对于不在内存的sstable就需要磁盘访问。因此,创建boom filter 关联一个家族组的所有sstable。我们可以查询指定行/列的数据是否包含在sstable中。如果查询的的行/列目前不存在,就不需要访问磁盘(访问磁盘之后告诉内存我也没有)。

6.4.1 事务提交的实现(commit-log implimentation)

       如果每一个tablet(行数据)都通过一个单独文件来保存提交的日志,会产生大量并发操作,而且会降低分组提交优化的效率。因此,采用一个统一的物理日志文件来存储不同tablet的提交事务。但是这样会导致故障恢复需要多次遍历提交日志来复现故障tablet服务器的状态。
       因此,通过通过(表,行号,日志顺序)的顺序对日志排序,这样把对同一个表(tablet)的操作连续存放。磁盘寻找时据就以批量读取同一个表的数据。这个排序过程在故障恢复开始时进行。
       同一个tablet服务器会有两个写线程,只有一个处于工作状态。选择性能较好,不受网络拥堵的那个

6.4.2 加速tablet恢复

       当主服务器把一个tablet从一个服务器转移到另一个服务器,就需要做一次压缩。???????

6.4.3 提高鲁棒性

       所有SSTable都是不变的,因此读sstable的数据不需要任何文件系统的同步,针对行的并发控制很高效。而memtable会同时被读和写,因此采用写时拷贝(只有内容变化时,才会复制一份给另一个进程),允许读和写并发执行。
       因为sstable是不变的,所以可以移除metadata表中的sstable注册项,标记为垃圾数据。

7.性能测试

       建立BigTable族,含有N台tablet服务器,改变N的值可以测试bigtable的可扩展性和性能。Tablet服务器把数据写入到GFS单元格中,*这里采用客户机和tablet服务器数量相等,防止客户端成为瓶颈 。*所有机器位于二层树形交换网络中,机器位于同一个域内(计算机网络的区)。
       每台机器运行1个GFS服务器,一部分机器运行1个tablet服务器和1个客户端进程,共有R个行健

7.1 写操作,benchmark

       顺序写:行健名0-R-1,把行健分成10N个区间,中央处理器调度到10N个客户端,客户端完成一个区间立刻再分配,防止当前进程状态改变对机器造成影响。
       在每个行健下面写一个随机的、单字符字符串,不可压缩,防止出现跨行压缩。
       随机写:上述步骤,加上对行健以R为摸进行哈希,均衡负载。

7.2 读操作,benchmark

       类比写,顺序读是读取存储在行键下的字符串。
       使用scan benchmark(bigtable的api),可以读取域内所有值,只需要一个RPC就可以从tablet服务器读取大量数据。

7.3 测试结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BB4T2CtO-1646977304531)(C:\Users\LXC\AppData\Roaming\Typora\typora-user-images\image-20220311134045233.png)]

7.3.1 单tablet服务器

       随机读性能差。随机读操作包括把一个64KB的sstable块通过GFS传输到tablet服务器,用到的只有1000B。
       从内存随机读更快,因为不需要从GFS中获取数据块。
       随机和顺序写的性能优于读,因为tablet服务器会把到达的写请求追加到日志中,并使用分组提交。这种情况下随即和顺序写没有太大区别,因为请求都写在一个日志中。
       顺序度性能优于随机读,因为读取了64KB的数据块,可以为后64个读服务(因为是顺序,一定在一个块里)。
       scan读更快,他的开销可以分摊到大量的值中。

7.3.2 scaling,增加服务器数量

       服务器数量增长带来吞吐量激增,但是达不到线性,每个服务器的吞吐量会降低(多服务器环境下,负载不均衡)。因为随机读的瓶颈是单个tablet服务器的cpu
       负载均衡算法无法完美解决的原因:1.为了减少tablet迁移的开销,系统有时会禁止负载均衡操作。2.benchmark的负载是动态变化的
       和单处理器一样,随机读的可扩展性是最差的每次读都需要一个64K的块,这会让网路负载达到饱和。

8.Applications(Service)

8.1 Google Analytics

       Google analytics 是帮助网站管理者分析网站流量的服务。每当页面被访问,一个js程序就会把访问用户的所有信息记录在谷歌分析中。
       例如,网站点击表:网站名;session(类似cookie,存储时间是浏览器关闭时间)的创建时间。这个表保证了访问同一个网站的session是最近的。
       再例如,汇总表,通过周期性运行mapreduce作业,获得网页最近的session信息。系统吞吐量受GFS吞吐量限制。

8.2 Google Earth(Google地图专业版)

       通过一个表进行数据预处理,另一个表给用户提供服务。预处理管道的表用来存储卫星照片,这个表有70TB的压缩影像数据,只能从磁盘读取,不需要bigtable再压缩了。
       每行代表一个地理片段,保证相邻地理地段临近,列表示地段数据,基本一张影像一列,很稀疏。
       预处理管道性能取决于Mapreduce的数据转换效率。这个服务系统通过表建立索引,索引表运用到多个tablet服务器上,增加可用性。

8.3 Personalized Search

       和之前的差不多,通过再bigtable上使用mapreduce形成用户的profile,利用profile帮助用户生成个性化结果。用户数据被分配到多个bigtable族簇中,早期使用的是客户端副本模式(见GFS文章),现在是复制子系统,一个内嵌到服务端的。
       这个表允许多个分组共享,其他分组可以添加新的用户信息到自己分组的列中,因此这个表的列是所有分组的和,很大。因此,bigtable通过配额限制应用的存储空间。

9.Lessons(教训)

       1.大的分布式系统会遇到很多问题,不只是网络故障,还有内存故障,时钟扭曲,机器挂起与恢复,其他系统的故障和兼容,GFS配额溢出,硬件维护…因此需要改变其他系统的一些假设,新增功能(例如,RPC机制的checksumming)。
       2.没想清楚特性的功能之前不随意添加。
       3.合适的系统级别的监视。
       4.简单设计

10.相关工作

       Boxwood基础框架,bigtable利用boxwood的类似文件系统和数据库,设计需要存储数据的客户端。
)))))))))))))))))))

11.Conclusion

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星辰的野望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值