极光高级工程师——胡冠军一、背景因UMS5.1版本当中短信签名,邮件支持上传本地图片/支持上传附件的产品需求,以及后续可能存在的需要大量文件存储的场景,所以需做一个私有云自己的文件服务器,并且该服务器也要兼容客户文件服务器(注:客户文件服务器一般都是兼容S3协议的)二、调研文件服务器经过各种调研,选型和组内讨论,最终决定选择minIO1.minIO简介minIO 是一个基于 Apache License v2.0 开源协议使用 Go 语言开发的对象存储服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以从几kb到最大5T不等。minIO 是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。2.minIO优势兼容 Amazon S3minIO使用 Amazon S3 v2 / v4 API。数据保护minIO使用erasure code来防止硬件故障。即使损坏一半以上的硬盘,仍然可以从中恢复数据。高度可用minIO服务器可以容忍分布式系统中高达(N / 2)-1 节点故障。Lambda 计算minIO服务器通过其兼容 AWS SNS / SQS 的事件通知服务触发 Lambda 功能。支持的目标是消息队列,如Kafka,AMQP,以及 Elasticsearch,Redis,MySQL 等数据库。加密和防篡改minIO为加密数据提供了机密性,完整性和真实性保证,而且性能开销微乎其微。使用 AES-256-GCM,ChaCha20-Poly1305 和 AES-CBC 支持服务器端和客户端加密。可对接后端存储除了minIO自己的文件系统,还支持 DAS、 JBODs、NAS、Google 云存储和 Azure Blob 存储。sdk 支持基于minIO轻量的特点,它得到类似 Java、Python 或 Go 等语言的 sdk 支持一致性minIO在分布式和单机模式下,所有读写操作都严格遵守read-after-write一致性模型。3.minIO架构图minIO采用去中心化的无共享架构,对象数据被打散存放在不同节点的多块硬盘,对外提供统一命名空间访问,并通过Web负载均衡器或DNS轮询(DNS round-robin)在各服务器之间实现负载均衡。4.minIO存储机制4.1 基本概念硬盘(Drive):即存储数据的磁盘,在 minIO 启动时,以参数的方式传入。组( Set ):即一组 Drive 的集合,分布式部署根据集群规模自动划分一个或多个 Set ,每个 Set 中的 Drive 分布在不同位置。一个对象存储在一个 Set 上。桶(Bucket):文件对象存储的逻辑位置,对于客户端而言,就相当于一个存放文件的顶层文件夹。4.2 纠删码minIO 使用纠删码(erasure code)和校验和(check sum)来保护数据免受硬件故障和无声数据损坏。 即便您丢失一半数量(N/2)的硬盘,您仍然可以恢复数据。什么是纠删码呢?它是一种恢复丢失和损坏数据的数学算法,minIO 采用Reed-Solomon Code实现纠删码,它将对象拆分成N/2 数据块和 N/2 奇偶校验块。这就意味着如果是 12 块盘,一个对象会被分成 6 个数据块、6 个奇偶校验块,您可以丢失任意 6 块盘(不管其是存放的数据块还是奇偶校验块),您仍可以从剩下的盘中的数据进行恢复。4.3 Reed-Solomon Code数据恢复原理简析RS编码以word为编码和解码单位,大的数据块拆分到字长为w(取值一般为8或者16位)的word,然后对word进行编解码。 数据块的编码原理与word编码原理相同,后文中以word为例说明,变量Di, Ci将代表一个word。把输入数据视为向量D=(D1,D2,…, Dn), 编码后数据视为向量(D1, D2,…, Dn, C1, C2,.., Cm),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的计算公式,如下图:(4)对D重新编码,可得到丢失的编码。4.4 以纠删码模式运行minIOminIO会自动生成12块盘,命令如下:4.5 存储形式数据对象在minIO集群中进行存储时,先进行纠删分片,后打散存储在各硬盘上。具体为:minIO自动在集群内生成若干纠删组,每个纠删组包含一组硬盘,其数量通常为4至16块;对数据对象进行分片,默认策略是得到相同数量的数据分片和校验分片;而后通过哈希算法计算出该数据对象对应的纠删组,并将数据和校验分片存储至纠删组内的硬盘上。如上图所示,假设某minIO集群内纠删组包含4块硬盘,某数据对象名为MyObject,其隶属存储桶名为MyBucket,哈希计算得到对应的纠删组为Disk 1~4。那么在Disk 1~4的数据路径下,都会生成MyBucket/MyObject子路径,子路径中包含2个文件,分别为存储元数据信息的xl.json和MyObject对象在该盘上的第一个分片part.1。其中,xl表示minIO中数据对象的默认存储格式。5.minIO golang SDK简单使用以下上传文件的例子可以直接运行,文件会上传到minIO官方服务器三、minIO在UMS系统中的实际应用1.应用系统架构整个架构中,模块之间使用http协议通信,并且每个模块的作用如下:(1)Web/API服务器的作用是提供UMS系统的认证和鉴权,即验证Web客户端或者开发者API请求接口的合法性;(2)文件管理服务器的作用是提供对外操作minIO服务器的接口,根据目前UMS系统的业务需求,只提供了获取上传文件presignedURL,设置过期时间, 设置对外访问策略,创建存储桶,生成下载文件URL的功能;那么什么是presignedURL呢?它是对象所有者使用自己的安全凭证来创建预签名的 URL,以授予有限时间内的上传或下载对象权限,从而与其他用户共享对象,注:即使是私有对象使用presignedURL也可以共享给他人,并且presignedURL最大有效期为7天。其中文件管理服务器获取上传文件presignedURL的方法直接使用了minIO官方API,当然你也可以自己实现presignedURL方法,此外,由于下载presignedURL最大保留时间为7天,不符合UMS系统业务需求,所以,文件管理服务器自己实现了一个生成下载URL的方法,此链接的过期时间可任意设置,但前提要把存储桶的对外访问策略设置为public。由此,客户端就可以直接使用上传presignedURL上文件到minIO服务器,使用下载链接直接下载文件即可。(3)minIO集群作用是存储实体文件,该集群采用去中心化无共享架构,各节点间为对等关系,连接至任一节点均可实现对集群的访问,minIO集群前端增加了Nginx实现反向代理;minIO节点之间的通信使用的都是rpc。此外,管理minIO服务器除了上面提到的SDK以外,官方还提供了命令行和web页面的形式,内容分别如下:把Nginx代理ip和端口号或者minIO集群中任意节点的ip和端口号输入浏览器,输入minIO的账户名和密码即可登录,界面如下:2.具体交互逻辑首先,客户端要请求业务服务器(WebServer/APIServer)获取上传文件的凭证(presignedURL),然后,业务服务器响应一个上传文件URL和下载文件的URL,客户端使用上传URL上传文件到文件服务器,使用下载URL作为请求后端的文件参数,如发送邮件消息支持上传本地图片,上传到后端的图片即可使用文件下载URL作为参数。该方案的优点如下:客户端直接上传文件到minIO服务器,不经过业务服务器,减轻业务服务器的压力,提高可用性数据库服务器只存储文件的下载URL,减少数据库的存储量支持上传超大文件,比如3G以上等,硬件性能足够的情况下,minIO服务器单个文件最大可达5T上传文件的数量没有限制可以解决同名文件覆盖问题可以适配任何兼容S3协议的文件服务器,满足不同客户的要求四、minIO分布式部署minIO分布式部署架构1.1 架构概述minIO集群采用去中心化无共享架构,各节点间为对等关系,连接至任一节点均可实现对集群的访问,这种节点间保持对等关系的设计并非最常见的分布式集群架构。当前大多数的分布式存储集群,其节点往往可划分为多类角色,例如负责连接并处理外部应用请求的访问节点、负责存储元数据的管理节点、实际的数据存储节点等。minIO与之不同,minIO集群中的所有节点都同时承担了多种角色,集元数据存储、数据存储、应用访问等功能于一体,真正实现了去中心化和所有节点的完全对等。其优势在于有效地减少了集群内的复杂调度过程以及因中心节点带来的故障风险和性能瓶颈。下图minIO集群增加了Nginx代理:部署minIO集群只需一条命令,但集群中每个节点都要执行相同的命令其中,官方推荐节点ip要连续。1.2 minIO扩容方案首先,minIO的极简设计理念使得minIO分布式集群并不支持向集群中添加单个节点并进行自动调节的扩容方式,这是因为加入单个节点后所引发的数据均衡以及纠删组划分等问题会为整个集群带来复杂的调度和处理过程,并不利于维护。因此,minIO提供了一种对等扩容的方式,即要求增加的节点数和磁盘数均需与原集群保持对等。例如原集群包含4个节点4块磁盘,则在扩容时必须同样增加4个节点4块磁盘(或为其倍数),以便系统维持相同的数据冗余SLA,从而极大地降低扩容的复杂性。如上例,在扩容后,minIO集群并不会对全部的8个节点进行完全的数据均衡,而是将原本的4个节点视作一个区域,新加入的4节点视作另一区域,当有新对象上传时,集群将依据各区域的可用空间比例确定存放区域,在各区域内仍旧通过哈希算法确定对应的纠删组进行最终的存放。此外,集群进行一次对等扩容后,还可依据扩容规则继续进行对等扩容,但出于安全性考虑,集群的最大节点数一般不得超过32个。minIO支持通过命令,指定新的集群来扩展现有集群(纠删码模式),命令行如下:现在整个集群就扩展了1024个磁盘,总磁盘变为2048个,新的对象上传请求会自动分配到最少使用的集群上。通过以上扩展策略,您就可以按需扩展您的集群。重新配置后重启集群,会立即在集群中生效,并对现有集群无影响。如上命令中,我们可以把原来的集群看做一个区,新增集群看做另一个区,新对象按每个区域中的可用空间比例放置在区域中。在每个区域内,基于确定性哈希算法确定位置。注:您添加的每个区域必须具有与原始区域相同的磁盘数量(纠删码集)大小,以便维持相同的数据冗余SLA。 例如,第一个区有8个磁盘,您可以将集群扩展为16个、32个或1024个磁盘的区域,您只需确保部署的SLA是原始区域的倍数即可。对等扩容的优点和缺点如下:优点:在于配置操作简单易行,通过一条命令即可完成扩容。缺点:①扩容需重启;②扩容存在限制,集群节点数一般不超过32个,这是由于MinIO集群通过分布式锁保证强一致性,若集群节点数过大,维护强一致性将带来性能问题。但对于初期存储量不是很大,并且集群短暂停机重启对业务影响不大的情况下,使用对等扩容即可。注意事项分布式minIO里所有的节点需要有同样的access秘钥和secret秘钥,即:用户名和密码分布式minIO存放数据的磁盘目录必须是空目录分布式minIO官方建议生产环境最少4个节点,因为有N个节点,得至少保证有N/2的节点才能可读,保证至少N/2+1的节点才能可写分布式minIO节点时间要相同,机器配置也要都相同分布式minIO会在每个磁盘都存一份数据文件保证数据的可靠性与安全性3.具体实施步骤网上很多人部署minIO集群都是使用单个脚本,这在实际生产环境中很不友好,因为minIO要求集群中每个节点都要执行相同的命令才能启动成功,所以最好的方式是使用ansible部署minIO集群。3.1 安装ansible3.2 使用ansible部署minIO集群Ansible编写的核心代码如下,具体细节读者可自行百度3.3 配置Nginx代理集群Nginx配置文件内容如下:3.4 验证minIO集群是否部署成功在浏览器上,输入Nginx所在服务器的地址外加Nginx配置里的监听端口即可访问文件服务器web页面,部署成功的效果如下:五、结语以上就是UMS私有云文件服务开发以及部署的主要内容,该方案已经得到实施验证,如果您想搭建兼容S3协议的文件服务器,那么该篇文章有参考价值,当然由于时间仓促并且初期文件存储量不是很大,该方案也有需要优化的地方,比如想实现动态扩容机制可以采用官方联邦扩容方式,不过这需要引入etcd,也需要更多的机器。总之,您还是需要根据具体业务场景来定,就像买鞋子不是越大越好,合脚的才是最好的。