minio对象存储
minio对象存储
基本使用
应用场景
一个亚马逊S3的云存储接口,适合存储非结构化数据,支持TB级别的对象存储OSS[1]
文档在这里,尽量参考英文网站,中文网站更新不是很及时,有可能版本不对导致错误
对象存储 OSS-阿里云帮助中心 关于OSS的概念
Minio基础 - 对象存储OSS概述 | Java学习笔记
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_USER
和MINIO_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.1 | HTTP / 1.0 |
---|---|---|
IE 11 | 6 | 6 |
IE 10 | 6 | 6 |
IE 9 | 10 | 10 |
IE 8 | 6 | 6 |
IE 6,7 | 2 | 4 |
火狐 | 6 | 6 |
Safari 3,4 | 4 | 4 |
Chrome 4+ | 6 | 6 |
Opera9.63,10.00alpha | 4 | 4 |
Opera 10.51+ | 8 | ? |
iPhone 2 | 4 | ? |
iPhone 3 | 6 | ? |
iPhone 4 | 4 | ? |
iphone 5 | 6 | ? |
分片上传,断点续传,断点续下,秒传流程图
如果要使用多线程下载,那就不要删除MD5文件夹,上面做一点小改动,开多个线程读取分片即可
#todo 前面的区域,以后再来探索吧ceph存储原理 mq和kafka选型场景_哔哩哔哩_bilibili