分布式文件系统 Minio

2024-08-07 12:53:13 浏览数 (2)

1. 分布式文件系统应用场景

互联网海量非结构化数据的存储需求

  • 电商网站:海量商品图片
  • 视频网站:海量视频文件
  • 网盘:海量文件
  • 社交网站:海量图片

1.1 Minio 介绍

Minio 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容 AWS S3 云存储服务接口,非常适合存储大容量非结构化的数据,如图片、视频、日志文件、备份数据等,而一个对象文件可以是任意大小,从几 kb 到最大 5T 不等。

Minio 是一个非常轻量的服务,可以很简单的和其他应用结合。

官网:https://minio.io

中文官网:https://www.minio.org.cn

对象存储服务(OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件,容量和处理能力弹性扩展。

在中国:阿里巴巴、腾讯、百度、中国联通、华为、中国移动等9000多家企业都在使用 Minio。

1.2 Minio 优点

  • 部署简单:一个二进制文件即是一切,还支持各种平台;
  • 支持海量存储:支持单个对象最大 5TB;
  • 兼容Amazon S3 接口
  • 低冗余且磁盘损坏高容忍:标准且最高的数据冗余系数为2(即存储一个 1M 的数据对象,实际占用的磁盘空间为 2M),但在任意 n/2 块磁盘损坏的情况下依然可以读取数据(n 为一个纠删码集合中的磁盘数量)并且这种损坏恢复是基于单个对象的,而不是基于整个存储卷的
  • 读写性能优异

1.3 Minio 的基本概念

  • Oject:存储到 minio 的基本对象
  • Bucket:用来存储 Object 的逻辑空间,每个 bucket 之间的数据是相互隔离的
  • Drive:存储数据的磁盘,在 minio 启动时,以参数的方式传入
  • Set:一组 Drive 的集合,分布式部署根据集群规模自动划分一个或多个 Set,每个 Set 中的 Drive 分布在不同的位置,一个对象存储在一个 Set 上。
    • 一个对象存储在一个 Set 上
    • 一个集群划分为多个 Set
    • 一个 Set 包含的 Drive 数量是固定的,默认由系统根据集群规模自动计算得出
    • 一个 Set 中的 Drive 尽可能分布在不同的节点上

1.4 纠删码 EC

Minio 使用纠删码机制来保证高可靠性,使用 highwayhash 来处理数据损坏(Bit Rot Protection)。简单来说就是通过数学计算,把丢失的数据进行还原,它可以将 n 份原始数据,增加 m 份数据,并能通过 n m 份中的任意 n 份数据,还原为原始数据,即如果有任意小于等于 m 份的数据失效,仍然能通过剩下的数据还原出来。

1.5 存储形式

文件对象上传到 minio,会在对应的数据存储磁盘中,以 Bucket 名称为目录名,文件名称为下一级目录,文件名下是 part.1 和 xl.meta,前者是编码数据块及校验块,后者是元数据文件

1.6 存储方案

2. Minio 环境搭建

官方文档:https://docs.min.io/docs/

中文文档:http://docs.minio.org.cn/docs/

代码语言:javascript复制
Minio 默认9000端口,在配置文件中加入 -address "127.0.0.1:9029" 可更改端口;
MINIO_ACCESS_KEY:用户名,长度最小为5个字符
MINIO_SECRET_KEY:密码,不能设置过于简单,长度最小为8个字符
-config-dir:指定集群配置文件目录
-address:api的端口,默认是9000
--console-address:web端口,默认随机,可以通过 --console-address ":PORT" 来指定静态端口

2.1 单机部署

minio server 的 standalone 模式,即要管理的磁盘都在 host 本地,该启动模式一般用于实验环境学习使用,在 standalone 模式下,还可以分为 non-erasure code mode 和 erasure code mode。

non-erasure code mode

​ 在此启动模式下,对于每一份对象数据,minio 直接在 data 目录下存储这份数据,不会建立副本,也不会启用纠删码机制,因此,这种模式无论是服务实例还是磁盘都是单点,无任何高可用保障,磁盘损坏就表示数据丢失。

erasure code mode

​ 此模式为 minio server 实例传入多个本地磁盘参数,一旦遇到多于一个磁盘参数,minio server 会自动启用 erasure code mode。erasure code 对磁盘的个数是有要求的,如不满足要求,实例启动将失败。erasure code启用后,要求传给 minio server 的磁盘个数至少为 4 个。

基于Centos 7 部署
代码语言:javascript复制
# 默认用户名和密码:minioadmin/minioadmin,修改默认用户名和密码:
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=123456789

# 默认的配置目录是${HOME}/.minio,可以通过 --config-dir 命令自定义配置目录:
./minio server --config-dir /mnt/config /mnt/data

# 控制台监听端口是动态生成的,可以通过 --console-address ":PORT" 来指定静态端口
./minio server --console-address ":50000" /mnt/data
基于 Docker 部署
代码语言:javascript复制
# 启动后,浏览器无法访问控制台,因为没有对外暴露控制台端口
docker run -p 9000:9000 --name minio -v /mnt/data:/data -v /mnt/config:/root/.minio minio/minio server /data

# 对外暴露控制台端口,通过 --console-address ":50000" 指定控制台端口,默认用户名和密码:minioadmin/minioadmin
docker run -d -p 9000:9000 -p 50000:50000 --name minio -v /mnt/data:/data -v /mnt/config:/root/.minio minio/minio server --console-address ":50000" /data

# 自定义用户名密码
docker run -d -p 9000:9000 -p 50000:50000 --name minio -e "MINIO_ROOT_USER=admin" -e "MINIO_ROOT_PASSWORD=123456789" -v /mnt/data:/data -v /mnt/config:/root/.minio minio/minio server --console-address ":50000" /data
纠删码模式

​ minio 使用纠删码 erasure code 和校验和 check sum 来保护数据免受硬件故障和数据损坏,即使丢失一半数量(n/2)的硬盘,仍然可以恢复数据。

​ 纠删码是一种恢复丢失和损坏数据的数学算法,Minio 采用 Reed-Solomon code 将对象拆分成 n/2 数据和 n/2 奇偶检验块,这就意味着如果是 12 块盘,一个对象会被分成6个数据块、6个奇偶校验块,可以丢失任意6块盘(不管是存放的数据块还是奇偶校验块),仍可以从剩下的盘中的数据进行恢复。

使用 Minio Docker 镜像,在8块盘中启动 Minio 服务:

代码语言:javascript复制
docker run -d -p 9000:9000 -p 50000:50000 --name minio 
-e "MINIO_ROOT_USER=admin" 
-e "MINIO_ROOT_PASSWORD=123456789" 
-v /mnt/data1:/data1 
-v /mnt/data2:/data2 
-v /mnt/data3:/data3 
-v /mnt/data4:/data4 
-v /mnt/data5:/data5 
-v /mnt/data6:/data6 
-v /mnt/data7:/data7 
-v /mnt/data8:/data8 
minio/minio server /data{1...8} --console-address ":50000"

2.2 分布式集群部署

​ 分布式 minio 可以让你将多块磁盘(可以在不同的机器上)组成一个对象存储服务,由于硬盘分布在不同的节点上,分布式 minio 避免了单点故障。

分布式 Minio 优势
数据保护

分布式 Minio 采用纠删码来防范多个节点宕机和位衰减 bit rot。

分布式 Minio 至少需要4块硬盘,使用分布式 Minio 自动引入了纠删码功能。

高可用

单机 Minio 服务存在单点故障,如果一个有 N 块硬盘的分布式 Minio,只要有 N/2 硬盘在线,数据就是安全的,不过需要至少 N/2 1 块硬盘来创建新的对象。

如:一个16节点的 Minio 集群,每个节点16块硬盘,就算有8个节点宕机,这个集群仍然是可读的,不过需要9个节点才能写数据。

一致性

Minio 在分布式和单机模式下,所有读写操作都严格遵守 read-after-write 一致性模型。

部署分布式 Minio

​ 运行一个分布式 Minio 实例,只需要把硬盘位置做为参数传给 Minio server 命令即可,然后,需要在所有其他节点运行同样的命令。

  • 分布式 Minio 里所有的节点都需要有同样的 access 秘钥和 secret 秘钥,这样这些节点才能建立联接,新版本使用 MINIO_ROOT_USER 和 MINIO_ROOT_PASSWORD。
  • 分布式 Minio 使用的磁盘必须是干净的,里面没有任何数据。
  • 分布式 Minio 里的节点时间相差不能超过3秒。
8个节点,每个节点1块硬盘

​ 启动分布式 Minio 实例,8个节点,每个节点1块硬盘,需要在8个节点上都运行下面的命令:

代码语言:javascript复制
mkdir -p /opt/minio/logs				# 创建日志存储目录
mkdir -p /opt/minio/data/data			# 在所有节点上创建存储目录
mkdir -p /etc/minio					   # 创建配置目录


# 在所有节点上都执行该文件,即以分布式的方式启动 minio
# 编写启动脚本 (/opt/minio/run.sh)
#/bin/bash
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=admin123456
minio server --address 0.0.0.0:9000 --console-address 0.0.0.0:9001 --config-dir /etc/minio 
	http://192.168.1.10/opt/minio/data/data 
	http://192.168.1.11/opt/minio/data/data 
	http://192.168.1.12/opt/minio/data/data 
	http://192.168.1.13/opt/minio/data/data 
	http://192.168.1.14/opt/minio/data/data 
	http://192.168.1.15/opt/minio/data/data 
	http://192.168.1.16/opt/minio/data/data 
	http://192.168.1.17/opt/minio/data/data >> /opt/minio/logs/minio_server.log
	
# 启动服务
sh /opt/minio/run.sh

# 通过systemctl启停服务
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.target
EOF
4个节点,每个节点4块硬盘

​ 启动分布式 Minio 实例,4个节点,每个节点4块硬盘,需要在4个节点上都运行下面的命令:

代码语言:javascript复制
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=123456
minio server --address ":9000" --console-address "9001" 
	http://192.168.1.10/data1	http://192.168.1.10/data2 
    http://192.168.1.10/data3	http://192.168.1.10/data4 
    http://192.168.1.11/data1	http://192.168.1.11/data2 
    http://192.168.1.11/data3	http://192.168.1.11/data4 
    http://192.168.1.12/data1	http://192.168.1.12/data2  
    http://192.168.1.12/data3	http://192.168.1.12/data4 
    http://192.168.1.13/data1	http://192.168.1.13/data2 
    http://192.168.1.13/data3	http://192.168.1.13/data4
扩展现有的分布式集群

例如我们是通过分区的方式启动 Minio 集群,命令如下:

代码语言:javascript复制
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=123456789
minio server http://host{1...32}/data{1...32}

Minio 支持通过命令,指定新的集群来扩展现有集群(纠删码模式),命令如下:

代码语言:javascript复制
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=123456789
minio server http://host{1...32}/data{1...32} http://host{33...64}/data{1...32}

现在整个集群就扩展了1024块磁盘,总磁盘变成了2048个,新的对象上传请求会自动分配到最少使用的集群上,通过以上扩展策略,就可以按需要扩展集群。重新配置后重启集群,会立即在集群中生效,对现有集群无影响。如上命令中,可以把原来的集群看作是一个区,新增的集群看作另一个区,新对象按每个区域中的可用空间比例放置在区域中,在每个区域内,基于确定性哈希算法确定位置。

说明:添加的每个区域必须具有与原始区域相同的磁盘数量大小,以便维持相同的数据冗余。例如,第一个区有8块磁盘,可以将集群扩展为16个、32个或1024个磁盘的区域,只需要确保部署的 SLA 是原始区域的倍数即可。

基于 docker-compose部署

​ 4个节点,每个节点一块硬盘

代码语言:javascript复制
version: "3.7"
services:
  minio:
    image: minio/minio:RELEASE.2021-11-09T03-21-45Z
    command: server --address ":9001" --console-address ":50001" http://minio0{1...4}/data
    restart: always
    hostname: minio01		# 每个节点修改成不同的名字
    container_name: minio01	# 每个节点修改成不同的名字
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: 123456789
      TZ: Asia/Shanghai
      MINIO_PROMETHEUS_AUTH_TYPE: public
      MINIO_PROMETHEUS_JOB_ID: minio-job
    extra_hosts:
      - "minio01:192.168.1.10"
      - "minio02:192.168.1.11"
      - "minio03:192.168.1.12"
      - "minio04:192.168.1.13"
    ports:
      - 9001:9001
      - 50001:50001
    volumes:
      - /data:/data
    network_mode: "host"
基于 Nginx 实现负载均衡
代码语言:javascript复制
upstream minio_api {
    server 192.168.1.10:9001;
    server 192.168.1.11:9001;
    server 192.168.1.12:9001;
    server 192.168.1.13:9001;
}

upstream minio_console {
	server 192.168.1.10:50001;
	server 192.168.1.11:50001;
	server 192.168.1.12:50001;
	server 192.168.1.13:50001;
}

server {
    listen	19001;
    server_name localhost;
    
    ignore_invalid_headers off;
    client_max_body_size 0;
    proxy_buffering off;
    
    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;
        proxy_connect_timeout 300;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;
        proxy_ignore_client_abort on;
        proxy_pass http://minio_api;
    }
}

server {
    listen	15000;
    server_name localhost;
    
    ignore_invalid_headers off;
    client_max_body_size 0;
    proxy_buffering off;
    
    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;
        proxy_connect_timeout 300;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;
        proxy_ignore_client_abort on;
        proxy_pass http://minio_console;
    }
}

2.3 S3客户端使用

Minio Client(mc)

命令

代码语言:javascript复制
ls			# 列出文件或目录
mb			# 创建一个桶
cat			# 显示文件和对象内容
pipe		# 将一个 STDIN 重定向到一个对象或文件或 STDOUT
share		# 生成用于共享的 URL
cp			# 拷贝文件或对象
mirror		# 给桶做镜像
find		# 查找文件
diff		# 比较两个文件或桶的差异
rm			# 删除文件或对象
events		# 管理对象通知
watch		# 监视文件或对象事件
policy		# 管理访问策略
config		# 管理 mc 配置文件
update		# 检查软件更新
version		# 查看版本信息

配置 mc

代码语言:javascript复制
mc 将所有的配置信息都存储在 ~/.mc/config.json 文件中

# 查看 mc host 配置
mc config host ls

# 添加 minio 服务
mc config host add minio-server http://192.168.1.10:9001 admin 123456789		# 配置 api 接口

# 删除 host
mc config host remove minio-server

上传下载文件

代码语言:javascript复制
# 查询所有的桶
mc ls minio-server

# 下载文件
mc cp minio-server/test/1.jpg /tmp

# 删除文件
mc rm minio-server/test/1.jpg 

# 上传文件
mc cp 2.jpg minio-server/test/

Bucket 管理

代码语言:javascript复制
# 创建 Bucket
mc mb minio-server/bucket01

# 删除 Bucket(如果 Bucket 不为空,使用 --force 强制删除)
mc rb --force minio-server/bucket01

mc admin 使用

代码语言:javascript复制
mc 提供了 admin 子命令来对 minio 部署执行管理任务

service			# 管理 minio 服务
update			# 更新 minio 服务
info			# 显示 minio 服务器信息
user			# 管理用户
group			# 管理组
policy			# 管理策略
config			# 管理 minio 服务器配置
heal			# 修复 minio 服务器上的磁盘、桶或对象
profile
top				# 查看 minio 的统计信息
trace			# 显示 minio 的http 跟踪信息
console			# 显示 minio 控制台日志
prometheus		# 管理 prometheus 配置
kms

用户管理

代码语言:javascript复制
# 创建用户
mc admin user add minio-server test01
mc admin user add minio-server test02 123456789

# 查看用户
mc admin user list minio-server

# 禁用用户
mc admin user disable minio-server test01

# 启用用户
mc admin user enable minio-server test01

# 查看用户信息
mc admin user info minio-server test01

# 删除用户
mc admin user remove minio-server test01

策略管理

代码语言:javascript复制
policy 命令用于添加、删除、列出策略

# 列出 minio 上的所有固定策略
mc admin policy list minio-server

# 查看 policy 信息
mc admin policy info minio-server readwrite
s3cmd 的使用

下载

代码语言:javascript复制
wget https://github.com/s3tools/s3cmd/releases/download/v2.2.0/s3cmd-2.2.0.tar.gz
解压,把 s3cmd 执行文件放到/usr/local/bin/目录下

配置

代码语言:javascript复制
# 生成配置文件
s3cmd --configure

# 最后修改以下几项
vim /root/.s3cfg
access_key = xxx
secret_key = xxx
host_base = ip:port			# s3 服务所使用的 ip 地址和端口
host_bucket = 
use_https = False

使用

代码语言:javascript复制
# 列出所有 bucket
s3cmd ls

# 创建 bucket
s3cmd mb s3://BUCKET_NAME

# 删除空 bucket
s3cmd rb s3://BUCKET_NAME

# 列出 bucket 中的内容
s3cmd ls s3://BUCKET_NAME

# 上传 file.txt 文件到某个 bucket
s3cmd put file.txt s3://BUCKET_NAME/file.txt

# 上传文件并将权限设置为所有人可读
s3cmd put --acl-public file.txt s3://BUCKET_NAME/file.txt

# 批量上传文件
s3cmd put ./* s3://BUCKET_NAME

# 下载文件
s3cmd get s3://BUCKET_NAME/file.txt file.txt

# 批量下载文件
s3cmd get s3://BUCKET_NAME/* ./

# 删除文件
s3cmd del s3://BUCKET_NAME/file.txt

# 获得对应 bucket 所占用的空间大小
s3cmd du -H s3://BUCKET_NAME

同步操作

代码语言:javascript复制
# 同步当前目录下所有文件
s3cmd sync ./ s3://BUCKET_NAME/

# 只列出需要同步的项目,不实际进行同步
s3cmd sync --dry-run ./ s3://BUCKET_NAME/

# 删除本地不存在的文件
s3cmd sync --delete-removed ./ s3://BUCKET_NAME/

# 不进行 MD5 校验,直接跳过本地已存在的文件
s3cmd sync --skip-existing ./ s3://BUCKET_NAME/

juicefs

官方文档:https://juicefs.com/docs/zh/community/command_reference/

用于在两个对象存储之间同步数据

语法格式

代码语言:javascript复制
# 语法格式
juicefs sync [command options] SRC DST

SRC:源路径
DST:目标路径
源路径和目标路径格式为:[NAME://][ACCESS_KEY:SECRET_KEY[:TOKEN]@]BUCKET[.ENDPOINT][/PREFIX]
NAME:JuiceFS 支持的数据存储类型(如 s3、oss)
ACCESS_KEY 和 SECRET_KEY:访问数据存储所需的密钥信息
TOKEN 用来访问对象存储的 token,部分对象存储支持使用临时的 token 以获得有限时间的权限
BUCKET[.ENDPOINT]:数据存储服务的访问地址,不同存储类型格式可能不同
[/PREFIX]:可选,源路径和目标路径的前缀,可用于限定只同步某些路径中的数据

选项:
# 并发线程数 (默认:10)
--threads value, -p value

# 当源文件更新时修改已存在的文件 (默认:false)
--update, -u

# 强制修改已存在的文件 (默认:false)
--force-update, -f

# 保留权限设置 (默认:false)
--perms

# 同步目录 (默认:false)
--dirs

# 同步后删除源存储的对象 (默认:false)
--delete-src, --deleteSrc

# 删除目标存储下的不相关对象 (默认:false)
--delete-dst, --deleteDst

# 不要使用 HTTPS (默认:false)
--no-https

# 限制最大带宽;单位为 Mbps (0 表示不限制) (默认:0)
--bwlimit value

0 人点赞