一. 概括
SeaweedFS(SeaWeed File System)是一个开源的分布式文件系统,旨在为大规模数据存储提供简单、高效、可扩展的解决方案。以下是一些关键特点和概念:
- 分布式架构: SeaweedFS被设计成一个分布式系统,可以横向扩展以满足大规模数据存储的需求。它可以在多台服务器之间分配数据,提高系统的性能和容量。
- 轻量级和简单: SeaweedFS的设计目标之一是简单易用。它采用了轻量级的设计原则,使得部署和管理变得相对简单。
- 容错性: SeaweedFS具有容错机制,能够处理节点故障或数据丢失的情况。它可以在数据丢失的情况下保持可用性,并提供数据冗余和复制。
- 支持多种存储后端: SeaweedFS支持多种存储后端,包括本地磁盘、S3、Hadoop HDFS等。这使得它能够适应不同的存储需求。
- 文件分配: SeaweedFS使用一种称为“Volumne Server”的组件来动态分配文件和目录。这使得它能够有效地管理存储空间,并确保负载平衡。
- Filer: SeaweedFS提供了一个称为Filer的元数据服务器,用于查询文件的元数据信息。这有助于高效的文件查找和检索。
- 支持HTTP和FUSE接口: SeaweedFS可以通过HTTP和FUSE(Filesystem in Userspace)接口访问。这使得它可以方便地与各种应用程序和工具集成。
二. 模块功能
1.Master Server功能职责
管理卷服务器:Master Server 负责管理所有的卷服务器(Volume Server)。
-
注册和注销:当一个卷服务器启动时,它会向 Master Server 发送注册请求,Master Server 在接收到请求后,会将这个卷服务器添加到它的服务器列表中。同样,当一个卷服务器关闭时,它会向 Master Server 发送注销请求,Master Server 在接收到请求后,会将这个卷服务器从它的服务器列表中移除。这个过程在 weed/server/master_grpc_server.go 文件中的 ServerHeartbeat 函数中实现。
-
心跳检测:卷服务器会定期向 Master Server 发送心跳消息,报告它的状态,包括当前的负载、存储空间的使用情况等。Master Server 在接收到心跳消息后,会更新卷服务器的状态信息。这个过程在 weed/server/master_grpc_server.go 文件中的 ServerHeartbeat 函数中实现。
-
卷管理:Master Server 负责管理所有的卷,包括卷的创建、删除、迁移等。当需要创建一个新的卷时,Master Server 会根据当前的负载情况,选择一个卷服务器,并向它发送创建卷的请求。这个过程在 weed/server/master_grpc_server_volume.go 文件中的 ProcessGrowRequest 函数中实现。
管理卷元数据:Master Server 负责管理所有的卷(Volume)的元数据,包括卷的 ID、大小、副本策略、TTL 策略等。对外提供接口"/dir/assign"来分配一个Volume对象(目录和卷)
- 首先获取到请求的复制策略和卷的数量
- 然后调用t.GetVolumeLayout(xxx).PickForWrite(count, option)函数遍历所有的卷服务器,计算每个卷服务器的权重,然后根据权重来选择卷服务器。权重的计算考虑了卷服务器的可用空间、负载、数据中心等因素。
- 挑选使用了Reservoir Sampling算法的一种变体,用于随机选择一个元素,使得每个元素被选中的概率相同,同时不需要存储所有元素的列表。这对于大型数据集的随机抽样非常有用。
var vid needle.VolumeId
var locationList *VolumeLocationList
counter := 0
for _, v := range vl.writables {
volumeLocationList := vl.vid2location[v]
for _, dn := range volumeLocationList.list {
if option.DataCenter != "" && dn.GetDataCenter().Id() != NodeId(option.DataCenter) {
continue
}
if option.Rack != "" && dn.GetRack().Id() != NodeId(option.Rack) {
continue
}
if option.DataNode != "" && dn.Id() != NodeId(option.DataNode) {
continue
}
counter++
if rand.Intn(counter) < 1 {
vid, locationList = v, volumeLocationList.Copy()
}
}
}
return &vid, count, locationList, nil
- 最后分配一个卷服务器。
卷分配和负载均衡:Master Server 负责根据当前的负载情况,决定在哪个卷服务器上创建新的卷,以实现负载均衡。主要依赖于 ProcessGrowRequest 函数。
- 在 ProcessGrowRequest 函数中,master server 会首先检查是否是领导者,只有领导者才会处理增长请求。
- 然后,它会检查是否有相同的请求正在处理,如果有,就会丢弃这个请求。
- 如果没有,它会调用 ShouldGrowVolumes 函数来判断是否应该在当前卷服务器上创建新的卷。
- ShouldGrowVolumes 函数会根据卷服务器的负载情况,包括卷服务器的空闲空间、卷的数量等因素,来决定是否应该在这个卷服务器上创建新的卷。
- 如果 ShouldGrowVolumes 函数返回 true,那么 master server 就会在这个卷服务器上创建新的卷,从而实现负载均衡。
提供 HTTP 和 gRPC 接口:Master Server 提供了一系列的 HTTP 和 gRPC 接口,供客户端和卷服务器进行通信。这些接口的实现可以在 weed/server/master_server.go 文件中找到。
[Master Server API] github.com/seaweedfs/s…
2.Filer Server功能职责
-
文件系统接口:Filer Server 提供了类似于文件系统的接口,允许用户通过路径名来访问和管理文件。这使得用户可以像操作本地文件系统一样操作 SeaweedFS。
-
元数据管理:Filer Server 负责管理文件的元数据,包括文件名、路径、大小、创建时间等。这些元数据存储在 Filer Server 的元数据数据库中。
-
代理请求:当用户通过 Filer Server 访问文件时,Filer Server 会根据文件的元数据,将请求代理到相应的 Volume Server。这个功能的实现可以在 weed/server/filer_server_handlers_proxy.go 文件中的 proxyToVolumeServer 函数中找到。
-
目录和文件操作:Filer Server 提供了一系列的接口,支持创建、删除、重命名目录和文件,以及读写文件内容。
[Filer Server API] github.com/seaweedfs/s…
3.Volume Server功能职责
-
存储数据:Volume Server 是 SeaweedFS 中的数据节点,它负责存储和管理数据卷(Volume),每个数据卷包含了多个文件的数据和元数据。
-
处理读写请求:Volume Server 提供了读写接口,客户端可以通过这些接口向 Volume Server 读写数据。这些接口的实现可以在 weed/server/volume_server.go 文件中找到。
-
数据迁移:Volume Server 支持将数据卷迁移到远程存储,如 S3、Azure Blob Storage 等。这个功能的实现可以在 weed/server/volume_grpc_tier_upload.go 和 weed/server/volume_grpc_tier_download.go 文件中找到。
-
与 Master Server 通信:Volume Server 会定期向 Master Server 发送心跳信息,报告其状态,并接收来自 Master Server 的指令,如创建新的数据卷、删除数据卷等。这个功能的实现可以在 weed/server/volume_grpc_client_to_master.go 文件中找到。
-
管理数据卷状态:Volume Server 可以将数据卷设置为只读或可写状态,这个功能的实现可以在 weed/server/master_grpc_server_volume.go 文件中的 VolumeMarkReadonly 函数中找到。
[Volume Server API] github.com/seaweedfs/s…
4.客户端功能职责
4.1 mount
-
1. 解析命令行参数:首先,程序会解析命令行参数,获取挂载点(-dir 参数)和 Filer Server 的地址(-filer 参数)。这个过程在 weed/command/mount.go 文件的 mountOptions 结构体中进行。
-
2. 创建 FUSE 客户端:然后,程序会创建一个 FUSE 客户端,用于与 FUSE 内核模块进行通信。这个过程在 weed/filer/mount/mount.go 文件的 Mount 函数中进行。
-
3. 挂载文件系统:接着,程序会调用 FUSE 库的 fuse.Mount 函数,将 SeaweedFS 挂载到指定的挂载点。这个过程在 weed/filer/mount/mount.go 文件的 Mount 函数中进行。
-
4. 启动 FUSE 服务:最后,程序会启动 FUSE 服务,处理来自 FUSE 内核模块的请求。这个过程在 weed/filer/mount/mount.go 文件的 Mount 函数中进行。
// weed/command/mount.go
type mountOptions struct {
filerOptions weed_server.FilerOptions
dir *string
collection *string
replication *string
ttl *string
chunkSizeLimitMB *int
dataCenter *string
allowOthers *bool
umask *string
nonempty *bool
}
// weed/filer/mount/mount.go
func Mount(dir string, collection string, replication string, ttlSec int32, chunkSizeLimitMB int, dataCenter string, filerOptions weed_server.FilerOptions) error {
// ...
fuse.Unmount(dir)
c, err := fuse.Mount(
dir,
fuse.FSName("seaweedfs"),
fuse.Subtype("seaweedfs"),
fuse.VolumeName("seaweedfs"),
fuse.AllowOther(),
)
// ...
go func() {
err = fs.Serve(c, wfs)
// ...
}()
// ...
}
[Client Libraries] github.com/seaweedfs/s…
三. 数据结构
层级结构 nodeType
1. DataNode:数据节点,代表一个存储数据的节点,它包含多个卷(Volume),每个卷存储了多个文件。
2. Rack:机架,代表一个物理的机架,它包含多个数据节点。在 SeaweedFS 的副本策略中,会尽量让副本分布在不同的机架上,以提高数据的可靠性。
3. DataCenter:数据中心,代表一个物理的数据中心,它包含多个机架。在 SeaweedFS 的副本策略中,也会尽量让副本分布在不同的数据中心上,以提高数据的可靠性。
4. Topology:拓扑,代表整个文件系统的拓扑结构,它包含多个数据中心。
四. 文件上传下载流程
上传文件流程:
-
发送上传请求:客户端向 Filer 发送上传请求,这个请求通常包括文件名、文件属性等信息。
-
文件信息保存:Filer Server接收客户端的上传请求,并开始处理请求。它生成一个文件ID(File ID),用于唯一标识上传的文件。同时,Filer Server记录文件的元数据,包括文件属性和路径。
-
请求master:Filer 向 Master 查询文件分配信息,这部分在 weed/filer/submit_file.go 文件的 SubmitToMasterServer 函数中实现。
-
返回文件位置:Filer 返回 Volume Server 地址给客户端,这部分在 weed/filer/submit_file.go 文件的 doAssign 函数中实现。
-
上传文件内容:客户端直接向 Volume Server 上传文件内容,这部分通常在客户端的代码中实现,不在 SeaweedFS 的源代码中。
-
更新信息:Filer 更新元数据信息,这部分在 weed/filer/submit_file.go 文件的 doUpload 函数中实现。
读取文件的流程 :
1. 发送读取请求:客户端首先向 Filer 发送读取请求,请求中包含要读取的文件名。
2. 查询文件位置:Filer 在收到读取请求后,会查询文件的元数据,获取文件在 Volume Server 上的位置信息。这部分在 weed/filer/filer_server_handlers_read.go 文件的 doLoad 函数中实现。
3. 返回文件位置:Filer 将查询到的文件位置信息返回给客户端。这部分在 weed/filer/filer_server_handlers_read.go 文件的 doLoad 函数中实现。
4. 读取文件内容:客户端根据返回的位置信息,直接向相应的 Volume Server 发送读取请求,获取文件内容。