MinIO替代汇总(二):GlusterFS、Garage、Free FS

继MinIO替代汇总(一):SeaweedFS、RustFS、Ceph

GlusterFS

官网,开源(GitHub,5.2K Star,1.1K Fork)文件系统,特别适合需要POSIX文件系统语义的场景。无元数据服务器:独特的无中心架构。

实战

3节点部署脚本:

bash 复制代码
#!/bin/bash
# GlusterFS 3节点集群快速部署脚本
# 在三个节点上执行类似命令
# 节点1:
gluster peer probe node2
gluster peer probe node3
# 创建分布式卷(数据分散在所有节点)
gluster volume create gv0 disperse 3 node1:/data/brick1 node2:/data/brick1 node3:/data/brick1
# 或创建复制卷(数据在所有节点复制)
gluster volume create gv1 replica 3 node1:/data/brick2 node2:/data/brick2 node3:/data/brick2
# 启动卷
gluster volume start gv0
gluster volume start gv1
# 在客户端挂载
mount -t glusterfs node1:/gv0 /mnt/glusterfs

Java

Java SDK集成:

java 复制代码
public class GlusterFSExample {
	private Path glusterMountPoint;
	
	public GlusterFSExample(String mountPath) {
		this.glusterMountPoint = Paths.get(mountPath);
		
		// 验证挂载点
		if (!Files.exists(glusterMountPoint)) {
			thrownew IllegalArgumentException("GlusterFS挂载点不存在: " + mountPath);
		}
		
		System.out.println("GlusterFS挂载点: " + mountPoint.toAbsolutePath());
	}
	
	// 写入文件 - GlusterFS自动处理数据分布
	public void writeFile(String filename, String content) throws IOException {
		Path filePath = glusterMountPoint.resolve(filename);
		
		// 创建父目录(如果需要)
		if (filePath.getParent() != null) {
			Files.createDirectories(filePath.getParent());
		}
		
		// 写入文件
		Files.write(filePath, 
					content.getBytes(StandardCharsets.UTF_8),
					StandardOpenOption.CREATE,
					StandardOpenOption.WRITE,
					StandardOpenOption.TRUNCATE_EXISTING);
		
		System.out.println("文件已写入GlusterFS: " + filePath);
	}
	
	// 读取文件
	public String readFile(String filename) throws IOException {
		Path filePath = glusterMountPoint.resolve(filename);
		if (Files.exists(filePath)) {
			byte[] content = Files.readAllBytes(filePath);
			returnnew String(content, StandardCharsets.UTF_8);
		}
		return null;
	}
	
	// 列出目录内容
	public List<String> listFiles(String directory) throws IOException {
		Path dirPath = glusterMountPoint.resolve(directory);
		
		if (Files.exists(dirPath) && Files.isDirectory(dirPath)) {
			try (Stream<Path> stream = Files.list(dirPath)) {
				return stream
					.filter(Files::isRegularFile)
					.map(Path::getFileName)
					.map(Path::toString)
					.collect(Collectors.toList());
			}
		}
		return Collections.emptyList();
	}
	
	// 获取文件信息
	public void printFileInfo(String filename) throws IOException {
		Path filePath = glusterMountPoint.resolve(filename);
		if (Files.exists(filePath)) {
			BasicFileAttributes attrs = Files.readAttributes(filePath, BasicFileAttributes.class);
			// logging
		}
	}
}

适用场景

  • 需要标准文件系统接口的应用
  • 媒体处理、日志存储等场景
  • 已有大量基于文件API的遗留系统

Garage

官网,源自法国国立计算机与自动化研究所(INRIA),Deuxfleurs(法国非营利集体)维护、Rust编写、开源(GitHub,4.3K Star,163 Fork)S3兼容分布式对象存储系统。

主打跨地域(Geo-Distributed)小型集群,适合自托管、跨多地异构廉价硬件部署,是MinIO、Ceph、SeaweedFS的轻量替代方案。为跨不同城市/机房、公网高延迟链路的小规模集群设计;不依赖K8s,单二进制,低资源占用,可跑在树莓派、老旧笔记本、廉价VPS上。

特点:

  • 轻量级:单二进制部署,无复杂依赖,可二进制/容器运行;
  • 低内存开销:资源消耗少,节点最低约1GB RAM,ARM原生支持;
  • 网络容错:跨公网高延迟、临时断网,恢复后自动同步;
  • 支持单节点模式(副本因子=1,仅测试);
  • 去中心化设计:无单点故障,生产推荐≥3节点、跨3个Zone;
  • 支持分片上传、Bucket策略、路径风格、兼容S3 API、虚拟主机风格S3访问;
  • 数据scrub后台巡检,自动检测坏块;

架构

  • 无中心主节点,对等节点架构:所有节点对等,使用类Raft协议做元数据协同;内置Zone(区域/机房)感知,强制副本分散到不同Zone,避免单区域断电断网丢数据。推荐replication_factor=3(3副本),3个节点分属3个不同区域,任一区域故障集群仍可读写,最多同时挂掉2个区域才会丢数据。
  • 数据模型:分块+元数据分离
    • 对象拆成固定大小Block(默认1MB),块数据落盘
    • 元数据用LMDB本地数据库存储(每个节点独立维护元数据)
    • 一致性模式可选:eventual:最终一致性,consistent:强一致性
  • API
    • 主接口:S3 API(子集),兼容AWS CLI、rclone、restic、Immich、Nextcloud、Mastodon、PeerTube;
    • 额外:内置静态网站托管(Bucket直接托管静态站点)
    • 管理:Garage CLI+管理API(3903 端口)
    • 端口默认:
      • 3900:S3 API
      • 3901:节点间 RPC
      • 3903:管理 API

限制

  • 仅副本复制,不支持纠删码(Erasure Coding)
  • 3副本需要3倍原始磁盘容量,大容量场景成本高,适合中小容量备份/图片,不适合PB级存储;
  • S3 API是子集:不支持对象版本、生命周期策略、Object Lock;
  • 没有内置TLS,S3 API裸HTTP,需前置Nginx、Caddy做HTTPS反向代理;
  • 没有细粒度IAM,权限模型简单(AccessKey绑定Bucket读写权限)。

实战

3节点集群部署示例docker-compose.yml

yml 复制代码
version:'3.8'
services:
garage1:
	image: dxflrs/garage:v0.9.0
	command: "garageserver"
	environment:
	  -GARAGE_NODE_NAME=node1
	  -GARAGE_RPC_SECRET=my-secret-key
	  -GARAGE_BIND_ADDR=0.0.0.0:3901
	  -GARAGE_RPC_BIND_ADDR=0.0.0.0:3902
	  -GARAGE_REPLICATION_MODE=3
	volumes:
	  -./data/garage1:/var/lib/garage
	ports:
	  -"3901:3901"
	  -"3902:3902"
garage2:
	image: dxflrs/garage:v0.9.0
	command: "garageserver"
	environment:
	  -GARAGE_NODE_NAME=node2
	  -GARAGE_RPC_SECRET=my-secret-key
	  -GARAGE_BIND_ADDR=0.0.0.0:3901
	  -GARAGE_RPC_BIND_ADDR=0.0.0.0:3902
	  -GARAGE_SEED=garage1:3902
	volumes:
	  -./data/garage2:/var/lib/garage
garage3:
	image: dxflrs/garage:v0.9.0
	command: "garageserver"
	environment:
	  -GARAGE_NODE_NAME=node3
	  -GARAGE_RPC_SECRET=my-secret-key
	  -GARAGE_BIND_ADDR=0.0.0.0:3901
	  -GARAGE_RPC_BIND_ADDR=0.0.0.0:3902
	  -GARAGE_SEED=garage1:3902
	volumes:
	  -./data/garage3:/var/lib/garage

Java SDK集成示例:

java 复制代码
public class GarageExample {
	// Garage完全兼容S3 API,可直接使用AWS SDK
	private AmazonS3 garageClient;
	
	public void initGarageConnection() {
	// Garage的配置与Minio非常相似
	AWSCredentials credentials = new BasicAWSCredentials(
		"GK...", // Garage生成的访问密钥
		"..."	 // 对应的秘密密钥
	);
	
	garageClient = AmazonS3ClientBuilder.standard()
		.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(
			"http://localhost:3900", // Garage的S3 API端口
			"garage" // 区域名称可自定义
			)
		)
		.withCredentials(new AWSStaticCredentialsProvider(credentials))
		.withPathStyleAccessEnabled(true)
		.build();
	}
	
	// 创建存储桶并设置策略
	public void createBucketWithPolicy(String bucketName) {
		//创建存储桶
		garageClient.createBucket(bucketName);
		// Garage支持灵活的存储策略配置
		String bucketPolicy = """
		{
			"version": "2026-08-01",
			"statement": [
				{
					"effect": "Allow",
					"principal": "*",
					"action": "s3:GetObject",
					"resource": "arn:aws:s3:::%s/*"
				}
			]
		}
		""".formatted(bucketName);
		garageClient.setBucketPolicy(bucketName, bucketPolicy);
		System.out.println("存储桶创建完成,已设置公开读取策略");
	}
	
	// 上传文件并生成访问URL
	public String uploadAndGenerateUrl(String bucketName, String objectKey, InputStream inputStream) {
		ObjectMetadata metadata = new ObjectMetadata();
		// 设置内容类型等元数据
		metadata.setContentType("application/octet-stream");
		PutObjectRequest request = new PutObjectRequest(
			bucketName, objectKey, inputStream, metadata
		);
		garageClient.putObject(request);
		// 生成预签名URL(Garage支持此功能)
		java.util.Date expiration = new java.util.Date();
		long expTimeMillis = expiration.getTime();
		expTimeMillis += 1000 * 60 * 60;
		expiration.setTime(expTimeMillis);
		GeneratePresignedUrlRequest generatePresignedUrlRequest = 
			new GeneratePresignedUrlRequest(bucketName, objectKey)
				.withMethod(HttpMethod.GET)
				.withExpiration(expiration);
		return garageClient.generatePresignedUrl(
			generatePresignedUrlRequest).toString();
	}
}

适用场景

  • 去中心化应用或区块链项目
  • 需要轻量级对象存储的场景

Free FS

官网,开源(GitHub,305 Star,69 Fork)文件管理系统:基于Spring Boot 3.5、MyBatis Flex、MySQL、Redis的企业级网盘系统。支持分片上传、断点续传、秒传、文件分享、在线预览。集成阿里云OSS、七牛云Kodo、MinIO、本地存储等多种存储方式。提供文件管理、用户权限、存储配额、回收站等完整功能。适用于企业网盘、文件管理、云存储、资源管理等场景。

左侧简洁的导航栏,右侧文件网格,支持分类筛选、多存储后端、秒传续传...甚至连UI风格都和我的原型相差无几。

功能

  • 多种上传方式:基于MD5校验,相同文件秒级完成,GB级大文件支持断点续传、分片上传
  • 多存储支持:原生支持阿里云OSS、七牛云、MinIO及本地存储,插件化架构灵活扩展
  • Sa-Token认证:集成成熟的权限体系,不是玩具项目,真能上生产环境
  • 前后端分离:前端现代感十足的界面,后端低内存高并发

实战

相关推荐
灯澜忆梦12 小时前
【minio】#5 | MinIO 分布式部署 + HTTPS 部署
分布式·网络协议·https·对象存储·minio
灯澜忆梦2 天前
【minio】#1 | 简介与安装
docker·对象存储·minio
灯澜忆梦2 天前
【minio】#2 | Web 控制台操作
对象存储·minio
xiaolin03335 天前
AWS SDK对接MinIO踩坑:AWS_REQUEST_CHECKSUM_CALCULATION
java·minio·s3
分布式存储与RustFS14 天前
MinIO 官方 Docker 镜像被移除:依赖它的项目该怎么办
docker·云原生·devops·对象存储·minio·分布式存储
分布式存储与RustFS14 天前
对象存储正在吞掉数据湖:RustFS 1.0 GA 与 MinIO AIStor Tables 把 2026 风向说清楚
iceberg·数据湖·对象存储·minio·s3·rustfs·ai存储
郭庆汝18 天前
MinIO 相关内容解析
minio
JIngles12320 天前
用 Dart 通过 S3 API 操作 MinIO:文件上传与下载 Demo
中间件·minio·存储
凤山老林1 个月前
企业级文件服务中台:Spring Boot 集成 MinIO 实现分片存储、生命周期管理与多租户隔离
java·spring boot·后端·minio·文件服务