谷歌文件系统GFS理解

前言:
         GFS是由Google设计并实现的一个可扩展的分布式文件系统,它适用于大型分布式计算密集型应用程序。与一般分布式文件系统具有诸多相同点,如性能、可伸缩性、可靠性和可用性,它的设计由Google应用工作负载和技术环境驱动。提出了一些不同的设计观点:
         1.系统是由许多经常会故障的廉价商品组件组成,所以必须要经常对它进行监控,以及在例行基础上进行检测、容错,以及故障组件的恢复
         2.系统存储了一定量的大文件。我们预计有数百万个文件,每个一般在100MB或更大。数GB的文件是很常见的情况,应该被有效的管理。小文件必须得到支持,但我们并不需要为它们进行优化
         3.工作负载主要包括两种读取情况:大型流式读取和小型随机读取。在大型流式读取中,单个操作一般会读取数百KB的内容,更常见的是1MB或更多。同一个客户端连续的操作通常会读取文件中的相邻区域。小型随机读取则一般会在随机偏移位置读取几KB的内容。注重性能的应用程序通常会对小量读取进行批处理和排序,以便稳步地向前读取文件而不是来回移动
         4.工作负载还有很多追加数据到文件的大型的顺序写入。一般操作的大小和读取的大小是相似的。一旦写入结束,文件就几乎不再进行改变。文件随机位置的少量写入是被支持的,但是效率不一定高
         5.文件通过Append发生改变,几乎不存在随机写,一旦写入文件只能读取(顺序读取),因此Append成为性能优化和原子性保证的重点,客户端缓存数据块则失去吸引力;
         6.通过共同设计应用程序和文件系统的API有利于提高整个系统的灵活性
         7.持续的高带宽比低延迟更重要。我们大多数的应用程序都非常重视以高速率批量处理数据,而几乎不会对单次读写有着严格的响应时间要求
GFS系统架构:
         一个GFS集群由单个master和数个chunkserver组成,可以被多个客户端访问,如图1所示。每个客户端通常都是由一台商用Linux服务器来运行用户级的服务器进程。
在这里插入图片描述
         文件分为固定大小的块,每个块都是由块创建时被master分配的一个全局且不可变的唯一64位块句柄标识,块服务器将块Linux文件存储在本地磁盘上,块数据的读写由块句柄和字节范围来指定。出于可靠性的考虑,每个块都在多个块服务器上进行复制。默认情况下,我们存储三个副本,但是用户可以为文件命名空间的不同区域指定不同的拷贝级别。
         master维护文件系统中包括命名空间,访问控制信息,文件到块的映射关系,以及块的当前位置在内的所有的元数据,同样也控制着系统范围内的活动,比如块的租约管理,孤立块的垃圾收集,还有块服务器之前的块迁移。master通过心跳消息和每个chunserver进行周期性的通信,以发送指令并收集它们的状态。
         GFS clients和ChunkServers都不缓存文件数据(但是会缓存元数据)(客户端的缓存没有意义,因为大多数的应用程序使用大型文件流工作,或是工作集过大导致难以缓存。没有这些地方的缓存就消除了缓存一致性,从而简化了客户端和整个系统(但是客户端会缓存元数据)。块服务器不需要缓存是因为块作为本地文件存储,Linux的缓存已经将频繁访问的数据保存在内存中了)
         master任意时刻只有一个,而chunkserver和gfs client可能有多个。只拥有一个master可以极大简化我们的设计,同时保证master能够应用全局信息来针对块的放置和备份作出复杂的决策。客户端永远不会通过master进行文件的读写,相反的,客户端只是询问master它应该与哪个块服务器建立通信。客户端会在一定时间内缓存此信息,并与块服务器直接进行交互来执行许多后续操作。
         对于master,HDFS采用增加Secondary NameNode节点处于Standby的状态,与Active的NameNode同时运行。当Active的节点出现故障时,切换到Secondary节点。
HDFS联邦
         虽然HDFS HA解决了“单点故障”问题,但是在系统扩展性、整体性能和隔离性方面仍然存在问题。
(1)系统扩展性方面,元数据存储在NN(NameNode)内存中,受内存上限的制约。
(2)整体性能方面,吞吐量受单个NN的影响。
(3)隔离性方面,一个程序可能会影响其他运行的程序,如一个程序消耗过多资源导致其他程序无法顺利运行。
         HDFS HA本质上还是单名称节点。HDFS联邦可以解决以上三个方面问题。
         在HDFS联邦中,设计了多个相互独立的NN,使得HDFS的命名服务能够水平扩展,这些NN分别进行各自命名空间和块的管理,不需要彼此协调。每个DN要向集群中所有的NN注册,并周期性的发送心跳信息和块信息,报告自己的状态。
         HDFS联邦拥有多个独立的命名空间,其中,每一个命名空间管理属于自己的一组块,这些属于同一个命名空间的块组成一个“块池”。每个DN会为多个块池提供块的存储,块池中的各个块实际上是存储在不同DN中的。
在这里插入图片描述

         master存储了3种主要类型的元数据:文件和块的命名空间,文件到块的映射,以及每个块副本的位置。所有元数据都保存在master的内存中。前两种类型(命名空间和文件到块的映射)通过将更新操作记录到存储在master本地磁盘的操作日志上来保证持久化,这份日志也会在远程服务器上进行备份。使用日志可以让我们简便可靠地更新master的状态,同时也避免了由于master故障导致不一致的风险。
         master不会保留哪些块服务器拥有给定块的副本这样的持久化信息,而只会在启动时对块服务器进行轮询来获取这些信息。master可以让自己保持最新状态,因为它控制着所有的块的放置,并通过定期的心跳消息来监控块服务器的状态 。
文件读取流程:
         1.首先,使用固定的块大小,客户端(chunk server)将应用程序中指定的文件名和字节偏移量转化为块索引,然后,客户端向master发送包含有文件名和块索引的请求(filename,chunk index)在缓存过期或是文件重新打开之前,对同一个块的后续读取操作不需要与master再进行交互。实际上,客户端通常会在一次请求中请求多个块,master也可以将这些请求的块信息包裹在一起返回。这些额外的信息几乎不需要什么开销就避免接下来的一些客户端和master的交互。
         2.master将块句柄(chunk handle)与chunk的副本位置告诉GFS client,客户端会使用文件名和块索引作为键值来缓存这些信息
         3.GFS client向最近的持有副本的Chunkserver发出读请求,请求中包含chunk id与范围
         4.ChunkServer读取相应的文件,然后将文件内容发给GFS client。
块大小:
         使用64M作为块的大小
中心化副本控制协议:
 GFS采用的是中心化副本控制协议,即对于副本集的更新操作有一个中心节点来协调管理,将分布式的并发操作转化为单点的并发操作,从而保证副本集内各节点的一致性。在GFS中,中心节点称之为Primary,非中心节点成为Secondary。中心节点是GFS Master通过lease选举的。
数据冗余的粒度:
         GFS中,数据的冗余是以Chunk为基本单位的,而不是文件或者机器。这个在刘杰的《分布式原理介绍》中有详细描述,冗余粒度一般分为:以机器为单位,以数据段为单位。
  以机器为单位,即若干机器互为副本,副本机器之间的数据完全相同。有点是非常简单,元数据更少。缺点是回复数据时效率不高、伸缩性不好,不能充分利用资源。
在这里插入图片描述
 上图中,o、p、q即为数据段,相比以机器为粒度的副本,以数据段为独立的副本机制,虽然维护的元数据更多一些,但系统伸缩性更好,故障恢复更迅速,资源利用率更均匀。比如上图中,当机器1永久故障之后,需要为数据o、p、q各自增加一份副本,分别可以从机器2、3、4去读数据。
 在GFS中,数据段即为Chunk,上面提到,这样元数据会多一些,且GFS master本身又是单点,这个有没有问题呢。GFS说,问题不大,因为GFS中,一个Chunk的信息,64byte就够了,且Chunk本身的粒度又是很大的(64M),所以数据量不会太大,而且,在GFS master中,chunk的位置信息是不持久化的。
  在MongoDB中,则是以机器为粒度进行副本冗余的。
数据写入过程:
租约:
Master节点为Chunk的一个副本建立一个租约,我们把这个副本所在的server叫做主Chunkserver。主 Chunkserver对Chunk的所有更改操作进行序列化。所有的副本都遵从这个序列进行修改操作。因此,修改操作全局的顺序首先由Master节点选择的租约的顺序决定,然后由租约中主Chunkserver分配的连续序列号决定。
租约时长为60秒,且在租约结束后如果不出问题,master尽量将租约付给原持有租约的chunkserver。
设置租约的目的:
我们使用租约 (lease)机制来保持多个副本间变更顺序的一致性,目的是为了最小化Master节点的管理负担。
GFS互斥操作:
互斥:任何的写或者追加操作
1.数据需要被写到所有的副本上
2.当多个用户请求修改操作时,保证同样的次序
在GFS中,数据流与控制流是分开的,如图所示
在这里插入图片描述
1.Client向master请求Chunk的副本信息,其中持有租约的chunk所在的ChunkServer叫主ChunkServer。如果没有ChunkServer持有租约,说明该chunk最近没有写操作,Master会发起一个任务,按照一定的策略将chunk的租约授权给其中一台ChunkServer。
2.Master返回客户端主副本和备副本所在的ChunkServer的位置信息,客户端将缓存这些信息供以后使用。如果不出现故障,客户端以后读写该chunk都不需要再次请求Master。如果出现chunkserver有错误,不可访问的时候,client会再次问询master。
3.client将数据(Data)链式推送到所有副本
4.一旦所有副本都确认收到了数据,client(客户端)就会向主副本发送写请求,这个请求标识了之前推送给所有副本的数据。主副本会为收到的所有数据变更操作(可能来自于多个客户端)分配连续的序列号,这提供了必要的串行化机制,它会按照序列号的顺序将更新应用于本地。
5.主副本将写请求发送给其他所有的次级副本,每一个次级副本都会按照主副本分配的同样的序列号顺序来执行数据变更
6.Secondary(次级副本)向Primary回复提交结果
7.primary回复client提交结果
         首先,为什么将数据流与控制消息分开,且采用链式推送方法呢,目标是最大化利用每个机器的网络带宽,避免网络瓶颈和高延迟连接,最小化推送延迟。
另外一种推送方式是主从模式:
在这里插入图片描述
         Client首先将数据推送到Primary,再由Primary推送到所有secodnary。很明显,Primary的压力会很大,在GFS中,既然是为了最大化均衡利用网络带宽,那么就不希望有瓶颈。而且,不管是Client还是replica都知道哪个节点离自己更近,所以能选出最优的路径。
  而且,GFS使用TCP流式传输数据,以最小化延迟。一旦chunkserver收到数据,即立刻开始推送,即一个replica不用收到完整的数据再发往下一个replica。HDFS采用的是串行副本写入。
同步的数据写入:  
  上述流程中第三步,只是将数据写到了临时缓存,真正生效还需要控制消息(第4 5步)。在GFS中,控制消息的写入是同步的,即Primary需要等到所有的Secondary的回复才返回客户端。这就是write all, 保证了副本间数据的一致性,因此可以读取的时候就可以从任意副本读数据。
GFS一致性模型:
并发的修改将导致一致性的问题。不同的Client对同一组数据执行修改。
一致:所有的Client读取的数据一致
确定:所有的Client可以读取全部的更新内容。当更新成功且不受并发写的影响时,内容是确定的(也是一致的)
在这里插入图片描述
serial write:
         当 client 串行更新时时,客户端自己知道写入文件范围以及写入数据内容,且本次写入在数据服务器的多副本上均执行成功。因此,本次写结果对于客户端来说就是明确的,且多副本上数据一致,故而结果是 defined。
在这里插入图片描述
在这里插入图片描述
concurrent write:
         多个 client 同时写入时, 由于多个客户端由于写入范围可能交叉覆盖。单个客户端无法决定写入顺序(只有 primary 才能决定谁先写谁后写),因此,即使写入成功,客户端仍无法确定在并发写入时交叉部分最终写入结果,但是因为写入成功,所以多副本数据必然一致。
         图中红色部分代表并发交叉覆盖部分,可能无法反映任何一个更新所写的内容,但由于更新成功,因此,所有客户看到的内容相同,这就是consistent but undefined。
所以官方建议不要用覆盖写(overwrite)因为不保证一致性,建议使用append
在这里插入图片描述
在这里插入图片描述
append:
         client 的 append 操作无需指定offset,由 chunk 的 primary 根据当前文件大小决定写入offset,在写入成功后将该offset返回给客户端。因此,客户端能够根据offset 确切知道写入结果,无论是串行写入还是并发写入,其行为是defined。
         如果写失败(错误可能发生在任意一个副本),导致了多副本之间从50至80的数据可能不一致。但接下来重试成功,从80至110之间的数据一致,因此,其状态是 interspersed with inconsistent。
在这里插入图片描述

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值