做一个免费的共享网盘,用户登录之后可以像使用本地磁盘一样管理自己的在线的文件。
该系统需要可以使用成本低廉的服务器集群水平扩展,当应用请求较多、或磁盘空间不足时,可以启用新的节点;
当其中一个节点故障(网络中断、节点关闭、节点崩溃……)不会对系统产生影响。
系统可以动态调整用户配额,用户可以分享自己的文件。
这套系统需要有基于角色的用户权限管理系统,分布式文件索引系统,开放的应用接口和分布式文件存储。
本系统参考Json Web Token使用自定义的简单网站令牌Simple Web Token. Simple Web Token的生成可以由独立系统完成。本系统只根据Simple Web Token协议来验证Token的有效性和用户角色。
文件索引是文件名(包含路径)到 File ID 的映射,是一个典型的 Key-Value 数据库。它至少需要支持以下方法:
除此以外,文件的Metadata还需要包含修改日期、大小等,方便List时快速获取到这些信息。文件索引是本系统中的最重要的部分,如果索引丢失,用户无法从API或UI上查询到任何关于File ID的信息,即使此时文件仍然存在,也会和消失没有什么区别。
前期为快速实现,使用Redis存储文件路径对应的File Id,修改日期,大小和其它Meta Data,同时保存目录结构信息。使用Redis Sentinel作为高可用文件索引的方案。Sentinel 帮助我们完成Master选举和切换功能,我们还需要使用twemproxy代理来将Redis连接分发到正确的Master上。
如何保存目录结构?给定一个Path,首先通过分解为几段再合并来格式化路径,然后判断文件是否存在,如果文件不存在,使用Set存储目录信息,包含目录名和文件名。然后创建文件。
以后会使用基本版本统一分布式一致性算法,完成高可用文件集群。
文件存储负责存储文件对象,并至少在不同的节点上保留一个备份。只要有一个备份可用,就能通过API获得文件。它至少需要支持以下方法:
选用较为轻量级、但性能占优的 SeaweedFS 作为存储后端。后面会优化该系统,使其支持大数据和多版本。
为了更好地管理网络文件,我们需要集成以后的功能完成一个统一的开放接口,包括友好的用户界面。需要编写代码,实现以下功能:
以存储一个文件 /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 来管理各个服务和节点,配合相关工具,很容易在云上部署。
