一、分布式存储基础概念

1.1 传统存储方案对比

在理解对象存储之前,先回顾三种经典的存储架构:

存储架构不是指某一块具体的硬盘或某一个软件,而是指数据从“应用”到“物理硬盘”之间的整个传输路径、组织方式和访问规则的设计蓝图。

类型 全称 特点 访问方式 典型场景
DAS Direct Attached Storage(直连存储) 存储设备直接挂载在服务器总线上(如SATA/SAS硬盘) 块设备(Block) 本地系统盘、数据库专用盘
NAS Network Attached Storage(网络附加存储) 存储设备接入网络,通过文件共享协议(NFS、CIFS、FTP)提供目录级访问 文件级(File) 办公文件共享、中小型备份
SAN Storage Area Network(存储区域网络) 通过高速专用网络(FC或iSCSI)将存储设备与服务器连接,提供裸块设备 块级(Block) 企业级数据库、虚拟化集群

请添加图片描述

💡 核心区别:DAS直连,NAS走网络且共享文件,SAN走高速网络且共享块设备。三者均不适合海量非结构化数据(图片、视频、日志)的弹性扩展。

虽然传统的“老三样”(DAS/NAS/SAN)里没有对象存储,但在现代云计算领域,对象存储已经被公认为第三种核心存储架构。它和块存储、文件存储平起平坐,共同构成了当今数据存储的三大基石。MinIO正是这种架构的杰出代表。

1.2 对象存储(Object Storage)

对象存储(如MinIO)是存储,不是数据库:虽然 MinIO 支持桶(Bucket)和键值(Key-Value)查询,但它是用来存图片、视频、压缩包的,不支持 SQL 查询或事务,所以它是存储服务

对象存储专门为海量非结构化数据而生。对象存储将数据作为对象(Object)来管理,而不是文件系统中的文件或块设备中的块,每个对象包含:

  • 数据(Data):文件本身的二进制内容。
  • 元数据(Metadata):描述数据的键值对(如文件名、大小、创建时间、自定义标签)。
  • 唯一标识符(Object ID):通过此ID可直接获取对象,无需关心物理位置。

典型应用场景:电商商品图片、视频网站文件、音乐库、社交网站图片、虚拟机镜像、云盘文件等。

对象存储服务的核心特点

  • 分布式架构,可水平扩展(Scale-Out)
  • 基于 RESTful API(如 S3 协议)访问
  • 扁平命名空间(无目录树,所有对象在同一桶内)
  • 高可用与持久性:数据自动复制或纠删码保护,跨多节点/机架
  • 适合大文件,支持分片上传
  • 常用于云计算环境(AWS S3、阿里云OSS、MinIO 等)

1.3 对象存储与传统存储的区别

块存储(DAS/SAN):将原始存储空间直接映射给服务器,让服务器觉得插上了一块大硬盘,需要格式化,依赖文件系统(如EXT4)。例如:磁盘的格式化挂载

文件存储(NAS):将原始存储空间格式化成共享文件夹,提供了文件夹和目录树,你可以像在Windows资源管理器里一样浏览。例如:NFS共享存储

对象存储(Object):舍弃了复杂的目录树,将原始存储空间改造成扁平的桶,把数据打包成一个“对象”(数据本体 + 丰富的自定义元数据 + 唯一ID),放在这个巨大的扁平池里。(所有数据位于同一层级,没有目录树结构)

块存储,类似插了一个硬盘,需要进行格式化;
文件存储,类似于分享给你的一块现成的存储空间;
对象存储,是把数据直接塞进一个扁平的大桶(Bucket)里,通过 HTTP 协议(通常是 9000 端口)调用 RESTful API,利用唯一的对象名(Key)直接定位并读写数据

1.4 基本存储概念区分

物理硬盘(SSD/HDD):提供原始的 0/1 存储空间。

存储架构(DAS/NAS/SAN/对象存储) :是硬盘与网络的物理/逻辑连接方案。把零散的物理盘聚合成统一的逻辑资源池,并负责提供这些逻辑空间的存储接口。它提供的是数据存放服务,面向的是你的数据怎么存储到你的硬盘,以及你怎么使用和获取数据

任何数据库软件,都必须依赖底层的存储架构才能“安家落户”

数据库:是一种软件,用来规范并管理你的数据, 是加工处理数据的智能大脑。它提供的是数据管理服务

文件系统(如 XFS):把原始存储空间格式化成有规则的结构(超级块、inode、数据块),它既是一种存储格式,也包含了一套存储格式的管理规则包。

当你执行 mkfs.xfs /dev/sdb1 时,系统实际上在硬盘开头画了三大块区域:
超级块(Superblock):“硬盘的身份证和总账本”。它记录了这个分区总共有多少GB、已经用了多少、还剩多少、以及 inode 和数据块的位置在哪里。如果超级块坏了,这块盘就彻底“失忆”了,系统会直接提示“未格式化”。
inode(索引节点):“文件的户口本”。每个文件都有一个唯一的 inode 编号。它记录了这个文件多大、权限是什么(rwx)、属于谁,以及最重要的——这个文件的碎片存放在下面哪个数据块里。注意:inode 只管属性,不管文件名(文件名在父目录的数据块里)。
数据块(Data Block):“存放真实货柜的仓库”。你的那张照片、那段视频的实际 0 和 1 二进制数据,就堆在这里。


二、MinIO 介绍

MinIO 是由 GlusterFS 创始人之一 Anand Babu Periasamy 发起的开源项目,使用 Go 语言编写,是高性能、云原生、与 S3 兼容的对象存储系统

MinIO 自身既是“存储架构”也是“管理软件”,它不依赖操作系统的文件系统来管理数据,而是直接调用底层的 XFS(硬盘),把文件切成碎片(纠删码),绕过操作系统目录树,直接以对象 ID 的形式散落在硬盘的每个角落,用 MinIO 自己内部的元数据引擎去管理这些碎片

MinIO 有两个核心的服务端口:

API 端口(默认 9000):这是 S3 服务端口。你的应用程序和 mc 客户端都是通过这个端口来上传、下载和管理数据的。

Web 控制台端口(默认 9001):这是 Web 管理界面端口。你可以通过浏览器访问这个端口,登录图形化界面来管理集群。

核心特性

特性 说明
高性能 官方宣称在 32 个 NVMe 节点上可达 325 GiB/s 读、165 GiB/s 写
S3 兼容 完全兼容 AWS S3 API,可无缝替代或配合 AWS S3 使用
轻量简单 单个二进制文件即可运行,使用和部署非常简单
云原生 是 Kubernetes 上运行对象存储的事实标准,有官方 Operator
开源 采用 GNU AGPL v3 许可证,社区活跃
分布式模式 支持多节点多盘集群,内置纠删码(Erasure Coding)

minio是一个存储架构,也是一个软件。需要注意的是,他的集群没有主从

主要应用场景

  • 私有云/混合云存储(自建 S3 服务)
  • AI/ML 大数据存储(模型、数据集、日志)
  • 备份归档(Velero、Veeam 等后端)
  • 微服务/移动应用的对象存储
  • Kubernetes CSI 持久化存储后端

官方资源

  • 官网:https://min.io/
  • 中文站:https://www.minio.org.cn/
  • GitHub:https://github.com/minio/minio

2.1 MinIO 写入与容量规划

写入策略

MinIO 不会自动在存储池之间重新平衡已有数据。新写入操作会优先选择剩余空间最多的存储池(按剩余空间占比加权)。同时,若某池使用率超过 99% 或 inode 不足 100,则不会写入该池。

容量规划建议

官方建议在集群使用率达到 70% 之前,规划足以存储 至少 2 年 数据的容量。频繁扩容往往意味着架构设计问题。例如,若每年新增 100 TiB 数据,且预期 3 年后扩容,则初始可用容量应为 500 TiB 左右(使 70% 阈值在 3 年后达到)。


2.2 纠删码(Erasure Coding,EC)

纠删码是 MinIO 实现数据高可用的核心机制,在可靠性和存储效率上显著优于传统多副本方案。 其工作原理是将一个对象切分为若干数据块与校验块,并分散存储于集群的不同驱动器(minio使用的目录)上。

假设你有四台服务器,每台服务器四个盘,那么你存在minio中的数据会被纠删码分割成16块碎片,分别存储到到四台主机上的16块盘之中。也就是说,数据块会平均分配到各个盘(驱动器),并且在分配的时候数据块和校验块不分先后,视为等同

当集群中发生多个驱动器或节点故障时,MinIO 能利用剩余的块即时触发对象级自动重建,修复粒度精细至单个对象,无需整盘恢复,极大缩短了修复窗口。同时,MinIO 结合端到端的校验和机制,不仅能抵御物理硬件故障,还能有效防止静默数据损坏。在默认配置下,即便集群中损失半数(N/2)的硬盘,系统依然能够完整恢复所有数据,确保业务零中断

需要注意的是,minio的切片存储与redis和es的目的不同。minio是“数学冗余拆分”,利用纠删码的机制,能保证损失多个切片后,仍能通过算法恢复完整数据
以默认的 EC 8+4 为例(12块盘),一个 12MB 的文件被切成 8 个数据块 + 4 个校验块。12块盘里,每一块都只存了文件的一小部分碎片。坏掉任意 4 块盘(哪怕是最重要的数据盘),剩下的 8 块盘里依然有完整的数据块,不需要任何额外的“副本”,数学公式直接现场算出来。存储开销仅为 150%(12MB空间存12MB数据)

传统副本的局限

  • 三副本:存储开销 300%(1 份数据存 3 份),空间利用率仅 33%。
  • 容错能力有限(最多丢失 2 个副本节点)。

纠删码原理

  • 将对象切分为 k 个数据块,计算生成 m 个校验块,总块数 n = k + m。
  • 只要丢失的块数 ≤ m,就能通过任意 k 个块恢复完整数据。
  • 例如 EC 4+2:4 数据块 + 2 校验块,可容忍任意 2 块丢失,存储开销 150%,存储效率 66.7%。
配置 数据块 校验块 容错块数 存储效率
三副本 1 2 2 33.3%
EC 4+2 4 2 2 66.7%
EC 8+4 8 4 4 66.7%
EC 16+8 16 8 8 66.7%

也就是说,只要丢失的块数不超过(≤)校验块的数量 m,就能通过数学算法 100% 无损恢复原始数据

注意:MinIO 的纠删码在节点/磁盘级别工作,块分布在不同节点和磁盘上,实现并行读写和负载均衡。

EC 策略是集群级的,但总碎片数必须等于集群的总硬盘数。如果你现在是有16块盘,只能搞“总数=16”的排列组合(比如8+8)

它会根据集群中磁盘数量自行分配数据块和校验块的数量,特定场景下也可以进行手动调试

纠删码计算器:
https://www.min.io/product/erasure-code-calculator

对比 RAID

特性 RAID MinIO EC
修复粒度 整盘重建 对象级增量修复
扩展性 有限 水平无限扩展
多节点支持 不支持 原生支持
访问接口 块设备 S3 对象 API

纠删码计算器

官方提供在线工具:https://www.min.io/product/erasure-code-calculator


查看校验块数量:在mc(minio客户端)执行:mc admin info mycluster1 命令,底部会显示:EC

请添加图片描述

2.3 MinIO 启动模式

MinIO 支持三种运行模式:

模式 缩写 描述 适用环境
单节点单盘 SNSD 单机一个目录/磁盘无冗余 开发测试
单节点多盘 SNMD 单机挂载多个磁盘(≥4),启用纠删码 小规模生产(仅磁盘级冗余)
多节点多盘 MNMD 多台服务器,每台 ≥4 磁盘 生产标准,节点+磁盘级冗余

启动命令示例:

# 单节点单盘
minio server /data

# 单节点多盘
minio server /data1 /data2 /data3 /data4

# 多节点多盘(4节点,每节点4盘)
minio server http://server{1...4}/data{1...4}

三、生产环境分布式部署(4 节点示例)

请添加图片描述

架构要求

  • 至少 4 台服务器(纠删码最低要求,若采用 4+2 则需 6 台,但 4 台也可用 2+2 模式,容错为 2 块)。
  • 每节点挂载独立磁盘(推荐 4~16 块,数量需一致)。
  • 节点间网络延迟 < 10ms。

主机规划示例

主机名 IP 磁盘数量
hd1 192.168.1.111 4
hd2 192.168.1.112 4
hd3 192.168.1.113 4
hd4 192.168.1.114 4

文件系统推荐

文件系统 推荐指数 场景
XFS ⭐⭐⭐⭐⭐ 生产首选,高性能大文件优化
ext4 ⭐⭐⭐⭐ 通用,成熟稳定
ZFS ⭐⭐⭐⭐ 高级功能(快照、压缩、校验)

3.1 部署步骤(所有节点执行)

1. 准备磁盘和挂载点
# 创建挂载目录(每台主机都要执行)
mkdir -p /data/disk{1..4}

# 分区(假设有 /dev/sdb~sde)
fdisk /dev/sdb

欢迎使用 fdisk (util-linux 2.32.1)。
更改将停留在内存中,直到您决定将更改写入磁盘。
使用写入命令前请三思。

设备不包含可识别的分区表。
创建了一个磁盘标识符为 0x15e6795b 的新 DOS 磁盘标签。

命令(输入 m 获取帮助):n
分区类型
   p   主分区 (0个主分区,0个扩展分区,4空闲)
   e   扩展分区 (逻辑分区容器)
选择 (默认 p):

将使用默认回应 p。
分区号 (1-4, 默认  1): 
第一个扇区 (2048-10485759, 默认 2048): 
上个扇区,+sectors 或 +size{K,M,G,T,P} (2048-10485759, 默认 10485759): 

创建了一个新分区 1,类型为“Linux”,大小为 5 GiB。

命令(输入 m 获取帮助):w
分区表已调整。
将调用 ioctl() 来重新读分区表。
正在同步磁盘。
# 因为我们要把每个磁盘分成一个分区,所以命令进入之后,输入n进入分区,一路回车就行,最后在:
#命令(输入 m 获取帮助):w
#输入w保存退出即可

fdisk /dev/sdc
fdisk /dev/sdd
fdisk /dev/sde
#其余三个盘以及其余主机的操作一致

#查看分区后的磁盘
[root@client ~]# lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda           8:0    0   20G  0 disk 
├─sda1        8:1    0    1G  0 part /boot
└─sda2        8:2    0   19G  0 part 
  ├─rl-root 253:0    0   17G  0 lvm  /
  └─rl-swap 253:1    0    2G  0 lvm  [SWAP]
sdb           8:16   0    5G  0 disk 
└─sdb1        8:17   0    5G  0 part 
sdc           8:32   0    5G  0 disk 
└─sdc1        8:33   0    5G  0 part 
sdd           8:48   0    5G  0 disk 
└─sdd1        8:49   0    5G  0 part 
sde           8:64   0    5G  0 disk 
└─sde1        8:65   0    5G  0 part 

# 格式化(XFS)并挂载
mkfs.xfs /dev/sdb1 
mount /dev/sdb1 /data/disk1
mkfs.xfs /dev/sdc1
mount /dev/sdc1 /data/disk2
mkfs.xfs /dev/sdd1
mount /dev/sdd1 /data/disk3
mkfs.xfs /dev/sde1
mount /dev/sde1 /data/disk4
# 同理 sdc1->disk2, sdd1->disk3, sde1->disk4
# 建议写入 /etc/fstab 实现开机自动挂载


#查看挂载情况
[root@client ~]# df -h
文件系统             容量  已用  可用 已用% 挂载点
......
/dev/sdb1            5.0G   68M  5.0G    2% /data/disk1
/dev/sdc1            5.0G   68M  5.0G    2% /data/disk2
/dev/sdd1            5.0G   68M  5.0G    2% /data/disk3
/dev/sde1            5.0G   68M  5.0G    2% /data/disk4

# 创建minio的存储目录(每台主机都要执行)
mkdir -p /data/disk{1..4}/minio

这里需要注意的是,要先把磁盘格式化挂载之后再创建minio的挂载目录

2. 下载 MinIO 二进制
#先下载wget根据
yum install -y wget
wget https://dl.min.io/server/minio/release/linux-amd64/minio
#授权
chmod +x minio
mv minio /usr/local/bin/
3. 创建专用用户
useradd -r minio -s /sbin/nologin
chown -R minio:minio /data/disk{1..4}/minio
4. 配置 systemd 服务(所有节点)

创建 /etc/systemd/system/minio.service

vim /etc/systemd/system/minio.service

[Unit]
Description=MinIO Distributed Object Storage
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target

[Service]
User=minio
Group=minio
Environment="MINIO_ROOT_USER=admin"
Environment="MINIO_ROOT_PASSWORD=Password@123"
ExecStart=/usr/local/bin/minio server \
  http://hd1/data/disk1/minio http://hd1/data/disk2/minio http://hd1/data/disk3/minio http://hd1/data/disk4/minio \
  http://hd2/data/disk1/minio http://hd2/data/disk2/minio http://hd2/data/disk3/minio http://hd2/data/disk4/minio \
  http://hd3/data/disk1/minio http://hd3/data/disk2/minio http://hd3/data/disk3/minio http://hd3/data/disk4/minio \
  http://hd4/data/disk1/minio http://hd4/data/disk2/minio http://hd4/data/disk3/minio http://hd4/data/disk4/minio \
  --console-address ":9001"
LimitNOFILE=65536
Type=simple
KillMode=process
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

⚠️ 注意:disk{1...4} 中的三个点是正确语法(有的文档写成两个点,但实际 MinIO 要求 {1...4}{1..4},官方文档使用 {1...4},表示展开为 disk1, disk2, disk3, disk4{1..4} 在 bash 中会被展开,但在 systemd 中需用 ... 避免歧义,此处建议使用 {1..4} 并配合 shell 解析,或直接写全路径。实际测试中 systemd 的 ExecStart 不支持大括号展开,应写完整路径或使用脚本包装。原文档此处有语法风险,我们在纠正中说明。)

5. 配置 hosts 解析(所有节点)
cat >> /etc/hosts <<EOF
192.168.1.111 hd1
192.168.1.112 hd2
192.168.1.113 hd3
192.168.1.114 hd4
EOF
6. 时间同步(所有节点)

生产环境建议指定内网自建的时间服务器

timedatectl set-ntp true
7. 启动服务
systemctl daemon-reload
systemctl enable minio.service
systemctl start minio.service

若之前启动失败,需要清理残留锁文件:

rm -rf /data/disk*/minio/.minio.sys
备选:脚本启动方式(不推荐生产)
vim /opt/minio-cluster.sh
#!/bin/bash
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=Password@123
/usr/local/bin/minio server \
  http://hd1/data/disk{1..4}/minio \
  http://hd2/data/disk{1..4}/minio \
  http://hd3/data/disk{1..4}/minio \
  http://hd4/data/disk{1..4}/minio \
  --console-address ":9001"
chmod +x /opt/minio-cluster.sh
nohup /opt/minio-cluster.sh > /var/log/minio.log 2>&1 &

3.2 MinIO 客户端(hd5)配置

在独立客户端主机(hd5)上安装 mc

mc就是MinIO Client(MinIO 客户端) 的缩写

wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
mv mc /usr/local/bin/

配置 hosts 并设置别名:

cat /etc/hosts

192.168.1.111 hd1
192.168.1.112 hd2
192.168.1.113 hd3
192.168.1.114 hd4
192.168.1.115 hd5

# 添加或者配置集群别名。这个命令作用就是设置一个别名,并且绑定用户名和密码
mc alias set mycluster http://hd1:9000 admin Password@123

验证连接:

mc admin info mycluster
踩坑记录

在执行这一步时,出现报错:
请添加图片描述
查看四台主机minio的状态,发现都正常运行。

查看日志,发现:
请添加图片描述
mismatching configuration(配置不匹配)

应该是我们service文件的问题,重新修改:

cat > /etc/systemd/system/minio.service << 'EOF'
[Unit]
Description=MinIO Distributed Object Storage
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target

[Service]
User=minio
Group=minio
Environment="MINIO_ROOT_USER=admin"
Environment="MINIO_ROOT_PASSWORD=Password@123"
ExecStart=/usr/local/bin/minio server \
  http://hd1/data/disk1/minio http://hd1/data/disk2/minio http://hd1/data/disk3/minio http://hd1/data/disk4/minio \
  http://hd2/data/disk1/minio http://hd2/data/disk2/minio http://hd2/data/disk3/minio http://hd2/data/disk4/minio \
  http://hd3/data/disk1/minio http://hd3/data/disk2/minio http://hd3/data/disk3/minio http://hd3/data/disk4/minio \
  http://hd4/data/disk1/minio http://hd4/data/disk2/minio http://hd4/data/disk3/minio http://hd4/data/disk4/minio \
  --console-address ":9001"
LimitNOFILE=65536
Type=simple
KillMode=process
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

然后重启minio即可。

但是查看日志,还是一直报错:
请添加图片描述
我明明把配置写对了,那为什么还找不到对应的目录?应该就是权限问题了。查看权限:

[root@hd1 ~]# ls -ld /data/disk1/minio
drwxr-xr-x 2 root root 6 814 12:24 /data/disk1/minio

确实是权限问题,权限应该给minio用户的。
我们修改属主(四台主机都进行):

[root@hd1 ~]# chown -R minio:minio /data/disk{1..4}

之后,在四台主机都重启minio

[root@hd1 ~]# systemctl restart minio

#再次查看日志,没有报错了
[root@hd1 ~]# journalctl -u minio -f
-- Logs begin at Fri 2026-08-14 11:21:53 CST. --
814 14:15:50 hd1 minio[11254]: ---------------------------
814 14:15:50 hd1 minio[11254]: MinIO Object Storage Server
814 14:15:50 hd1 minio[11254]: Copyright: 2015-2026 MinIO, Inc.
814 14:15:50 hd1 minio[11254]: License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
814 14:15:50 hd1 minio[11254]: Version: RELEASE.2025-09-07T16-13-09Z (go1.24.6 linux/amd64)
814 14:15:50 hd1 minio[11254]: API: http://192.168.1.111:9000  http://127.0.0.1:9000
814 14:15:50 hd1 minio[11254]: WebUI: http://192.168.1.111:9001 http://127.0.0.1:9001
814 14:15:50 hd1 minio[11254]: Docs: https://docs.min.io
814 14:15:50 hd1 minio[11254]: ---------------------------
814 14:15:50 hd1 minio[11254]: INFO: IAM load(startup) finished. (duration: 4.345741ms)

常用 mc 操作(hd5)

命令方面了解即可,实际生产中通常是用python脚本来连接minio

mc 的通用路径格式:
mc 命令 [参数] <别名/桶/对象路径>

# 开启命令补全
mc --autocompletion && bash

# 创建存储桶
mc mb mycluster/mybucket

# 上传文件
[root@hd5 ~]# mc cp 1.txt mycluster/mybucket
/root/1.txt:          4 B / 4 B ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 1.21 KiB/s 0s 
mc cp --recursive aaa/ mycluster/mybucket

# 下载
mc cp mycluster/mybucket/aaa/3.txt .

# 列出
mc ls mycluster/mybucket

# 删除
mc rm mycluster/mybucket/1.txt

# 查看占用空间
mc du mycluster/mybucket

# 删除桶(需为空,或加 --force)
mc rb mycluster/mybucket --force

# 桶内复制、跨桶复制、跨集群复制
mc cp mycluster/mybucket/source.txt mycluster/mybucket/copy.txt
mc cp mycluster/source-bucket/file.txt mycluster/dest-bucket/
mc cp myminio1/bucket/file.txt myminio2/bucket/
mc cp --recursive mycluster/mybucket mycluster/dest-bucket/

命令与参数速查表

操作类型 命令 常用参数 作用解析
Shell 增强 mc --autocompletion && bash 开启 mc 命令的 Tab 键自动补全功能(仅当前会话)。
管理桶 (Bucket) mc mb Make Bucket,在集群中创建一个新的存储桶。
mc rb --force Remove Bucket,删除一个存储桶。如果桶内有文件,必须加 --force 强制删除(慎用)。
管理对象 (Object) mc cp --recursive (或 -r) Copy,用于上传、下载或复制文件/文件夹。加 -r 代表递归处理整个文件夹。
mc ls List,列出桶或指定路径下的文件和文件夹列表。
mc rm Remove,删除指定的单个文件。注意:删除文件夹需加 --recursive
mc du Disk Usage,统计桶或文件夹占用的总存储空间大小。

需要注意命令中的路径问题,如果带 / ,只会上传目录中的内容;如果不带 / ,会直接把整个目录连带着里面的内容一起上传

–recursive 或 -r(递归参数):处理文件夹时必须加上。不加会报错
–force(强制删除参数):跳过确认提示,强制执行。


四、监控与运维

4.1 健康检查与信息查看(hd5)

# 检查集群自愈状态(建议业务低谷执行)
mc admin heal -r mycluster

# 查看集群整体信息(节点状态、磁盘使用等)
mc admin info mycluster

请添加图片描述
🟢 绿色 (Green):一切正常
表示数据是健康的,所有副本或纠删码分片都完整无误,无需任何修复操作。

🟡 黄色 (Yellow):部分数据需要修复
表示部分数据出现了不一致,比如某个对象在某个磁盘上的副本或分片丢失了。MinIO 会在后台自动修复这些问题,通常无需人工干预。

🔴 红色 (Red):存在严重问题
表示有磁盘处于离线(offline)、未格式化(unformatted)或损坏(faulty) 等状态,导致数据无法访问或已丢失,需要立即人工介入排查。

⚪️ 灰色 (Grey):状态不确定
表示状态无法被明确判定,通常是由于系统内部出现了一些“奇怪的情况”,比如网络抖动或临时性的读取错误。

Web 控制台

访问任意节点(非mc节点) IP 的 9001 端口(如 http://hd1:9001),使用 MINIO_ROOT_USER (默认账号)/ MINIO_ROOT_PASSWORD (默认密码)登录。

但我们在前面已经设置过用户名:admin,密码:Password@123,用这个登录即可

请添加图片描述

若未在启动命令中指定 --console-address,默认端口为 9001。


4.2 Prometheus 监控集成

方式一:通过 mc 直接获取指标

这个是minio的内置认证,适合偶尔看一眼。生产环境需要持续进行监控

mc admin prometheus metrics mycluster
方式二:配置 Prometheus 使用 Bearer Token(推荐)

通过普罗米修斯获取指标需要进行单独认证

生成 Token:

mc admin prometheus generate mycluster cluster

输出示例(包含 bearer_tokentargets):

scrape_configs:
- job_name: minio-job
#这个就是Token
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJwcm9tZXRoZXVzIiwic3ViIjoiYWRtaW4iLCJleHAiOjQ5MzYxNDQ5NTh9.MfHhiUtNi4jtUDsWnigRgVd2S2p97gSSPEtFivZWsiEszrQRmiZKGd23tB-K7OKO3UIs8IX0rpkeTV3_zSfuDA
  metrics_path: /minio/v2/metrics/cluster
  scheme: http
  static_configs:
  - targets: ['hd1:9000']

将此片段加入 Prometheus 配置文件即可。

测试 Token 是否有效:

curl -k -H "Authorization: Bearer <token>" http://hd1:9000/minio/v2/metrics/cluster
配置 Prometheus 的步骤

找到你 Prometheus 服务器的配置文件(通常是 prometheus.yml),在 scrape_configs: 部分下方,完整地粘贴上一步生成的token

合并后的配置文件看起来会像这样:

global:
  scrape_interval: 15s

scrape_configs:
  # 这里是你原有的其他抓取任务(如果有的话)
  # - job_name: 'node_exporter'
  #   ...

  # 以下是刚才从 mc 命令生成的 MinIO 抓取配置
  - job_name: minio-job
    bearer_token: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9...  #把你的token放这里
    metrics_path: /minio/v2/metrics/cluster 
    scheme: http
    static_configs:
    - targets: ['hd1:9000']

配置修改保存后,重启 Prometheus 服务,或通过 API 热加载配置使其生效

在 Prometheus 的 Web 界面(默认 http://:9090)中,进入 Status -> Targets 页面,找到 minio-job,确认其状态为 UP,就代表配置成功了

在生产环境中,官方强烈建议不要使用 admin 这类根账号的凭证来生成 Token,推荐创建专用监控账号,或者用专用账号生成配置

Grafana 仪表板
  • MinIO 集群仪表板 ID:13502
  • 节点主机监控(Node Exporter)常用仪表板:8919, 1860, 11074, 13978

4.3 日志管理

配置日志轮转(logrotate):

cat > /etc/logrotate.d/minio <<EOF
/var/log/minio.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 644 minio minio
}
EOF

这段配置的作用是:每天都会把昨天的日志打包成 minio.log-20260814.gz,只保留一个干净的新文件供今天写入;只保留最近 30 天的压缩备份,空日志不处理,并自动重建新日志文件,保持 minio 用户有写入权限

如果不做日志轮转,MinIO 会把所有日志都堆在同一个 minio.log 文件里。随着时间推移,这个文件可能会涨到几十 GB 甚至上百 GB,最终导致磁盘空间耗尽,也会增加排错的难度。

配合 systemd 的 StandardOutput=journal,也可以直接通过 journalctl -u minio 查看日志。


需要注意的是,我们之前配置service文件(通过 systemd 启动)的时候,指定了MinIO 默认把日志输出到 journald 系统日志中,而不是直接写入 /var/log/minio.log。所以如果想让我们的这个配置生效,就需要修改我们之前的service文件,在 ExecStart 这行的末尾(–console-address “:9001” 后面),加上一个参数:

ExecStart=/usr/local/bin/minio server \
  http://hd1/data/disk1/minio ... (此处省略完整路径) \
  --console-address ":9001" \
  --log-file /var/log/minio.log   #加上这个

然后解决权限问题,手动创建一个空日志文件,并把属主交给 minio 用户:

# 1. 创建一个空文件
touch /var/log/minio.log

# 2. 把文件的所有权交给 minio 用户
chown minio:minio /var/log/minio.log

注意:这个操作只需要做一次。以后 logrotate 轮转时,配置里的 create 644 minio minio 会保证新文件自动归 minio 所有,权限永久正确

然后重新加载并重启服务即可

systemctl daemon-reload
systemctl restart minio
systemctl status minio   # 确认没有报错,状态为 active (running)

在生产环境中,同时使用 journald 和日志文件是更稳健和推荐的做法。我们刚刚的配置就实现了这个。
此外,当我们定了 --log-file 参数后,默认会“区别对待”日志内容:写入日志文件的内容最全、最详细,写入 journald 的内容通常就只包含 启动时的初始化信息、致命错误(Fatal)、以及服务退出的信号等。

五、数据备份与恢复(桶复制)

使用 MinIO 的桶复制(Bucket Replication) 功能实现跨桶/跨集群的数据备份。

  1. 创建目标桶:
mc mb mycluster/backupbucket
  1. 启用版本控制(复制要求源和目标均开启版本控制):
mc version enable mycluster/mybucket
mc version enable mycluster/backupbucket
  1. 配置复制规则(同步删除操作):
mc replicate add mycluster/mybucket \
  --remote-bucket mycluster/backupbucket \
  --replicate "delete"

复制规则支持同步新增、删除、元数据变更等。注意,跨集群复制需要目标集群别名配置。


六、故障处理与案例

常见问题速查表

现象 可能原因 解决方案
节点无法加入集群 时间不同步 / 网络不通 / hosts 错误 检查 NTP、防火墙、/etc/hosts
磁盘空间不足 未设置配额 / 日志或旧版本堆积 设置桶配额,清理非当前版本
客户端连接慢 DNS 解析慢 使用 IP 地址或配置 hosts

案例1:节点服务故障后自动恢复

模拟故障:

# 在 hd3 停止服务
systemctl stop minio

在其他节点查看状态,会看到 hd3 离线。

[root@hd5 ~]# mc admin info mycluster
......
●  hd3:9000
   Uptime: offline
   Drives: 0/4 OK 
......

模拟磁盘数据损坏(hd3操作):

rm -rf /data/disk{1..4}/minio/*
mkdir /data/disk{1..4}/minio
chown -R minio.minio /data/disk{1..4}/minio
systemctl start minio

启动后,集群会自动从其他节点恢复数据(df -h 可观察到磁盘使用量逐渐增加)。

查看状态:

[root@hd5 ~]# mc admin info mycluster
......
●  hd3:9000
   Uptime: 41 seconds 
   Version: 2025-09-07T16:13:09Z
   Network: 4/4 OK 
   Drives: 4/4 OK 
   Pool: 1
......

重新启动 hd3 后,集群会自动同步数据(通过纠删码重建缺失的块)。


案例2:节点故障,用新节点替换损坏节点(IP 变更)

场景:hd3 节点永久损坏,用新机器(IP 192.168.1.130)替换损坏节点。

  1. 安装 MinIO 二进制并准备好相同数量的磁盘。
  2. 在所有节点的 /etc/hosts 中,将 hd3 的 IP 改为新 IP:
192.168.1.130 hd3
  1. 所有节点重启 MinIO 服务:
systemctl restart minio
  1. 集群会自动将数据同步到新节点(通过纠删码恢复)。

案例3:磁盘故障,更换磁盘

  1. 检查磁盘健康(smartctl):
smartctl -a /dev/sdX
  1. 尝试修复(XFS):
xfs_repair /dev/sdX   #逻辑修复,此硬盘必须是xfs系统
  1. 若无法修复,就是硬件的故障。更换同规格新磁盘,分区、格式化(XFS),挂载到原路径。
  2. 重新启动 MinIO 服务,纠删码会自动重建该磁盘上的数据块。

5.1 MinIO 扩容与缩容

扩容
  • 准备与现有集群规格相同(节点数、每节点磁盘数)的新服务器池(Server Pool)。
  • 在配置中增加新的 pool 的 endpoint,例如原有 4 节点,新增 4 节点,则启动命令变为包含 8 个节点 URL。
  • 修改所有节点的 systemd 服务文件,重启服务。
  • 注意:扩容后新数据会优先写入剩余空间最多的 pool,旧数据不会自动重平衡
缩容(不建议)
  • 缩容相当于重新部署集群(因为 MinIO 不支持从配置中移除节点后自动迁移数据)。
  • 需先备份所有数据,然后修改配置仅保留剩余节点,启动新集群,最后恢复数据。
  • 生产环境不建议缩容,除非数据量大幅减少且允许停机。

升级流程(滚动升级)

MinIO 支持滚动升级,但需逐节点进行

# 1. 查看当前版本
minio --version

# 2. 下载新版本
wget -O minio.new https://dl.min.io/server/minio/release/linux-amd64/minio

# 3. 在单个节点上停止服务(灰度发布)
systemctl stop minio

# 4. 备份旧的二进制文件(为应急回滚作准备),替换为新版本的
mv /usr/local/bin/minio /usr/local/bin/minio.old
mv minio.new /usr/local/bin/minio


# 5. 增加权限并启动该节点
chmod +x /usr/local/bin/minio
systemctl start minio

# 6. 观察 24 小时(监控日志和性能),若无问题,继续升级下一个节点

🔔 关键提醒

  • 生产环境务必使用 分布式部署(≥4节点)
  • 定期测试备份恢复流程
  • 监控磁盘使用率,超过 80% 需考虑扩容。
  • 重要操作前制定回滚计划

七、Kubernetes 中使用外部 MinIO 集群

本节介绍在 K8s 中接入外部已有 MinIO 集群的三种模式,以及详细操作。

架构选择

方案 描述 适用场景
方案一:直接 S3 API 访问 应用通过 S3 SDK 或 mc 直接操作 MinIO 90% 场景推荐,简单且原生高性能
方案二:S3FS/FUSE 挂载 使用 s3fs 将桶挂载为文件系统 兼容旧应用(需要 POSIX 文件接口)
方案三:CSI 驱动 使用 csi-s3 或 JuiceFS 提供 PVC 挂载 生产级文件接口,支持 RWX

7.1 创建访问凭证 Secret

# minio-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: miniosecret
  namespace: default
type: Opaque
stringData:
  accesskey: "admin"    #实际访问的用户名
  secretkey: "Password@123"   #实际访问的密码
  endpoint: "http://192.168.1.111:9000"   #minio集群的节点
  bucket: "mybucket"

应用:

kubectl apply -f minio-secret.yaml

方法1:使用 MinIO Client (mc) 的 Pod 测试

# pod-mc.yaml
apiVersion: v1
kind: Pod
metadata:
  name: minio-mc-test
spec:
  containers:
  - name: mc
    image: minio/mc
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh", "-c"]
    args:     #args作为command的参数
    - |
      # 配置 MinIO 别名
      mc alias set myminio http://192.168.1.111:9000 $MINIO_ACCESS_KEY $MINIO_SECRET_KEY;   
      mc mb myminio/mybucket --ignore-existing;
      #上传测试文件
      echo "Hello from Kubernetes!" > test.txt;
      mc cp test.txt myminio/mybucket/;
      # 列出文件
      echo "=== Files in bucket ===";
      mc ls myminio/mybucket;
      # 保持运行
      while true; do sleep 60; done
    env:
    - name: MINIO_ACCESS_KEY
      valueFrom:
        secretKeyRef:
          name: miniosecret
          key: accesskey
    - name: MINIO_SECRET_KEY
      valueFrom:
        secretKeyRef:
          name: miniosecret
          key: secretkey

加载镜像(如内网环境需提前下载):

docker load -i minio.mc.tar.gz   # 在各节点执行

部署 Pod:

kubectl apply -f pod-mc.yaml

测试:

kubectl exec -it minio-mc-test -- /bin/bash
bash-5.1# mc ls myminio/mybucket

方法2:使用 MinIO CSI 驱动(csi-s3)

CSI 驱动可以将 S3 桶作为 PVC 挂载到 Pod 中。

部署 CSI 驱动
git clone https://github.com/ctrox/csi-s3.git
cd csi-s3
kubectl apply -f deploy/kubernetes/
# 检查状态
kubectl get pods -n kube-system | grep s3-csi
配置 Secret 和 StorageClass
# csi-config.yaml
apiVersion: v1
kind: Secret
metadata:
  name: csi-s3-secret
stringData:
  accessKeyID: "admin"
  secretAccessKey: "Password@123"
  endpoint: "http://192.168.1.111:9000"
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-s3
provisioner: ch.ctrox.csi.s3-driver
parameters:
  mounter: rclone
  options: "allow_other,uid=1000,gid=1000"
  csi.storage.k8s.io/provisioner-secret-name: csi-s3-secret
  csi.storage.k8s.io/provisioner-secret-namespace: default
  csi.storage.k8s.io/node-publish-secret-name: csi-s3-secret
  csi.storage.k8s.io/node-publish-secret-namespace: default
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-s3-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: csi-s3
  resources:
    requests:
      storage: 5Gi
测试 Pod
# csi-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: csi-test-pod
spec:
  containers:
  - name: test
    image: alpine
    command: ["/bin/sh", "-c"]
    args:
    - |
      echo "Testing CSI volume mount...";
      ls -la /data;
      echo "Hello from CSI" > /data/test.txt;
      cat /data/test.txt;
      sleep 3600
    volumeMounts:
    - name: csi-volume
      mountPath: /data
  volumes:
  - name: csi-volume
    persistentVolumeClaim:
      claimName: csi-s3-pvc

验证:

kubectl get pods
kubectl logs csi-test-pod
kubectl exec -it csi-test-pod -- cat /data/test.txt

在 MinIO 侧检查文件是否生成:

mc ls myminio/mybucket

八、拓展:JuiceFS 分布式文件系统(基于 MinIO 作为数据存储)

8.1 JuiceFS 简介

JuiceFS 是一个为云环境设计的高性能开源分布式文件系统,将数据与元数据分离存储

  • 数据存储:对象存储(如 MinIO、AWS S3、阿里云 OSS)
  • 元数据引擎:关系型数据库或 KV 存储(Redis、PostgreSQL、MySQL、TiKV、SQLite 等)
  • 客户端:挂载到应用节点,提供 POSIX、HDFS、S3 和 Kubernetes CSI 接口

优势

  • 性价比高(利用低成本对象存储)
  • 兼容性强(POSIX、HDFS、S3、CSI)
  • 适合海量非结构化数据(AI 训练、大数据分析、备份归档)

8.2 JuiceFS 部署步骤(以 MinIO 为后端)

第一步:安装客户端(所有需要挂载的节点)
curl -sSL https://d.juicefs.com/install | sh -
# 或直接下载二进制到 /usr/local/bin/juicefs
第二步:准备后端资源
  • MinIO Bucket:已存在(mybucket)
  • Redis 元数据引擎:安装 Redis 并配置密码
yum install -y redis
systemctl start redis
vim /etc/redis.conf
# 修改 bind 0.0.0.0,设置 requirepass 123456
systemctl restart redis

设置环境变量(方便后续命令):

cat >> /etc/profile <<EOF
export ACCESS_KEY="admin"
export SECRET_KEY="Password@123"
export REDIS_PASSWORD="123456"
export REDIS_HOST="127.0.0.1"
export REDIS_PORT="6379"
export REDIS_DB="1"
EOF
source /etc/profile
第三步:格式化文件系统(创建 JuiceFS 元数据)
juicefs format \
  --storage minio \
  --bucket http://192.168.1.111:9000/mybucket \
  --access-key $ACCESS_KEY \
  --secret-key $SECRET_KEY \
  "redis://:$REDIS_PASSWORD@$REDIS_HOST:$REDIS_PORT/$REDIS_DB" \
  myjfs

此命令会在 MinIO 的 mybucket 中创建 JuiceFS 的数据目录,并在 Redis 中建立元数据。

第四步:挂载 JuiceFS
mkdir /mnt/jfs
juicefs mount -d "redis://:$REDIS_PASSWORD@$REDIS_HOST:$REDIS_PORT/$REDIS_DB" /mnt/jfs
df -h | grep jfs
第五步:性能调优(缓存)
mkdir -p /var/juicefs/cache
juicefs mount -d \
  --cache-size 1024 \         # 1GB 内存缓存
  --cache-dir /var/juicefs/cache \
  "redis://:$REDIS_PASSWORD@$REDIS_HOST:$REDIS_PORT/$REDIS_DB" /mnt/jfs
第六步:配置 systemd 开机自启
cat > /etc/systemd/system/juicefs.service <<EOF
[Unit]
Description=JuiceFS Mount Service
After=network-online.target

[Service]
Type=forking
Environment="REDIS_PASSWORD=123456"
ExecStart=/usr/local/bin/juicefs mount -d \
    "redis://:\${REDIS_PASSWORD}@127.0.0.1:6379/1" /mnt/jfs
ExecStop=/usr/local/bin/juicefs umount /mnt/jfs
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable juicefs
systemctl start juicefs
常用管理命令
# 查看文件系统状态
juicefs status "redis://:$REDIS_PASSWORD@127.0.0.1:6379/1"

# 查看配置
juicefs config "redis://:$REDIS_PASSWORD@127.0.0.1:6379/1"

# 手动垃圾回收
juicefs gc "redis://:$REDIS_PASSWORD@127.0.0.1:6379/1"

# 实时统计
juicefs stats /mnt/jfs

# 卸载
juicefs umount /mnt/jfs
Redis 优化建议
# /etc/redis.conf
maxmemory 2gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec

九、拓展:Kubernetes 使用 JuiceFS(hostPath 方式)

若只需在 K8s Pod 中简单使用 JuiceFS,可采用 hostPath 方式,无需部署 CSI。

步骤
  1. 在所有 K8s 节点上安装 JuiceFS 客户端并挂载到统一路径(如 /mnt/jfs):
scp /usr/local/bin/juicefs hd1:/usr/local/bin/
# 每个节点执行:
mkdir /mnt/jfs
juicefs mount -d "redis://:123456@192.168.1.115:6379/1" /mnt/jfs
  1. 在 Pod 定义中挂载 hostPath:
# jfs_pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: juicefs-app
spec:
  containers:
  - name: nginx
    image: nginx:latest
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: jfs-data
  volumes:
  - name: jfs-data
    hostPath:
      path: "/mnt/jfs"
  1. 部署并测试:
kubectl apply -f jfs_pod.yaml
kubectl exec -it juicefs-app -- cat /usr/share/nginx/html/index.html

十、复杂故障案例:MinIO 节点重启后 JuiceFS 间歇性写入失败

现象

JuiceFS 客户端出现间歇性 I/O Error,大文件上传超时,但 MinIO 控制台显示所有节点在线。

排查过程

  1. 检查 JuiceFS 日志(/var/log/juicefs.log),发现大量 flush timeoutslow request 警告。
  2. 使用 mc admin info 查看集群,发现某节点(node-3)重启时间与其他节点不同。
  3. 使用 mc admin heal 查看该节点状态,发现大量数据块处于 “自愈中(Healing)”

根本原因

MinIO 节点重启后,自动触发后台自愈(重建缺失或损坏的数据块),该过程占用大量磁盘 I/O 和网络带宽,导致该节点成为“亚健康”节点。当 JuiceFS 写入请求恰好被负载均衡分配到这个节点时,就会因超时而失败,呈现“间歇性”特征。

解决方案

  • 临时规避:等待自愈完成,或从负载均衡中暂时摘除该节点。
  • 长期根治:运维流程中加入“节点重启后必须监控 Healing 状态,待完成后再宣布服务恢复”。
  • 调整自愈策略:限制自愈带宽(需更复杂配置)。

教训

  • 集群“所有节点在线”不等于“所有节点健康”,自愈中的节点会影响上层业务。
  • 分布式系统问题常常跨层传导,需全链路监控。
  • 自动化机制(如自愈)在资源紧张时可能成为“背景噪音”,需建立应对策略。

附录:补充说明与提醒

📝 知识点补充

  1. 纠删码 EC 与节点数的关系

    • 若每节点有 4 盘,4 节点共 16 盘,则可配置 EC 8+4(总 12)或 10+6 等,但需保证数据块+校验块 ≤ 总盘数。需注意,MinIO 的 EC 设置是在 启动时由磁盘总数自动决定(默认 EC 为总盘数的一半,即 n/2 校验块),也可通过环境变量 MINIO_ERASURE_SET_DRIVE_COUNT 调整。文档未深入,我们补充此说明。
  2. Prometheus 监控的安全建议

    • 建议使用 HTTPS 和 Token 认证,生产环境应启用 TLS。
  3. JuiceFS 的垃圾回收

    • juicefs gc 可回收删除文件的空间,但需注意对性能的影响,建议在低峰期执行。
  4. Kubernetes CSI 驱动替代方案

    • 除了 csi-s3,还有 JuiceFS CSI 驱动(官方提供),更适合生产,文档中未提及,我们补充建议使用 JuiceFS CSI 以获得更完善的功能。
  5. MinIO 版本升级注意事项

    • 升级前务必阅读 Release Notes,检查是否有不兼容变更,尤其是 API 或配置参数。
  6. 关于 hostPath 挂载 JuiceFS 的风险

    • 所有 Pod 共享宿主机挂载点,存在安全隔离问题,建议仅用于测试。生产环境推荐 JuiceFS CSI。

📌 最终提醒

  • 所有密码、密钥应使用 Kubernetes Secret 或外部密钥管理,避免明文写在 YAML 中。
  • 定期演练故障恢复流程(节点宕机、磁盘损坏、数据损坏)。
  • 监控报警必须覆盖磁盘使用率、节点状态、自愈状态、客户端超时等指标。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐