【前言】在应用开发中,经常会遇到附件图片上传、文件存储的场景,这时是对象存储大显身手的地方,为我们文件的存取提供了很大的便利和保障。今天以开源对象存储工具MINIO为例,简要介绍对象存储的前世今生。
01、为什么引入对象存储
在谈对象存储之前,我们先看看一直占据存储市场的两种主要存储方式:块存储和文件存储。
块存储像是一块块硬盘直接挂载在主机上,以卷或硬盘形式体现,对于存储的数据内容和格式一无所知,只关心读取和写入,不关心关系和用途,数据按字节来访问,性能很高。但是太偏向于底层,不利于扩展,常见的有DAS(直连式存储)、SAN(存储区域网络)。
DAS是指将存储设备通过SCSI接口直接连接到一台服务器上使用,存储介质直接挂载到内部总线上,数据存储是整个服务器结构的一部分。
SAN是通过高速网络将一个或多个存储设备和服务器连接起来的专用存储系统,可以把SAN理解成一个网络,里面包含着磁盘阵列、交换机等各种元素。
文件存储一般以文件和目录形式体现,有多级访问路径和基于文件系统的目录结构,数据以文件的形式进行存储和访问,对数据也可以进行一些高级管理功能,比如文件层面的访问权限控制等。文件存储可以很方便的进行共享,用途也非常广泛,但是其读写速度相对较慢。常见的有NAS(网络附加存储服务器)。
NAS设备本质就是将本地主机的文件系统迁移至IP网络设备上,多个用户节点可以公用同一个NAS上的同一个文件系统。
由于块存储和文件存储的存储特点,并不适合公有云存储,一般只适合在局域网内部使用。另外随着互联网需求的发展,数据量爆炸式的增长,不断吞食着存储资源;数据类型也逐渐多元化,各类非结构化的数据占比显著增加,如何应对新的存储需求?对象存储应运而生。
02、什么是对象存储
对象存储是一种基于对象的存储设备,综合了NAS和SAN的优点,同时具有SAN的高速直接访问和NAS的分布式数据共享等优势。适合存储海量图片、视频、日志文件、备份数据、容器镜像等。
2006年美国亚马逊发布了AWS S3(Simple Storage Service)服务,正式将对象存储作为一种云存储服务,引入云计算领域,正式开启了对象存储的黄金年代,S3现在也作为一种主流的对象存储协议标准,让很多服务实现厂家都需要进行兼容。
对象存储底层存储硬件介质,仍旧是硬盘,这一点和块存储、文件存储没有区别,但是底层硬件之上的系统和两者完全不同。
对象存储非常简单,只有两个核心概念:桶(bucket)和对象(object),储数据组织形式按照“租户-桶-对象”的方式进行组织:
- 用户可以创建用于访问不同存储桶权限的租户。
- 租户可以隔离存储资源,创建不通的存储桶和对象。
- 存储桶是承装对象的容器集合,一个存储桶可以有很多对象,这些对象都是平级的(扁平化)。
- 对象是数据存储的实体单位,类似于hash表项,key为对象名称,value为对象内容,以一种KV方式存储。
对象存储通常是通过REST API接口(HTTP动作)去处理资源信息,接口命令也十分简洁,存储协议是S3、swift等,以S3为例,主要接口命令有PUT/GET/DELETE等;扁平化的数据组织结构,也带来了极高的可扩展性,
在对象存储选型中,我们往往希望在满足基本性能的前提下,方案越简单越好,在众多的开源对象存储方案中,MINIO凭借着其极简主义的指导思想,脱颖而出。
极简理念——采用尽可以简单可靠的集群管理方案,摒弃复杂的大规模集群调度管理,减少风险因素与性能瓶颈,聚焦产品的核心功能,打造高可靠的集群、灵活的扩展能力以及超高的性能;
积木式扩展——建立众多的中小规模、易管理的集群,支持跨数据中心将多个集群聚合成超大资源池,而非直接采用大规模、统一管理的分布式集群。
03、MINIO原理
- MINIO宏观架构(去中心化)
MINIO整个集群是由多个角色完全相同的节点组成,没有特殊节点,任何一个节点宕机,都不会影响整个集群,对象被分片打散之后存放在不同节点的多块硬盘上,对外提供统一的命名空间,通过Web负载均衡或DNS轮询(Round Robin)的方式在各个节点上实现负载均衡。每个节点都能兼容S3接口。
-
MINIO节点存储
介绍节点存储之前,我们首先要介绍几个概念:
1)Drive: 存储数据的磁盘称之为Drive;
2)Set: 一组Drive的集合构成一个Set;每个Set的Drive尽可能分布在不同节点上;一个对象存储在一个Set上;
3)Bucket: 文件对象存储的逻辑位置;对于客户端而言,相当于存放文件的顶层文件夹;
MINIO不是以多副本的形式存储,而是通过数据编码,将原来的数据编码成多份,然后通过Set的形式落地存储在对应的Drive上。
一个集群包含多个Set,具体存储到哪个set是通过对象名称进行哈希,映射到唯一一个Set上,这种方式可以使得数据均匀分布在所有的Drive上。
一个集群具体包含多少个Set,minio默认会根据集群规模自动计算得出,也可以自行指定配置。本着鸡蛋放在多个篮子,保证数据可靠性的原则,一个Set的Drive尽可能分布在不同的节点上。
如上图所示,每一行是一个机器节点,每一个小块是一个Drive(磁盘),图中的黄、蓝色块各组成了一个Set。当写入对象时,通过数据编码,将原来的数据编码成N份,N就是一个Set中Drive的数量,之后通过对象名称Hash找到唯一的Set,将每一份数据写到Set中对应的Drive上,完成对象在Set上的存储。
-
数据可靠性保证
MINIO通过使用纠删码Erasure code和校验和Checksum来保证数据的可靠性,即使丢掉一半数量(N/2)的硬盘,仍可恢复数据。
-
ERASURE-CODED
将一个对象编码成若干数据块和校验块,为了方便,将数据块和校验块统称为编码块,纠删码就是可以根据编码块的一部分还原出整个对象的机制,当然前提需要保证故障磁盘的数量小于等于校验盘的数量。
一般情况下,一个Set会有一半的Drive作为数据块,一半的Drive作为校验块,这种方式可靠性最强,且冗余度最高,所有的编码块大小加起来是源文件大小的2倍。但是和多副本存储的方式相比,冗余度大大降低了(只冗余多存了一份数据),且可靠性最高,可容忍一半磁盘的丢失和损坏。
其实质是冗余编码机制将存储机器空闲的CPU利用起来,通过纠删码特定算法的计算处理,保证数据的可靠性。
-
BitRot
存储介质可能存在的另一个问题就是位衰减问题(bit rot),它是指在遇到磨损、灰尘、辐射、高热等因素下,存储介质中的数据性能和完整性缓慢恶化的问题,这些细微的损坏,可能常常不会被OS和硬件所觉察,但是会导致向存储介质写入一段比特流,一段时间再读出来,二者不一致的现象。
为了应对bit rot问题,MINIO将之前的编码块通过HighwayHash算法计算校验和,以保证正确性,同时提供了一个管理工具,对有问题的编码块进行修复。
从数据可靠性角度看存储,首先把对象分成若干等长的片段,之后通过纠删码算法分成若干数据分片和校验分片,每个分片都存储在一个Drive上。
-
- 数据存放形式
在存储设备上表现形式是以文件目录的形式存储在文件系统上,假设MINIO集群内纠删组包含4块硬盘,我们要存储的对象名为MyObject,其隶属的存储桶名为MyBucket,哈希计算得到的磁盘为Disk1-4,那么在这4个磁盘上都会生成MyBucket/MyObject的子路径,MyObject路径目录下包含两个文件,分别是存储元数据信息的xl.json和对应的分片part.1。
对象存储对于分片的数据如何管理它们呢?如何找到想要的数据或信息呢?这里涉及到的就是对象元数据管理。对象的元数据就是用来管理数据的存储、分片以及数据本身的信息,因为元数据单独存储,所以我们可以为一个对象扩展任意多的元数据,这也是文件存储做不到的。
对象存储是扁平化存储(所有对象平铺在桶中),如果我们想使对象像文件系统那样看起来有目录层级结构,可以考虑通过设定带有层级的对象名称来达到多级目录的效果(eg. KEY为Temp/MyObject)。
04、集群部署与搭建
-
分布式集群搭建
生产环境最少4个节点(少于4台节点无法启动)。
1.目录创建
创建启动脚本及二进制文件目录 /opt/minio,将minio程序放置该目录下;
创建数据存储目录data;
创建配置文件目录 /etc/minio;
2.编辑集群启动脚本
```bash
vim /opt/minio/run.sh
```
MINIO_ACCESS_KEY:用户名,长度最少是5个字符
MINIO_SECRET_KEY:密码,不能设置过于简单,不然会启动失败,长度最小8个字符
-config-dir: 指定集群配置文件目录
#!/bin/bash
export MINIO_ACCESS_KEY=minio
export MINIO_SECRET_KEY=minioadmin
/opt/minio/minio server --config-dir /etc/minio \
http://ip1/data/minio/data01 http://ip2/data/minio/data02 http://ip3/data/minio/data03 http://ip4/data/minio/data04 > minio_server.log
# ps:如果机器资源不足的情况下,可在单机器上按如下方式模拟4个节点
/opt/minio/minio server --config-dir /etc/minio \
/data/minio/data01 /data/minio/data02 /data/minio/data03 /data/minio/data04 > minio_server.log
- 配置系统服务 minio.service
vim /usr/lib/systemd/system/minio.service
-
WorkingDirectory: 二进制文件目录
-
ExecStart : 指定集群启动脚本
[Unit] Description=Minio service Documentation=https://docs.minio.io/ [Service] WorkingDirectory=/opt/minio/ ExecStart=/opt/minio/run.sh Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target
- 权限修改
给所有涉及到的文件或目录添加权限
-
service文件
-
二进制文件
-
集群启动脚本
chmod +x /usr/lib/systemd/system/minio.service chmod +x /opt/minio/run/minio chmod +x /opt/minio/run/run.sh
- 启动集群
systemctl daemon-reload # Systemd会将Unit文件的内容写到缓存中,因此当Unit文件更新时,告诉Systemd读取所有Unit文件
systemctl enable minio # 激活服务,开机启动
systemctl start minio # 启动服务
systemctl status minio # 查看服务状态
ps: 在存储文件之前,我们需要新建一个存储桶,通过编辑策略按钮来改变桶的访问策略