分布式文件管理平台

需求

做一个免费的共享网盘,用户登录之后可以像使用本地磁盘一样管理自己的在线的文件。

该系统需要可以使用成本低廉的服务器集群水平扩展,当应用请求较多、或磁盘空间不足时,可以启用新的节点;

当其中一个节点故障(网络中断、节点关闭、节点崩溃……)不会对系统产生影响。

系统可以动态调整用户配额,用户可以分享自己的文件。

系统分析与设计

这套系统需要有基于角色的用户权限管理系统,分布式文件索引系统,开放的应用接口和分布式文件存储。

基于角色的用户权限管理

本系统参考Json Web Token使用自定义的简单网站令牌Simple Web Token. Simple Web Token的生成可以由独立系统完成。本系统只根据Simple Web Token协议来验证Token的有效性和用户角色。

文件索引系统(File Store)

文件索引是文件名(包含路径)到 File ID 的映射,是一个典型的 Key-Value 数据库。它至少需要支持以下方法:

  1. Get 文件
  2. Put 新增或更新一个文件。
  3. Delete 删除一个文件。
  4. List 罗列出路径下的所有文件或文件夹。

除此以外,文件的Metadata还需要包含修改日期、大小等,方便List时快速获取到这些信息。文件索引是本系统中的最重要的部分,如果索引丢失,用户无法从API或UI上查询到任何关于File ID的信息,即使此时文件仍然存在,也会和消失没有什么区别。

技术实现

前期为快速实现,使用Redis存储文件路径对应的File Id,修改日期,大小和其它Meta Data,同时保存目录结构信息。使用Redis Sentinel作为高可用文件索引的方案。Sentinel 帮助我们完成Master选举和切换功能,我们还需要使用twemproxy代理来将Redis连接分发到正确的Master上。

如何保存目录结构?给定一个Path,首先通过分解为几段再合并来格式化路径,然后判断文件是否存在,如果文件不存在,使用Set存储目录信息,包含目录名和文件名。然后创建文件。

以后会使用基本版本统一分布式一致性算法,完成高可用文件集群。

文件对象存储(Data Store)

文件存储负责存储文件对象,并至少在不同的节点上保留一个备份。只要有一个备份可用,就能通过API获得文件。它至少需要支持以下方法:

  1. Post 新增或更新一个文件,并返回 File ID
  2. Delete 根据 File ID 移除一个文件

技术实现

选用较为轻量级、但性能占优的 SeaweedFS 作为存储后端。后面会优化该系统,使其支持大数据和多版本。

文件系统开放接口

为了更好地管理网络文件,我们需要集成以后的功能完成一个统一的开放接口,包括友好的用户界面。需要编写代码,实现以下功能:

  1. 用户权限验证 是否有访问权限 是否可以写入数据(配额判断)
  2. 文件操作 CreateFile 创建文件 DeleteFile 删除文件 CreateDirectory 创建目录 DeleteDirectory 删除目录 ListDirectories 列出某个目录下的目录和文件
  3. 扩展操作 复制,移动,重命名等操作 分享文件或文件夹
  4. 用户界面 自适应的操作界面,可以完成以上所有操作

用例

以存储一个文件 /foo/bar.txt 为例,需要经过以下步骤: 检查目录 /foo 是否存在;如果不存在,需要创建目录,并把新目录加入 / 的目录树中。 检查文件 /foo/bar.txt 是否存在;如果存在,则先从 Data Store 中删除文件。 上传文件 bar.txt 到 Data Store,得到 File ID。 存储条目 /foo/bar.txt 到 File Store,并加入到 /foo/ 的目录树中。 对于文件的索引,很自然的,将/foo/bar.txt 映射到 File ID

使用前缀查询是无法满足多级目录树的需求的。我们在 Redis 中创建如下的条目以储存目录结构,来满足 ListFiles 和 ListDirectories 的需求: 使用Redis Set存储目录中的内容,使用Redis String 存储文件的FileID 备注:第一个版本为了简单不记录文件或文件夹的MataData。

完整架构

以下是分布式文件系统项目的整体架构。系统使用 Docker + Kubernetes 来管理各个服务和节点,配合相关工具,很容易在云上部署。