本文较长,建议细细品读,必有不一样的收获。算法
分布式文件系统是分布式领域的一个基础应用,其中最著名的毫无疑问是 HDFS/GFS。现在该领域已经趋向于成熟,但了解它的设计要点和思想,对咱们未来面临相似场景/问题时,具备借鉴意义。数据库
而且,分布式文件系统并不是只有 HDFS/GFS 这一种形态,在它以外,还有其余形态万千、各有千秋的产品形态,对它们的了解,也对扩展咱们的视野有所俾益。缓存
本文试图分析和思考,在分布式文件系统领域,咱们要解决哪些问题、有些什么样的方案、以及各自的选择依据。安全
在几十年之前,分布式文件系统就已经出现了,以 Sun 在 1984 年开发的“Network File System (NFS)”为表明,那时候解决的主要问题,是网络形态的磁盘,把磁盘从主机中独立出来。性能优化
这样不只能够得到更大的容量,并且还能够随时切换主机,还能够实现数据共享、备份、容灾等,由于数据是电脑中最重要的资产。NFS 的数据通讯图以下:服务器
部署在主机上的客户端,经过 TCP/IP 协议把文件命令转发到远程文件 Server 上执行,整个过程对主机用户透明。网络
到了互联网时代,流量和数据快速增加,分布式文件系统所要解决的主要场景变了,开始须要很是大的磁盘空间,这在磁盘体系上垂直扩容是没法达到的,必需要分布式,同时分布式架构下,主机都是可靠性不是很是好的普通服务器,所以容错、高可用、持久化、伸缩性等指标,就成为必需要考量的特性。架构
对一个分布式文件系统而言,有一些特性是必需要知足的,不然就没法有竞争力。主要以下:并发
除此以外,还有些特性是分布式加分项,具体以下:框架
从业务模型和逻辑架构上,分布式文件系统须要这几类组件:
而在部署架构上,有着“中心化”和“无中心化”两种路线分歧,便是否把“管理组件”做为分布式文件系统的中心管理节点。两种路线都有很优秀的产品,下面分别介绍它们的区别。
以 GFS 为表明,中心节点负责文件定位、维护文件 meta 信息、故障检测、数据迁移等管理控制的职能,下图是 GFS 的架构图:
该图中GFS master 即为 GFS 的中心节点,GF chunkserver 为 GFS 的存储节点。其操做路径以下:
在这种方案里,通常中心节点并不参与真正的数据读写,而是将文件 meta 信息返回给 Client 以后,即由 Client 与数据节点直接通讯。其主要目的是下降中心节点的负载,防止其成为瓶颈。这种有中心节点的方案,在各类存储类系统中获得了普遍应用,由于中心节点易控制、功能强大。
以ceph为表明,每一个节点都是自治的、自管理的,整个 ceph 集群只包含一类节点,以下图 (最下层红色的 RADOS 就是 ceph 定义的“同时包含 meta 数据和文件数据”的节点)。
无中心化的最大优势是解决了中心节点自身的瓶颈,这也就是 ceph 号称能够无限向上扩容的缘由。但由 Client 直接和 Server 通讯,那么 Client 必需要知道,当对某个文件进行操做时,它该访问集群中的哪一个节点。ceph 提供了一个很强大的原创算法来解决这个问题——CRUSH 算法。
对于文件系统来讲,持久化是根本,只要 Client 收到了 Server 保存成功的回应以后,数据就不该该丢失。这主要是经过多副本的方式来解决,但在分布式环境下,多副本有这几个问题要面对。
同步写入是保证副本数据一致的最直接的办法。当 Client 写入一个文件的时候,Server 会等待全部副本都被成功写入,再返回给 Client。
这种方式简单、有保障,惟一的缺陷就是性能会受到影响。假设有 3 个副本,若是每一个副本须要N秒,则可能会阻塞 Client 3N 秒的时间,有几种方式,能够对其进行优化:
还有一种方式是采用 CAP 中所说的 W+R>N 的方式,好比 3 副本 (N=3) 的状况,W=2,R=2,即成功写入 2 个就认为成功,读的时候也要从 2 个副本中读。这种方式经过牺牲必定的读成本,来下降写成本,同时增长写入的可用性。这种方式在分布式文件系统中用地比较少。
这主要避免的是某机房或某城市发生天然环境故障的状况,因此有一个副本应该分配地比较远。它的反作用是会带来这个副本的写入性能可能会有必定的降低,由于它离 Client 最远。因此若是在物理条件上没法保证够用的网络带宽的话,则读写副本的策略上须要作必定考虑。
能够参考同步写入只写 2 副本、较远副本异步写入的方式,同时为了保证一致性,读取的时候又要注意一些,避免读取到异步写入副本的过期数据。
若是有中心节点,则数据节点按期和中心节点进行通讯,汇报本身的数据块的相关信息,中心节点将其与本身维护的信息进行对比。若是某个数据块的 checksum 不对,则代表该数据块被损坏了;若是某个数据块的 version 不对,则代表该数据块过时了。
若是没有中心节点,以 ceph 为例,它在本身的节点集群中维护了一个比较小的 monitor 集群,数据节点向这个 monitor 集群汇报本身的状况,由其来断定是否被损坏或过时。
当发现被损坏或过时副本,将它从 meta 信息中移除,再从新建立一份新的副本就行了,移除的副本在随后的回收机制中会被收回。
这里的策略就比较多了,好比 round-robin、速度最快的节点、成功率最高的节点、CPU 资源最空闲的节点、甚至就固定选第一个做为主节点,也能够选择离本身最近的一个,这样对总体的操做完成时间会有必定节约。
当在集群中加入一台新的存储节点,则它主动向中心节点注册,提供本身的信息,当后续有建立文件或者给已有文件增长数据块的时候,中心节点就能够分配到这台新节点了,比较简单。但有一些问题须要考虑。
首先要有评价存储节点负载的指标。有多种方式,能够从磁盘空间使用率考虑,也能够从磁盘使用率 +CPU 使用状况 + 网络流量状况等作综合判断。通常来讲,磁盘使用率是核心指标。
其次在分配新空间的时候,优先选择资源使用率小的存储节点;而对已存在的存储节点,若是负载已通过载、或者资源使用状况不均衡,则须要作数据迁移。
当系统发现当前新加入了一台存储节点,显然它的资源使用率是最低的,那么全部的写流量都路由到这台存储节点来,那就可能形成这台新节点短时间负载过大。所以,在资源分配的时候,须要有预热时间,在一个时间段内,缓慢地将写压力路由过来,直到达成新的均衡。
在有中心节点的状况下,这个工做比较好作,中心节点就包办了——判断哪台存储节点压力较大,判断把哪些文件迁移到何处,更新本身的 meta 信息,迁移过程当中的写入怎么办,发生重命名怎么办。无需上层应用来处理。
若是没有中心节点,那代价比较大,在系统的总体设计上,也是要考虑到这种状况,好比ceph,它要采起逻辑位置和物理位置两层结构,对Client暴露的是逻辑层 (pool 和 place group),这个在迁移过程当中是不变的,而下层物理层数据块的移动,只是逻辑层所引用的物理块的地址发生了变化,在Client看来,逻辑块的位置并不会发生改变。
若是有中心节点,还要考虑它的伸缩性。因为中心节点做为控制中心,是主从模式,那么在伸缩性上就受到比较大的限制,是有上限的,不能超过单台物理机的规模。咱们能够考虑各类手段,尽可能地抬高这个上限。有几种方式能够考虑:
7、高可用性
中心节点的高可用,不只要保证自身应用的高可用,还得保证 meta data 的数据高可用。
meta data 的高可用主要是数据持久化,而且须要备份机制保证不丢。通常方法是增长一个从节点,主节点的数据实时同步到从节点上。也有采用共享磁盘,经过 raid1 的硬件资源来保障高可用。显然增长从节点的主备方式更易于部署。
meta data 的数据持久化策略有如下几种方式:
当前内存服务 + 日志文件持久化是主流方式。一是纯内存操做,效率很高,日志文件的写也是顺序写;二是不依赖外部组件,独立部署。
为了解决日志文件会随着时间增加愈来愈大的问题,以让系统能以尽快启动和恢复,须要辅助之内存快照的方式——按期将内存 dump 保存,只保留在 dump 时刻以后的日志文件。这样当恢复时,从最新一次的内存 dump 文件开始,找其对应的 checkpoint 以后的日志文件开始重播。
在前面“持久化”章节,在保证数据副本不丢失的状况下,也就保证了其的高可用性。
这些年随着基础设施的发展,局域网内千兆甚至万兆的带宽已经比较广泛,以万兆计算,每秒传输大约 1250M 字节的数据,而 SATA 磁盘的读写速度这些年基本达到瓶颈,在 300-500M/s 附近,也就是纯读写的话,网络已经超过了磁盘的能力,再也不是瓶颈了,像 NAS 网络磁盘这些年也开始普及起来。
但这并不表明,没有必要对读写进行优化,毕竟网络读写的速度仍是远慢于内存的读写。常见的优化方法主要有:
缓存的使用在提升读写性能的同时,也会带来数据不一致的问题:
这类问题有几种方法:
因为分布式文件存储系统,确定是一个多客户端使用、多租户的一个产品,而它又存储了多是很重要的信息,因此安全性是它的重要部分。
主流文件系统的权限模型有如下这么几种:
Discretionary Access Control
,就是咱们熟悉的 Unix 类权限框架,以 user-group-privilege 为三级体系,其中 user 就是 owner,group 包括 owner 所在 group 和非 owner 所在的 group、privilege 有 read、write 和 execute。这套体系主要是以 owner 为出发点,owner 容许谁对哪些文件具备什么样的权限。Mandatory Access Control
,它是从资源的机密程度来划分。好比分为“普通”、“机密”、“绝密”这三层,每一个用户可能对应不一样的机密阅读权限。这种权限体系起源于安全机构或军队的系统中,会比较常见。它的权限是由管理员来控制和设定的。Linux 中的 SELinux 就是 MAC 的一种实现,为了弥补 DAC 的缺陷和安全风险而提供出来。关于 SELinux 所解决的问题能够参考 What is SELinux?Role Based Access Control
,是基于角色 (role) 创建的权限体系。角色拥有什么样的资源权限,用户归到哪一个角色,这对应企业 / 公司的组织机构很是合适。RBAC 也能够具体化,就演变成 DAC 或 MAC 的权限模型。市面上的分布式文件系统有不一样的选择,像 ceph 就提供了相似 DAC 但又略有区别的权限体系,Hadoop 自身就是依赖于操做系统的权限框架,同时其生态圈内有 Apache Sentry 提供了基于 RBAC 的权限体系来作补充。
有连续空间和链表空间两种。连续空间的优点是读写快,按顺序便可,劣势是形成磁盘碎片,更麻烦的是,随着连续的大块磁盘空间被分配满而必须寻找空洞时,连续分配须要提早知道待写入文件的大小,以便找到合适大小的空间,而待写入文件的大小,每每又是没法提早知道的 (好比可编辑的 word 文档,它的内容能够随时增大);
而链表空间的优点是磁盘碎片不多,劣势是读写很慢,尤为是随机读,要从链表首个文件块一个一个地往下找。
为了解决这个问题,出现了索引表——把文件和数据块的对应关系也保存一份,存在索引节点中 (通常称为 i 节点),操做系统会将 i 节点加载到内存,从而程序随机寻找数据块时,在内存中就能够完成了。经过这种方式来解决磁盘链表的劣势,若是索引节点的内容太大,致使内存没法加载,还有可能造成多级索引结构。
实时删除仍是延时删除? 实时删除的优点是能够快速释放磁盘空间;延时删除只是在删除动做执行的时候,置个标识位,后续在某个时间点再来批量删除,它的优点是文件仍然能够阶段性地保留,最大程度地避免了误删除,缺点是磁盘空间仍然被占着。在分布式文件系统中,磁盘空间都是比较充裕的资源,所以几乎都采用逻辑删除,以对数据能够进行恢复,同时在一段时间以后 (多是 2 天或 3 天,这参数通常均可配置),再对被删除的资源进行回收。
怎么回收被删除或无用的数据? 能够从文件的 meta 信息出发——若是 meta 信息的“文件 - 数据块”映射表中包含了某个数据块,则它就是有用的;若是不包含,则代表该数据块已是无效的了。因此,删除文件,实际上是删除 meta 中的“文件 - 数据块”映射信息 (若是要保留一段时间,则是把这映射信息移到另一个地方去)。
有不少这样的场景,好比电商——那么多的商品图片、我的头像,好比社交网站——那么多的照片,它们具备的特性,能够简单概括下:
针对这种业务场景,主流的实现方式是仍然是以大数据块的形式存储,小文件以逻辑存储的方式存在,即文件 meta 信息记录其是在哪一个大数据块上,以及在该数据块上的 offset 和 length 是多少,造成一个逻辑上的独立文件。这样既复用了大数据块系统的优点和技术积累,又减小了 meta 信息。
文件指纹就是根据文件内容,通过算法,计算出文件的惟一标识。若是两个文件的指纹相同,则文件内容相同。在使用网络云盘的时候,发现有时候上传文件很是地快,就是文件指纹发挥做用。云盘服务商经过判断该文件的指纹,发现以前已经有人上传过了,则不须要真的上传该文件,只要增长一个引用便可。在文件系统中,经过文件指纹能够用来去重、也能够用来判断文件内容是否损坏、或者对比文件副本内容是否一致,是一个基础组件。
文件指纹的算法也比较多,有熟悉的 md五、sha25六、也有 google 专门针对文本领域的 simhash 和 minhash 等。
分布式文件系统内容庞杂,要考虑的问题远不止上面所说的这些,其具体实现也更为复杂。本文只是尽可能从分布式文件系统所要考虑的问题出发,给予一个简要的分析和设计,若是未来遇到相似的场景须要解决,能够想到“有这种解决方案”,而后再来深刻研究。
同时,市面上也是存在多种分布式文件系统的形态,下面就是有研究小组曾经对常见的几种分布式文件系统的设计比较。
从这里也能够看到,选择其实不少,并非 GFS 论文中的方式就是最好的。在不一样的业务场景中,也能够有更多的选择策略。