GFS笔记

GFS笔记

文件系统的演变过程是:

单机文件系统——> 分布式文件系统——>GFS

其中有两个变化的过程,分别成为A和B,两次变化中会涉及到很多问题。如

A1:文件如何分散存储在多台服务器上? 如何实现自动扩容?

A2:怎么样知道一个文件存储在哪些(那台)机器上?

A3:怎么保证服务器故障时文件不损坏不丢失

A4:如果使用多副本的话,怎么保证副本之间的一致性?


B1:怎么样支持大文件的存储?(几个G)

B2:超多机器的情况下,怎么样实现自动监控,容错和恢复?

B3:怎么样支持快速的顺序读和追加写?

在这里插入图片描述

存储设计:

A1: 大多数的分布式存储系统都会把要存储的文件分割为若干个大小相等的块(GFS也是),这里英文为chunk。 在GFS中这个chunk为64mb,当然为不同类型的应用提供不同服务的系统会有不同的大小设计。

为什么GFS用64MB呢?

  1. GFS存储的文件都是普遍较大的文件,所以较大的chunk能够减少系统的寻址和交互次数。反之如果存储的时较小的文件,如果chunk过大就会导致大量的chunk内部有空余内存,导致空间浪费。
  2. 大的chunk 意味着client可能在同一个chunk上做多个操作,例如:这可以复用TCP连接,节省网络开销。以及如果要追加一定大小的内容,那么很可能只需要一个chunk就能够完成。
  3. 更大的chunk可以减少chunk的数量,节省元数据的内存开销,这是最珍贵的内存资源。

缺点:当然较大的chunk 可能会导致热点问题,当同一个chunk同时要被多个client访问时,一致性就是要考虑的问题,这样可能会导致性能降低。

master的设计

master中的元数据时非常重要的,而GFS选择实现的是单中心节点,而非分布式的中心节点。这样实现难度低,而且一致性容易保证。但是单中心节点可能会导致整个系统产生瓶颈,这样GFS的任务就是提高访问速度,以及缩减元数据。

master节点用来存储整个文件系统的三类元数据:

  1. 所有文件,以及chunk的namespace (持久化的)
  2. 文件到chunk的映射(持久化)
  3. 每个chunk的位置(非持久化)

这样通过GFS访问数据的简略过程就是:

通过文件名->获得文件所对应的chunk->获得所有的chunk的位置->依次到对应的chunkserver中读取chunk

为什么就单单每个chunk的位置不做持久化呢?

做持久化是为了 防止master 宕机后丢失元数据,而GFS的设计是master每次重启都会重新去所有的chunkserver去获得chunk 的位置,这样就不要持久化了。 当然 持久化也可能会加快master的重启初始化时间,但是考虑到master基本上不会宕机,所以这里选择不持久化chunk的位置。

GFS采取了一系列的措施来确保master 不会成为整个系统的瓶颈:

  1. GFS所有的所有数据流都不会经过master,而是直接有client和chunkserver进行交互。(GFS把控制流和数据流分离,只有数据流才会经过master) 根本原因,不然单点master根本无法处理了大量的访问。
  2. GFS的client会缓存master的元数据,大部分的情况下,都无需访问master。
  3. 为了避免master的内存成为系统的瓶颈,GFS用一系列的手段来节省master的内存,包括增大chunk的大小以节省chunk的数量,对元数据进行定制化的压缩等。

A1: 如何实现自动扩缩容? 只需要在单master上增加减少元数据,并且修改chunk所在的位置就行。

时至今日,大部分的分布式系统还是会倾向于选择中心节点。因为单点的瓶颈不想想象的那么难以解决,非中心节点的实现难度也不如想象的那样可控

GFS的高可用设计

元数据的高可用设计

  1. master的高可用通过主备方法来实现,即创建一个master的副本(主master和副master)。当然只有持久化的数据需要备份,也就是所有文件和chunk的namespace 以及 文件到chunk的映射。

  2. 所有对元数据所做出的修改操作,都需要记录在日志WAL中,再去修改内存的元数据。.

    例如,当我们将元素据中添加一个chunk,其高可用的过程为:

    1. 生成新增元数据的日志并且写入本地磁盘。
    2. 把WAL(日志)传输给(副)shadow master
    3. 得到反馈后再正式的修(主)primary master

    其实当日志落盘的那一刻起,就可以认为修改任务完成,因为宕机重启后,master可以通过Wsl来同步之前的数据。

  3. 实现自动切换,通过 Chubby(共识算法)来识别并且切换到shadow master

chunk的高可用设计

每一个chunk都有三个副本,每次一对chunk的写入,都必须确保三个副本中都写入完成才可以。

一个chunk的所有副本都会有完成的数据,并且副本不会都储存在一个chunkserver中如果一个chunkserver宕机,那么master就可以去寻找另外的两个chunk。如果宕机的副本在一段时间内还没有恢复,那么master就会再次创建一个副本。

GFS的读写流程

文件系统的读写流程与一致性机制是系统中最重要的一点。

GFS推荐基本上所有的操作都用追加来实现。但是不妨碍GFS还是支持改写。

对于读取,GFS要求极致的性能, 甚至可以读取到落后的版本但是一定不能是错误的。对于改写,不用在性能,能准确就好。对于追加,要求极致的性能,甚至允许一定的一场,但是追加的数据不能丢失。

GFS的写入总体概念

GFS在写入时药在三个副本全部完成写入后才能够返回写入结果。

GFS的写入采用了两个现在看起来都很高端的技术:

  1. 流水线技术
  2. 数据流和控制分离技术

其中流水线技术就是,当client要发送数据给chunkserver的时候,直接选择就近的chunkserver,而不是选择主服务器(有租约的服务器),并且当一个服务器接收到数据后,立刻以数据流的方式传递给下一个chunkserver。传统的主备方式必须要先将数据同步给主服务器然后再由主服务器传递给副服务器。

而数据同步完成之后,才会进行一致性的保证,也就是数据流与控制流的分离,这样一致性保证就不会受数据同步的干扰。

直观的理解就是:数据流的数据量很大,大伙一起干事,有力出力,全部都动员,而数据量很小的控制流,则由有租约的chunkserver自己决定,来单独负责写入的一致性保证。从而达到性能和一致性的均衡。

GFS的写入具体流程

  1. Client 向master中询问要写入的chunk的租约在那个chunkserver(主chunk)上,以及其他的副本chunk的位置
  2. client会将所有的数据都推送到所有的副本上,这一步就会用到流水线的操作技术,也是写入过程的位置的数据流操作。
  3. 所有的副本都收到数据后,client 发送正式的写入请求到主chunkserver中,然后根据请求对于数据进行顺序的执行写入,也就是由主chunk唯一确定的顺序,并且负责保证副本的一致性。
  4. 主chunk将写入数据的顺序同步给副chunk 中,这一步执行的条件时主chunk的执行已经是成功的。
  5. 所有的副chunk返回主server中 表示写入完成。
  6. 主chunk返回 client表示写入操作完成。

最后一步由两个可能:

  1. 所有的副本都写入成功,皆大欢喜
  2. 部分的副本写入失败,那么client就i认为写入失败,从第二部的同步数据开始重新执行。

疑问 :为啥那么控制流不用数据流一样的传输方式呢?

上述的步骤完全符合改写的过程。但是改写是很不推荐使用的,为什么呢?

虽然改写不会涉及到重新写的问题,但是改写会存在这样的问题:一个改写操作很可能涉及到一个文件多个chunk的改写,如果部分chunk成功,部分chunk失败,我们读到的文件就是错误的!(所有的chunk共同组成一个文件),那么这样当一个chunk的读写出现问题,那么所有的文件都需要进行阻塞。代价很大。而追加不会有这个问题,追加只会涉及到最后一个chunk,并且追加的失败并不会影响原来的内容,最多只会读到过期的数据。但是追加也不是万能的,追加涉及到重复追加的问题。这里后面会提到。所以GFS推荐用追加来写入文件

GFS的读取流程

  1. client收到读取一个文件的请求后,首先会查看自身的缓存中有没有元数据,如果没有那么就去请求master获取元数据信息并且缓存。
  2. client计算文件的偏移量以及对应的chunk
  3. client向离自己最近的chunkserver发送读请求。如果在这个过程中发现目标的chunkserver没有chunk,代表着缓存的元数据过期了,重新向master获取数据并且缓存
  4. 读取后会对chunk进行校验和校验,如果不通过,那么就会向其他的chunk副本进行获取。
  5. 返回获取结果。

B3 怎么支持快速的顺序读和追加写?

总体上时三写一读的模式。写入采用了流水线技术和数据流与控制流分离的技术保证性能。 追加写一致性的保证更加简单,也是更加高效,所以写入用追加写的方式。 读就通过就近对,性能很高。

GFS的一致性模型

对于多副本情况,在正常状况下,只有三个chunk副本全部写完后才返回结果,这保证的副本间的一致性。但是在实际应用中,因为又多个client可能会并发写入数据,这会带来副本间不一致的风险。

GFS把文件数据的一致性大体分为三个层次:inconsistent,consistent,defined。consistent:一致的,表示文件无论从哪个副本读取,读到的结果都是一样的(inconsistent就是不一致的)。 defined:已定义的。文件发生了修改操作后,读取时是一致的,并且client可以看到最新的修改结果(也就是在consistent的基础上还能够与用户最新的写入保持一致。)

串行改写成功:defined。因为所有的副本都完成改写后才能返回成功,并且重复执行改写也不会产生副本间不一致,所以串行改写成功数据是defined。

写入失败,那肯定是inconsistent。

并发改写成功的一致性为:consistent but undefined。 也就是读取时chunk副本都是一致的,但是可能不是我们预期的结果。 原因是 一个 改写操作可能涉及到多个chunk,而租约决定的控制流只能保证相同chunk副本之间执行的顺序一致,而不同chunk 很可能会选择不同的执行顺序,又一个执行改写会操作多个chunk 所以会导致最终的chunk出现问题。也即是说GFS没有全局事务的概念。

追加操作成功(串行并行)都是defined but may inconsistent(已定义但又可能存在副本间不一致,也就是对内不是一致,而对外是一致性的),显然追加的操作在出现异常时会重复数据,导致副本间不一致,但是GFS为了实现defined,做出了一些限制:

  1. 单次的追加不超过 64MB 也就是不能跨chunk
  2. 如果文件的最后一个chunk的大小不足以提供此次的追加,则把空间用padding 填满,然后新增chunk进行追加。

这样就能保证每次的追加操作只涉及一个chunk,这样就不存在并发的问题。至于重复性追加就比较好解决,比如记录文件的长度,或者定期的对副本进行校验,读取数据的时候去除掉重复部分,以及通过校验和来去除异常数据,

A4 使用多副本的化,如何保证副本间的一致性?

  1. 对于一个chunk的副本的写入顺序时一致的。这是由控制流与数据流 分离来实现性能的提高。控制流都是由主chunk到副chunk 而 数据流则就近原则。
  2. 使用chunk版本号来检测chunk副本是否实现过宕机。失效的副本不会进行写入操作,master不会记录这个副本消息。GC会自动回收这些副本。
  3. master 会定期检测chunk副本的checksum来确认是否正确
  4. GFS 推荐应用使用追加来达到更高的一致性。

快照

快照就是生成当前存储系统的一个对外的“备份”。当然这里的备份肯定不是直接的全部复制一遍,这样太浪费性能。

快照采用的机制是类似进程拷贝的机制,也就是COW(copy on write 复制写实)。

进程的复制 开始只会拷贝虚拟页表,并且把对应的指向的物理内存的引用加一。当需要修改某个物理内存时,才会涉及到真正的数据拷贝操作。

快照与上述类似:

  1. master回收对应的chunk租约,停止对应chunk的所有写入(例如 要对fileA进行快照,就会将其对应的所有chunk都停止写入)。
  2. 拷贝一份文件的元数据 并且命名为快照文件,快照文件的元数据仍然指向原来的chunk
  3. 增加所有chunk的引用计数。
  4. master正常进行授权租约,允许对chunk进行写入。
  5. 当要修改文件的chunk时,发现其chunk的引用计数大于1,那么修改时会首先拷贝一个新的chunk,在在新的chunk上进行写入,而原来的元数据指向新的chunk,快照元数据仍然指向原来的chunk

GFS的垃圾回收(GC)机制

需要GC的场景:

  1. 客户端直接删除文件
  2. 因丢失修改操作而失效的副本
  3. 因checksum校验丢失而失效的副本

GC的机制:

  1. 不立刻清除chunk的物理内存,而时修改文件的元数据,把文件名改成一个包含删除时间戳的名字,master会定期对这些元数据进行扫描,当发现文件删除超过了3天,就会把元数据删除掉。对应的chunk 就会走2、3流程。
    1. master定期扫描各个chunkserver汇报的chunk集合,当发现没有对应的元数据的chunk时,chunkserver就可以把chunk直接删除了。

GFS的GC时惰性的删除,也就是不会立刻主动的删除chunk,而是统一的在常规检查时删除。

综上GFS显然不是一个强一致性的模型,松弛的一致性模型,仅仅保证了其在某些应用场景下适合,够用而已。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值