-
总体设计是什么?
- 一个网络文件系统
- 与现有应用(文本编辑器等)透明地配合
- 类似于雅典娜的AFS
- [用户;工作站 + Frangipani;网络;petal]
- Petal:块存储服务;复制;为性能而条纹化+分片
- Frangipani在Petal中存储了什么?
- 目录、inode、文件内容块、空闲位图
- Frangipani:去中心化文件服务;为了性能而缓存
- 一个网络文件系统
-
预期的用途是什么?
- 环境:单一实验室与协作工程师;作者的研究实验室;编程、文本处理、电子邮件等
- workstations in offices
- 大多数文件访问是针对用户自己的文件
- 需要在任何工作站之间潜在地共享任何文件
- 用户/用户的协作
- 一个用户登录到多个工作站
- 因此:
- 常见情况是独占访问;
- 希望这样的访问速度快
- 但有时需要共享文件;希望这样的共享是正确的
- 在写这篇论文时,这是一个常见的情景
-
为什么Frangipani的设计适用于预期的用途?
- 具有人类对文件系统的期望的强一致性
- 在每个工作站中进行缓存 - 写回
- 所有更新最初仅在工作站的缓存中应用 - 快速,包括创建文件、创建目录、重命名等
- 如果所有内容都已缓存,更新将无需任何RPC进行
- 因此,文件系统代码必须驻留在工作站而非服务器中
- 大部分复杂性位于客户端而非共享的Petal服务器中
- 更多的客户端 -> 更多的CPU功率
- 复杂的服务器在以前的系统中是一个严重的瓶颈,如NFS、AFS
-
如果WS1想要创建并写入/grades,会发生什么?
- 从Petal中读取/的信息到WS1的缓存
- 在缓存中仅添加"grades"的条目
- 不立即写回到Petal!以防WS1想要进行更多修改
-
"缓存一致性"解决了"读取看到写入"的问题
-
目标是线性一致性和缓存
-
许多系统使用"缓存一致性协议"例如,多核、文件服务器、分布式共享内存
-
Frangipani的一致性协议(简化版):除非持有锁,否则不缓存
-
锁服务器(LS),每个文件/目录一个锁 文件 拥有者 ----------- x WS1 y WS1 工作站(WS)Frangipani缓存: 文件/目录 锁 内容 ----------------------- x 忙碌 ... y 空闲 ... 如果WS持有锁, 忙碌:正在使用数据 空闲:持有锁但当前未使用缓存的数据 工作站规则: 除非持有锁,否则不缓存 获取锁,然后从Petal中读取 向Petal写入后释放锁 一致性协议消息: 请求(WS -> LS) 授予(LS -> WS) 撤销(LS -> WS) 释放(WS -> LS) 锁的命名是按文件/目录(实际上是i节点)命名的, 尽管锁服务器实际上并不了解文件系统或Petal的任何信息。 例子:WS1更改文件z,然后WS2读取z WS1 LS WS2 读取z --请求(z)--> 拥有者(z)=WS1 <--授予(z)--- (从Petal中读取并缓存z的数据) (在本地修改z) (完成后,缓存的锁处于状态) 读取z <--请求(z)-- <--撤销(z)-- (将修改后的z写入Petal) --释放(z)--> 拥有者(z)=WS2 --授予(z)--> (从Petal中读取z) 要点: 锁和规则强制读取看到最后一次写入 锁确保“最后一次写入”是明确定义的 注意: 在工作站释放对文件的锁之前, 它必须将修改后的文件内容以及元数据写入Petal 因此,工作站对文件内容以及元数据都获得一致性 即文件读取看到最新的内容 一致性优化: “空闲”状态已经是一种优化 Frangipani具有共享读锁和排他写锁
-
-
-
下一个挑战:原子性
- 如果两个工作站同时尝试创建相同的文件会怎样? 部分完成的多写操作是否可见?
- 例如,文件创建初始化i节点,添加目录条目; 例如,重命名(两个名称都可见?两者都不可见?)
- Frangipani实现了事务性文件系统操作:
- 操作对应于系统调用(创建文件、删除文件、重命名等)
- WS获取将要修改的所有文件系统数据的锁
- 持有所有锁执行操作
- 仅在完成时释放
- 仅在整个操作完成后才响应“撤销”
- 因此,没有其他WS可以看到部分完成的操作; 也没有其他WS可以同时执行冲突的更新
- 请注意,Frangipani的锁正在执行两个不同的任务:
- 缓存一致性(显示写入)
- 原子事务(隐藏写入)
- Frangipani实现了事务性文件系统操作:
-
下一个挑战:崩溃恢复
- Frangipani在崩溃恢复中使用预写式日志,在将任何操作的缓存块写入Petal之前,首先将日志写入Petal
- 因此,如果崩溃的工作站已经对一个操作进行了一些Petal写入,但并没有完成全部写入,可以从Petal的日志中完成写入
- 但是
- Frangipani为每个工作站使用单独的日志 这避免了日志成为瓶颈,使去中心化变得更加容易,但是会将对给定文件的更新分散到许多日志中
- Frangipani的日志存储在共享的Petal存储中,而不是本地磁盘 ,WS2可以读取WS1的日志来从WS1的崩溃中恢复 单独的日志是一种有趣且不寻常的安排
-
日志中包含什么?
- 日志entry:
- 日志序列号
- 更新数组:
- 块号,新版本号,地址,新字节
- 仅包含元数据更新,不包含文件内容更新
- 例如——创建文件d/f会产生一个日志entry:
- 一个包含两个条目的更新数组:
- 向d的内容块添加一个“f”条目,带有新的i编号
- 初始化f的i节点
- 最初,日志条目在WS的本地内存中(尚未存储到Petal中)
- 一个包含两个条目的更新数组:
- 日志entry:
-
当WS从LS收到对已修改目录的锁撤销时:
- 强制将整个日志写入Petal,然后
- 将缓存的更新块发送到Petal,然后
- 向LS释放锁
-
为什么WS在更新Petal中的i-node和目录等之前必须将日志写入Petal?为什么要延迟写入日志,直到LS撤销锁?当WS1在持有锁的同时崩溃时会发生什么?
- 不会有太多影响,直到WS2请求WS1持有的锁;LS向WS1发送撤销请求,但未收到响应;LS超时,告诉WS2从Petal中的WS1日志中进行恢复
- WS2从WS1的日志中进行恢复时会发生什么?
- 从Petal中读取WS1的日志,执行由日志中记录的操作所描述的Petal写入,告诉LS完成了,以便LS可以释放WS1的锁
- 请注意,每个WS的日志都存储在Petal中非常关键,以便任何WS都可以读取它进行恢复。
-
如果WS1在将其最近的日志写入Petal之前崩溃会怎么样?
- 如果WS1崩溃,WS1的最近操作可能会完全丢失。 但是在Petal中的文件系统将保持内部一致。
-
为什么只重放一个日志是安全的,尽管其他工作站对相同文件进行了交叉操作?
- 例子:
- WS1: delete(d/f) crash
- WS2: create(d/f)
- WS3: recover WS1
- WS3正在恢复WS1的日志——但它不查看WS2的日志,恢复是否会重新播放删除操作?
- 不会——通过“版本号”机制阻止
- Petal中每个元数据块(i节点)中都有一个版本号,每个记录的操作中的版本号是块的版本号加一,仅当操作的版本号 > 块版本号时,恢复才会重新播放。即仅当块尚未被此操作更新时
- WS3是否需要获取d或d/f锁?
- 不需要:如果版本号与操作之前相同,WS1没有进行写入,因此它不可能释放锁, 因此没有其他人可能拥有该锁,因此WS3在Petal中更新是安全的
- 例子:
-
如果: WS1持有一个锁,WS2认为WS1已经死亡,进行恢复,释放WS1的锁,如果WS1实际上是活着的,它随后能够尝试写入被锁定的数据吗?
- 锁有租约! 锁所有者不能在租约期满后继续使用锁 直到租约到期后,LS才开始进行恢复
-
对于什么工作负载,Frangipani可能性能较差? 大量读/写共享? 大量小文件?
- Petal细节
- Petal为Frangipani提供容错存储,因此值得讨论
- 块读/写接口,与现有文件系统兼容,看起来像单个巨大的磁盘,但有很多服务器和很多磁盘
- 大而高性能,条带化,64 KB块 虚拟:64位稀疏地址空间,写入时分配,地址转换映射
- 主/备份(一个备份服务器),主服务器将每个写操作发送到备份,使用Paxos在每个虚拟地址范围上达成主服务器的一致性
- 崩溃后的恢复怎么办?
- 假设一对是S1+S2
- S1失败,S2现在是唯一的服务器
- S1重新启动,但已经错过了许多更新
- S2记住了它写入的每个块的列表! 因此S1只需要读取那些块,而不是整个磁盘 记录
- 虚拟->物理映射和错过写入信息
- 局限性
- 对于程序员工作站等使用最为实用,其他情况下可能不太适用
- 文件系统对于许多应用程序而言不是一个很好的API,例如网站
- Frangipani强制执行权限,因此工作站必须是可信的
- Frangipani/Petal分离有点尴尬
- 两个层都进行日志记录
- Petal可能接受来自“下层”Frangipani工作站的更新
- 比简单文件服务器更多的RPC消息
- 要记住的想法
- 复杂的客户端共享简单的存储 —— 或许可扩展
- 缓存一致性
- 分布式事务
- 分布式崩溃恢复
- 上述所有的交互
- Petal细节
-
在这个系统中有哪些客户端和服务器?
- Petal服务器存储块数据。每个用户的工作站运行一个Frangipani实例。Frangipani充当Petal的客户端,但也充当运行在同一工作站上的应用程序的文件服务器。因此,不清楚是否应该使用 “客户端” 还是 “服务器” 来指代Frangipani的一个实例。
-
第5节说,当Frangipani工作站释放读锁时,必须使缓存数据失效,并在释放写锁时将修改后的缓存数据写回Petal。这不会严重限制Frangipani从缓存中受益吗?
- 在Frangipani工作站获取锁之后,它将保持锁,直到另一个工作站尝试获取它。也就是说,如果用户在目录中创建文件(因此获取该目录的写锁,并缓存目录的信息),然后稍作暂停,再在同一目录中创建第二个文件,用户的工作站很可能不会需要两次获取目录锁。因此,工作站将只从Petal读取目录信息一次,并仅在其本地缓存副本中修改该信息。如果其他工作站需要使用该目录,那么该工作站将向锁服务器发送获取消息,锁服务器将向第一个工作站发送撤销消息,第一个工作站将从其缓存中将目录的修改信息写回Petal(然后从其缓存中删除数据),然后通知锁服务它放弃了该锁。因此,只要没有太多的读/写共享,Frangipani在缓存锁和数据方面表现得相当不错。
-
Frangipani和GFS有什么区别?
- 一个重要的架构差异是,GFS将大部分文件系统逻辑放在服务器上,而Frangipani在运行Frangipani的工作站上分布逻辑。换句话说,Frangipani并没有像GFS那样真正意义上的文件服务器的概念。为了允许工作站在其本地缓存中纯粹执行文件系统操作,Frangipani将文件系统逻辑放在工作站上。当大部分活动是工作站读取和写入单个用户的(缓存的)文件时,这是有道理的。Frangipani有许多机制来确保工作站缓存保持一致,这样一个工作站上的写操作对另一个工作站上的读操作立即可见,同时复杂的操作(如创建文件)即使其他工作站试图查看涉及的文件或目录,也是原子的。对于Frangipani来说,最后一种情况是棘手的,因为没有指定的文件服务器执行对给定文件或目录的所有操作。
- 相比之下,GFS根本没有缓存,因为它的重点是对无法放入任何缓存的大型文件进行顺序读写。通过将每个文件分布在许多GFS服务器上,它在读取大型文件时获得了高性能。由于GFS没有缓存,它没有缓存一致性协议。由于文件系统逻辑在服务器上,GFS客户端相对较简单;只有服务器需要进行锁定并担心崩溃恢复。
- Frangipani看起来是一个真正的文件系统,你可以与任何现有的工作站程序一起使用。从这个意义上说,GFS并不像文件系统那样呈现出来;应用程序必须明确编写以通过库调用使用GFS。
-
Frangipani现在已经有20多年的历史了;分布式文件系统的现状是什么?
- 尽管一些组织今天在分布式文件系统上存储用户和项目文件,但随着笔记本电脑的兴起(必须是自包含的)和商业云服务的崛起,它们的重要性已经减弱。尽管如此,仍然有许多用户使用现有的文件系统协议,如SMB、NFS和AFS,以及更近期的分布式文件系统,如xtreemfs、Ceph、Lustre和Dropbox。许多网络存储由NetAPP和EMC等公司销售,但我不清楚人们在多大程度上使用磁盘级别的存储(通过例如iSCSI)还是作为文件服务器(例如通过NFS与NetAPP服务器通信)。
- 网站、大数据和云计算的兴起已经改变了存储系统开发的重心。网站可以与类似数据库的服务器配合使用,包括键/值存储;文件服务器在这里不是很合适。大数据处理系统通常使用文件系统,例如GFS用于MapReduce,但重点是处理大文件的高并行吞吐量;Frangipani的缓存、一致性和锁定在这里是不需要的。
-
论文中提到Frangipani并不会立即将新的日志条目发送到Petal。如果一个工作站在系统调用完成后,但在发送相应的日志条目到Petal之前崩溃会发生什么?
-
论文中提到Frangipani并不会立即将新的日志条目发送到Petal。如果一个工作站在系统调用完成后,但在发送相应的日志条目到Petal之前崩溃会发生什么?
假设在运行在Frangipani工作站上的应用程序创建了一个文件。在一段时间内,关于新创建文件的信息只存在于该工作站的缓存(RAM)中。如果工作站在将信息写入Petal之前崩溃,那么新文件就会完全丢失。它将无法被恢复。
因此,类似以下这样的应用程序:
plaintextCopy codecreate file x; print "I created file x";
可能会打印 “I created file x”,但是(如果然后发生崩溃)文件 x 可能实际上并不存在。
这可能看起来不幸,但即使对于本地磁盘文件系统(如Linux)也是相当常见的。一个需要确保其数据真正永久保存的应用程序可以调用
fsync()
。
-
-
条带化文件是什么意思?这类似于分片吗?
- 将文件进行条带化类似于分片。具体来说,它指的是将单个文件的块分布在多个服务器(本文中指的是Petal服务器)上,以便例如文件的块0存储在服务器0上,块1存储在服务器1上,块2存储在服务器0上,块3存储在服务器1上,依此类推。进行这样的操作的一个原因是为了在读取单个大文件时获得高性能,因为同一文件的不同部分可以从不同的服务器/磁盘上读取。另一个原因是确保负载在服务器上均匀分布。
Frangipani: A Scalable Distributed File System(解读)
最新推荐文章于 2024-09-09 22:06:44 发布