MinIO—分布式对象存储服务器

Published at 2025-03-24 08:57

Author:haix

View:60


MinIO

背景介绍

MinIO是一个高性能、轻量级的对象存储服务器,并且是世界上最快的(单个节点可达1.32 Tbps,支持并行多部分上传(Multipart Upload))。它提供了与Amazon Web Services S3兼容的API,并支持所有核心S3功能。 MinIO可以在任何环境中部署 - 物理服务器、虚拟机、容器。

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

Docker搭建MinIO

1.下载MinIO镜像

(base) [user@server ~]# docker pull minio/minio

2.创建目录

用来存储上传文件的目录,启动前需要先创建储存上传文件的目录

(base) [user@server ~]# mkdir -p /media/disk2/minio-data

3.创建MinIO容器并运行

(base) [user@server ~]# docker run -dt \
  -p 9000:9000 -p 9001:9001 \
    -v /media/disk2/minio-data \
    -e 'MINIO_ACCESS_KEY=minioadmin' \
    -e 'MINIO_SECRET_KEY=minioadmin' \
  --name 'minio' \
  minio/minio server --console-address ":9001"

4.连接MinIO

可以直接通过浏览器输入https://localhost:9001 访问MinIO的Web页面。

使用之前配置好的账号’MINIO_ACCESS_KEY’,密码’MINIO_SECRET_KEY’登录

如果忘记账号密码可以使用下面命令查看

(base) [user@server ~]# docker inspect minio | grep -i 'MINIO_ROOT_USER\|MINIO_ROOT_PASSWORD'

MinIO客户端

MinIO客户端 mc 命令行工具提供了一个现代化的替代方案, 支持文件系统和与Amazon S3兼容的云存储服务,适用于UNIX命令如 ls 、 cat 、 cp 、 mirror 和 diff 。

mc 命令行工具是为了与 AWS S3 API 兼容而构建的,并且已经过测试, 以确保在与 MinIO 和 AWS S3 配合使用时,功能和行为符合预期。

MinIO 不对其他 S3 兼容服务提供任何保证,因为它们的 S3 API 实现是 未知的,因此不受支持。尽管 mc 命令 可能 如文档中所 述工作,但任何此类使用都是您自己的风险。

安装mc

(base) [user@server ~]# curl https://dl.min.io/client/mc/release/linux-amd64/mc \
  --create-dirs \
  -o <img src="http://latex.codecogs.com/gif.latex?HOME%2Fminio-binaries%2Fmc%0D%0A%0D%0A%28base%29%5Buser%40server%7E%5D%23chmod%2Bx">HOME/minio-binaries/mc
(base) [user@server ~]# export PATH=<img src="http://latex.codecogs.com/gif.latex?PATH%3A">HOME/minio-binaries/

mc基本操作命令

1.使用mc alias set命令将 Amazon S3 兼容服务添加到mc配置中

(base) [user@server ~]# mc alias set myminio https://localhost:9000 minioadmin minioadmin

2.测试链接,如果成功,该命令将返回有关 S3 服务的信息

(base) [user@server ~]# mc admin info myminio

3.列出当前配置的所有MinIO主机的信息

(base) [user@server ~]# mc config host list

4.创建名称为haix的bucket(储存桶)

(base) [user@server ~]# mc mb myminio/haix

5.查看bucket

(base) [user@server ~]# mc ls myminio

6.删除指定bucket或删除某bucket中指定文件

删除bucket

(base) [user@server ~]# mc rm myminio/haix/ --force

删除bucket中指定文件

(base) [user@server ~]# mc rm myminio/haix/KP-1.fasta

7.上传文件

上传文件夹

#上传文件夹
(base) [user@server ~]# mc cp --recursive /media/disk3/haix/Klebsiella_work/11_kp_genome myminio/haix

上传文件

#上传文件
(base) [user@server ~]# mc cp /media/disk3/haix/Klebsiella_work/11_kp_genome/KP-1.fasta myminio/hai

Pyhton连接MinIO

1.pip安装MinIO

pip install minio

2.连接MinIO服务器,检查是否连接成功

from minio import Minio

#使用endpoint、access_key和secret_key初始化minioClient对象
client = Minio('https://localhost:9000',
               access_key='minioadmin',
               secret_key='minioadmin',
               secure=False,
               )

try:
    buckets = client.list_buckets()
    for bucket in buckets:
        print(bucket.name, bucket.creation_date)
except Exception as e:
    print("Failed connection", str(e))

3.MinIO储存桶(bucket)基本操作

MinIO的储存桶名称需要符合DNS命名规范

① 只能包含小写字母、数字和短横线(-)

② 长度3-63字符

③ 不能以短横线开头或结尾

from minio import Minio
from minio.error import MinioException

class BucketManager:
    def __init__(self, client):
        self.client = client

    # 创建bucket
    def create_bucket(self, bucket_name):

        try:
            if self.client.bucket_exists(bucket_name):
                print(f"Bucket ' {bucket_name}'already exists")
            else:
                self.client.make_bucket(bucket_name)
                print(f"Bucket '{bucket_name}' created")
        except MinioException as e:
            print(f'Bucket crated failed {e}')

    # 列出当前bucket
    def get_bucket_list(self):
        try:
            buckets = self.client.list_buckets()
            for bucket in buckets:
                print(f'Bucket: {bucket.name}, Created: {bucket.creation_date}')
        except MinioException as e:
            print(f'Error listing buckets: {e}')

    # 删除bucket
    def get_remove_bucket(self, bucket_name):
        try:
            self.client.remove_bucket(bucket_name)
            print(f"Bucket: '{bucket_name}' deleted")
        except MinioException as e:
            print(f'Error deleting bucket {e}')

if __name__ == '__main__':
        # 初始化MinIO客户端
    client = Minio('https://localhost:9000',
                   access_key='minioadmin',
                   secret_key='minioadmin'
                   secure=False,
                   )

    manager = BucketManager(client)
    # 创建新bucket
    manager.create_bucket('newtest')
    # 显示所有bucket,并检验是否创建成功
    manager.get_bucket_list()

4.MinIO文件上传下载基本操作

在文件传输场景中,大文件小文件的操作方式有本质区别。 ①小文件传输(如get/put_object) 直接将二进制数据流加载到内存中操作,适用于10MB以下的配置文件、JSON或图片等场景,其优势在于代码简洁,但存在内存溢出(OOM)风险且依赖内存带宽。

②大文件传输(如fget/fput_object) 则通过本地文件系统分块读写实现,专为50MB以上的视频、压缩包等场景设计,采用流式传输避免内存压力,支持断点续传且通过系统级缓存优化稳定性,虽然代码需处理文件路径和异常,但能有效规避内存瓶颈,其性能主要受磁盘IO速度限制。两类方法在内存管理、异常容错和性能瓶颈等维度形成鲜明对比,需根据文件体量和业务需求针对性选择。

from minio import Minio
from minio.error import MinioException
import os

class ObjectOperation:
    def __init__(self, client, bucket_name, object_name, local_file_path=None):
        """
        :param client: 连接的Minio客户端
        :param bucket_name: 操作的储存桶名称
        :param object_name: 操作对象在储存桶中的名称
        :param local_file_path: 本地路径(上传/下载)
        """
        self.client = client
        self.bucket_name = bucket_name
        self.object_name = object_name
        self.local_file_path = local_file_path

    # 从储存桶中下载文件到本地(小文件)
    # 小文件操作:直接将数据加载到内存中,适合处理较小的文件(<10Mb)

    def get_object(self):
        """获取对象数据流"""
        response = None
        try:
            response = self.client.get_object(
                self.bucket_name,
                self.object_name
            )
            print(f'Successfully download object {self.object_name}')
            return response.data
        except MinioException as e:
            print(f'Error download object: {e}')
            return None
        finally:
            # 确认关闭流
            if 'response' in locals():
                response.close()

    # 从储存桶中下载文件到本地(大文件)
    # 大文件操作:使用流式传输或分块读写,可以避免占用过高内存
    def fget_object(self, save_path):
        try:
            if not save_path:
                raise ValueError('Path must be specified')  # 必须指定路径

            self.client.fget_object(
                self.bucket_name,
                self.object_name,
                save_path
            )
            print(f'Successfully download object {self.object_name}')
            return True
        except (MinioException, ValueError) as e:
            print(f'Error download object: {e}')
            return False

    # 从本地上传文件到MinIO(小文件)
    def put_object(self, data):
        try:
            result = self.client.put_object(
                self.bucket_name,
                self.object_name,
                data,  # 二进制数据
                length=len(data)
            )
            print(f'File uploaded successfully  {self.object_name}')
            return result
        except MinioException as e:
            print(f'File uploaded failed {e} ')
            return None

    # 从本地上传文件到MinIO (大文件)
    def fput_object(self, file_path=None):
        try:
            # 确定最终路径(传入参数优先级更高,其次是初始化参数)
            final_path = file_path or self.local_file_path
            if not final_path:
                raise ValueError('Path must be specified')

            # 标准化路径
            final_path = os.path.abspath(final_path)

            if not os.path.exists(final_path):
                raise FileNotFoundError(f'{final_path} not exists')

            result = self.client.fput_object(
                self.bucket_name,
                self.object_name,
                final_path,
            )
            print(f'File upload Successfully {self.object_name}')
            return result
        except (MinioException, FileNotFoundError, ValueError) as e:
            print(f'File uploaded failed: {e}')
            return None       

if __name__ == '__main__':
    # 初始化MinIO客户端
    client = Minio('https://localhost:9000',
                   access_key='minioadmin',
                   secret_key='minioadmin'
                   secure=False,
                   )

    # 上传本地文件到MinIO
    uploader = ObjectOperation(
        client=client,
        bucket_name="newtest",
        object_name='test.txt',  # 对象在MinIO中的路径
        local_file_path=r'E:\kp_work\test.txt'
    )
    uploader.fput_object()

    # 下载MinIO文件到本地指定路径
    downloader = ObjectOperation(
        client=client,
        bucket_name='test',
        object_name='11_kp_fa/KP-8.fasta',  # MinIO中对象的路径
    )
    downloader.fget_object(
        save_path=r'E:\kp_work\KP-8.fasta'
    )