Linux下的分布式Minio部署实践
分布式Minio部署可以将多块硬盘(位于相同机器或者不同机器)组成一个对象存储服务,避免单机环境下硬盘容量不足、单点故障等问题。
1. 简介
在当前的云计算和大数据时代,IT系统通常的设计理念都是无中心和分布式。Minio分布式模式可以帮助搭建一个高可靠、高可用、弹性扩展的对象存储服务。
分布式部署,minio拓扑为Multi-Node Multi-Drive (MNMD), 即多个节点,每个节点有多个磁盘。可用于如下场景:
-
企业级的高性能对象存储。
-
多节点/多硬盘级别的可靠性,可配置容忍最多 1/2 节点或硬盘的损失。
-
用于AI/ML、分布式查询、分析以及其他数据湖组件的主要存储。
-
可扩展到 PB 级别的工作负载,具备存储容量和性能的双重扩展能力。
2. minio的数据保护机制
2.1 Erasure Code(纠删码)
Minio 使用 Erasure Code 提供数据的冗余:
- 分布式 Minio 采用
Erasure Code
来防范多个节点宕机和位衰减。 - 分布式 Minio 至少需要 4 个节点(4台服务器),使用分布式 Minio 就会自动启用纠删码功能。
Erasure Code
是一种恢复丢失和损坏数据的数学算法, Minio 采用Reed-Solomon Code
将对象拆分成 N/2 数据 和 N/2 奇偶校验块。MinIO 在 N / 2 个数据盘 和 N / 2 个奇偶校验盘上分片对象。这就意味着如果是12块盘, 一个对象会被分成6个数据块、6个奇偶校验块, 可以丢失任意6块盘的情况下(不管其是存放的数据块还是奇偶校验块), 仍可以从剩下的盘中的数据进行读取和恢复。- Minio 纠删码是作用在对象级别,可以一次恢复一个对象,而RAID 是作用在卷级别,数据恢复时间很长。Minio 对每个对象单独编码,存储服务一经部署,通常情况下是不需要更换硬盘或者修复。
DataDrives :
纠删码中的数据盘,用来存储 Object 原始数据。ParityDrives:
纠删码中的校验盘,用来存储 Object 计算出来的校验数据。- Minio 纠删码的默认配置为
1 : 1
, 即数据盘 ( DataDrives )和 校验盘 ( ParityDrives ) 个数相同, 使用minio分布式部署最终真正可用的存储空间,只有所有磁盘总空间的一半大小。 - 一个
ErasureCode 组/ Sets
中有多个 Drive(DataDrives + ParityDrives), Minio 会先将一块 Block 按照 Drives 数量, 划分为多个小块, 这些小块在 Minio 中叫做 Shards。比如一个 Block 是 10MB, 而 Set 里有 16 个 Drive(8 DataDrives + 8 ParityDrives), 此时 Minio 会将 Block 按照 10 MB / 8 DataDrives 的方式,将数据划分到 8 个 Data Shards,并额外再创建 8 个 空 Shards,用来存储编码后的冗余数据。 - 接着 Minio 就会对
Data Shards
进行纠删码编码, 并将编码后的冗余数据存储到前面创建的 8 个空 Shards 中, 也就是parity shards
中。
2.2 数据保护
分布式 MinIO 使用 Erasure Code
提供针对 多个节点/驱动器 故障 和 Bit Rot
保护。
- 由于分布式 MinIO 所需的 最小磁盘为 4(与擦除编码所需的最小磁盘相同), 因此在您启动分布式 MinIO 时,擦除代码会自动启动。
- 因此 只要
m / 2
个服务器 或m * n / 2
个或更多磁盘在线, 具有 m个服务器 和 n个磁盘 的分布式 MinIO 设置将使您的数据安全。 ( M 表示 服务器总数, N 表示 数据库盘 总数 ) Erasure Code
是用来保证 Object 的每个 Block 的数据正确和可恢复的, 而Bitrot
技术是用来检验磁盘数据的正确性的。Erasure Code
技术比较复杂, 但是Bitrot
技术就比较简单了。本质就是在写数据之前, 先计算好数据的 hash, 然后将 hash 先写入磁盘, 再写入需要存储的数据。这样读取数据时,就可以通过重新计算 hash,和原始写入的 hash进行一致性比较,来判断数据是否有损坏。- 上传文件时,Minio 不是直接上传到 object 在磁盘的最终存储目录的,而是先写到一个临时目录,等所有数据都写到临时目录后,Minio 才会进行 rename 操作,将 object 数据存储到最终存储目录。
3. 部署分布式Minio
3.1 环境准备
机器准备
hostname | os | 配置 | ip | disk |
---|---|---|---|---|
minioserver1 | centos7.9 | 8C32G | 192.168.1.10 | vdb,vdc,vdd,vde |
minioserver2 | centos7.9 | 8C32G | 192.168.1.11 | vdb,vdc,vdd,vde |
minioserver3 | centos7.9 | 8C32G | 192.168.1.12 | vdb,vdc,vdd,vde |
minioserver4 | centos7.9 | 8C32G | 192.168.1.13 | vdb,vdc,vdd,vde |
- 各节点按照上表信息完成基础配置。
- 各节点配置ntp服务,确保时间同步。
- 各节点关闭防火墙或者放行9000和9001端口:
bash
firewall-cmd --permanent --zone=public --add-port=9000-9001/tcp
firewall-cmd --reload
磁盘和挂载点准备
本文以4节点的分布式Minio为例,每个节点4块盘为例。将4块盘分别挂载到4个节点上,并在每个节点上创建目录。
- 格式化磁盘并配置挂载点
bash
]# cat disk-mount.sh
#!/bin/bash
mkfs.xfs /dev/vdb -L DISK1
mkfs.xfs /dev/vdc -L DISK2
mkfs.xfs /dev/vdd -L DISK3
mkfs.xfs /dev/vde -L DISK4
mkdir -p /data/minio/data0{1..4}
cat >> /etc/fstab <<-EOF
LABEL=DISK1 /data/minio/data01 xfs defaults,noatime 0 2
LABEL=DISK2 /data/minio/data02 xfs defaults,noatime 0 2
LABEL=DISK3 /data/minio/data03 xfs defaults,noatime 0 2
LABEL=DISK4 /data/minio/data04 xfs defaults,noatime 0 2
EOF
mount -a
在4个节点依次执行上述脚本sh disk-mount.sh
,确保硬盘挂载到相应目录:
bash
]# lsblk -f
NAME FSTYPE LABEL UUID MOUNTPOINT
sr0 iso9660 config-2 2024-09-18-14-22-17-00
vda
└─vda1 xfs a8486478-6076-4541-bfc7-8d945834d5a0 /
vdb xfs DISK1 c4f4442a-f805-4404-ab5b-2e27b46a2b75 /data/minio/data01
vdc xfs DISK2 dba519e6-7a01-4eaf-a3cc-3d2b2a23a39a /data/minio/data02
vdd xfs DISK3 369b7795-510f-4f50-b314-7fc3b533a36b /data/minio/data03
vde xfs DISK4 360ccb99-029a-496d-9f2c-22d58cb51206 /data/minio/data04
注意:
确保用于minio的数据盘是干净无数据的。
- 禁用XFS Retry On Error
MinIO 强烈建议通过 max_retries
配置禁用以下错误类别的重试行为:
- EIO 错误:读写时发生的输入/输出错误
- ENOSPC 错误:设备上空间不足
- 默认:所有其他错误
默认的 max_retries
设置通常会让文件系统在错误发生时无限期地重试,而不是传播错误。MinIO 可以正确处理 XFS 错误,因此重试行为只会引入不必要的延迟或性能下降。
以下脚本会遍历指定挂载路径下的所有硬盘,并将 XFS 的 max_retries
设置为 0,或设置为"在发生错误时立即失败",以符合推荐的错误类别。该脚本会忽略未挂载的硬盘(无论是手动挂载还是通过 /etc/fstab
)。请根据您的 MinIO 硬盘修改 /data/minio/data
行以匹配使用的模式。
bash
#!/bin/bash
for i in $(df -h | grep /data/minio/data | awk '{ print $1 }'); do
mountPath="$(df -h | grep $i | awk '{ print $6 }')"
deviceName="$(basename $i)"
echo "Modifying xfs max_retries and retry_timeout_seconds for drive $i mounted at $mountPath"
echo 0 > /sys/fs/xfs/$deviceName/error/metadata/EIO/max_retries
echo 0 > /sys/fs/xfs/$deviceName/error/metadata/ENOSPC/max_retries
echo 0 > /sys/fs/xfs/$deviceName/error/metadata/default/max_retries
done
exit 0
将上述脚本保存为 /opt/minio/xfs-retry-settings.sh
,添加执行权限:chmod +x /opt/minio/xfs-retry-settings.sh
。并在所有 MinIO 节点上运行此脚本,以禁用 XFS 的错误重试功能。
因为 Linux 操作系统通常在重启不会保留这些更改,可以使用带有 @reboot
时间参数的 cron
作业,在节点重启时运行上述脚本,以确保所有硬盘禁用错误重试功能。使用 crontab -e
创建以下任务,并根据每个节点的实际情况修改脚本路径:
bash
@reboot /opt/minio/xfs-retry-settings.sh
说明:
官方建议使用本地存储类型(DAS),同时文件系统使用xfs,磁盘使用的存储介质和容量建议一致。
关于minio部署的硬件要求可以参考:https://min.io/docs/minio/linux/operations/checklists.html
minio软件准备
在每个节点上安装minio:
bash
# 在节点的/opt目录下载安装minio软件
mkdir -p /opt/minio
mv minio /opt/minio/
cd /opt/minio/
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
3.2 启动分布式Minio
以下两种方式任选一种,用于配置启动分布式Minio服务:
通过后台运行命令启动
在4个节点下依次创建并配置开机自动运行如下脚本:
bash
# minio文件和运行脚本
]# pwd
/opt/minio
]# ls
minio minio-cluster-start.sh
# 配置脚本开机运行
]# chmod +x minio-cluster-start.sh
]# echo "/opt/minio/minio-cluster-start.sh" >> /etc/rc.d/rc.local
]# chmod +x /etc/rc.d/rc.local
其中minio-cluster-start.sh
脚本内容如下:
bash
#!/bin/bash
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=minioadmin
nohup /opt/minio/minio server --address :9000 --console-address :9001 \
http://192.168.1.10/data/minio/data01 http://192.168.1.10/data/minio/data02 http://192.168.1.10/data/minio/data03 http://192.168.1.10/data/minio/data04 \
http://192.168.1.11/data/minio/data01 http://192.168.1.11/data/minio/data02 http://192.168.1.11/data/minio/data03 http://192.168.1.11/data/minio/data04 \
http://192.168.1.12/data/minio/data01 http://192.168.1.12/data/minio/data02 http://192.168.1.12/data/minio/data03 http://192.168.1.12/data/minio/data04 \
http://192.168.1.13/data/minio/data01 http://192.168.1.13/data/minio/data02 http://192.168.1.13/data/minio/data03 http://192.168.1.13/data/minio/data04 \
> /var/log/minio.log 2>&1 &
配置系统服务管理
也可以将minio配置为系统服务,实现systemctl
统一管理。
bash
# minio文件和运行脚本
]# pwd
/opt/minio
]# ls
minio run.sh
]# chmod +x run.sh
其中run.sh
脚本内容如下:
bash
#!/bin/bash
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=minioadmin
/opt/minio/minio server --address :9000 --console-address :9001 \
http://192.168.1.10/data/minio/data01 http://192.168.1.10/data/minio/data02 http://192.168.1.10/data/minio/data03 http://192.168.1.10/data/minio/data04 \
http://192.168.1.11/data/minio/data01 http://192.168.1.11/data/minio/data02 http://192.168.1.11/data/minio/data03 http://192.168.1.11/data/minio/data04 \
http://192.168.1.12/data/minio/data01 http://192.168.1.12/data/minio/data02 http://192.168.1.12/data/minio/data03 http://192.168.1.12/data/minio/data04 \
http://192.168.1.13/data/minio/data01 http://192.168.1.13/data/minio/data02 http://192.168.1.13/data/minio/data03 http://192.168.1.13/data/minio/data04
在3个节点上创建minio.service文件:
bash
# minio.service文件内容
]# cat > /usr/lib/systemd/system/minio.service <<-EOF
[Unit]
Description=Minio service
Documentation=https://docs.minio.io/
[Service]
WorkingDirectory=/opt/minio/
ExecStart=/opt/minio/run.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targe
EOF
# 配置minio服务启动
]# systemctl daemon-reload
]# systemctl enable minio && systemctl start minio
3.3 访问minio console
此时通过任意节点的ip和端口(9001)访问minio console
,默认用户名和密码为admin/minioadmin
。
4. 配置nginx代理minio集群
通过nginx反向代理4台minio节点,统一访问入口并做负载均衡。这里使用两台机器搭建高可用的nginx集群。
hostname | ip | 操作系统 | 软件版本 |
---|---|---|---|
nginx1 | 192.168.1.2 | centos7.9 | keepalived-1.3.5-19.el7.x86_64; nginx-1.20.1-10.el7.x86_64 |
nginx2 | 192.168.1.9 | centos7.9 | keepalived-1.3.5-19.el7.x86_64; nginx-1.20.1-10.el7.x86_64 |
说明:
Minio官方建议的LB方案为nginx和Haproxy,本文使用nginx做为LB。
4.1 安装keepalived和nginx
bash
]# yum -y install keepalived nginx
配置keepalived
主节点keepalived配置。编辑 /etc/keepalived/keepalived.conf
,配置如下:
bash
global_defs {
router_id nginx1
}
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh" # 指定检查脚本路径
interval 2 # 每2秒检查一次
weight -10 # 如果Nginx挂掉,优先级减10。确保降低优先级后低于slave节点优先级
fall 10
rise 2
}
vrrp_instance VI_1 {
state MASTER # 主节点为 MASTER,备节点为 BACKUP
interface eth0 # 绑定的网卡接口
virtual_router_id 51 # VRID 相同,表示同一个虚拟路由器
priority 100 # 优先级,主节点要比备节点高
advert_int 1 # 检测时间间隔
authentication {
auth_type PASS # 认证方式
auth_pass 1111 # 认证密码
}
unicast_src_ip 192.168.1.2 #配置单播的源地址,即本机地址
unicast_peer { # 默认为组播模式,此处配置单播
192.168.1.9 # 备节点的IP地址,如果由多个备节点,可以配置多个,每行一个
}
virtual_ipaddress {
192.168.1.14 # 虚拟IP地址 (VIP)
}
track_script {
chk_nginx # 跟踪Nginx检查脚本
}
}
备节点keepalived配置。编辑 /etc/keepalived/keepalived.conf
,配置如下:
bash
global_defs {
router_id nginx2
}
vrrp_instance VI_1 {
state BACKUP # 备节点为 BACKUP
interface eth0
virtual_router_id 51 # VRID 相同
priority 99 # 优先级,备节点要比主节点低
advert_int 1
authentication {
auth_type PASS
auth_pass 1111 # 认证密码相同
}
unicast_src_ip 192.168.1.9 #配置单播的源地址,即本机地址
unicast_peer { # 默认为组播模式,此处配置单播
192.168.1.2 # 备节点的IP地址,如果由多个备节点,可以配置多个,每行一个
}
virtual_ipaddress {
192.168.1.14 # 虚拟IP地址 (VIP)
}
track_script {
chk_nginx # 跟踪Nginx检查脚本
}
}
配置健康检查脚本:
在每台nginx节点上创建一个检查脚本,例如/etc/keepalived/check_nginx.sh
,内容如下:
bash
#!/bin/bash
if ! pidof nginx > /dev/null; then
exit 1 # Nginx 没有运行,返回非 0 值表示失败
fi
exit 0 # Nginx 运行正常
该脚本通过pidof命令检查Nginx进程是否正常运行,如果nginx进程不存在则返回状态码非0,这样Keepalived可以根据返回状态做出决定。
添加脚本的执行权限:
bash
]# sudo chmod +x /etc/keepalived/check_nginx.sh
配置nginx
通过使用 nginx 代理,在主节点和备节点上分别配置nginx,编辑 /etc/nginx/nginx.conf
,配置如下:
bash
upstream minio-server {
least_conn;
server 192.168.1.10:9001 weight=25 max_fails=2 fail_timeout=30s;
server 192.168.1.11:9001 weight=25 max_fails=2 fail_timeout=30s;
server 192.168.1.12:9001 weight=25 max_fails=2 fail_timeout=30s;
server 192.168.1.13:9001 weight=25 max_fails=2 fail_timeout=30s;
}
server{
listen 80;
listen [::]:80;
server_name localhost;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_body_buffer_size 10M;
client_max_body_size 10G;
proxy_buffers 1024 4k;
proxy_connect_timeout 300;
proxy_next_upstream error timeout http_404;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://minio-server; # This uses the upstream directive definition to load balance
}
}
其中主要是 upstream
及 proxy_pass
的配置,配置到nginx.conf
中的http块中。
启动配置服务
bash
# keepalived服务
]# systemctl start keepalived
]# systemctl enable keepalived
# nginx服务
]# systemctl start nginx
]# systemctl enable nginx
4.2 验证
访问 [http://${VIP}:80](http://$%7BVIP%7D:80) 即可访问minio console。
4.3 FAQ
- **问题详情:**配置nginx代理后,通过nginx访问minio。在浏览桶中的列表的时候,始终在loading,无法加载桶内的文件列表。通过浏览器F12调试界面查看有很多的WebSocket connection的错误。
解决方式:
在nginx配置中,确保添加如下参数:
bash
location / {
...
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
...
}
5. 参考资料
- https://min.io/docs/minio/linux/operations/install-deploy-manage/deploy-minio-multi-node-multi-drive.html
- https://min.io/docs/minio/linux/integrations/setup-nginx-proxy-with-minio.html
- https://min.io/docs/minio/linux/operations/checklists/hardware.html#minio-hardware-checklist-memory
- Minio Cluster 详解 )