【迁移】读完了GFS论文之后的感悟

发布于: 2 小时前

首先,是一点关于设计分布式文件系统的思路和出发点,即要考虑自己应用的负载情况和技术环境的分析,综合考量之后才能更好的定义设计原型,体现更多的概念完整性和适用性。 

另外,设计一门新技术首先就是要观察现有的技术有哪些缺陷需要改进或重造,不然谁会乐意更换一套东西呢?何况是一位不知名的设计师或一个从没有见诸报端的设计团队创造的。 

通用的考虑既是性能、可伸缩性、可靠性以及可用性,而我更倾向于将可用性放在首位,这一点满足了之后我们再来谈SLA,为什么?因为可用性直接影响了客户与你的关系,也因此影响了你的公司或团队的直接收益。另一个词叫做用户体验,可用性和用户体验是息息相关的,如果你的系统都用不了了,谁来买账呢?更谈不上用户体验了。

 

组件失效是常态 

任何时间内都可能发生组件无法工作的情况,并且其中某些组件都无法从故障中恢复。 

大容量需求 

大容量需求导致了在设计文件系统时,你不能或者不应当采用管理数百亿个KB级大小的文件,而应当重新考虑I/O操作和Block的尺寸。 

AOF是个大秘密 

我们知道文件的写入一般采用的是追加的方式,而且一旦写入之后,读取一般都是顺序的。所以对于海量访问模式,应该考虑将追加操作的性能优化和原子性保证提到门面上来,此时的数据块缓存已经没有太大用处。 

黑科技 

一般存在两种骚操作,一个是大规模流式读取,另一个是小规模随机读取,而小规模的随机读取一般采用合并+排序,之后按顺序批量读取,就解决了在文件中移动读取位置时磁头变换带来的机械和时间损耗。 

对于风险我们这么看 

一个GFS集群包含一个单独的Master节点和多台Chunk服务器,而且这些服务器可以放在同一台运行着用户进程的机器上,这样的后果是我们必须承担不可靠的应用程序代码(程序员往往不这么想)带来的稳定性的下降,这一点风险是我们必须要承担的。 

仿佛看到了未来 

由于GFS在几年前就有了,所以在其中还是能够看到很多现代系统设计的一些影子,比如Master-Worker模式,心跳检测等等,可以和时下最火的AWS对比。 

惰性空间 

首先解释下什么叫做惰性空间,就像人具有懒惰性一样,空间的分配也可以具有懒惰性,简单说,如果Chunk在刚开始没有分配这么多空间,而是在需要的时候按需进行扩容,这种方法既节省了空间的浪费,也使得内部造成的碎片不会太多。而为什么我们选择64MB作为一个Chunk的大小,那是因为他有几个优势。首先,这样减少了客户端和Master节点的通讯需求。另外采用较大的Chunk有助于客户端进行块的多次操作,可以减少网络负载,最后减少了Master节点保存的元数据的数量(元数据下面就要说)。 

元数据 

元数据即是存放Chunk的命名空间和文件对应关系、Chunk和文件对应关系以及每个Chunk副本的存放地点。元数据一般具有64个字节,这对于现代内存来讲不是很大。这样做的目的是的系统更加具备简洁性、可靠性、高性能和灵活性。 

容灾 

在通过操作日志记录系统状态的时代,日志的收集策略成了我们需要关注的问题,首先是全量还是增量,另外写入日志是通过AOF还是修改,这里利用了一种叫做Checkpoint的技术,即在关键点或者日志增长到一定量时做一个全量备份。在灾难恢复时,Master就通过从磁盘上读取这个Checkpoint,重演checkpoint之后的日志就可以恢复系统。这里的数据结构采用了压缩B-树提高了恢复速度。 

一致性怎么保证 

一致性是在分布式系统中尤其是分布式文件存储中广泛讨论的话题。这里GFS采用了命名空间锁保证了文件修改的原子性与正确性。这里提到两个概念,一个是一致,另一个是已定义。已定义的意思大致可以理解为数据修改后,region是一致的,并且客户端可以看到写入操作全部的内容(隐含了一致性)。并行修改之后,region处于短暂的一致性并且未定义的状态:所有客户端看到同样的数据,但是无法读到任何一次写入操作写入的数据。如果一个操作失败了,那么region就会处于不一致的状态。 

这里也存在租约吗(最近听说北京房租涨的厉害有点怕) 

对,你没听错,这里也存在租约,英文是lease。它是用来做什么的?难道真是收房租?哈哈,骗你的,其实租约的学术含义是保持多个副本间变更顺序的一致性的一种手段而已。Master会为Chunk的其中一个副本建立一个租约,这里的Master可以理解为房东,而副本可以视为它手下的一个房源的中介负责人。租约也有超时设置,可以视为租期。如果合同(Chunk)被修改,那么副本(主Chunk)就可以申请更长的租期,通过Master的确认才可以延长租约的事件,它是建立在Master和Chunk之间的心跳消息(房东和中介之间私密的消息或通话)来传递。如果Master提前取消租约(想把房子卖出去),那么即使Master和主Chunk之间失联,也是可以在旧的租约到期之后和另一个Chunk副本(中介负责人)签订新租约。(现实中可能存在差别,如果房东联系不到中介,那么他们可能会通过工商局将中介公司依法进行惩处) 

数据的写入可分为7步:

  1. 客户端向Master查询待写入的chunk的副本信息,

  2. Master返回副本列表,第一项为主副本,即当前持有租约的副本;

  3. 客户端向多副本推送待写入数据,这里的推送是指将数据发送至chunk多副本,chunkserver会缓存这些数据,此时数据并不落盘;

  4. 客户端向主副本发起Sync请求;

  5. 主副本将数据写入本地的同时通知其他副本将数据写入各自节点,此时数据方才落盘;

  6. 主副本等待所有从副本的sync响应;

  7. 主副本给客户端返回写入成功响应

又是流 

从上面这张图可以看出,数据流和控制流是分开的,那么为什么这样做呢?因为我们使用流的目标就是为了充分利用每台机器的带宽,避免网络拥塞和高延时的连接,最小化推送所有数据的延时。这里采用流式链路而不是树的方式就在于树的拓扑不是线性的,他会分散带宽出口,导致每个节点不是最搞笑的。另外考虑到TCP管道式传输可以达到全双工交换网络,有个公式:B/T+RL用来表明B字节的数据到R个副本的理想时间(T是网络吞吐量,L是两台机器的传输延迟)。 

何为Master 

Master在现实生活中一般表示你的领导,或者某个长官,当然还有学校中的博士。那么他们是有一定权力的,也行使等同重量的义务,那就是管理好下面的服务器。他们依赖名称空间管理,通过锁来处理并发修改。副本是进行节点间的复制用的。还可以多次进行负载均衡操作。并且Master还可以通过之前那个惰性空间中遗留的数据,进行GC操作(垃圾回收操作)。 

当一个文件被应用程序删除时,Master只是将这个删除操作记录了日志而没有立刻删除,并将它们隐藏了起来。等到做常规扫描时,再一次性删除三天前的这些隐藏文件。而此时也会存在某些孤儿Chunk(也就是不被任何文件包含),确定了它们的元数据已经不存在的条件下,Master会任意删除它们的数据。这样的GC策略当然是没法和JVM的GC机制比拟了,这样的策略虽然有些简单粗暴,但是对于分布式文件系统已经是很高效的方式了。

快到了说再见的时候了,这里介绍下使用中的经验吧,这也可能是在读者经历了漫长的理论说教之后唯一能感到精神抖擞的部分。 

这些经验包括失败和成功的,有些是操作上的,有些是技术上的。 

其中最大的问题还是资源问题,涉及到磁盘和操作系统。很多磁盘只支持Linux最新的驱动,偶尔会由于协议不匹配导致驱动和内核对于驱动器的状态判断失误。数据有可能会因为内核中的问题被破坏。所以GFS团队最终决定采用Checksum来校验数据,同时修复了内核驱动。 

fsync()的效率问题也是很关键的一个,它与文件的大小有关,如果操作文件过大,那么我们通过同步写可想而知会是件很痛苦的事情,可能会花费一周的时间做这件事,最后移植到Linux2.4内核解决了这个问题。 

最后要讲的是读写锁的问题,也就是在某一个地址空间的任意一个线程都必须在从磁盘page in的时候先hold住,然后在mmap()调用的时候改写地址空间。它会在磁盘线程交换映射数据时,将网络线程锁住,新数据就无法映射到内存。后来采用了pread()替代了mmap(),使用copy解决了这个问题。

总结下,其实GFS提供了在设计大规模和高成本的数据处理任务时提供了可靠的存储与数据处理解决方案,在保证了并发读写环境下的高吞吐条件下,通过持续监控复制关键数据,自动回复提供了容灾方案。而且这种在线修复具备周期性、透明性。 

它是处理整个Web范围内难题的一个重要工具,不论是作为存储还是数据处理平台,都能满足生产级别应用的需求。

发布于: 2 小时前 阅读数: 21
用户头像

罗琦

关注

后浪 2017.12.15 加入

字节跳动工程师

评论 (1 条评论)

发布
用户头像
非常干货,InfoQ首页推荐。小建议:段落之间最好加上空行,阅读体验更好。
2 小时前
回复
好的
1 小时前
回复
没有更多了
【迁移】读完了GFS论文之后的感悟