Skip to content

mumu-architect/QFS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

59 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QFS分布式存储系统

  • Website: https://github.com/mumu-architect/QFS
  • Chat: Gitter
  • QFS 是一个开源的高性能分布式文件系统。 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡。主要解决了海量数据存储问题,特别适合以中小文件(建议范围:1MB < file_size <500MB)为载体的在线服务。

QFS主要功能

1.高可用,每个小集群都是1主2从,leader挂自动选新的leader

2.安全,文件分别存在3台节点上,数据不会丢失,主从文件同步,数据落盘

3.大量数据或文件存储,使用槽位分片技术把文件存到不同的小集群中,可以存储大量数据

4.上传客户端使用qfsSDK进行文件上传

5.扩容还没开发,缩容计划不会开发

6.系统安全性还待开发,系统扩展性待优化,系统性能待优化

7.集群启动方法,后期会优化

	// go run main.go --shardID 128 --id 1 --shardIDS "128,129" --ip 127.0.0.1 --port 9001 --peers "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003" --nodeInfo "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003,4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --rpcPort 6061 --rpcPeers "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063" --rpcNodeInfo "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063,4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --raftPort 19001  --raftPeers "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003" --raftNodeInfo "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003,4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --logPort 8081 --logPeers "1=127.0.0.1:8081,2=127.0.0.1:8082,3=127.0.0.1:8083" --filePort 7071 --filePeers "1=127.0.0.1:7071,2=127.0.0.1:7072,3=127.0.0.1:7073" --incrementFilePort 5051 --incrementFilePeers "1=127.0.0.1:5051,2=127.0.0.1:5052,3=127.0.0.1:5053"
	// go run main.go --shardID 128 --id 2 --shardIDS "128,129" --ip 127.0.0.1 --port 9002 --peers "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003" --nodeInfo "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003,4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --rpcPort 6062 --rpcPeers "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063" --rpcNodeInfo "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063,4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --raftPort 19002  --raftPeers "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003" --raftNodeInfo "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003,4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --logPort 8082 --logPeers "1=127.0.0.1:8081,2=127.0.0.1:8082,3=127.0.0.1:8083" --filePort 7072 --filePeers "1=127.0.0.1:7071,2=127.0.0.1:7072,3=127.0.0.1:7073" --incrementFilePort 5052 --incrementFilePeers "1=127.0.0.1:5051,2=127.0.0.1:5052,3=127.0.0.1:5053"
	// go run main.go --shardID 128 --id 3 --shardIDS "128,129" --ip 127.0.0.1 --port 9003 --peers "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003" --nodeInfo "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003,4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --rpcPort 6063 --rpcPeers "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063" --rpcNodeInfo "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063,4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --raftPort 19003  --raftPeers "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003" --raftNodeInfo "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003,4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --logPort 8083 --logPeers "1=127.0.0.1:8081,2=127.0.0.1:8082,3=127.0.0.1:8083" --filePort 7073 --filePeers "1=127.0.0.1:7071,2=127.0.0.1:7072,3=127.0.0.1:7073" --incrementFilePort 5053 --incrementFilePeers "1=127.0.0.1:5051,2=127.0.0.1:5052,3=127.0.0.1:5053"
	// go run main.go --shardID 129 --id 4 --shardIDS "128,129" --ip 127.0.0.1 --port 9004 --peers "4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --nodeInfo "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003,4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --rpcPort 6064 --rpcPeers "4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --rpcNodeInfo "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063,4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --raftPort 19004  --raftPeers "4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --raftNodeInfo "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003,4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --logPort 8084 --logPeers "4=127.0.0.1:8084,5=127.0.0.1:8085,6=127.0.0.1:8086" --filePort 7074 --filePeers "4=127.0.0.1:7074,5=127.0.0.1:7075,6=127.0.0.1:7076" --incrementFilePort 5054 --incrementFilePeers "4=127.0.0.1:5054,5=127.0.0.1:5055,6=127.0.0.1:5056"
	// go run main.go --shardID 129 --id 5 --shardIDS "128,129" --ip 127.0.0.1 --port 9005 --peers "4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --nodeInfo "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003,4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --rpcPort 6065 --rpcPeers "4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --rpcNodeInfo "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063,4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --raftPort 19005  --raftPeers "4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --raftNodeInfo "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003,4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --logPort 8085 --logPeers "4=127.0.0.1:8084,5=127.0.0.1:8085,6=127.0.0.1:8086" --filePort 7075 --filePeers "4=127.0.0.1:7074,5=127.0.0.1:7075,6=127.0.0.1:7076" --incrementFilePort 5055 --incrementFilePeers "4=127.0.0.1:5054,5=127.0.0.1:5055,6=127.0.0.1:5056"
	// go run main.go --shardID 129 --id 6 --shardIDS "128,129" --ip 127.0.0.1 --port 9006 --peers "4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --nodeInfo "1=127.0.0.1:9001,2=127.0.0.1:9002,3=127.0.0.1:9003,4=127.0.0.1:9004,5=127.0.0.1:9005,6=127.0.0.1:9006" --rpcPort 6066 --rpcPeers "4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --rpcNodeInfo "1=127.0.0.1:6061,2=127.0.0.1:6062,3=127.0.0.1:6063,4=127.0.0.1:6064,5=127.0.0.1:6065,6=127.0.0.1:6066" --raftPort 19006  --raftPeers "4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --raftNodeInfo "1=127.0.0.1:19001,2=127.0.0.1:19002,3=127.0.0.1:19003,4=127.0.0.1:19004,5=127.0.0.1:19005,6=127.0.0.1:19006" --logPort 8086 --logPeers "4=127.0.0.1:8084,5=127.0.0.1:8085,6=127.0.0.1:8086" --filePort 7076 --filePeers "4=127.0.0.1:7074,5=127.0.0.1:7075,6=127.0.0.1:7076" --incrementFilePort 5056 --incrementFilePeers "4=127.0.0.1:5054,5=127.0.0.1:5055,6=127.0.0.1:5056"

8.上传案例代码

package main

import (
	"fmt"
	"os"
	"time"

	"mumu.com/redis-go/qfsSdk"
)

func main() {
	// 1. 初始化SDK
	qfsSdk.InitSDK(&qfsSdk.QFSConfig{
		ClusterEntry: []string{
			"127.0.0.1:9001",
			"127.0.0.1:9002",
			"127.0.0.1:9003",
		},
		Timeout: 15 * time.Second,
	})

	// 2. 读取测试文件
	fileName := "22.pdf"
	filePath := fmt.Sprintf("./%s", fileName)
	file, err := os.Open(filePath)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// 3. 直接调用SDK上传
	resp, err := qfsSdk.Upload(file, fileName)
	if err != nil {
		panic(err)
	}

	println("上传结果:", string(resp))
}

编译

go mod init redis-cli
go build -o myredis-cli main.go
./myredis-cli 127.0.0.1:6379

使用HashiCorp主从切换完整实现

核心设计

1.使用HashiCorp Raft,测试通过主从切换 2.HTTP服务端口 :9001,9002 ,9003 3.RaftAddr:127.0.0.1:19001,127.0.0.1:19002,127.0.0.1:19003,

已开发完成

1.开发完成日志系统logger,日志自动滚动创建且压缩。[已完成]
2.开发完成配置系统config[已完成]
3.开发完成雪花算法生成自增id,从配置文件获取中心id和机器id然后生产唯一自增id[已完成]
4.开发redis-go客户端的包,连接服务器上传图片。分片上传和断点续传,断点续传未测试 [未完成]
5.缓存服务器客户端开发测试完成,当下支持单机访问,后期修改为集群模式 [未完成]
6.浏览器存入redis报错,RESP[已完成]
7.开发内存数据持久化,3台电脑的主从数据同步,高可用[完成]
8.开发完成raft3各节点选主,主节点挂掉,自动选择新的主节点[已完成]
9.不同电脑node信息存到一个map中,验证住更新后,nodes数据是否更新,2.nodes存储所有节点数据,未实现 3.主从切换后,主节点不能写入数据
9.1."github.com/lni/dragonboat/v4"实现多主集群,集群状态信息,2槽分配
9.2. dragonboat任何3个节点都能写入元数据和查询,元数据落盘,重启后数据不丢失,主节点会修改。[测试完成]
9.3. dragonboat任何3个节点,代码写入数据成功,查询数据成功[测试完成]
9.4. nh.StartOnDiskReplica(initialMembers, *join, dragonboatRaft.NewDiskKV, rc);默认initialMembers第一个启动的节点为主节点, [测试完成]
9.5. 1.dragonboat任何6个节点主从切换测试。[测试通过]2.官方设计就是:不同 ShardID 数据 100% 不互通、不同步![测试通过]3.数据要在每个分片单独写入4.定义全局shardID=9999,任何6个节点都能写入元数据和查询 [测试通过]
9.7.dragonboat 数据全局存储GlobalShardID=9999[测试完成]
9.8. 1.qfs_meta:1=NodeMeta qfs_meta:2=NodeMeta 1.存储所有集群id:qfs_meta:ShardIDS="1,2,3"[测试完成]
9.9. 1.启动6个节点,初始化槽信息,首次平均分配槽qfs_meta:9999:NodeSlotMetas[已完成] 2.存储每个shardID: qfs_meta:9999:128 qfs_meta:9999:129[已完成] 3.存储leaderID: get qfs_meta:9999:129:ShardNodeLeaderID get qfs_meta:9999:128:ShardNodeLeaderID,leader切换时,槽对应的leaderID要动态跟着修改 [已完成]
10. 与源代码的集群相结合,实现主节点写入,从节点读取,主节点切换后,新主节点写入[已完成]
11.log管理使用组件wal
11.1.log写入本地文件json格式行存储,每个文件128M[已完成]
11.2.节点重启,从本地log获取日志,重新写入内存[已完成]
11.3.节点重启,从本地log日志读取最新日志自增编号,同时请求shard的leader获取最新的自增id,读取主节点的数据到获取的leader之前读取的最大自增id,接下来机器提供正常服务[已完成]
11. 1.文件上传,分片上传[已完成]
12. 1.上传文件实时发送rpc到从机,从机实时同步主机文件[完成并测试通过]
12.2.文件上传,rpc通知发送roukeKey到leader,[完成并测试通过]
12.3.文件上传,电脑重启,同步增量文件,[完成但未测试]

{"fileId":"145351743520108544","fileName":"22.pdf","filePath":"./file_data/data_7074/file_20260516/22.pdf","mineType":"application/pdf","fileSize":80529272,"createTime":1778880031113,"updateTime":1778880031113,"isDeleted":false,"status":"Pending"}

{"fileId":"145351743520108544","fileName":"22.pdf","filePath":"./file_data/data_7074/file_20260516/22.pdf","mineType":"application/pdf","fileSize":80529272,"createTime":1778880031113,"updateTime":1778880031113,"isDeleted":false,"status":"Pending"}

origin_1.log文件第一发任务后,offset=0读取文件为空,node_incre_task_manager文件DispatchOriginToWorker方法,batchReadLimitWithOffset

13.开发对象存储oss,存储图片字段:

原始名称,新名称,创建时间,修改时间,图片大小,图片分辨率,MIME类型,图片格式jpg,图片内容的crc64校验图片完整性,

开发进程

1.发送心跳链接集群

1.节点定时发心跳注册监控节点, 2.节点定时修改监控上注册的节点信息, 3.监控服务接口访问节点注册的数据,展示节点信息ip:port,权重,是否在线 4.使用hashmap存储节点信息

2.监控服务

1.数据节点服务8080 2.监控节点服务9090 3.数据节点,监控节点分别存到hashmap 4.同时只有一个监控节点工作,其余节点待命1分钟

3.同步监控节点间的数据

1.监控monitor节点通过发送json消息同步node节点数据 2.选举产生新的监控主节点(未实现)

4.测试raft

1.raft测试通过github.com/hashicorp/raft 2.项目全部使用module形式发布

5.编写选主,发送主信息到数据节点

1.编码选主raft 2.编码发送主节点ip端口到数据节点

QFS分布式文件存储系统设计方案

1.带解决问题(存储中小型文件)

1.raft选主,高可用

1.1.自动选主

1.2.元数据存储(1.master主节点槽数据信息 2.文件路径),落盘

2.gossip协议集群管理

2.1心跳定时检测各机子是否存活

2.2所有集群机器合集hasmap,master和slave对应关系,用masterNodeId=主机的id

2.2新机上线,添加到集群,hasmap添加,更新集群状态信息hasmap

2.3新机下线,从集群移除,hasmap删除,更新集群状态信息hasmap

3.文件上传,

3.1根据槽选择数据master主机,

3.2文件路径元数据存到主节点,自动同步到从节点

4.文件同步,

4.1jsonLog数据同步,master主机同步到slave从机(参照mysql的binlog)

5.动态扩容,

命令扩容,参考Redis的命令

6.动态缩容,

命令缩容,参考Redis的命令

7.使用自研QPHP框架写集群管理面板,

7.1.集群状态监控(在线,下线,重启)

7.2.cpu和内存,磁盘使用率监控

7.3.面板动态扩容,面板动态缩容

8.对象存储oss设计

About

QFS 是一个开源的高性能分布式文件系统。 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡。主要解决了海量数据存储问题,特别适合以中小文件(建议范围:1MB < file_size <500MB)为载体的在线服务。

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages