Bigtable_2 (MIT 6.824: Lec 3: Reading)

  • 2020 年 12 月 15 日
  • AI

从本篇文章开始,专栏将以《MIT 6.824:Distributes Systems》的课程逻辑出发,逐步更新课程内的全部内容,敬请关注,谢谢。

如果想要跟方便的查看课程的更新内容,也欢迎关注微信公众号:《油麻酥爱学习爱健身》,微信号:youmasu

除了MIT分布式课程的学习以外,公众号还会不定期分享自己的健身经验,包括,家庭自重健身,健身房增肌减脂,日常饮食营养等健身内容,再次谢谢大家。

一、性能测试

在执行性能测试时,我们定义Bigtable集群内,拥有N台tablet servers。每一次评估,N是可变的。每台tablet server都是1GB内存,都会往一个1786台机器组成的GFS里写数据,每台GFS机器拥有2块400GB的IDE硬盘。同时,我们使用与tablet server相同数量的client来模拟负载,确保client不会成为性能瓶颈。

物理机层面,每台物理机使用双核Opteron 2GHz,足够大的物理内存运行所有进程,一个千兆网卡。所有物理机配置在一个两层树状的交换机网络中,汇聚交换机可用带宽在100-200Gbps之间。同时,所有物理机处在同一个IDC环境,确保任意2台机器间的round-trip在1ms内。Tablet servers、master、test client和GFS都部署在上述的物理机上。每台物理机上都会部署一个GFS server。其他进程混合部署在任意机器上。

R是性能测试中Bigtable row keys的数量。通过对R的调节,保证在每个benchmark测试间,每个tablet server的读写数据都在1GB左右。

Sequential write的benchmark使用R个row keys,分别命名为[0, (R-1)]。整个row keys的空间被划分至10N个相同大小的range。每个range的row key都通过中心调度器分配给N个client。一旦某个client完成了当前的range,将马上处理下一个range。这个动态的任务分配是为了防止运行在client机器上的其他进程对当前性能测试的干扰。每个key都会被分配一个独立、随机、未压缩的字符串作为value写入。Random write的benchmark方法类似。除了在写入前会将row key哈希后与R取模,可以在整个性能测试期间平分整个row space产生的写入负载。

Sequential read的benchmark中,row key的生成方式和sequential read相同。但它主要是读取row key上先前被写入的字符串。Random read操作上也类似。

Scan的benchmark与Sequential read类似。但它主要使用Bigtable原生支持的API来遍历一个row range上的全部value。主要为了减少整个benchmark上的RPC调用。

Random read(mem)的benchmark与random read类似。区别是所有要读取的locality group一定都来自内存而不是GFS。因此,为了匹配机器的内存大小,从每台tablet server中读取的数据量也从1GB调整至100MB。

下图展示了所有benchmark在读写1000个字节的value时,Bigtable的2个性能视角。表格展示了每台tablet server在每秒的性能。曲线展示了所有tablet server在每秒的性能。

1、单台tablet server的性能

即使每一次random read都只需要1KB的数据,都需要将一个64KB的SSTable block从GFS经由网络传输到tablet server的过程,所以它的性能最低,每秒只有1200次random read能力,这也对应Bigtable可以从GFS读取75MB/s数据的能力。这个读取能力可以打满tablet的CPU和网卡。因此,大多数Bigtable应用会将SSTable block调小至8KB。

Sequential read的性能就好很多,因为从GFS读取的64KB数据会被缓存起来,满足接下来63次sequential read的要求。

Random read(mem)就起飞了,毕竟每次读取1KB的数据全部在内存中返回,完全不用从GFS中加载。

Random和Sequential write比random read就快多了,并且两者的性能也大致相当。因为每个tablet server会先在一个commit log中的尾部写入所有的write操作,接着再以流的形式分组提交至GFS。

Scan的效率也非常高,主要是因为一次client RPC调用就能返回大量的value。

2、扩容tablet server的性能

当我们将tablet server数从1扩容至500时,所有tablet server汇总的性能快速上升。比如,random read(mem)的性能就增加了300倍,整个性能测试的瓶颈主要在CPU上。

从图表中也看到,性能的提升并非线性的。对大多数benchmark来说,当tablet server扩容至50时,单台的性能就出现跳水。这主要是因为不同的机器配置,导致在测试期间的负载不均衡,这通常来源于在同一台机器上混合部署的其他进程占用的CPU和网络带宽。Bigtable的负载均衡算法也尝试缓解,但不能彻底解决这个情况。主要是2个原因:一是rebalance会加剧tablet server不可用的隐患(每当一个tablet被移动时,都会有短暂地小于1秒的不可用状态);二是基准测试本身的负载也会随时间变化。

Random read展示了最差的扩容后性能。因为每当读取1KB的数据就要从GFS中加载64KBd额数据,当机器扩容时,网络带宽最先被打满。

二、应用场景

截至到2006年8月,生产环境中总计有24500台tablet servers组成388个Bigtable集群。一部分是面向用户产品使用,一部分是内部产学研的批处理使用,下图展示了部分集群的部分参数。包括,谷歌分析、谷歌地球和个性化搜索。

三、经验总结

在设计、实现、维护和支持Bigtable的过程中,有不少值得分享的实战经验。

1、经验一

大型分布式系统对各种错误天然有种脆弱性。包括分布式协议中涉及的网络分区错误和失败-停止错误在内,还存在各式各样的错误情况。比如,内存或网络损坏,机器时钟偏差,机器挂起,第三方系统bug(Chubby),GFS资源超限,计划或非计划的硬件维护等等。当这些错误发生次数越来越多,我们只能尝试优化通信协议以解决它们,比如在RPC通信时使用checksumming。或者,拒绝相信三方系统做出的任何保证,比如Chubby操作只会返回一个给定错误集中的错误码。

2、经验二

对大型分布式系统而言,加入任何新特性前,一定要将其使用的场景考虑清楚。比如,一开始Bigtable计划在API设计中加入通用的分布式事务机制,但经过业务方的仔细调研,发现绝大多数业务只需要Bigtable能保证单行事务即可。同时,对那些需要分布式事务的应用来说,他们最重要的需求是用Bigtable来维护二级索引,我们就设计了一种特殊的机制来满足他们的要求。新的机制虽然没有实现通用分布式事务,但它在满足业务需求的同时,复杂性更低,效率更高,并且和优化过的跨数据中心replication的schema有更好的交互。

3、经验三

实际使用中,对Bigtable本身和其client的“系统级监控“非常重要。比如,对RPC调用中的重要操作进行采样,追踪调用情况的详细信息。这能帮助我们解决tablet 数据结构中的锁阻塞,向GFS提交Bigtable mutation的慢写入,当METADATA tablet不可用时的访问挂起。监控的另一个好处是可以跟踪所有在Chubby中注册的Bigtable集群。观察它们的大小,查看它们的版本,监控它们的读写流量,是否存在非预期的大延时。

4、经验四

最重要的经验是,保持系统设计的简单性。整个Bigtable的逻辑和错误处理代码加起来大致10万行左右,这使得代码的维护和调试非常简单。比如,在系统membership协议上,Bigtable的最初设计是:master周期性的向tablet server发布租约,tablet server在租约到期时kill掉自己。但这个协议在网络有问题时会严重降低可用性,同时对master的恢复时间非常敏感。因此,我们重新设计,并反复修改了几次协议才解决问题。但此时协议的复杂性非常高,并严重依赖Chubby的一个为人所不知且很少经过验证的特性。我们花了大量的时间在验证那些极其隐晦的corner case上,既要测试Bigtable还要测试Chubby,让人晕头转向。最后,我们放弃了这个实现,转而实现了一个更简单的协议,该协议仅依赖一项Chubby中一个众所周知的特性。

四、相关成果

Boxwood project提供了一系列的分布式协议,锁和分布式chunk存储,B-tree存储,所以它在功能上和Chubby,GFS和Bigtable都有诸多重叠。但Boxwood的目标是提供一份构建分布式文件系统或数据库的底层套件,但Google service则直接提供服务,可以供那些想存储数据的客户端直接使用。

当前已经有很多分布式存储,比如CAN,Chord,Tapestry和Pastry,来解决广域网中的各种网络问题,比如多变的带宽,不可信的成员和经常性的重新配置,但这并不是Bigtable要担心的问题。同时,去中心化的控制和拜占庭容错也不是Bigtable的目标。

并且,使用B-tree和hash表构建的Key-Value数据存储模型受限颇多。Key-Value pairs不应当仅仅被当做building block提供给开发者,Bigtable还支持稀疏的semi-structured数据。同时,它还可以使用非常简单有效的flat-file表示,并通过类似locality group的方式允许用户微调整个系统,而不用关注Bigtable本身。

一些数据库提供商也开发了并行数据库以支持并行存储大数据,比如,Orable的Real Application Cluster使用共享磁盘(Bigtable使用GFS)和分布式锁管理器(Bigtable使用Chubby)来存储数据。IBM基于shared-nothing架构开发了DB2 Parallel Edition。跟Bigtable的tablet server一样,每一个DB2 server仅对一个存储在本地关系型数据库表中的某些列负责。这2款产品都支持完整的关系型数据库事务。

Bigtable使用locality groups实现了列式存储数据库,比如C-Store和Sybas IQ,SenSage,KDB+和MonetDB/X100中的压缩算法,以提高磁盘的读性能。AT&T的Daytona数据库则通过将垂直和水平数据拆分至flat files以实现较高的压缩比。Locality groups并不支持CPU-cahce级别的优化,但这一点被Ailamaki做到了。

Bigtable使用memtable和SSTable来存储tablet的更新,也与Log-Structured Merge Tree将更新存储索引数据的方法类似。这2个数据库都会将排序后的数据优先放在内存中,之后才写入磁盘,同时,任何读数据操作都要将内存和硬盘上的数据合并后返回。

C_Store和Bigtable有很多相似的特点:使用shared-nothing架构;有2种不同的数据结构:一种用做recent write,一种用来存储long-lived数据;存在将数据在不同form间移动的机制。但它们的API有非常大的不同:C-Store的API更像一个“经过了读优化的关系型数据库“,而Bigtable则提供更底层的读写接口,并在设计上支持每台tablet server达到数千级别的TPS,适用于读写均敏感的业务。

相比前面介绍的其他DB,Bigtable的负载均衡器更简单:不用考虑同一份数据多份copy的可能性;让client告诉Bigtable,它需要的数据在磁盘还是内存中;没有复杂的quey需要去执行或优化。

五、最后结论

Bigtable的接口设计是如此与众不同,让很多习惯了传统的,拥有完整事务的关系型数据库的业务很难适应。但事实是,已经有大量的Google应用开始使用Bigtable也足以说明Bigtable设计的合理性。尤其是那些追求高性能和高可用的业务来说,只需要增加机器,平行扩容即可满足需求。

六、参考文章

链接:static.googleusercontent.com

Exit mobile version