Frangipani: A Scalable Distributed File System 论文阅读

Frangipani是一篇1997年“分布式文件系统”的论文,其中关于缓存一致性分布式事务分布式故障恢复的简单并且优秀的设计思想,依旧值得我们学习和借鉴

本文将按照以下几个方面透彻介绍Frangipani的方方面面

目录

一、Background

1.历史背景

  • 在1997年,笔记本还不流行,主要是工作站,也就是一个带有键盘鼠标显示器和操作系统的计算机。
  • 随着工作站用户和文件的不断增长,需要不断增加disk(当时的存储介质)和machine,以及大量的人工管理(运维)
  • 作者们是一个研究所的成员,他们习惯于使用共享的基础设施,因此想让所有的工作站共享一个大容量的“disk”

2.技术背景

同作者在1996年发表了《Petal: Distributed virtual disks》

一个分布式shared disk,具有如下的特点:

  • 1 << 64 的地址空间,需要实际存储时,才会分配实际存储资源
  • 可增加数据副本,提高可用性
  • 可在线生成snapshot
  • 对外提供disk接口

由此,同作者想把Petal的特性,发挥到上层file system中,于是设计了Frangipani

Frangipani的设计feature包括

  • 一致性:强一致(线性一致性)
  • 拓展性:可透明的增加,去掉机器,尽量少的人工参与
  • 容错性:可以failover
  • 可在线生成snapshot

二、System Structure

1.架构图

Frangipani: A Scalable Distributed File System 论文阅读

有三种机器:

  • mount Frangipani fs的机器
  • Petal cluster的机器
  • Lock Service的机器

三种机器,在不影响相互工作的情况下,理论上可以分布在任意机器上,并非图中那样的分布

比如,第一种和第二种机器可以是一台机器,第二种和第三种也不必在一台机器上

2.两层设计

  • 上层:Frangipani file system
  • 下层:Petal Shared disk

3.Frangipani file system

  • 运行在kernel
  • 作为一个fs实现,提供标准的文件系统接口

4.安全性考虑

Frangipani: A Scalable Distributed File System 论文阅读

并非所有mount了Frangipani的机器都可以访问Petal,原因是kernel不同,可能存在bug

但可以通过在已有Frangipani机器上,再搭建一层Service来实现C-S访问Frangipani,如图中的架构

三、 Disk Layout

本节会介绍Petal的layout

1.Layout

Frangipani: A Scalable Distributed File System 论文阅读

  • 0 - 1T : 全局配置参数,论文中约占几K
  • 1 - 2T : 256份logs (每份4GB)
  • 2 - 5T : 块申请的bitmaps,也被分为若干份,但论文未给出多少份
  • 5 - 6T : 2G个inodes (每个512B)
  • 6 - 134T : 32G个data blocks (每个4KB)
  • 134T-264 : 略小于16M个data blocks (每个1TB)

2.details

  • 注意到每部分的大小是固定的,原因是简单,可以低成本地更改大小的配置
  • logs每个Frangipani Server独占一份log,因此没有全局有序的log
  • 每个bitmap被一个Frangipani Server独占,bitmap较多,一个bitmap被用完后,Frangipani Server会重新申请一个
  • bitmap和inode有固定的映射关系,拥有bitmap的Frangipani Server只能alloc对应的inode,但可以读写任意位置的inode
  • 文件大小的上限是16 * 4KB + 1 * 1TB,也就是一个文件,最多申请16个小data block和1个大data block

四、 The Lock Service

简单来说,Frangipani的cache coherence和failover是通过读写锁实现的

1.features

  • 分布式锁
  • 读写锁
  • sticky,拿到锁的客户端不会释放锁,直到Lock Server请求客户端释放锁
  • lease,持锁超过lease还没有renew,Lock Server会收回这把锁,客户端锁也会无效

2.架构

文章并没有详细描述分布式锁的架构,但可以从描述中窥见一二

  • 一个分布式Lock Server集群 + Frangipani Server内置clerk module
  • 分布式Lock Server集群
    • 通过Paxos在所有Server之间共享meta:Lock Server list;Lock 和 Lock Server的对应关系; active clerk list
    • 每把Lock只被一个Lock Server拥有
    • 当Lock Server crash后,通过meta去进行failover
    • 可以自动进行负载均衡
  • clerk module
    • 当Frangipani Server存活时,clerk 持有Lock table,维护持有那些锁以及锁的状态

3.锁的划分

  • 每份log一把Lock,确保一份log只被一个Frangipani Server独占

  • 每个bitmap一把锁,确保一个bitmap只被一个Frangipani Server独占;

    同时bitmap锁,还保护:他所对应的data block,他所对应的inode,前提是这些block或者inode还没被alloc

  • 每个file/directory/symbolic link一把锁,保护inode,以及对应的data block;该类锁的key应该是inode号

4.实现

处于性能考虑,采用异步消息来实现分布式锁的部分功能

  • clerk -> Lock Server
    • Request : 请求某锁
    • Release : 释放某锁
  • Lock Server -> clerk
    • Grant : 赋予某锁
    • Revoke : 剥夺某锁

他们的用法会在之后叙述中介绍

五、Cache coherence

简单来说,是利用读写锁实现

  • 获得锁的权利
    • 读锁:读取数据,并cache
    • 写锁:读取数据,并cache,更改数据,允许本地cache和Petal存储不一致
  • 释放锁的义务
    • 释放读锁:失效cache
    • 释放写锁:把dirty cache写回Petal,然后失效cache
    • 写锁降级为读锁:把dirty cache写回Petal,可以继续持有cache

下面通过两个例子介绍锁的机制

假设有两个workstation(WS1,WS2),一个Lock Server(LS),以及涉及的文件(F)

Case1:WS1想要写F

  • WS1 request -> 请求写锁 LS
  • LS 查看该写锁没有被其他WS占用,或者还没有该写锁(可能是个新文件),会直接创建个新读写锁,并利用Paxos同步
  • LS grant -> 赋予写锁 WS1
  • WS1可以读取数据,cache数据,并更改数据
  • WS1使用完该写锁后,依旧持有这把写锁(busy -> idle),并不断renew lease,直到LS剥夺

Case2:WS2之后也想要写F

  • WS2 request -> 请求写锁 LS

  • LS 发现这把写锁被 WS1占用,于是剥夺WS1的写锁

  • LS revoke -> 剥夺写锁 WS1

  • WS1收到消息后,发现写锁处于idle状态,会先把dirty cache写入Petal,失效cache,然后释放锁

    如果写锁处于busy状态,会等WS1处理完自己的事情,置于idle后继续上述流程

  • WS1 release -> 释放写锁 LS

  • LS grant -> 赋予写锁 WS2

  • WS2可以读取数据,cache数据,并更改数据

  • WS2使用完该写锁后,依旧持有这把写锁(busy -> idle),并不断renew lease,直到LS剥夺

可能出现的情形包括以下几种

  • 请求读锁
    • 没WS持锁: 直接获得读锁
    • 一些WS持有读锁: 直接获得读锁
    • 一个WS持有写锁: 先剥夺该写锁,或者降级该写锁为读锁
  • 请求写锁
    • 没WS持锁: 直接获得写锁
    • 一些WS持有读锁: 先剥夺所有WS的读锁
    • 一个WS持有写锁: 先剥夺该写锁

六、Log and crash recovery

简单来说,通过WAL实现failover

写log流程

  • 获取涉及更改的所有锁
  • 关于meta data更改的事务,把所有的更改写进一条log里,放在memory或者sync进Petal
  • log写进Petal后,才可以更改Petal的实际存储

details

  • WAL只记录meta data相关的log,比如创建文件,删除文件,重命名文件等
  • log记录在Petal而非Frangipani,每个Frangipani Server独占一份log(前面介绍一共256份log,所以最多256个Server,但是可调)
  • 论文介绍,log最大128KB,满了reuse
  • 因为reuse,可能出现找不到log起始位置的情况,因此每个log block附带一个递增的序列号
  • 因为log没有全局有序,所以重演log时要遵守以下规则
    • 持有log内涉及的所有写锁:说明没有其他客户端更改
    • meta data block维护递增版本号,log内附带该版本号,只重演符合预期的log

failure detect

  • Lock Server:lease过期;或者no reply for request
  • client of Frangipani Server:no reply for request

failover

failover步骤如下:

  • Lock Server让另一台Frangipani Server去执行Failover
  • Lock Server会赋予recovery Server之前crash Server的所有锁
  • 重演合适的log(条件见上details)
  • 释放crash Server的所有锁
  • 其他被crash Server持有锁阻塞请求的Server可以继续工作
  • 可以选择restart这台机器

七、Other details

1.问题

论文中指出了几个问题

  • 两层设计可能会log两次
  • Lock的粒度是file而不是block
  • 不知道file的确切物理位置

2.增删机器

可以几乎透明,不影响其他机器地增删机器

  • 增加机器:指明Lock Service 和 Petal 即可
  • 删除机器:直接关机即可
  • Petal集群增删机器也是类似的

3.数据备份

  • Petal层面可以在线生成snapshot,用copy on write技术;

    因为是Petal层面,所以依然存在file system的log,需要recovery才能使用

  • 未来会采用一把特殊的锁,任何写操作都需要持有锁,锁可以shared

    当需要snapshot时,back up 进程会让Lock Server会要求所有Frangipani Server释放该锁,此时dirty Data会写到Petal,并阻塞其他写操作,当所有机器都完成后,back up生成snapshot,并恢复正常

4.timestamp问题

问题:锁的lease检查之后在Frangipani Server,如果网络delay过大,request到达Petal时已经过期,这是不符合预期的

解决:使用maigin Time, 容忍一定的delay

未来的解决:到达Petal的request附带过期时间戳,如果时间没有误差,可以保证正确

5.性能

由于是1997年的论文(比我的年龄还大),并没有关注性能

但是可以看到,随着机器的增加,吞吐近乎线性的增长,这归功于去中心化的设计

以上就是我对于Frangipani主要内容的理解

欢迎一起讨论

上一篇:币圈修心:什么是分布式账本(Distributed Ledger)?


下一篇:git历史回退