Seaweedfs是一个简单,高扩展性的分布式文件系统,它的两个目标分别是:
存储数十亿级的文件
快速响应文件。
seaweedfs选择以键值对(key->file)的实现方式,这有点像“NoSQL",你可以陈其为”NoFS“。
seaweedfs的中心节点(center master)并不会管理所有文件的元数据而仅仅管理文件卷(file volmume),文件及其元数据的管理是由volume server实现的。这可以缓解center master的并发压力,并且将文件元数据分配到volume server可以实现更快的文件访问(只需一次磁盘读取操作)。
通常,分布式文件系统将每个文件拆分为块,中央主服务器保持文件名,到块句柄的块索引以及每个块服务器具有的块。
主要缺点是中央主服务器无法高效地处理许多小文件,并且由于所有读请求都需要通过块主服务器,所以对于许多并发用户来说可能无法很好地扩展。
SeaweedFS管理主服务器中的数据卷,而不是管理块。每个数据卷大小为32GB,并且可以容纳大量文件。每个存储节点可以有很多数据卷。所以主节点只需要存储关于卷的元数据,这是相当少量的数据,并且通常是稳定的。
实际的文件元数据存储在卷服务器上的每个卷中。由于每个卷服务器只管理自己磁盘上的文件的元数据,每个文件的元数据只有16个字节,因此所有文件访问都可以从内存中读取文件元数据,只需要一次磁盘操作即可实际读取文件数据。
该架构非常简单。实际数据存储在存储节点的卷上。一个卷服务器可以有多个卷,并且都可以支持基本认证的读写访问。
所有卷由主服务器管理。主服务器包含卷ID到卷服务器映射。这是相当静态的信息,可以轻松缓存。
在每个写入请求上,主服务器还会生成一个file key,这是一个不断增长的64位无符号整数。由于写入请求通常不如读取请求频繁,因此一台主服务器应该能够很好地处理并发
当客户端发送写入请求时,主服务器为该文件返回(volume id, file key, file cookie, volume node url)。客户端然后联系卷节点并发送文件的内容。
当客户端需要根据(volume id, file key, file cookie)读取文件时,它可以通过卷标id询问主服务器(volume node url, volume node public url),或从缓存中检索。然后客户端可以获取内容,或者只是在网页上呈现URL并让浏览器获取内容。
在当前的实现中,每个卷可以是8x2 ^ 32个字节(32GiB)。这是因为将内容对齐到8个字节。通过更改2行代码,可以轻松地将其增加到64G或128G,或者更多,代价是由于对齐而导致的一些浪费的填充空间。
可以有2 ^ 32卷。因此总系统大小为8 x 2 ^ 32字节x 2 ^ 32 = 8 x 4GiB x 4Gi = 128EiB(2 ^ 67字节或128 exbibytes)。
每个单独的文件大小都受限于卷大小。
默认最大7个,你可以设置100等等。。。
可以选择是否使用数据副本,以及副本的级别
master servers失败自动漂移-杜绝但点故障
根据文件的mime类型自动进行gzip压缩(linux查看文件的mime类型,file --mime-type)
删除及更新操作之后通过压缩实现自动的磁盘空间回收
集群中的服务器之间可以存在不同的磁盘空间,文件系统,操作系统
添加/删除服务不会导致数据的重新平衡
可选择修复jpeg图片的方向
https://github.com/chrislusf/seaweedfs
master 存储映射关系,文件和fid的映射关系 weed master
Node 系统抽象的结点,抽象为datacenter、rack、datanode
datacenter 数据中心,包含多个rack,类似一个机房
rack :属于一个datacenter,类似机房中的一个机架
datanode : 存储节点,存储多个volume,类似机架中的一个机器 weed volume
volume :逻辑卷,存储needle
needle: 逻辑卷中的object,对应存储的文件
collection:文件集,默认所有文件都属于""文件集。如果想给某些文件单独分类,可以在申请id的时候指定相同的文件集
filer :指向一个或多个master的file服务器,多个使用逗号隔开。 weed filer
weed volume会创建一个 datanode ,可以指定所属的 datacenter rack和master ,会根据配置存储文件,默认一开始没有volume,当开始存储文件的时候才会创建一个volume,当这一个volume大小超过了volumeSizeLimitMB 就会新增一个volume,当volume个数超过了max则该datanode就不能新增数据了。那就需要在通过weed volume命令新增一个datanode。
默认000 不备份
defaultReplication
000 不备份, 只有一份数据
001 在相同的rackj里备份一份数据
010 在相同数据中心内不同的rack间备份一份数据
100 在不同的数据中心备份一份数据
200 在两个不同的数据中心各复制2次
110 在不同的rack备份一份数据, 在不同的数据中心备份一次
如果数据备份类型是 xyz形式
各自的意义
x 在别的数据中心备份的份数
y 不相同数据中心不同的racks备份的份数
z 在别的服务器相同的rack的备份份数
因为是研究测试使用,就粗糙一点,都是在一台机器上完成
计划: 一个master(master只能为奇数个【好像master是以ip来做确定个数的,我做实验时,使用不同的端口启动三个master,在申请卷信息的时候报错,所以这里改成一个】)三个volume 一个filter
mkdir -p /usr/local/weedfs/
cd /usr/localweedfs/
从官网的release仓库选择一个版本下载下来,这里选择的是1.70版本
上传到/usr/local/weedfs目录
解压:
tar -xzvf linux_amd64.tar.gz
得到一个weed可执行文件,weedfs的master 和volume的可执行文件都是它。
创建数据卷根目录以及各个数据卷目录、master数据目录和filter目录
mkdir -p /data/weedfs_data
mkdir -p /data/weedfs_data/vola
mkdir -p /data/weedfs_data/volb
mkdir -p /data/weedfs_data/volc
mkdir -p /data/weedfs_data/master
mkdir -p /data/weedfs_data/filter
# nohup /usr/local/weedfs/weed -v=3 master -mdir=/data/weedfs_data/master -peers=localhost:9333,localhost:9334,localhost:9335 -defaultReplication="001" >> /data/weedfs_data/master/wdfsmaster.log & ##同个ip指定使用三个端口启动的master,在后面使用中会报错。
nohup /usr/local/weedfs/weed -v=3 master -mdir=/data/weedfs_data/master -defaultReplication="001" >> /data/weedfs_data/master/wdfsmaster.log &
nohup /usr/local/weedfs/weed -v=3 volume -port=8081 -dir=/data/weedfs_data/vola -mserver=localhost:9333 -rack=rack1 >> /data/weedfs_data/vola/wefsvola.log &
nohup /usr/local/weedfs/weed -v=3 volume -port=8082 -dir=/data/weedfs_data/volb -mserver=localhost:9333 -rack=rack2 >> /data/weedfs_data/volb/wefsvolb.log &
nohup /usr/local/weedfs/weed -v=3 volume -port=8083 -dir=/data/weedfs_data/volc -mserver=localhost:9333 -rack=rack3 >> /data/weedfs_data/volc/wefsvolc.log &
此时volume下面还没有任何数据,volume server会在第一次写入数据时建立相应的.idx文件和.dat文件。
先生成一个配置文件,如下图
/usr/local/weedfs/weed scaffold -config=filer -output=.
修改filer.toml,把filer的数据目录指向导/data/weedfs_data/filer/leveldb2下
mkdir -p /data/weedfs_data/filer/leveldb2
nohup /usr/local/weedfs/weed -v=3 filer -port=8888 -master=localhost:9333 >> /data/weedfs_data/filer/filer.log &
为了方便本地操作,把一个collection里面的内容挂载导某个目录,方便操作
mkdir -p /data/weedfs_data/filermount/data
nohup /usr/local/weedfs/weed mount -filer=localhost:8888 -dir=/data/weedfs_data/filermount/data -filer.path=/ >> /data/weedfs_data/filermount/wefsmount.log &
要上传文件:首先,向/ dir / assign发送HTTP POST,PUT或GET请求以获取fid和卷服务器url【理解:master负责管理卷,并生成要上传文件的fid,并给指定需要上传文件的卷服务器,所以我们在上传文件之前,需要向master请求获得这些信息,然后根据这些信息直接往指定的volume里面上传文件】
SeaweedFS在卷级应用复制策略。因此,当您获得文件id时,您可以指定复制策略。例如
curl http://localhost:9333/dir/assign?replication=001
当申请卷信息时,报如下错误。这是因为我们使用的replication模式是 001,即对于一个needle来说,会在同一个机架下的两个volume中保存相同的文件。由于上面我们创建的3个volume都分别指定了不同的机架,所以本教程目前的拓扑(逻辑)结构就是: 只有一个数据中心(默认的数据中心),包含有三个机架 rack1,2,3。每个机架下各只有一个节点(datanode --默认的节点,相当于一台机器,即localhost),然后这个datanode下面又有一个volume server(创建的,比如8081)然后这个volume又会创建默认
拓扑结构如下
按上面的添加volume的方式再添加一个vold
mkdir -p /data/weedfs_data/vold
nohup /usr/local/weedfs/weed -v=3 volume -port=8084 -dir=/data/weedfs_data/vold -mserver=localhost:9333 -rack=rack1 >> /data/weedfs_data/vold/wefsvold.log &
并重新申请就能返回如下结果
这个时候看一个各个volume下的情况,如下图
因为vola和vold同属于一个机架rack1 而replication策略又是001,所以vola和vold都有数据,并且数据是相同的两份。
同样的操作也rack2和3也创建相应的volume
mkdir -p /data/weedfs_data/vole
nohup /usr/local/weedfs/weed -v=3 volume -port=8085 -dir=/data/weedfs_data/vole -mserver=localhost:9333 -rack=rack2 >> /data/weedfs_data/vole/wefsvole.log &
mkdir -p /data/weedfs_data/volf
nohup /usr/local/weedfs/weed -v=3 volume -port=8086 -dir=/data/weedfs_data/volf -mserver=localhost:9333 -rack=rack3 >> /data/weedfs_data/volf/wefsvolf.log &
上传文件
上传文件之前
上传完以后,再测试了一下下载。
比较上传前后卷空间大小变化,可以发现,卷空间增加的大小正好等于上传文件的大小
删除文件:
因为weedfs对删除文件,磁盘空间释放需要额外的操作,这里做一下测试,验证一下
调用删除api 删除刚刚上传的jenkins.war
curl -X DELETE 127.0.0.1:8081/2,1111abd523
果然如官方所说,删除完以后,并不会释放磁盘空间
使用下面的api查看卷状态信息,可以看到,id为2的卷文件数目是1,因为我删除了id为2的卷上面的文件,所以下面id为2的卷信息显示"DeleteCount": 1。 (有个疑问是,replication为001的模式,为啥没有看到其他卷上面有删除记录)
[root@localhost weedfs_data]# curl "http://localhost:8081/status?pretty=y"
{
"DiskStatuses": [
{
"dir": "/data/weedfs_data/vola",
"all": 18238930944,
"used": 12890963968,
"free": 5347966976,
"percent_free": 29.321712,
"percent_used": 70.67828
}
],
"Version": "30GB 1.70",
"Volumes": [
{
"Id": 1,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 2,
"Size": 66207889,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 1,
"DeleteCount": 1,
"DeletedByteCount": 66207889,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 3,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 4,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 5,
"Size": 127262,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 1,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 6,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
}
]
}[root@localhost weedfs_data]#
既然空间没有释放出来,那么我们就按官网的说明,手动释放一下。
发现磁盘空间果然被释放了。这个时候再查看一个卷信息
[root@localhost weedfs_data]# curl "http://localhost:8081/status?pretty=y"
{
"DiskStatuses": [
{
"dir": "/data/weedfs_data/vola",
"all": 18238930944,
"used": 12758888448,
"free": 5480042496,
"percent_free": 30.045855,
"percent_used": 69.95415
}
],
"Version": "30GB 1.70",
"Volumes": [
{
"Id": 1,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 2,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 1,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 3,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 4,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 5,
"Size": 127262,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 1,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
},
{
"Id": 6,
"Size": 0,
"ReplicaPlacement": {
"SameRackCount": 1,
"DiffRackCount": 0,
"DiffDataCenterCount": 0
},
"Ttl": {
"Count": 0,
"Unit": 0
},
"Collection": "",
"Version": 3,
"FileCount": 0,
"DeleteCount": 0,
"DeletedByteCount": 0,
"ReadOnly": false,
"CompactRevision": 0,
"ModifiedAtSecond": 0,
"RemoteStorageName": "",
"RemoteStorageKey": ""
}
]
}[root@localhost weedfs_data]#
发现id为2的卷下的DeleteCount也变成了0了,验证了官网所说。
weedfs的使用
master
申请volume信息:curl http://localhost:9333/dir/assign?replication=001 ###文件上传首先需要请求master, 去分配一个逻辑卷和fid
查看集群信息:http://$IP:9333/cluster/status?pretty=y
查看某个卷的上传信息:http://localhost:9333/dir/lookup?volumeId=3
上传文件:curl -F file=@/home/chris/myphoto.jpg http://127.0.0.1:8080/3,01637037d6
请求一个上传了的文件: http://localhost:8080/3,01637037d6.jpg
删除文件:curl -X DELETE http://127.0.0.1:8080/3,01637037d6
查看集群toplogy结构: curl “http://localhost:9333/dir/status?pretty=y”
上传一个目录:curl -F file=@/home/chris/myphoto.jpg http://localhost:9333/submit
强制垃圾回收:curl “http://localhost:9333/vol/vacuum” curl “http://localhost:9333/vol/vacuum?garbageThreshold=0.4”
给某个collection指定volume的数量:curl “http://localhost:9333/vol/grow?collection=staff&count=1”
volume
查看volume中某个大文件被分块的清单:curl http://127.0.0.1:8080/3,01637037d6?cm=false
查看卷信息:curl “http://localhost:8080/status?pretty=y” ##可以看到删除了多少文件,以及删除的大小。这个对调试还有多少空间没有释放很有帮助
下面是使用filer的一些api
# POST a file and read it back
curl -F "[email protected]" "http://localhost:8888/path/to/sources/"
curl "http://localhost:8888/path/to/sources/README.md"
# POST a file with a new name and read it back
curl -F "filename=@Makefile" "http://localhost:8888/path/to/sources/new_name"
curl "http://localhost:8888/path/to/sources/new_name"
# list sub folders and files, use browser to visit this url: "http://localhost:8888/path/to/"
# To list the results in JSON:
curl -H "Accept: application/json" "http://localhost:8888/path/to"
# To list the results in pretty JSON
curl -H "Accept: application/json" "http://localhost:8888/path/to?pretty=y"
# The directory list limit is default to 100
# if lots of files under this folder, here is a way to efficiently paginate through all of them
http://localhost:8888/path/to/sources/?lastFileName=abc.txt&limit=50