分布式存储学习2-Minio部署

分布式存储学习2-Minio部署

分布式存储学习2-Minio部署

分布式存储学习2-Minio部署

前言

上一章大致说明了应用场景与软件的选型与介绍,下面来实际操作,部署下Minio

做为一个高可用的分布式对象存储,Minio支持包括单机,集群,Docker,Kubernates等多种部署方式。

单机模式适合早期的开发与评估,实际生产推荐集群模式部署

实战示例

Minio支持离线部署(二进制)、在线部署(Homebrew)、容器化部署(Docker/K8s)。部署中具体启动参数放在后面的注意要点一起集中说

单机模式

单机模式的部署方式比较简单,以Mac为例,其他平台也基本相同

下载可执行文件

Mac可通过Homebrew安装 brew install minio/stable/minio

开发环境建议下载可执行文件

wget https://dl.min.io/server/minio/release/darwin-amd64/minio

启动服务

/data参数可根据需要替换成实际希望Minio存储的目录,例如/test,/dist1等等

注意! 如果是个人开发环境建议加上./当前目录,方便多次测试,重新搭建环境把现有的目录删除就可以了

chmod +x minio
./minio server ./data

离线部署可以根据 Release Download 按照实际环境下载。如果没有指定,Minio默认的用户密码为minioadmin/minioadmin,部署后可以通过两种方式测试

  • Minio Console

Minio Console是一个内嵌在Minio服务的Web管理客户端,通过默认用户密码即可登录,默认为随机端口。通过浏览器里可以方便直观的操作,比如创建存储Bucket, 上传文件Upload,查看Minio服务状态Status等等

  • Minio Clinet

可以通过任何S3的兼容工具,比如mcMinio CommandLine Tool 或者 SDK,mc的具体命令如下,更详细的可以参考 MinIO | MinIO Client Quickstart Guide

cli可能使用的不会特别多,因为有Console,还是比较方便的。可能在维护方面会使用cli操作

S3这个我也不是很熟悉,这块不展开

启动完成

会看到如下输出信息,默认启动Minio会输出警告日志并建议修改Console的端口与默认的Root用户的用户名与密码

# 连接地址
API: http://127.0.0.1:9000                     
RootUser: minioadmin 
RootPass: minioadmin 
# Console地址,默认启动Console监听为随机地址
Console: http://127.0.0.1:61422           
RootUser: minioadmin 
RootPass: minioadmin 
# 命令行
Command-line: https://docs.min.io/docs/minio-client-quickstart-guide
   $ mc alias set myminio http://127.0.0.1:9000 minioadmin minioadmin
# 文档
Documentation: https://docs.min.io
# 警告,具体参数下文详细说明
WARNING: Console endpoint is listening on a dynamic port (61422), please use --console-address ":PORT" to choose a static port.
WARNING: Detected default credentials 'minioadmin:minioadmin', we recommend that you change these values with 'MINIO_ROOT_USER' and 'MINIO_ROOT_PASSWORD' environment variables

所以我们将启动参数稍作修改

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

登录Console

浏览器访问 http://127.0.0.1:9001, 可以看到Minio的基本概览,下图是本机的一些信息

image-20211221145020315

功能测试

进入Buckets,点击右上角Create Bucket,创建存储。可以看到版本控制,对象锁,配额。都是在分布式模式才可以开启

这里我们创建一个名为minio-test的桶

Bucket为了方便理解的,可以假设是创建一个文件夹/目录

image-20211221145448650

剩余的就是对Bucket的操作,上传,下载,创建目录path, 删除等操作。总体来说还是比较方便的

image-20211221150041942

SDK连接测试

具体的SDK文档请参考 MinIO | The MinIO Quickstart Guide 找到左侧的Minio SDKS

以Node示例

Webpack

# javascript
npm install --save minio
# typescript
npm install --save-dev @types/minio

代码示例

/**
 * Minio 示例代码
 * @author shadow
 * @date 2021-12-21 15:57:00
 */

// 依赖模块
const Minio = require('minio')
const Path = require('path')

// 创建客户端连接
const minioClient = new Minio.Client({
  endPoint: '127.0.0.1',
  port: 9000,
  useSSL: false,
  accessKey: 'minioadmin',
  secretKey: 'minioadmin'
})

// 上传文件
const objectname = 'README.md'
const file = Path.join(__dirname, objectname)
// 桶名称
const bucket = 'minio-test'

/**
 * 判断bucket是否存在
 * 不存在先创建然后上传
 */
minioClient.bucketExists(bucket, (err, exists) => {
  if (err) {
    return console.log(err)
  }
  if (!exists) {
    // zh-cn的参数为region,官方没有具体的解释,猜测是标注服务区域,默认是 us-east-1
    minioClient.makeBucket(bucket, 'zh-cn', err => {
      if(err){
        return console.log(err)
      }
      putObject()
    })
    
  } else {
    putObject()
  }
})

const putObject = () => {
  // 这里对中文对象名进行测试,Minio-Console下载有乱码, 其他没有乱码情况
  minioClient.fPutObject(bucket, '文件名.md', file, {}, (err, objInfo) => {
    if (err) {
      return console.log(err)
    }
    console.log('Success', objInfo.etag, objInfo.versionId)
  })
}

集群模式

假设现在我们准备4台服务器,每台服务器4个磁盘并且分别挂载在data1...4上,同时所有服务器都在内部网络的172.16.1.x网段

准备工作

  • 准备一台负载均衡服务器(比如Nginx)
  • 所有服务节点网络双向互通
  • 所有节点的配置尽量保持一致(操作系统,CPU,内存,磁盘)
  • 节点尽可能使用TLS通信(内部网路会好一些,如果节点有外部网络,比如互联网访问权限。TLS可以保证安全性)
  • 对所有服务器定义域名,然后写入服务器的host
172.16.1.1 minio.example1.com 
172.16.1.2 minio.example2.com 
172.16.1.3 minio.example3.com
172.16.1.4 minio.example4.com 

启动集群

在每台服务器上启动Minio

./minio http://minio.example{1..4}.com/data{1..4}

观测结果,minio检测到域名对应的服务器与磁盘

然后配置负载均衡,简单示例如下:

upstream minio {
	server: 172.16.1.1:9000;
	server: 172.16.1.2:9000;
	server: 172.16.1.3:9000;
	server: 172.16.1.4:9000;
}
upstream minio-console {
  server: 172.16.1.1:9001;
  server: 172.16.1.2:9001;
  server: 172.16.1.3:9001;
  server: 172.16.1.4:9001;
}
server {
  listen       80;
  location ~ ^/minio/ {
    proxy_pass http://minio;
    rewrite: ^/minio/(.*)$ /$1 break;
  }
  
  location ~ ^/minio-console/ {
    proxy_pass http://minio-console;
    rewrite: ^/minio-console/(.*)$ /$1 break;
  }
}

是的,服务器保持网络通常就好,启动和单机基本一致

创建服务

刚刚是手动创建集群,现在我们将minio做成系统服务

chmod +x minio
sudo mv minio /usr/local/bin/

手动创建安装/etc/systemd/system/minio.service服务文件,官方示例如下

[Unit]
Description=MinIO
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio

[Service]
WorkingDirectory=/usr/local

# 执行用户,可以更改
User=minio-user
Group=minio-user
ProtectProc=invisible

EnvironmentFile=-/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

# Let systemd restart this service always
Restart=always

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536

# Specifies the maximum number of threads this process can create
TasksMax=infinity

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target

# Built for ${project.name}-${project.version} (${project.name})

minio示例使用minio-user的用户、组启动服务,一般为了安全也会给软件单独指定用户与组,命令如下

# 创建组,然后将用户加入组
groupadd -r minio-user
useradd -M -r -g minio-user miniouser
# data1...4 请根据实际路径填写,这里我用的测试路径就是1~4
chown minio-user:minio-user /data1 /data2 /data3 /data4

按照准备工作中写的配置好host,负载均衡,tls等,但是不要启动,接下来创建/etc/default/minio的服务配置文件,同样,官方实例如下

# minio 数据卷
MINIO_VOLUMES="https://minio{1...4}.example.net/mnt/disk{1...4}/minio https://minio{5...12}.example.net/mnt/disk{1...8}/minio"

# minio 配置参数
MINIO_OPTS="--console-address :9001"

# 用户名密码
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minio-secret-key-CHANGE-ME

# 有负载均衡设置负载均衡,没有的话可以设置一台服务器做为临时方案
# Set to the URL of the load balancer for the MinIO deployment
# This value *must* match across all MinIO servers. If you do
# not have a load balancer, set this value to to any *one* of the
# MinIO hosts in the deployment as a temporary measure.
MINIO_SERVER_URL="https://minio.example.net"

重要: 如果是扩容的话,需要停掉所有的minio,然后再启动,minio不支持滚动重启

sudo systemctl stop minio.service

启动所有minio

sudo systemctl start minio.service
sudo systemctl status minio.service

纠删码

纠删码的内容大部分是解读官方文档和其他资料进行的理解和汇总,难免有信息偏差和误解

再者,我对这块的了解仅限于知道,具体的细节就不做深入了

纠删码通过算法对数据进行恢复, 其实是通过CPU和网络的开销换存储空间

纠删码又称作擦除编码,是一种数据保护技术,其他的有Raid、副本。纠删码算是Raid的一种延伸,解决的Raid、副本存储空间过于浪费的问题,同时恢复的代价更小

目前主流使用Reed-Solomon(下文简称RS)类纠删码,主要有n 个数据快 + m个校验块组成。数据块和校验块按照一定的规则设定、存放。

这样可以保证

  • 在一定范围内数据块或者校验块损坏的情况下,整体数据可以根据剩余的数据块计算得出,数据不会丢失,存储是可用状态的
  • 丢失的数据块/校验块是可以做恢复,保证高可用
  • 数据块和校验块的比例可调整,比如 12+46+3

Minio的纠删码允许最多支持一半的磁盘(drives)和校验块(N/2-1)的丢失,仍然可以支持读写操作,最少需要4个磁盘。

纠删集(Erasure Sets)

纠删集就是Minio支持纠删码的一组驱动器,Minio通过GCD(最大公约数)来划分所有的驱动器组。这样做是为了更均匀,不重复的分配数据块与校验块分配在各个纠删集上。

加入一个集群有5个服务器,各8个驱动器。通过GCD得出4 * 10这样的配置,这样数据分配会不均匀,不能保证每台服务器有均衡的数据块与校验块,所以MInio会调整为5*8

重点:

  1. 纠删集部署Minio时就会开始计算
  2. 如果整体驱动器数量为奇数, Minio会抛出错误
  3. 每个纠删集的驱动器数量最小4,最大16
ERROR Invalid command line arguments: Incorrect number of endpoints provided

所以服务器数量尽量保证为偶数,保证每个服务器(节点)的数据块和校验块都是均匀的

注意要点

文档有两处,两份有时候可能要串着看,个人觉得老文档写的相对清晰一点。比如SDK,我在裸金属这块的文档中就没找到

MinIO High Performance Object Storage — MinIO Baremetal Documentation 新文档

MinIO | The MinIO Quickstart Guide — MinIo Legacy Docuemnt 历史文档

参数解释

按照我的个人习惯,一般执行前除了文档(特别是文档不是很友好的那种)。都会看看--help看看具体命令和参数,下面让我们看看分别是有哪些信息

环境变量

示例为Mac/LInux,Windows可将EXPORT替换为SET,设置用户名与密码

EXPORT MINIO_ROOT_USER=minioadmin
EXPORT MINIO_ROOT_PASSWORD=minioadmin

minio --help

# 命令格式
USAGE:
  minio [FLAGS] COMMAND [ARGS...]

# 启动命令,gateway模式或者server模式
COMMANDS:
  server   start object storage server
  gateway  start object storage gateway
  
# 参数 
FLAGS:
	# TLS证书目录,可以自定义,默认读取当前用户目录的.mino/certs
  --certs-dir value, -S value  path to certs directory (default: "/Users/shadow/.minio/certs")
  # 静默启动,不打印启动信息
  --quiet                      disable startup information
  # 匿名模式,不打印敏感信息
  --anonymous                  hide sensitive information from logging
  # 日志打印json格式,这个非常适配filebeat之类的日志抽取工具,方便对日志进行分析
  --json                       output server logs and startup information in json format
  # 帮助和版本
  --help, -h                   show help
  --version, -v                print the version

minio server --help

节选常用与较重要的一些信息,部分和minio --help重复的不再贴出

需要注意的是目录不存在会自动创建,建议先按照磁盘和规划预先创建好目录,特别是一机多磁盘。预先做好挂载

# 命令格式
USAGE:
  minio server [FLAGS] DIR1 [DIR2..]
  minio server [FLAGS] DIR{1...64}
  minio server [FLAGS] DIR{1...64} DIR{65...128}

# DIR的解释信息,Minio推荐每个服务有最少4个硬盘,所以通过DIR的参数指定,可以不断追加,或者根据...的规则自动新增
# 比如目录没有连续性,像/mnt/disk-north /mnt/disk-south,就可以携程
# minio server /mnt/dist-north /mnt/dist-south
# 如果连续可以使用...缩写目录,例如4个磁盘分别挂载在/mnt/disk1,2,3,4. 就可以这样写:
# minio server /mnt/disk{1...4}
# 
DIR:
  DIR points to a directory on a filesystem. When you want to combine
  multiple drives into a single large system, pass one directory per
  filesystem separated by space. You may also use a '...' convention
  to abbreviate the directory arguments. Remote directories in a
  distributed setup are encoded as HTTP(s) URIs.

# 参数
FLAGS:
	# 服务监听端口,默认:9000
  --address value              bind to a specific ADDRESS:PORT, ADDRESS can be an IP or hostname (default: ":9000")
  # Console的监听地址,如果不指定会随机
  --console-address value      bind to a specific ADDRESS:PORT for embedded Console UI, ADDRESS can be an IP or hostname
  --listeners value            bind N number of listeners per ADDRESS:PORT (default: 1)
  
EXAMPLES:
  1. Start minio server on "/home/shared" directory.
     $ minio server /home/shared

  2. Start single node server with 64 local drives "/mnt/data1" to "/mnt/data64".
     $ minio server /mnt/data{1...64}

  3. Start distributed minio server on an 32 node setup with 32 drives each, run following command on all the nodes
     $ export MINIO_ROOT_USER=minio
     $ export MINIO_ROOT_PASSWORD=miniostorage
     $ minio server http://node{1...32}.example.com/mnt/export{1...32}

  4. Start distributed minio server in an expanded setup, run the following command on all the nodes
     $ export MINIO_ROOT_USER=minio
     $ export MINIO_ROOT_PASSWORD=miniostorage
     $ minio server http://node{1...16}.example.com/mnt/export{1...32} \
            http://node{17...64}.example.com/mnt/export{1...64}

其他

  • Minio-Console 文件下载中文名乱码

该问题为Minio-Console的Bug,社区已有修复提交记录,后续版本应该会更新 Solve the problem of garbled file names when downloading Chinese files

  • region参数是干什么的?

不清楚,官方文档中没有明细的说明,有可能只是做一个区分。因为Minio也没有做类似HDFS的机架感知机制,可能后续要看一下源码。此问题后续看情况更新

引用资料

MinIO | The MinIO Quickstart Guide

Expand a Distributed MinIO Deployment — MinIO Baremetal Documentation

下章预览

  • JuiceFS环境搭建
  • Minio纠删码详解
  • Minio元数据处理机制解析
  • 其他