目录
Minio 简介
1、MinIO 是在 Apache License v2.0 下发布的对象存储服务器。 它与 Amazon S3 云存储服务兼容。 它最适合存储非结构化数据,如照片,视频,日志文件,备份和容器/ VM 映像。 对象的大小可以从几 KB 到最大 5TB。
2、MinIO 服务器足够轻,可以与应用程序堆栈捆绑在一起,类似于 NodeJS,Redis 和 MySQL。
3、 一种高性能的分布式对象存储服务器,用于大型数据基础设施。它是机器学习和其他大数据工作负载下Hadoop HDFS 的理想 s3 兼容替代品。
为什么要用 Minio
选择它的理由
1、Minio 有良好的存储机制
2、Minio 有很好纠删码的算法与擦除编码算法
3、拥有RS code 编码数据恢复原理
4、公司做强做大时,数据的拥有重要性,对数据治理与大数据分析做准备。
5、搭建自己的一套文件系统服务,对文件数据进行安全保护。
6、拥有自己的平台,不限于其他方限制。
存储机制
Minio使用纠删码erasure code和校验和checksum来保护数据免受硬件故障和无声数据损坏。 即便丢失一半数量(N/2)的硬盘,仍然可以恢复数据。
纠删码
纠删码是一种恢复丢失和损坏数据的数学算法,目前,纠删码技术在分布式存储系统中的应用主要有三类,阵列纠删码(Array Code: RAID5、RAID6 等)、RS(Reed-Solomon)里德-所罗门类纠删码和 LDPC(LowDensity Parity Check Code)低密度奇偶校验纠删码。Erasure Code 是一种编码技术,它可以将 n 份原始数据,增加 m 份数据,并能通过 n+m 份中的任意 n 份数据,还原为原始数据。即如果有任意小于等于 m 份的数据失效,仍然能通过剩下的数据还原出来。
RS code 编码数据恢复原理
RS 编码以 word 为编码和解码单位,大的数据块拆分到字长为 w(取值一般为 8 或者 16位)的 word,然后对 word 进行编解码。 数据块的编码原理与 word 编码原理相同,后文中以 word 为例说明,变量 Di, Ci 将代表一个 word。把输入数据视为向量 D=(D1,D2,…, Dn), 编码后数据视为向量(D1, D2,…, Dn, C1, C2,.., m),RS 编码可视为如下(图 1)所示矩阵运算。图 1 最左边是编码矩阵(或称为生成矩阵、分布矩阵,Distribution Matrix),编码矩阵需要满足任意 n*n 子矩阵可逆。为方便数据存储,编码矩阵上部是单位阵(n 行 n 列),下部是m 行 n 列矩阵。下部矩阵可以选择范德蒙德矩阵或柯西矩阵。
RS 最多能容忍 m 个数据块被删除。 数据恢复的过程如下:
(1)假设 D1、D4、C2 丢失,从编码矩阵中删掉丢失的数据块/编码块对应的行。(图 2、3)
(2)由于B'
是可逆的,记B'
的逆矩阵为(B'^-1)
,则B' * (B'^-1) = I
单位矩阵。两边左乘B'
逆矩阵。 (图 4、5)
(3)得到如下原始数据 D 的计算公式 。
擦除代码
MinIO 使用每个对象的内联擦除编码来保护数据,这种编码是用汇编代码编写的,可以提供尽可能高的性能。MinIO 使用 Reed-Solomon 代码将对象条带化为 n/2 数据和 n/2 奇偶校验块——尽管这些可以配置为任何所需的冗余级别。这意味着在 12 个驱动器设置中,一个对象被分割为 6 个数据和 6 个奇偶校验块。即使您丢失了 5 个(n/2) -1 个驱动器,无论是奇偶校验还是数据,您仍然可以从剩余驱动器可靠地重构数据。MinIO 的实现确保即使多个设备丢失或不可用,也可以读取对象或写入新对象。最后,MinIO 的擦除代码在对象级别,可以一次治愈一个对象。
体系结构
1、MinIO 支持从机器学习到备份的一系列现代工作负载
2、使用云本地技术并分解计算和存储层
3、创建高效和可伸缩的对象存储解决方案。
安装minio
minio docker地址:https://hub.docker.com/r/minio/minio
拉取minio的docker镜像。(此次拉取的版本为:RELEASE.2021-08-05T22)
1 |
docker pull minio/minio |
创建文件夹
1 |
mkdir -p /var/docker/minio/{data,config} |
data:存放数据。
config:存放配置。
运行
1 2 3 4 5 6 7 8 9 |
docker run -d \ -p 9000:9000 \ -p 9001:9001 \ -e "MINIO_ROOT_USER=admin" \ -e "MINIO_ROOT_PASSWORD=admin123456" \ -v /var/docker/minio/data:/data \ -v /var/docker/minio/config:/root/.minio \ --name minio \ minio/minio server /data --console-address ":9001" |
9000端口
:服务端口,通过这个端口直接访问文件。
9001端口
:管理后台端口。
MINIO_ROOT_USER
:管理后台-账户
MINIO_ROOT_PASSWORD
:管理后台-密码
-v xxx:/data
:minio数据
-v xxx:/root/.minio
:minio配置
server /data
:指定minio数据存放位置
--console-address ":9001"
:指定9001端口为后台管理端口
浏览器访问:http://yourIp:9001/。登录账号/密码就是MINIO_ROOT_USER
/MINIO_ROOT_PASSWORD
设置的值。
minio管理后台,没有中文,需要中文的,建议使用有翻译功能的浏览器。
创建桶并上传文件
php使用(laravel)
composer安装aws-sdk-php-laravel扩展包。
要在composer.json的加上依赖
1 2 3 4 5 |
{ "require": { "aws/aws-sdk-php-laravel": "~3.0" } } |
然后执行命令composer update
,即可。
配置基本项
app配置(app/config/app.php)
1 2 3 4 5 |
// 将下面代码追加到 providers 数组中 Aws\Laravel\AwsServiceProvider::class, // 将下面代码追加到 aliases 数组中 'AwsFacade' => Aws\Laravel\AwsFacade::class, |
发布配置文件
1 |
php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider" |
最后会在config/
下,生成aws.php配置文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?php use Aws\Laravel\AwsServiceProvider; return [ /* |-------------------------------------------------------------------------- | AWS SDK Configuration |-------------------------------------------------------------------------- | | The configuration options set in this file will be passed directly to the | `Aws\Sdk` object, from which all client objects are created. This file | is published to the application config directory for modification by the | user. The full set of possible options are documented at: | http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/configuration.html | */ 'credentials' => [ 'key' => env('AWS_ACCESS_KEY_ID', ''), // 账号 'secret' => env('AWS_SECRET_ACCESS_KEY', ''), // 密码 ], 'region' => env('AWS_REGION', 'us-east-1'), // 区域 'version' => 'latest', 'endpoint' => env('AWS_ENDPOINT', 'http://localhost:9000'), // minio服务地址 // 我们将use_path_style_endpoint设置为true以使用AWS SDK for PHP来操作MinIO。 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 'ua_append' => [ 'L5MOD/' . AwsServiceProvider::VERSION, ], ]; |
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
<?php namespace App\Http\Controllers; use Aws\Laravel\AwsFacade; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; class FileController extends Controller { private $bucket = 'wemall'; private $allowedExtensions = ["png", "jpg", "gif"]; public function upload(Request $request,$field = 'image') { $s3 = AwsFacade::createClient('s3'); if($request->hasFile($field) && $request->file($field)->isValid()){ $file=$request->file($field); //文件扩展名 $extend = $file->getClientOriginalExtension(); if (!in_array($extend, $this->allowedExtensions)) { return response()->json(['message'=>'只能上传png,jpg和gif格式的图片'],400); } # 自定义文件名 $fileName = date('Ymd') . '-' . uniqid() . '.' . $extend; try { $s3_return = $s3->putObject([ 'Bucket' => $this->bucket, //存储桶名称 'Key' => 'image/'.$fileName, //文件名(包括后缀名) 'Body' => file_get_contents($file) //要上传的文件 ]); if (isset($s3_return['ObjectURL']) && !empty($s3_return['ObjectURL'])) { // $addr = $s3_return['ObjectURL']; // $addr = $this->preSignedUrl('image/'.$fileName); $addr = $this->plainUrl('image/'.$fileName); } Log::info($s3_return); } catch (\Exception $e) { return response()->json(['message'=>$e->getMessage()],400); } } return response()->json(['data'=>$addr,'message'=>'上传成功']); } //生成临时公共文件在线查看(pre-signed URL) public function preSignedUrl($uriPath) { $s3 = AwsFacade::createClient('s3'); $s3_command = $s3->getCommand('GetObject', [ 'Bucket' => $this->bucket, 'Key' =>$uriPath ]); $s3_pre_signed_return = $s3->createPresignedRequest($s3_command, '+30 minutes'); //临时存在的时长(分钟数) return (string)$s3_pre_signed_return->getUri(); } // 获取永久公共桶下文件在线查看(plain URL) public function plainUrl($uriPath) { $s3 = AwsFacade::createClient('s3'); return (string)$s3->getObjectUrl($this->bucket, $uriPath); } // 下载 public function download() { $file = 'image/20210813-6116256a93e40.jpg'; $save_path = "./20210813-6116256a93e40.jpg"; $s3 = AwsFacade::createClient('s3'); $s3->getObject([ 'Bucket' =>$this->bucket, 'Key' =>$file, 'SaveAs' =>$save_path //这里是你要下载到本地的具体路径(比如:D:\www\1.jpg) ]); } // 创建桶 public function createBucket() { $bucketName = 'test'; $s3 = AwsFacade::createClient('s3'); $s3->createBucket(['Bucket' => $bucketName]); //创建桶 } // 删除桶(涉及调用多个s3相关函数) public function deleteBucket() { $s3 = AwsFacade::createClient('s3'); // 列出所有的Buckets $list_buckets = $s3->listBuckets()['Buckets']; // 以下Buckets不需要删除 $not_del = ['wemall']; if(!empty($list_buckets)) { //要做非空判断 foreach ($list_buckets as $bucket) { if (!in_array($bucket['Name'], $not_del)) { //排除掉不想被处理的桶 //获取桶内对象(文件)列表 $list_objects = $s3->listObjects(['Bucket' => $bucket['Name']])['Contents']; if (!empty($list_objects)) { //要做非空判断 foreach ($list_objects as $object) { //删除桶内文件,因为有文件的桶是不能删除的 $s3->deleteObject([ 'Bucket'=>$bucket['Name'], 'Key'=>$object['Key'] ]); } } $s3->deleteBucket(['Bucket' => $bucket['Name']]); //删除桶 } } } } public function test() { try { // $this->download(); // $this->createBucket(); $this->deleteBucket(); } catch (\Exception $e) { return response()->json(["message"=>$e->getMessage()]); } } } |
参考
中文文档
关于在laravel中使用aws的操作(aws-sdk-php-laravel)