minio对象存储

ooowl
  • 对象存储
  • minio
  • 对象存储
  • 文件存储
About 9 min

minio对象存储

基本使用

应用场景

一个亚马逊S3的云存储接口,适合存储非结构化数据,支持TB级别的对象存储OSS[1]
文档在这里open in new window,尽量参考英文网站,中文网站更新不是很及时,有可能版本不对导致错误
对象存储 OSS-阿里云帮助中心open in new window 关于OSS的概念
Minio基础 - 对象存储OSS概述 | Java学习笔记open in new window

quote

Minio使用纠删码erasure code和校验和checksum来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。纠删码是一种恢复丢失和损坏数据的数学算法, Minio采用Reed-Solomon code将对象拆分成N/2数据和N/2 奇偶校验块。 这就意味着如果是12块盘,一个对象会被分成6个数据块、6个奇偶校验块,你可以丢失任意6块盘(不管其是存放的数据块还是奇偶校验块),你仍可以从剩下的盘中的数据进行恢复。

结构

Bucket是顶层的单元,所有的操作都是在Bucket中进行的,Bucket里面有东西是删不掉的,可以强制递归删除,在Bucket中存储的是Object
Object可以是文件字节流等等任何东西。Drive是使用的磁盘,可以在启动的时候指定多块磁盘映射进去。
Set算是一组磁盘的集合,当使用分布式的存储使用了很多块磁盘的时候, minio会自动分组,Set中包含几个几个磁盘是根据集群规模自动计算的,一个Set的Drive会尽量分布在不同的节点上。在使用多块盘的时候会自动启用纠删码模式,1M以下不会生成part

多节点部署,分布式部署的时候可以防止宕机和位腐化bit rot,至少需要4个硬盘。

高可用: 单机Minio服务存在单点故障,相反,如果是一个有N块硬盘的分布式Minio,只要有N/2硬盘在线,你的数据就是安全的。不过你需要至少有N/2+1个硬盘来创建新的对象。例如,一个16节点的Minio集群,每个节点16块硬盘,就算8台服務器宕机,这个集群仍然是可读的,不过你需要9台服務器才能写数据。Minio在分布式和单机模式下,所有读写操作都严格遵守 read-after-write 一致性模型。 #todo 查查这个模型

==分布式minio的时间节点时间差不能超过3s!!!==太细了,而且要映射的盘里面必须没有数据,所有节点必须要有相同的 ACCESS_KEY SECRET KEY or? MINIO_ROOT_USERMINIO_ROOT_PASSWORD
如果是分布式多节点的部署,需要使用Nginx做负载均衡做入口,控制台用其中一个就行了,上传用负载均衡的ip-hash

📌Tip

如果我们在minio 启动的数据目录中直接创建文件夹,就会直接暴露为s3 bucket,比较适合的场景是系统部署的时候
需要依赖一个s3 bucket,我们可以直接先创建好
如果是使用volume那就使用脚本提前创建 单机版存在这样一个问题如果一个文件夹 a/下面有多个object(100万个全放 a/下面),list 性能会非常低,单机版似乎是以源文件方式直接存到磁盘的。
建议不要放太多的 object ,应该分开放。比如以日期,或者文件 hash 取几位建目录再把 object 放进去。

创建bucket的元数据操作:对于Erasure Set(2+2)为例:创建一个bucket,对应底层文件系统的4次目录创建。创建一个文件,需要对应底层4次目录创建,8次文件创建操作。对于小文件,数据和元数据都保存在meta文件中,也需要4次文件创建操作。由此可知,minio对应大量小文件的性能非常差。

用户和权限

#todo 前面的区域,以后再来探索吧

docker部署

单机版直接一条命令

docker run -d \
   -p 9000:9000 \
   -p 9001:9001 \
   --name minio \
   -v ~/minio/data:/data \
   -e "MINIO_ROOT_USER=ROOTNAME" \
   -e "MINIO_ROOT_PASSWORD=CHANGEME123" \
   quay.io/minio/minio server /data --console-address ":9001"

官方给的集群compose

Click to see more

nginx的配置

user root;  
worker_processes auto;  
pid /run/nginx.pid;  
  
events {  
   worker_connections 16384;  
}  
  
http {
    # 基础配置我就不写了

    upstream minio {  
        server minio1:9000;  
        server minio2:9000;  
        server minio3:9000;  
        server minio4:9000;  
    }  
      
    upstream console {  
        ip_hash;  
        server minio1:9001;  
        server minio2:9001;  
        server minio3:9001;  
        server minio4:9001;  
    }  
      
    server {  
        listen       9000;  
        listen  [::]:9000;  
        server_name  localhost;  
      
        # To allow special characters in headers  
        ignore_invalid_headers off;  
        # Allow any size file to be uploaded.  
        # Set to a value such as 1000m; to restrict file size to a specific value    client_max_body_size 0;  
        # To disable buffering  
        proxy_buffering off;  
        proxy_request_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;  
            # Default is HTTP/1, keepalive is only enabled in HTTP/1.1  
            proxy_http_version 1.1;  
            proxy_set_header Connection "";  
            chunked_transfer_encoding off;  
      
            proxy_pass http://minio;  
        }  
    }  
      
    server {  
        listen       9001;  
        listen  [::]:9001;  
        server_name  localhost;  
      
        # To allow special characters in headers  
        ignore_invalid_headers off;  
        # Allow any size file to be uploaded.  
        # Set to a value such as 1000m; to restrict file size to a specific value    client_max_body_size 0;  
        # To disable buffering  
        proxy_buffering off;  
        proxy_request_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_set_header X-NginX-Proxy true;  
      
            # This is necessary to pass the correct IP to be hashed  
            real_ip_header X-Real-IP;  
      
            proxy_connect_timeout 300;  
            # To support websocket  
            proxy_http_version 1.1;  
            proxy_set_header Upgrade $http_upgrade;  
            proxy_set_header Connection "upgrade";  
            chunked_transfer_encoding off;  
      
            proxy_pass http://console;  
        }  
    }
}

docker-compose文件

version: "3.8"  
  
x-minio-common: &minio-common  
  image: quay.io/minio/minio:latest  
  command: server --console-address ":9001" http://minio{1...4}/data{1...2}  
  expose:  
    - "9000"  
    - "9001"  
  environment:  
    MINIO_ROOT_USER: minioadmin  
    MINIO_ROOT_PASSWORD: minioadmin  
  healthcheck:  
    test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]  
    interval: 30s  
    timeout: 20s  
    retries: 3  
  
services:  
  
  minio1:  
    <<: *minio-common  
    hostname: minio1  
    volumes:  
      - data1-1:/data1  
      - data1-2:/data2  
  
  minio2:  
    <<: *minio-common  
    hostname: minio2  
    volumes:  
      - data2-1:/data1  
      - data2-2:/data2  
  
  minio3:  
    <<: *minio-common  
    hostname: minio3  
    volumes:  
      - data3-1:/data1  
      - data3-2:/data2  
  
  minio4:  
    <<: *minio-common  
    hostname: minio4  
    volumes:  
      - data4-1:/data1  
      - data4-2:/data2

版本控制

#todo 前面的区域,以后再来探索吧

SDK和上传下载

常用上传下载


MINIO_ENDPOINT = "192.168.123.175:9000"  
MINIO_ACCESS_KEY = "ROOTNAME"  
MINIO_SECRET_KEY = "CHANGEME123"  
BUCKET_NAME = "demo"  
minioClient = Minio(  
    endpoint=MINIO_ENDPOINT,  
    access_key=MINIO_ACCESS_KEY,  
    secret_key=MINIO_SECRET_KEY,  
    secure=False,  # 根据你的MinIO服务器配置选择是否启用安全连接  
)

def put_data_minio():  
    f = open("sql基础知识.pdf", mode="rb")  
    filename = "sql基础知识.pdf"  
    content = f.read()  # 这里是字节数据  
    result = minioClient.put_object(  
        BUCKET_NAME,  
        filename,  
        io.BytesIO(content),  # 这里是字节数据  
        len(content),  
        content_type="application/octet-stream"  # 这个头是做什么的  
    )  
    print(result)  
    f.close()  
  
  
def load_data_minio():  
    data = minioClient.get_object(BUCKET_NAME, "sql基础知识.pdf")  
    with open("sql基础知识1.pdf", 'wb') as file_data:  
        for d in data.stream(32 * 1024):  
            file_data.write(d)  
    return data.data  
  
  
put_data_minio()  
load_data_minio()

# 从Minio获取文件  
response = minioClient.get_object(ftype, file_name)
# fastapi使用的时候返回文件使用流式响应
return StreamingResponse(response.stream(32 * 1024), media_type="application/octet-stream")

自带的分片上传

def multipart_upload(object_name, file_path):  # 传入的对象名称,文件路径  
    headers = {"Content-Type": "application/octet-stream"}  
    part_size = 50 * 1024 * 1024  # 上传的文件大于5MiB时启动分片上传  
    upload_id = minioClient._create_multipart_upload(BUCKET_NAME, object_name, headers=headers)  # 1. 初始化一个新的分片上传并获得upload_id  
    parts = []  
    with open(file_path, 'rb') as file_data:  # 2. 上传每个分片  
        part_number = 1  
        while True:  
            data = file_data.read(part_size)  # warn 注意这里是按照分片大小直接读取的文件流数据  
            if not data:  
                break  
            etag = minioClient._upload_part(BUCKET_NAME, object_name, data, headers, upload_id, part_number)  
            parts.append(Part(part_number, etag))  
            part_number += 1  
    minioClient._complete_multipart_upload(BUCKET_NAME, object_name, upload_id, parts)  # 3. 完成分片上传,应该是合并

分片上传的大小可能影响效率,5MB大小和50MB分片大小,分别是17s和15s,可以考虑的方面有文件的io,网络io,上传开销。小于分片的大小会直接报错
使用fastapi的时候,分成三个接口,一个申请,一个上传,一个校验结束,可以自己加一些自己的校验。

断点续下载

#todo 直接配合fastapi的路由实现

自己实现分片上传

分片上传需要并发,主流浏览器对HTTP 1.1和HTTP 1.0的最大并发连接数目,可以参考如下表格:

浏览器HTTP / 1.1HTTP / 1.0
IE 1166
IE 1066
IE 91010
IE 866
IE 6,724
火狐66
Safari 3,444
Chrome 4+66
Opera9.63,10.00alpha44
Opera 10.51+8
iPhone 24
iPhone 36
iPhone 44
iphone 56

分片上传,断点续传,断点续下,秒传流程图

如果要使用多线程下载,那就不要删除MD5文件夹,上面做一点小改动,开多个线程读取分片即可

#todo 前面的区域,以后再来探索吧ceph存储原理 mq和kafka选型场景_哔哩哔哩_bilibiliopen in new window

踩坑记录


  1. MINIO 了解及使用 | Server 运维论坛open in new window ↩︎

Loading...