jjzjj

分布式文件存储系统Minio

小脑斧攻城狮 2024-01-01 原文

一、Minio介绍

MinIO基于Apache License 2.0开源协议的对象存储服务。它兼容Amazon S3云存储接口。适合存储非结构化数据,如图片,音频,视频,日志等。对象文件最大可以达到5TB

官网:https://min.io/  中文 http://minio.org.cn/

 1、Minio基础概念

  • Object:存储到Minio的基本对象,如文件字节流,Anything
  • Bucket:用来存储Object的逻辑空间。每个Bucket之间的数据是相互隔离的。对于客户端而言,就相当于一个存放文件的顶层文件夹。
  • Drive:即存储数据的磁盘,在MinlO启动时,以参数的方式传入。Minio中所有的对象数据都会存储在Drive里
  • Set:即-组Drive的集合,分布式部署根据集群规模自动划分一个或多个Set,每个Set中的Drive分布在不同位置。一个对象存
    储在一个Set上。(For example:{1…64} is divided into 4sets each of size16)
  1. 一个对象存储在一个Set上
  2. 一个集群划分为多个Set
  3. 一个Set包含的Drive数量是固定的,默认由系统根据集群规模自动计算得出
  4. 一个SET中的Drive尽可能分布在不同的节点上

1.1 纠删码

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

1.2 存储形式

文件对象上传到Minio,会在对应的数据存储磁盘中,以Bucket名称为目录,文件名称为下一级目录,文件下是part.1(超过10M时候才会有此文件)和xl.meta,前者是编码数据块以及检验块,后者是元数据文件

1.3 存储方案

二、Minio环境搭建

1、单机部署

基于Centos7

安装路径 /usr/local/soft

wget https://dl.min.io/server/minio/release/darwin-amd64/minio
chmod +x minio
./minio server /mnt/data

 

 访问 http://192.168.150.129:41922 用户名密码:minioadmin

 发现图中有警告:WARNING: Console endpoint is listening on a dynamic port (41922), please use --console-address ":PORT" to choose a static port.

 目前启动的时候端口是动态的,只要在启动命令后加上 --console-address ":PORT" ,就变成静态端口

再次启动

./minio server /mnt/data --console-address ":9001"

 图中还有警告:WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables

意思是我们在启动的时候可以通过MINIO_ROOT_USERMINIO_ROOT_PASSWORD设置用户密码访问

完整启动命令:

MINIO_ROOT_USER=admin MINIO_ROOT_PASSWORD=12345678 ./minio server /mnt/data --console-address ":9001"

访问 http://192.168.150.129:9001 账号:admin 密码:12345678

 基于docker部署

安装docker命令(如果已经安装就跳过此步骤)

yum install -y yum-utils device-mapper-persistent-data lvm2

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

yum install docker-ce

启动docker

systemctl start docker

部署命令以及自定义用户名密码

docker run -d -p 9000:9000 -p 9001:9001 --name minio \
  -e "MINIO_ROOT_USER=admin" \
  -e "MINIO_ROOT_PASSWORD=12345678" \
  -v /mnt/data:/data \
  -v /mnt/config:/root/.minio \
  minio/minio server /data --console-address ":9001"

获取容器ID

在容器中使用Docker命令, 你需要知道这个容器的 容器ID 。 为了获取 Container ID, 运行
docker ps -a

-a flag 确保你获取所有的容器(创建的,正在运行的,退出的),然后从输出中识别Container ID

启动和停止容器

启动容器,你可以使用 docker start 命令。
docker start <container_id>

停止一下正在运行的容器, 使用 docker stop 命令。
docker stop <container_id>

MinIO容器日志

获取MinIO日志,使用 docker logs 命令。
docker logs <container_id>

监控MinioDocker容器

监控MinIO容器使用的资源,使用 docker stats 命令.
docker stats <container_id>

minio纠删码模式

Minio使用纠删码erasure code和校验和checksum来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。

纠删码是一种恢复丢失和损坏数据的数学算法, Minio采用Reed-Solomon code将对象拆分成N/2数据和N/2 奇偶校验块。 这就意味着如果是12块盘,一个对象会被分成6个数据块、6个奇

偶校验块,你可以丢失任意6块盘(不管其是存放的数据块还是奇偶校验块)

docker run -d -p 9000:9000 -p 9001:9001 --name minio-ec \
  -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 ":9001"

2、分布式集群部署

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


  

分布式存储可靠性常用方法

分布式存储,很关键的点在于数据的可靠性,即保证数据的完整,不丢失,不损坏。只有在可靠性实现的前提下,才有了追求一致性、高可用、高性能的基础。而对于在存储领域,一般对于保证数据可靠性的方法主要有两类,一类是冗余法,一类是校验法。
冗余
冗余法最简单直接,即对存储的数据进行副本备份,当数据出现丢失,损坏,即可使用备份内容进行恢复,而副本备份的多少,决定了数据可靠性的高低。这其中会有成本的考量,副本数据越多,数据越可靠,但需要的设备就越多,成本就越高。可靠性是允许丢失其中-份数据。当前已有很多分布式系统是采用此种方式实现,如Hadoop的文件系统(3个副本),Redis的集群,MvSOL的主备模式等。
校险
校验法即通过校验码的数学计算的方式,对出现丢失、损坏的数据进行校验,还原。注意,这里有两个作用,一个校验,通过对数据进行校验和(checksum)进行计算,可以检查数据是否完整,有无损坏或更改,在数据传输和保存时经常用到,如TCP协议:二是恢复还原通过对数据结合校验码,通过数学计算,还原丢失或损坏的数据,可以在保证数据可章的前提下,降低冗余,如单机硬盘存储中的RAID技术,纠删码(ErasureCode)技术等。Minlo采用的就是纠删码技术。

分布式Minio优势

数据保护

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

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

高可用

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

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

注意,只要遵守分布式Minio的限制,你可以组合不同的节点和每个节点几块硬盘。比如,你可以使用2个节点,每个节点4块硬盘,也可以使用4个节点,每个节点两块硬盘,诸如此类。

一致性

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

运行分布式Minio

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

  • 所有运行分布式 MinIO 的节点都应该共享一个共同的根凭证,以便节点相互连接和信任。为此,建议在执行 MinIO 服务器命令之前,将 root 用户和 root 密码导出为环境变量,MINIO_ROOT_USER并在所有节点上导出。MINIO_ROOT_PASSWORD如果未导出,minioadmin/minioadmin则应使用默认凭据。
  • MinIO 创建每组216 个驱动器的纠删码集。您提供的驱动器总数必须是这些数字之一的倍数。
  • MinIO 选择最大的 EC 集大小,将其划分为给定的驱动器总数或节点总数 - 确保保持均匀分布,即每个节点参与每组相同数量的驱动器
  • 每个对象都写入单个 EC 集,因此分布在不超过 16 个驱动器上。
  • 建议运行分布式 MinIO 设置的所有节点是同质的,即相同的操作系统、相同数量的磁盘和相同的网络互连。
  • MinIO 分布式模式需要新目录。如果需要,驱动器可以与其他应用程序共享。您可以通过使用 MinIO 独有的子目录来执行此操作。例如,如果您已将卷安装在 下/export,则将其作为参数传递/export/data给 MinIO 服务器。
  • 下面的 IP 地址和驱动器路径仅用于演示目的,您需要将它们替换为实际的 IP 地址和驱动器路径/文件夹。
  • 运行分布式 MinIO 实例的服务器之间的间隔应小于 15 分钟。您可以启用NTP服务作为最佳实践,以确保跨服务器的时间相同。
  • MINIO_DOMAIN应为桶 DNS 样式支持定义和导出环境变量。
  • 在Windows操作系统上运行分布式 MinIO被认为是实验性的。请谨慎行事。

前期准备

四台服务器开启时间同步,命令:

yum -y install ntp
systemctl enable ntpd
systemctl start ntpd
timedatectl set-ntp yes
ntpdate -u cn.pool.ntp.org
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime   
watch -n 1 'date'

 关闭防火墙

1.首先查看防火墙状态:
service iptables status
2.永久性生效,重启后不会复原
开启:
chkconfig iptables on
关闭:
chkconfig iptables off
3.即时生效,重启后复原
开启:
service iptables start
关闭:
service iptables stop
4.设置后重启:
reboot

4个节点,每节点4块盘

每台服务器中都要配置如下hostname 

服务器 IPhostname说明
192.168.150.128minio1.comMinio节点
192.168.150.129minio2.comMinio节点
192.168.150.130minio3.comMinio节点
192.168.150.131minio4.comMinio节点
192.168.150.132minio5.com

Nginx负载均衡

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

1、给每台服务器新增一块硬盘,这里使用的10G(这里使用的是虚拟机,自行百度怎么添加,不使用新硬盘部署集群会报错)

2、格式化硬盘 (不格式化会提示只读模式)

mkfs.ext4 /dev/sdb

3、创建minio数据目录,挂载数据磁盘到数据目录
mkdir  -p /data/minio{1..4}   // 模拟四块硬盘
mount /dev/sdb /data

实现永久挂载需要配置 vim /etc/fstab 

4、minio-cluster.sh脚本

4.1 第一中写法

#!/bin/bash
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
nohup /usr/local/soft/minio server --address ":9000" --console-address ":9001" \
http://192.168.150.128:9000/data/minio1 \
http://192.168.150.128:9000/data/minio2 \
http://192.168.150.128:9000/data/minio3 \
http://192.168.150.128:9000/data/minio4 \
http://192.168.150.129:9000/data/minio1 \
http://192.168.150.129:9000/data/minio2 \
http://192.168.150.129:9000/data/minio3 \
http://192.168.150.129:9000/data/minio4 \
http://192.168.150.130:9000/data/minio1 \
http://192.168.150.130:9000/data/minio2 \
http://192.168.150.130:9000/data/minio3 \
http://192.168.150.130:9000/data/minio4 \
http://192.168.150.131:9000/data/minio1 \
http://192.168.150.131:9000/data/minio2 \
http://192.168.150.131:9000/data/minio3 \
http://192.168.150.131:9000/data/minio4 >/data/minio.log 2>&1 &

4.2 第二中写法 

#!/bin/bash
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=12345678
nohup /usr/local/soft/minio server --address ":9000" --console-address ":9001" http://minio{1...4}.com:9000/data/minio{1...4} >/data/minio-data.log  2>&1  &

5、Nginx负载均衡配置


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    # Minio配置---开始
upstream minio_console {
    server 192.168.150.128:9001 max_fails=3 fail_timeout=5s;
    server 192.168.150.129:9001 max_fails=3 fail_timeout=5s;
    server 192.168.150.130:9001 max_fails=3 fail_timeout=5s;
    server 192.168.150.131:9001 max_fails=3 fail_timeout=5s;
}
upstream minio_api {
    server 192.168.150.128:9000 max_fails=3 fail_timeout=5s;
    server 192.168.150.129:9000 max_fails=3 fail_timeout=5s;
    server 192.168.150.130:9000 max_fails=3 fail_timeout=5s;
    server 192.168.150.131:9000 max_fails=3 fail_timeout=5s;
}

server {
    listen          9001;   #或者用80端口也可以
    server_name     192.168.150.132;    #可以用域名
    location / {
	    #Nginx默认是上传一个不能超过1M大小的文件
        #client_body_buffer_size 配置请求体缓存区大小, 不配的话,
        #client_body_temp_path 设置临时文件存放路径。只有当上传的请求体超出缓存区大小时,才会写到临时文件中
        #client_max_body_size 设置上传文件的最大值
	    client_max_body_size 600M;
        client_body_buffer_size 600M;
        proxy_next_upstream     http_500 http_502 http_503 http_504 error timeout invalid_header;
        proxy_set_header        Host  $host;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass              http://minio_console;
        expires                 0;
    }
}

server {
    listen          9000;
    server_name     192.168.150.132;   #可以用域名
    location / {
	    #Nginx默认是上传一个不能超过1M大小的文件
        #client_body_buffer_size 配置请求体缓存区大小, 不配的话,
        #client_body_temp_path 设置临时文件存放路径。只有当上传的请求体超出缓存区大小时,才会写到临时文件中
        #client_max_body_size 设置上传文件的最大值
	    client_max_body_size 600M;
        client_body_buffer_size 600M;
        proxy_next_upstream     http_500 http_502 http_503 http_504 error timeout invalid_header;
        proxy_set_header        Host  $host;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass              http://minio_api;
        expires                 0;
    }
}
  # Minio配置---结束
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

有关分布式文件存储系统Minio的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  8. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  9. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  10. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

随机推荐