weed-fs 学习笔记

文件目录

当讨论文件系统的时候,人们通常任务它要有目录、列出目录下的文件等功能。

同时如果要把 weed-fs 和 linux、haddop等来绑定的话,也需要有这样子的功能。

简单用法

有两种方法启动 weed filer 服务:

# 在 master 服务和 volume 服务启动了之后
weed filer
# 该命令会一起启动 weed-fs 的 master、volume、filer 服务。
weed server -filer=true

现在你就可以添加、删除文件了,甚至可以获得子目录或者文件列表。

# 先上传一个文件
curl -F "filename=@README.md" "http://localhost:8888/path/to/sources/"
curl "http://localhost:8888/path/to/sources/README.md"
# 用一个新的名字上传文件
curl -F "filename=@Makefile" "http://localhost:8888/path/to/sources/new_name"
curl "http://localhost:8888/path/to/sources/new_name"
# 列出文件列表
curl "http://localhost:8888/path/to/sources/?pretty=y"
# 如果文件列表太多,可以过滤
curl "http://localhost:8888/path/to/sources/?lastFileName=abc.txt&limit=50&pretty=y"

设计

一般的文件系统都会通过 inode 来保存文件或者目录的元数据。文件目录通常就像是树的结构。那么整个件系统的结构通常就会组织成一个类似 b+tree 的结构。这样子在保存文件的时候会很灵活,但是访问文件的时候,就会变得很慢,因为这样子在读取文件内容之前,需要多次的io读写。

weed-fs 希望尽可能低减少对硬盘的读取,而且还要保存大量的文件元数据,所以我们需要换个思考的角度。

从一个完整的文件路径获取文件内容,需要下面几个不走:

父目录 => 目录 id
目录 id + 文件名 => 文件 id
文件 id => 文件内容

因为默认的 weed-fs 系统只提供文件id => 文件内容 的匹配。所以,第一二步需要我们来实现。

文件系统通常有下面几个特征:

  • 目录的数量,通常很小
  • 文件的数量固定

所以,把目录和文件的元数据分开保存,也许是最快的方式。

weed filer 服务提供了实现通用文件接口的剩下两个特征:父目录到目录 id 及目录 id + 文件 id 的匹配。

架设

基于前面的分析,有下面的架设:

  • 目录的数量通常很小而且文件的数量通常大很多
  • 在一个目录下面的文件数量可以很大
  • 目录的元数据会被经常访问

数据结构

目录和文件之间的区别,也导致了他们的元数据的数据结构应该不一样。

  • 在内存中保存目录数据
    • 希望在内存中保存所有的目录数据
    • 可以有效地移动、重命名、列出文件列表
  • 保存文件元数据在一个 目录 id / 文件名,文件 id 格式的并且排好序的表中
    • 可以有效的列出文件列表
    • 可以高效地定位文件,基于二分查找

复杂度

对于一个文件检索,如果一个父目录包含 n 个子目录,那么就需要 n 步从父目录找到指定目录。但是这里的 n 步都是在内存里面执行的,事实证明,它会执行得很快。

对于一个文件检索,目录 id + 文件名 => 文件 id 的检索,通过 LevelDB 来时间,复杂度和 B-Tree 一样。

对于一个列出目录下面的文件操作,对于 levelDB 来说只是简单的扫描,因为这些记录在 levelDB 里面就已经是排好序的。但是,对于 b-tree 来说,可能需要对硬盘的多次查找。

对于一个修改目录名的操作,只需要修改目录名或者修改父目录名,因为文件 id 依然是一样的,目录的元数据没有修改。

对于修改文件名操作,需要在 LevelDB 里面删除并且添加一条记录。

细节

在当前版本中,目录 id + 文件名 => 文件 id 匹配在一个嵌入的 leveldb 中保存。因为是嵌入的,所以他们跑在同一台机器上面。所以,他不是线性扩展的。然而,它已经可以处理大量的文件了。当然,也可以使用其他分布式数据库来实现。

保存在内存中的目录结构,可以提高内存的效率。通常来说,简单的内存字典在目录数少于100万的时候,运行的良好。100目录的时候,用了差不多500MB的内存。

用例

用户可以通过 HTTP 接口来访问 weed filer 服务。

虽然一个 weed filer 服务只能运行在一台机器上面,你可以在不同的机器上面启动不同的 weed filer 服务。每一个 weed filer 服务代表其对应的 collection,有不同的命名空间,但是共同服务于同一个 weed-fs 集群。

计划

在将来的版本,父目录 => 目录 id 和 目录 id + 文件名 => 文件 id 匹配,会被重构为支持不同的存储系统。

目录元数据可能会改成用其他内存数据库来保存。

LevelDB 可能会改成其他外部数据存储。例如:Mysql、TokyoCabinet等。优先考虑纯 go 实现。

添加高可用方案,不同的 weed filer 服务可以分享一样的文件元数据。

创建 FUSE 或者 HCFS 插件,整合其他已经存在的系统。

links