您的位置  > 互联网

分布式文件存储系统架构的设计与设计方案的区别?

分布式存储系统可以理解为多个独立的存储系统,各司其职,协同工作,统一对外提供存储服务。 因此,无论是存储非结构化数据的分布式文件系统、存储结构化数据的分布式数据库,还是存储半结构化数据的分布式KV,系统设计主要需要满足以下需求(但不限于):基本读写功能、性能、可扩展性、可靠性、可用性。

1. 有一个中央管理节点并且存储节点有主从

具有这种架构的系统以GFS为代表。 以下面的系统为例。 整体设计与GFS类似。 最近发现小米的分布式KV系统也采用了同样的架构设计。

就基本读写功能而言,分布式文件系统主要提供文件读/写/删除功能,那么从哪里读写呢? 如何阅读和写作? 以什么形式存储?也就是上一篇文章提到的数据定位和存储引擎问题

在有中央控制节点的分布式文件系统中,从哪里读写的任务基本都是由中央控制节点,也就是图中的节点来完成。 为了完成这个核心任务,节点需要做两件重要的事情:

1.存储节点信息和状态

对于分布式文件系统来说,从单机上的一个文件到磁盘上的一个位置,都会有一个逻辑拓扑,方便分区扩展或者数据隔离等。拓扑包括存储池、分区、服务器、磁盘、文件目录等从上到下。

节点需要保存整个集群的全局视图。 为了提高性能,这种逻辑拓扑一般会缓存在内存中,并定期持久化在节点的磁盘上。

节点需要监控系统中所有数据节点和磁盘的状态,例如节点的在线、离线状态,并进行相应的事件处理,以保证系统状态的正确性。

同时,为了使系统的数据分布和资源使用更加均衡,节点可以获取数据节点的容量、负载等状态,以便读写调度模块可以策略性地分配可写资源。

2、文件读写的调度策略

由于没有像Hash算法那样静态计算读写位置,因此需要中央控制节点起到调度的作用。 当客户端发起写请求时,第一步是去节点获取文件ID。 节点根据客户端读写的文件大小、备份数量以及当前系统节点的状态和权重等参数选择合适的节点和备份,返回给客户端有文件ID,这个文件ID包含了该文件的多个副本的位置信息。 这样做的好处是不需要存储每个文件的映射关系。 对于对象存储系统来说,由于功能需求,必须保存对象与文件之间的映射关系。

节点除了完成以上两个主要功能外,还需要承担维护副本数量和内容正确性的责任,因为毕竟它知道的太多了,数据恢复调度的任务只能是它自己的,这里不讨论。

3、存储节点选择

对于有主从存储节点的系统,每次备份的主从节点的选择也需要由节点来控制。

数据节点除了负责文件在独立系统上如何存储外,还负责维护存储节点备份数据的一致性,存储节点分为主从。 可以概括为以下几个要点:

1、独立存储引擎的实现

主从存储节点之间独立存储引擎的实现几乎没有区别。 他们解决的是如何存储文件。不同系统之间还有一个区别:一个存储引擎负责一台机器中所有磁盘的存储,或者一个磁盘负责一个存储引擎。 这里我们使用一个存储引擎来负责一张磁盘的设计。

分布式文件系统的存储引擎大多基于独立的文件系统,数据最终以文件的形式存在。 独立文件系统以目录的形式组织文件。 这个系统基本遵循了这个思想,根据目录而不是节点来划分副本。 它的名称与Swift相同,是备份的基本单位。 以三重备份为例,中心节点会根据策略选择三个不同的物理磁盘创建相同的ID。 不同物理磁盘中同一个磁盘上存储的文件是相同的。

这里还有一个问题,即是否合并存储在独立文件系统上的文件的问题。 简单直接的方法就是直接将文件存放在指定的目录中。 这种方法带来的问题也是直接可见的。 它们直接受到文件系统随机读写性能的限制。 对于小文件读写较多的场景,磁盘往往会成为整个系统的瓶颈,进而不得不通过增加节点来扩大吞吐能力。

因此,本系统将多个文件追加并合并为一个较大且固定大小的文件,将随机写入转变为顺序写入。 实验表明,可以极大地提高单机存储的吞吐量。 该方案带来的性能提升是显而易见的,但也增加了一定的实现复杂度。 合并必然会带来需要对定位文件的最终位置进行二次映射,即合并后文件中的偏移量。

2、保证备份一致性

在保证备份一致性方面,主从存储节点的角色存在一些差异。 对于节点选择的主存储节点,需要根据主从一致性协议将数据推送到其他从节点。 一般采用存储节点划分主从的系统会选择强一致性协议,即主节点采用向从节点发送数据的方式。 收到成功的响应后,会将数据持久化到本地,并返回成功的响应给用户,使得用户读取到的数据始终一致。 当然,整个过程并没有那么简单,一致性协议部分稍后会进行扩展。

3. 报道新闻并遵循指示

存储节点需要与节点维护心跳信息,同时向节点报告自己当前的容量和资源使用情况。 从控制系统的角度来看,这形成了一个负反馈系统。

同时,存储节点处于备用状态,等待节点调度任务,如数据备份恢复、迁移等。

一般用作分布式文件系统的访问层,对于写操作,接受用户数据流并将数据写入存储节点; 对于读操作,它会从多个副本中随机选择一个副本进行读取。同时,为了提高系统的整体性能和可用性,系统一般会负责额外的功能

从性能角度来看,节点不会成为系统瓶颈。 毕竟现在的服务器处理能力已经非常高了。 无论是节点缓存的集群信息占用的内存,还是数万台机器的集群的调度,单机节点都是可以承受的。 说到这里,在做系统性能测试时,必须对分布式存储系统中管理节点的性能,即管理流程场景进行模拟和覆盖。 实验证明,这样的场景确实可以检测到很多性能问题。

那么对于一个有中心管理节点、数据节点分为主从的系统来说,性能瓶颈在哪里呢? 根据理论分析,假设单机存储系统参数或代码实现不当导致的性能问题已经排除和解决,即纵向性能优化基本符合预期。 在这样的系统中,对于小文件读写场景,磁盘和文件数量有限,如果数据不是很分散,主要的性能瓶颈在于集群中某些磁盘的吞吐能力,而在读取时大文件的写入,在写入场景中,系统的瓶颈是主节点出口网卡的流量。 以三个备份为例,主节点需要向两个从节点写入数据。 此时主节点的出口网卡流量是入口网卡流量的2倍。 如果出口和入口都是千兆网卡,则入口网卡的流量只能是满的。 网卡最大流量的一半。 因此,在设计时,将该单元作为备份的基本单元。 这样每个节点都有主从,每个节点的流量基本都能满。

我们先停止性能分析。 分布式存储系统的性能测试和优化非常重要,涉及到很多知识和内容。 当我们有机会时,我们将对此进行扩展。

从可用性的角度来看,如果不设计高可用,节点就是系统的单点。 消除系统单点的方法有很多种,在分布式系统中往往直接使用,以保证节点的高可用性。 所以其实中心控制节点的单点问题并没有那么严重。 相比之下,中央控制节点的调度策略更为重要,因为数据分布的平衡性直接影响系统对外服务的性能。

2、无中心管理节点,无主从存储节点

以Swift为例,从其基本架构可以看出,Swift采用完全对称且所有组件均可扩展的分布式系统架构设计。 该系统没有单点存在。 去掉Proxy层对象映射的逻辑,就可以看做是要讨论的分布式文件系统了。 从另一个角度来看,Proxy-也可以看作是分布式文件系统的客户端,只不过在实现上与对象存储在逻辑上是耦合的。 比较接近。

另外,对象存储逻辑层的认证服务和缓存服务被忽略,暂时不讨论。 - 和 - 和 - 的设计基本相同,因此仅讨论 - 。

以下是Swift的基本架构图,包括主要组件

Swift 的对象业务逻辑与底层分布式文件系统紧密耦合。 为了便于分离和理解,可以将Proxy-node视为分布式文件系统的一端。

抛开Proxy节点作为对象服务的功能,作为系统侧的非中心控制节点,它承担着两个更重要的角色。

1、备份一致性的保证

Swift使用了一个协议,我不会详细介绍这个协议。 该协议在一致性保证方面很灵活。 Swift 的默认选择是写入三个备份才算成功。 也可以通过配置参数选择写入2份后返回。 剩下的份数是——确保份数正确。 对于读取操作,Swift 默认读取任何备份数据并将其返回。 这种弱一致性模型很有可能读取到旧版本的数据,但它支持用户在读操作请求头中添加x-=true参数同时读取。 获取两个副本的元数据信息,然后比较时间戳确定哪个版本是最新的,并将最新数据返回给用户。

对于Swift选择的最终一致性模型的实现来说,单纯依靠数据流来保证备份一致是不可靠的,所以在其上会有一个流程来定期检查备份是否一致,这个会在后面讨论在 - 部分。

2、系统可靠性保证

对于无中心的分布式文件系统来说,系统可靠性的保证并不是单一节点的责任。 Proxy节点主要用于在处理用户数据流时保证用户请求能够成功处理。 但当用户发送对象上传请求时,Proxy节点发现存储节点出现故障。 应该如何处理呢?

Swift引入了节点,可以理解为备份节点。 其中,Swift的Ring对象的方法会返回一组节点。 如何在不先展开节点的情况下选择节点? 总体思路是尝试选择一个与故障节点不在同一逻辑域的逻辑域和物理域,然后开始重试。 重试次数由Proxy节点决定。 由配置文件参数决定,默认为备份次数的2倍。

Swift 由以下组件组成。

,即提供文件元数据和内容存储的独立存储引擎实现。 每个文件的内容作为文件存储在文件系统中,元数据作为文件属性存储。 每个文件都以生成的时间戳命名。

-,主要用于保证副本数量和位置的正确性和一致性。 在Swift的实际使用中,有几种场景会导致副本的数量和位置不正确。 这里先举一个简单的例子,后面讲数据恢复的时候再详细解释。 例如,当如上所述临时写入节点时,数据将根据环计算的信息移动到正确的位置。 再比如由于增加了磁盘或者机器导致环发生变化,然后Proxy节点配置写亲和性。 Proxy节点首先将数据写入某个分区,最后将数据跨分区复制到正确的位置。 在某些节点出现故障或者用户选择只写两个备份然后返回的场景下,副本会出现备份很少的情况,这也是需要做的。

-同时会保证副本的一致性,以/为基本单位(下子目录),根据每个文件的时间戳计算出的哈希值保存在该目录下的.pkl文件中,通过请求远程备份- 获取.pkl 并将其与本地值进行比较。 如果发现不一致,将通过推送更新远程副本。 使用远程文件复制工具rsync来同步数据。 rsync 采用 - 参数。 对于具有相同文件名的文件,复制将被忽略,从而避免进行完整复制。 这样,不同版本的数据文件就可以以相同的文件名存放在远程备份目录中。 this-在处理读操作时,会选择最新的数据返回。 从这个角度来说,-起到了保证副本一致性的作用。

-:主要用于检测复制数据是否正确。 当发现位级错误时,文件将被隔离,这样当远程检测到副本丢失时,正确的副本将被推送过来。

-:主要解决对象存储的元数据更新问题。 简单来说,文件创建成功后,对象名称将更新为-。 - 当由于负载过高而无法立即更新时,任务将保存在本地。 以便服务恢复后可以异步更新; 该服务主要负责系统恢复正常后更新扫描任务。

本文仅简单阐述了架构,Swift 的核心关键 Ring 的实现尚未展开。 Ring作为数据定位的关键实现,下面将详细讲解。

没有中心控制节点,所以Swift可靠性的保证落在各个节点上。 职责分工也如上所述。 这也需要每个节点都拥有整个集群的配置信息,即Ring文件才能工作。 。 因此,一旦Ring发生变化,需要同步到集群中的所有节点,否则系统将无法正常工作。 虽然对于Swift系统来说,只有管理员在进行添加、删除节点等运维操作时才会改变Ring结构,然后同步到各个节点,但往往在生产使用中,最好需要第三方监控过程。 比较每个节点的Ring文件的MD5,保证集群中所有节点的Ring文件始终一致。

从性能角度来看,对于没有中心管理节点、有主从数据节点服务的系统,还需要考虑集中式典型场景,分别考虑其性能瓶颈。 还需要假设单机存储系统参数或代码实现不当导致的性能问题已经消除,即纵向性能优化基本满足需求。

对于小文件读写场景,磁盘和文件数量有限,性能瓶颈也会限制集群中部分磁盘的吞吐量。 另外,如果不合并小文件,性能会进一步受到影响。 Swift 作为一个对象存储系统,存在的不仅仅是性能瓶颈和问题。 当我们有机会时,我们将进一步描述它们。

在大文件写入场景下,系统的瓶颈是Proxy节点的出口网卡流量。 以三个备份为例,Proxy节点默认需要写入三个备份才能成功返回。 Proxy节点出口网卡流量是入口网卡流量的3倍。 在相同机器硬件条件下,性能受到很大限制。 只能通过扩展网卡或者机器扩展的方法才能达到同样的性能。

从上面可以看出,分布式文件系统的架构很难适应所有场景。 如何选型和设计往往是根据需求,留有扩展空间,然后不断优化系统。