精华内容
下载资源
问答
  • minio简介 MinIO 是在 Apache License v2.0 下发布的对象存储服务器。...一种高性能的分布式对象存储服务器,用于大型数据基础设施。它是机器学习和其他大数 据工作负载下 Hadoop HDFS 的理想 s3 兼容

    minio简介

    • MinIO 是在 Apache License v2.0 下发布的对象存储服务器。 它与 Amazon S3 云存储服务兼容。 它最适合存储非结构化数据,如照片,视频,日志文件,备份和容器/ VM 映像。 对象的大小可以从几 KB 到最大 5TB。
    • MinIO 服务器足够轻,可以与应用程序堆栈捆绑在一起,类似于 NodeJS,Redis 和 MySQL。
    • 一种高性能的分布式对象存储服务器,用于大型数据基础设施。它是机器学习和其他大数
      据工作负载下 Hadoop HDFS 的理想 s3 兼容替代品

    为什么要用 Minio

    选择它的理由
    • Minio 有良好的存储机制
    • Minio 有很好纠删码的算法与擦除编码算法
    • 拥有RS code 编码数据恢复原理
    • 公司做强做大时,数据的拥有重要性,对数据治理与大数据分析做准备。
    • 搭建自己的一套文件系统服务,对文件数据进行安全保护。
    • 拥有自己的平台,不限于其他方限制。

    存储机制

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

    直入正题SpringBoot操作minio

    引入依赖
     <dependency>
                <groupId>io.minio</groupId>
                <artifactId>minio</artifactId>
                <version>${minio.version}</version>
            </dependency>
            <dependency>
                <groupId>me.tongfei</groupId>
                <artifactId>progressbar</artifactId>
                <version>0.5.3</version>
            </dependency>
    
    配置文件
    minio:
      endpoint: 
      accessKey: 
      secretKey: 
      bucketName: filebucket
    
    配置类
    @Configuration
    @IntegrationComponentScan
    @Slf4j
    public class MinioConfig {
    
        @Value("${minio.endpoint}")
        private String endpoint;
        @Value("${minio.bucketName}")
        private String bucketName;
        @Value("${minio.accessKey}")
        private String accessKey;
        @Value("${minio.secretKey}")
        private String secretKey;
    
        @Bean
        public MinioUtils creatMinioClient() {
            return new MinioUtils(endpoint, bucketName, accessKey, secretKey);
        }
    
    }
    
    工具类
    /**
     * @Author: Cyw
     * @Date: 2020/12/01/10:02
     * @Description: Minio工具类
     */
    
    @Slf4j
    public class MinioUtils {
    
        private static MinioClient minioClient;
    
        private static String endpoint;
        private static String bucketName;
        private static String accessKey;
        private static String secretKey;
    
        private static final String SEPARATOR = "/";
    
        private MinioUtils() {
        }
    
        public MinioUtils(String endpoint, String bucketName, String accessKey, String secretKey) {
            MinioUtils.endpoint = endpoint;
            MinioUtils.bucketName = bucketName;
            MinioUtils.accessKey = accessKey;
            MinioUtils.secretKey = secretKey;
            createMinioClient();
        }
    
        /**
         * 创建minioClient
         */
        public void createMinioClient() {
            try {
                if (null == minioClient) {
                    log.info("minioClient create start");
                    minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey)
                            .build();
                    createBucket();
                    log.info("minioClient create end");
                }
            } catch (Exception e) {
                log.error("连接MinIO服务器异常:{}", e);
            }
        }
    
        /**
         * 获取上传文件的基础路径
         *
         * @return url
         */
        public static String getBasisUrl() {
            return endpoint + SEPARATOR + bucketName + SEPARATOR;
        }
    
    
        /**
         * 初始化Bucket
         * 操作存储桶
         *
         * @throws Exception 异常
         */
        private static void createBucket()
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException, RegionConflictException {
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        }
    
        /**
         * 验证bucketName是否存在
         *
         * @return boolean true:存在
         */
        public static boolean bucketExists()
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        }
    
        /**
         * 创建bucket
         *
         * @param bucketName bucket名称
         */
        public static void createBucket(String bucketName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException, RegionConflictException {
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        }
    
        /**
         * 获取存储桶策略
         *
         * @param bucketName 存储桶名称
         * @return json
         */
        private JSONObject getBucketPolicy(String bucketName)
                throws IOException, InvalidKeyException, InvalidResponseException, BucketPolicyTooLargeException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException {
            String bucketPolicy = minioClient
                    .getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());
            return JSONObject.parseObject(bucketPolicy);
        }
    
        /**
         * 获取全部bucket
         * <p>
         * https://docs.minio.io/cn/java-client-api-reference.html#listBuckets
         */
        public static List<Bucket> getAllBuckets()
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.listBuckets();
        }
    
        /**
         * 根据bucketName获取信息
         *
         * @param bucketName bucket名称
         */
        public static Optional<Bucket> getBucket(String bucketName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
        }
    
        /**
         * 根据bucketName删除信息
         *
         * @param bucketName bucket名称
         */
        public static void removeBucket(String bucketName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
        }
    
    
        /**
         * 判断文件是否存在
         * 操作文件对象
         *
         * @param bucketName 存储桶
         * @param objectName 对象
         * @return true:存在
         */
        public static boolean doesObjectExist(String bucketName, String objectName) {
            boolean exist = true;
            try {
                minioClient
                        .statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
            } catch (Exception e) {
                exist = false;
            }
            return exist;
        }
    
        /**
         * 判断文件夹是否存在
         *
         * @param bucketName 存储桶
         * @param objectName 文件夹名称(去掉/)
         * @return true:存在
         */
        public static boolean doesFolderExist(String bucketName, String objectName) {
            boolean exist = false;
            try {
                Iterable<Result<Item>> results = minioClient.listObjects(
                        ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
                for (Result<Item> result : results) {
                    Item item = result.get();
                    if (item.isDir() && objectName.equals(item.objectName())) {
                        exist = true;
                    }
                }
            } catch (Exception e) {
                exist = false;
            }
            return exist;
        }
    
        /**
         * 根据文件前置查询文件
         *
         * @param bucketName bucket名称
         * @param prefix     前缀
         * @param recursive  是否递归查询
         * @return MinioItem 列表
         */
        public static List<Item> getAllObjectsByPrefix(String bucketName, String prefix,
                                                       boolean recursive)
                throws ErrorResponseException, InsufficientDataException, InternalException, InvalidBucketNameException, InvalidKeyException, InvalidResponseException,
                IOException, NoSuchAlgorithmException, ServerException, XmlParserException {
            List<Item> list = new ArrayList<>();
            Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
            if (objectsIterator != null) {
                for (Result<Item> o : objectsIterator) {
                    Item item = o.get();
                    list.add(item);
                }
            }
            return list;
        }
    
        /**
         * 获取文件流
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @return 二进制流
         */
        public static InputStream getObject(String bucketName, String objectName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient
                    .getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
        }
    
        /**
         * 断点下载
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @param offset     起始字节的位置
         * @param length     要读取的长度
         * @return 流
         */
        public InputStream getObject(String bucketName, String objectName, long offset, long length)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.getObject(
                    GetObjectArgs.builder().bucket(bucketName).object(objectName).offset(offset).length(length)
                            .build());
        }
    
        /**
         * 获取路径下文件列表
         *
         * @param bucketName bucket名称
         * @param prefix     文件名称
         * @param recursive  是否递归查找,如果是false,就模拟文件夹结构查找
         * @return 二进制流
         */
        public static Iterable<Result<Item>> listObjects(String bucketName, String prefix,
                                                         boolean recursive) {
            return minioClient.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
        }
    
        /**
         * 通过MultipartFile,上传文件
         *
         * @param bucketName 存储桶
         * @param file       文件
         * @param objectName 对象名
         */
        public static ObjectWriteResponse putObject(String bucketName, MultipartFile file,
                                                    String objectName, String contentType)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            InputStream inputStream = file.getInputStream();
            return minioClient.putObject(
                    PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType)
                            .stream(
                                    inputStream, inputStream.available(), -1)
                            .build());
        }
    
        /**
         * 上传本地文件
         *
         * @param bucketName 存储桶
         * @param objectName 对象名称
         * @param fileName   本地文件路径
         */
        public static ObjectWriteResponse putObject(String bucketName, String objectName,
                                                    String fileName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.uploadObject(
                    UploadObjectArgs.builder()
                            .bucket(bucketName).object(objectName).filename(fileName).build());
        }
    
        /**
         * 通过流上传文件
         *
         * @param bucketName  存储桶
         * @param objectName  文件对象
         * @param inputStream 文件流
         */
        public static ObjectWriteResponse putObject(String bucketName, String objectName,
                                                    InputStream inputStream)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.putObject(
                    PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
                            inputStream, inputStream.available(), -1)
                            .build());
        }
    
        /**
         * 创建文件夹或目录
         *
         * @param bucketName 存储桶
         * @param objectName 目录路径
         */
        public static ObjectWriteResponse putDirObject(String bucketName, String objectName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.putObject(
                    PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
                            new ByteArrayInputStream(new byte[]{}), 0, -1)
                            .build());
        }
    
        /**
         * 获取文件信息, 如果抛出异常则说明文件不存在
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         */
        public static ObjectStat statObject(String bucketName, String objectName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient
                    .statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        }
    
        /**
         * 拷贝文件
         *
         * @param bucketName    bucket名称
         * @param objectName    文件名称
         * @param srcBucketName 目标bucket名称
         * @param srcObjectName 目标文件名称
         */
        public static ObjectWriteResponse copyObject(String bucketName, String objectName,
                                                     String srcBucketName, String srcObjectName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.copyObject(
                    CopyObjectArgs.builder()
                            .source(CopySource.builder().bucket(bucketName).object(objectName).build())
                            .bucket(srcBucketName)
                            .object(srcObjectName)
                            .build());
        }
    
        /**
         * 删除文件
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         */
        public static void removeObject(String bucketName, String objectName)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
        }
    
        /**
         * 批量删除文件
         *
         * @param bucketName bucket
         * @param keys       需要删除的文件列表
         * @return
         */
      /*public static Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> keys) {
        List<DeleteObject> objects = new LinkedList<>();
        keys.forEach(s -> {
          objects.add(new DeleteObject(s));
        });
        return minioClient.removeObjects(
            RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build());
      }*/
        public static void removeObjects(String bucketName, List<String> keys) {
            List<DeleteObject> objects = new LinkedList<>();
            keys.forEach(s -> {
                objects.add(new DeleteObject(s));
                try {
                    removeObject(bucketName, s);
                } catch (Exception e) {
                    log.error("批量删除失败!error:{}", e);
                }
            });
        }
    
    
        /**
         * 获取文件外链
         * 操作Presigned
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @param expires    过期时间 <=7 秒级
         * @return url
         */
        public static String getPresignedObjectUrl(String bucketName, String objectName,
                                                   Integer expires)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, InvalidExpiresRangeException, ServerException, InternalException, NoSuchAlgorithmException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            return minioClient.presignedGetObject(bucketName, objectName, expires);
        }
    
        /**
         * 给presigned URL设置策略
         *
         * @param bucketName 存储桶
         * @param objectName 对象名
         * @param expires    过期策略
         * @return map
         */
        public static Map<String, String> presignedGetObject(String bucketName, String objectName,
                                                             Integer expires)
                throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, InvalidExpiresRangeException, ServerException, InternalException, NoSuchAlgorithmException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
            PostPolicy policy = new PostPolicy(bucketName, objectName,
                    ZonedDateTime.now().plusDays(7));
            policy.setContentType("image/png");
            return minioClient.presignedPostPolicy(policy);
        }
    
    
        /**
         * 将URLDecoder编码转成UTF8
         *
         * @param str
         * @return
         * @throws UnsupportedEncodingException
         */
        public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
            String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
            return URLDecoder.decode(url, "UTF-8");
        }
    
        public static String getUrl(String objectName) throws Exception {
            return minioClient.getObjectUrl(bucketName, objectName);
        }
    
    }
    
    

    之后就可以进行测试,根据项目需求进行调用工具类就可以了

    展开全文
  • 云平台技术选型之七:分布式对象存储,对市面上的分布式对象存储OSS方案进行了调研,并确定了最终的选型
  • 聊一聊分布式对象存储解决方案

    千次阅读 2019-05-11 09:42:43
    OSS(Object Storage Service)俗称对象存储,主要提供图片、文档、音频、视频等二进制文件的海量存储功能。本文列举了常见的开源方案:

    OSS(Object Storage Service)俗称对象存储,主要提供图片、文档、音频、视频等二进制文件的海量存储功能。目前除了公有云提供对象存储服务外,一般私有云比较关心一些开源的分布式对象存储解决方案,本文列举了一些常见的技术方案供参考。

    概念普识

    块存储
    通常SAN(Storage Area Network)结构的产品属于块存储,比如我们常见的硬盘、磁盘阵列等物理盘。

    文件存储
    一般NAS(Network Attached Storage)产品都是文件级存储,如Ceph的CephFS,另外GFS、HDFS等也属于文件存储。

    对象存储
    同时兼顾着SAN高速直接访问磁盘特点及NAS的分布式共享特点的一类存储,一般是通过RESTful接口访问。

    开源解决方案介绍

    Swift

    Swift 是 OpenStack 社区核心子项目,是一个弹性可伸缩、高可用的分布式对象存储系统,使用Python语言实现,采用 Apache 2.0 许可协议。

    Swift 提供一个基于RESTful HTTP接口的 Object Storage API,用于创建,修改和获取对象和元数据。用户可以使用 Swift 高效、安全且廉价地存储大量数据。Swift 整体架构:

    总的来说,企业如果想要建立可扩展的分布式对象存储集群,可以考虑 Swift。

    Ceph

    Ceph是一种高性能、高可用、可扩展的分布式存储系统,统一的对外提供对象存储、块存储以及文件存储功能,底层使用C/C++语言。

    其中对象存储功能支持 2 种接口:
    1、兼容S3:提供了对象存储接口,兼容 S3 RESTful 接口的一个大子集。
    2、兼容Swift:提供了对象存储接口,兼容 Openstack Swift 接口的一个大子集。

    Ceph是一个企业级分布式存储系统,功能强大,不仅可以为企业建立对象存储服务,还可以帮助企业建立自己的云平台,具有广泛的应用场景特别是在云环境下使用广泛。

    Minio

    Minio是一个企业级、兼容S3接口的对象存储系统。Minio基于 Apache 2.0 许可协议,采用Go语言实现,客户端支持Java、Python、Go等多种语言,是一种轻量级、高并发的开源解决方案,可以作为云存储方案用来保存海量的图片,视频,文档等。

    大数据集成方面,Minio支持各种常见的查询计算引擎,比如Spark、Presto、Hive以及Flink等,可以使用这些处理框架查询分析对象数据,此外,Minio支持Parquet,Json、Csv格式等多种文件存储格式,包括压缩与编码。更多特性可以参考官网 地址https://min.io。Minio架构:

    Minio主要为人工智能、机器学习而设计,并适用于其他大数据负载。从架构与功能方面考虑,Minio是一个比较好的开源对象存储解决方案。

    HBase MOB

    这是利用HBase的MOB特性支持对象存储功能。Apache HBase2.0 版本开始支持中等对象存储(Medium Object Storage,简称 MOB),这个特性使得HBase能够非常良好的存储大小在100KB-10M的图片、文档、音频、短视频等二进制数据。

    架构如上,HBase MOB的设计类似于HBase + HDFS的方式,中等对象在写入HDFS之前同样是先写入MemStore,但是刷写与其他写入数据不同,MOB数据被刷写到MOB File中,MOB File被存放在特殊的Region中。

    MOB特性在Apache HBase 2.0、CDH 5.4.x 或 HDP 2.5.x 及以上版本支持,用户可以基于HBase MOB特性设计自己的对象存储服务。

    Hadoop Ozone

    Ozone是 Apache Hadoop 的子项目,为了提供分布式、可扩展的对象存储功能,主要是为了弥补HDFS在小文件存储方面的不足之处。Ozone建立在一个高可用、支持块复制的Hadoop分布式数据存储层之上,称为Hadoop Distributed Data Store(HDDS),上层可对接 Spark、Hive 以及 Yarn 等计算调度引擎。但是目前还处于alpha内部测试版本,暂时不建议生产环境中使用。

    小结

    对象存储主要是解决海量图片、文档、音视频的存储,其中主流的重量级解决方案是Swift与Ceph,它们各有特点,可以参考搜索引擎上的对比,Hadoop生态体系中备受关注的是HBase MOB,另外轻量级的Minio也是一种比较好的选择。MongoDB也提供了大文件存储模块GridFS。建议根据实际情况做技术选型。

    往期推荐

    1、HBase最佳实践 | 聊聊HBase核心配置参数
    2、Apache Hudi:剑指数据湖的增量处理框架
    3、Hadoop社区比 Ozone 更重要的事情
    4、MapReduce Shuffle 和 Spark Shuffle 结业篇

    展开全文
  • 1 基本概念介绍 1.1 存储空间(Bucket) 存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。... 存储空间的名称在 OSS 范围内必须是全局唯一的,一旦创建之后无法修

    1 基本概念介绍

    1.1 存储空间(Bucket)

    存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。您可以设置和修改存储空间属性用来控制地域、访问权限、生命周期等,这些属性设置直接作用于该存储空间内所有对象,因此您可以通过灵活创建不同的存储空间来完成不同的管理功能。

    • 同一个存储空间的内部是扁平的,没有文件系统的目录等概念,所有的对象都直接隶属于其对应的存储空间。
    • 每个用户可以拥有多个存储空间。
    • 存储空间的名称在 OSS 范围内必须是全局唯一的,一旦创建之后无法修改名称。
    • 存储空间内部的对象数目没有限制。

    存储空间的命名规范如下:

    • 只能包括小写字母,数字和短横线(-)。
    • 必须以小写字母或者数字开头。
    • 长度必须在3-63字节之间。

    1.2 对象/文件(Object)

    对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的 Key 来标识。对象元信息是一个键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。

    根据不同的上传方式,对象的大小限制是不一样的。分片上传 最大支持 48.8TB 的对象大小,其他的上传方式最大支持 5GB。

    对象的生命周期是从上传成功到被删除为止。在整个生命周期内,对象信息不可变更。重复上传同名的对象会覆盖之前的对象,因此,OSS 不支持修改文件的部分内容等操作。

    OSS 提供了 追加上传 功能,用户可以使用该功能不断地在Object尾部追加写入数据。

    对象的命名规范如下:

    • 使用UTF-8编码。
    • 长度必须在1-1023字节之间。
    • 不能以“/”或者“\”字符开头。
    • 对象名称需要区分大小写。如无特殊说明,本文档中的对象、文件称谓等同于 Object。

    1.3 Region(区域)

    Region 表示 OSS 的数据中心所在的区域,物理位置。用户可以根据费用、请求来源等综合选择数据存储的 Region。一般来说,距离用户更近的 Region 访问速度更快。详细请查看 OSS 已经开通的 Region

    Region是在创建 Bucket 的时候指定的,一旦指定之后就不允许更改,该 Bucket 下所有的 Object 都存储在对应的数据中心,目前不支持 Object 级别的 Region 设置。

    1.4 Endpoint(访问域名)

    Endpoint 表示 OSS 对外服务的访问域名。OSS 以 HTTP RESTful API 的形式对外提供服务,当访问不同的 Region 的时候,需要不同的域名。通过内网和外网访问同一个 Region 所需要的 Endpoint 也是不同的。例如杭州 Region 的外网 Endpoint 是 oss-cn-hangzhou.aliyuncs.com,内网 Endpoint 是 oss-cn-hangzhou-internal.aliyuncs.com。具体的内容请参见 各个 Region 对应的 Endpoint

    1.5 AccessKey(访问密钥)

    AccessKey,简称 AK,指的是访问身份验证中用到的 AccessKeyId 和AccessKeySecret。OSS 通过使用 AccessKeyId 和 AccessKeySecret 对称加密的方法来验证某个请求的发送者身份。AccessKeyId 用于标识用户,AccessKeySecret 是用户用于加密签名字符串和 OSS 用来验证签名字符串的密钥,其中 AccessKeySecret 必须保密。对于 OSS 来说,AccessKey 的来源有:

    • Bucket 的拥有者申请的 AccessKey。
    • 被 Bucket 的拥有者通过 RAM 授权给第三方请求者的 AccessKey。
    • 被 Bucket 的拥有者通过 STS 授权给第三方请求者的 AccessKey。

    更多 AccessKey 介绍请参见 访问控制

    1.6 强一致性

    Object 操作在 OSS 上具有原子性,操作要么成功要么失败,不会存在有中间状态的Object。OSS 保证用户一旦上传完成之后读到的 Object 是完整的,OSS 不会返回给用户一个部分上传成功的 Object。

    Object 操作在 OSS 上同样具有强一致性,用户一旦收到了一个上传(PUT)成功的响应,该上传的 Object 就已经立即可读,并且数据的三份副本已经写成功。不存在一种上传的中间状态,即 read-after-write 却无法读取到数据。对于删除操作也是一样的,用户删除指定的 Object 成功之后,该 Object 立即变为不存在。

    强一致性方便了用户架构设计,可以使用跟传统存储设备同样的逻辑来使用OSS,修改立即可见,无需考虑最终一致性带来的各种问题。

    1.7 OSS与文件系统的对比

    OSS 是一个分布式的对象存储服务,提供的是一个 Key-Value 对形式的对象存储服务。用户可以根据 Object 的名称(Key)唯一的获取该Object的内容。虽然用户可以使用类似 test1/test.jpg 的名字,但是这并不表示用户的 Object 是保存在test1 目录下面的。对于 OSS 来说,test1/test.jpg 仅仅只是一个字符串,和a.jpg 这种并没有本质的区别。因此不同名称的 Object 之间的访问消耗的资源是类似的。

    文件系统是一种典型的树状索引结构,一个名为 test1/test.jpg 的文件,访问过程需要先访问到 test1 这个目录,然后再在该目录下查找名为 test.jpg 的文件。因此文件系统可以很轻易的支持文件夹的操作,比如重命名目录、删除目录、移动目录等,因为这些操作仅仅只是针对目录节点的操作。这种组织结构也决定了文件系统访问越深的目录消耗的资源也越大,操作拥有很多文件的目录也会非常慢。

    对于 OSS 来说,可以通过一些操作来模拟类似的功能,但是代价非常昂贵。比如重命名目录,希望将 test1 目录重命名成 test2,那么 OSS 的实际操作是将所有以 test1/ 开头的 Object 都重新复制成以 test2/ 开头的 Object,这是一个非常消耗资源的操作。因此在使用 OSS 的时候要尽量避免类似的操作。

    OSS 保存的 Object 不支持修改(追加写 Object 需要调用特定的接口,生成的 Object 也和正常上传的 Object 类型上有差别)。用户哪怕是仅仅需要修改一个字节也需要重新上传整个 Object。而文件系统的文件支持修改,比如修改指定偏移位置的内容、截断文件尾部等,这些特点也使得文件系统拥有广泛的适用性。但另外一方面,OSS 能支持海量的用户并发访问,而文件系统会受限于单个设备的性能。

    因此,将 OSS 映射为文件系统是非常低效的,也是不建议的做法。如果一定要挂载成文件系统的话,建议尽量只做写新文件、删除文件、读取文件这几种操作。使用 OSS 应该充分发挥其优点,即海量数据处理能力,优先用来存储海量的非结构化数据,比如图片、视频、文档等。

    1.8 OSS 术语表

    英文中文
    Bucket存储空间
    Object对象或者文件
    EndpointOSS 访问域名
    Region区域或者数据中心
    AccessKeyAccessKeyId 和 AccessKeySecret 的统称,访问密钥
    Put Object简单上传
    Post Object表单上传
    Multipart Upload分片上传
    Append Object追加上传
    Get Object简单下载
    Callback回调
    Object Meta文件元信息。用来描述文件信息,例如长度,类型等
    Data文件数据
    Key文件名
    ACL (Access Control List)存储空间或者文件的权限
    展开全文
  • MinIO分布式对象存储

    千次阅读 2020-11-02 16:38:17
    MinIO 分布式部署支持Docker Compose、Docker Swarm、Kubernetes等几种方式,Docker-Compose是单机多实例,伪分布式,可测试使用,因没有kubernetes环境,这里使用Docker Swarm 有3台服务器,一台docker swar

    MinIO 分布式部署需要4块磁盘,可以是4台服务器分别挂载一块磁盘,也可以是2台服务器分别挂载两块磁盘,可参考:https://docs.min.io/cn/deploy-minio-on-docker-swarm.html

    MinIO 分布式部署支持Docker Compose、Docker Swarm、Kubernetes等几种方式,Docker-Compose是单机多实例,伪分布式,可测试使用,因没有kubernetes环境,这里使用Docker Swarm

    有3台服务器,一台docker swarm manger ,两台worker

    主机IP角色
    172.16.0.5manager
    172.16.0.2worker
    172.16.0.8woker
    • 1.在 172.16.0.5 机器上使用:docker swarm init --advertise-addr 172.16.0.5
    • 2.一旦swarm初使化了,你可以看到下面的响应信息,复制这段信息,在两台worker节点上执行
    docker swarm join \
      --token  SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
      172.16.0.5:2377
    
    • 3.在manger节点上
      查看节点信息: docker node ls
      添加节点标签: docker node update --label-add minio1=true (ID) ,该ID为docker node ls 查询出来的worker节点ID
     docker node update --label-add minio1=true lzqc0e1lojlq64mtzhurkqojc
     docker node update --label-add minio2=true lzqc0e1lojlq64mtzhurkqojc
     docker node update --label-add minio3=true 9kyb2ztxmrk4uwyor3xxjysb6
     docker node update --label-add minio4=true 9kyb2ztxmrk4uwyor3xxjysb6
    

    在这里插入图片描述

    • 4.为MinIO创建Docker secret
    echo "AKIAIOSFODNN7EXAMPLE" | docker secret create access_key -
    echo "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" | docker secret create secret_key -
    
    • 5.下载docker-compose-secrets.yaml 部署文件
    wget https://raw.githubusercontent.com/minio/minio/master/docs/orchestration/docker-swarm/docker-compose-secrets.yaml
    
    • 6.修改部署文件里面的内容(基本不用改什么,可以修改volumes,挂载宿主机指定磁盘目录)
    version: '3.7'
    
    services:
      minio1:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio1
        volumes:
          - minio1-data:/export
        ports:
          - "9001:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio1==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
      minio2:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio2
        volumes:
          - minio2-data:/export
        ports:
          - "9002:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio2==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
      minio3:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio3
        volumes:
          - minio3-data:/export
        ports:
          - "9003:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio3==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
      minio4:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio4
        volumes:
          - minio4-data:/export
        ports:
          - "9004:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio4==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
    volumes:
      minio1-data:
      minio2-data:
      minio3-data:
      minio4-data:
    
    networks:
      minio_distributed:
        driver: overlay
    
    secrets:
      secret_key:
        external: true
      access_key:
        external: true
    
    • 7.启动集群:docker stack deploy --compose-file=./docker-compose-secrets.yaml minio_stack
      使用docker service ls 查看4个minio服务
      在这里插入图片描述
      在两台worker节点上执行docker ps,可以看到每台worker服务器分别启动了2个minio实例
      在这里插入图片描述
      在两台worker节点上执行docker volume ls ,查看minio容器把文件存放在什么位置
      docker volume inspect minio_stack_minio1-data
      在这里插入图片描述
    • 8.使用Nginx对4个MinIO服务实例进行代理
      安装nginx请参考:https://zhuyu.blog.csdn.net/article/details/103696133
      nginx.conf配置文件内容如下:
        upstream minio-cluster {
           server 172.16.0.2:9001;
           server 172.16.0.2:9002;
           server 172.16.0.8:9003;
           server 172.16.0.8:9004;  
        }
        server {
            listen       9000;
            server_name  172.16.0.5;
            location / {
                proxy_pass http://minio-cluster;
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                proxy_connect_timeout 90;
                proxy_send_timeout 90;
                proxy_buffer_size 4k;
                proxy_buffers 4 32k;
                client_max_body_size 10m;
                client_body_buffer_size 256k;
                #请注意加上下面2个配置参数
                proxy_buffering off;
                proxy_redirect off;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    

    访问 172.16.0.5:9000 就可以访问 MinIO服务操作文件了,如下创建了名称为test的桶,创建目录,上传了文件,在MinIO worker服务器的数据存放目录查看是否有文件
    在这里插入图片描述

    可以看到在4个minio实例的每个volume目录下都能看到如下图的信息,每个实例(每个磁盘)都全量存储数据,这样实现了高可用,但是未实现分布式大数据量存储呀(可能是我配置有误,如有网友知道请留言)
    在这里插入图片描述

    • 9.删除分布式MinIO services
    #删除集群
    docker stack rm minio_stack
    
    #删除volume
    docker volume ls
    docker volume rm volume_name 
    
    • 10.扩展集群也比较方便,请查看官网:
    启动分布式Minio实例,4节点,每节点4块盘,需要在4个节点上都运行下面的命令
    minio server http://192.168.1.11/export1 http://192.168.1.11/export2 \
                   http://192.168.1.11/export3 http://192.168.1.11/export4 \
                   http://192.168.1.12/export1 http://192.168.1.12/export2 \
                   http://192.168.1.12/export3 http://192.168.1.12/export4 \
                   http://192.168.1.13/export1 http://192.168.1.13/export2 \
                   http://192.168.1.13/export3 http://192.168.1.13/export4 \
                   http://192.168.1.14/export1 http://192.168.1.14/export2 \
                   http://192.168.1.14/export3 http://192.168.1.14/export4
    
    MinIO支持通过命令,指定新的集群来扩展现有集群(纠删码模式),命令行如下:
    minio server http://host{1...32}/export{1...32} http://host{33...64}/export{1...32}
    
    • 10.指定minio挂载磁盘目录,在两台worker节点上创建目录,如果挂载的是新磁盘请格式化等处理后mount到 根目录
      worker1节点:mkdir /minio1_data ,mkdir /minio2_data
      worker2节点:mkdir /minio3_data ,mkdir /minio3_data
    version: '3.7'
    
    services:
      minio1:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio1
        volumes:
          # 指定宿主机根目录下的minio1_data目录挂载映射到容器/export目录
          - /minio1_data:/export
        ports:
          - "9001:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio1==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
      minio2:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio2
        volumes:
          - /minio2_data:/export
        ports:
          - "9002:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio2==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
      minio3:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio3
        volumes:
          - /minio3_data:/export
        ports:
          - "9003:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio3==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
      minio4:
        image: minio/minio:RELEASE.2020-10-28T08-16-50Z
        hostname: minio4
        volumes:
          - /minio4_data:/export
        ports:
          - "9004:9000"
        networks:
          - minio_distributed
        deploy:
          restart_policy:
            delay: 10s
            max_attempts: 10
            window: 60s
          placement:
            constraints:
              - node.labels.minio4==true
        command: server http://minio{1...4}/export
        secrets:
          - secret_key
          - access_key
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
          interval: 30s
          timeout: 20s
          retries: 3
    
    networks:
      minio_distributed:
        driver: overlay
    
    secrets:
      secret_key:
        external: true
      access_key:
        external: true
    
    展开全文
  • 分布式对象存储解决方案 OSS(Object Storage Service)俗称对象存储,主要提供图片、文档、音频、视频等二进制文件的海量存储功能。目前除了公有云提供对象存储服务外,一般私有云比较关心一些开源的分布式对象...
  • 一句话:MinIO是高性能、可扩展、云原生支持、操作简单、开源的分布式对象存储产品。 你可以把它和FastDFS、HDFS作为类比,但它比其它都更简单,极简是MinIO的设计初衷之一,而且他的性能很好。 当然也有很多商用的...
  • 大家好今儿给大家带来的是springboot 整合分布式文件存储服务器OSS 目录大家好今儿给大家带来的是springboot 整合分布式文件存储服务器OSS1.OSS简单介绍及操作2.创建Bucket3.springboot整合OSS4.OSS上传文档介绍5....
  • 分布式存储对象存储概述
  • 文件存储NAS与对象存储OSS

    千次阅读 2021-02-04 15:44:47
    摘要:本文主要介绍文件存储NAS与对象存储OSS这2种目前主要的存储技术,以及差异,并介绍了各自的主要使用场景。 一、技术介绍 1.1、文件存储NAS 1.1.1概念 NAS(Network Attached Storage):是一套网络储存...
  • 开源分布式对象存储-MinIO

    千次阅读 2020-01-22 22:23:02
    但随着业务的快速发展,我们需要存储一些身份信息用于审核和实名相关的数据,这部分数据较为敏感,因此对于敏感数据的存储我们选择了使用兼容S3协议的开源分布式对象存储-Minio来进行自建服务。 前言 Minio可能...
  • 阿里云对象存储OSS的基本介绍

    千次阅读 2019-03-26 09:54:44
    对象存储OSS的基本介绍 OSS是一种面向互联网的分布式存储服务,具有海量、安全、高性能、高可靠性、低成本的特点。 OSS非常适合用来存储大量不同大小、格式的非结构化数据,比如视频、图像、文本、日志等。它可以...
  • 目前除了公有云提供对象存储服务外,一般私有云比较关心一些开源的分布式对象存储解决方案,本文列举了一些常见的技术方案供参考。概念普识块存储通常SAN(Storage Area Network)结构的产品属于块存储,比如我们...
  • 阿里云对象存储OSS和文件存储NAS有什么区别?文件存储NAS和对象存储OSS如何选择?NAS是传统的NFS挂载共享文件夹,OSS可以使用RESTful API,阿里云百科从技术、使用方式、容量、存储内容、性能及使用场景等方面来详细...
  • 对象存储OSS是阿里云提供的海量、安全、低成本、高持久性的云存储服务。本文将OSS与传统的自建存储进行对比,让您更好的了解OSSOSS与自建存储对比的优势 对比项 对象存储OSS 自建服务器存储 持久性 ...
  • 本文分享阿里云在对象存储 OSS(Open Storage Service) 的可用性 SLA (Service Level Agreement) 上的实践和技术沉淀。一 概述阿里云对象存储 OSS 通过十年积累的技术红利,长期在双十一淘宝应用如丝般顺滑体验需求的...
  • 五、对象存储OSS 块存储适合存放本地使用的一些文件,而且成本比较高,容量也有一些限制,不是适合数据量庞大的大数据。 1、对象存储OSS的概念 1.1 什么是对象存储OSS 存储分类 块存储:阿里云为云服务器ECS...
  • 怎么统一管理的,我这里就教给大家一种简单的方法,统一存储在阿里云服务器的对象存储OSS中。 oss是什么我就不讲了,百度一搜一大堆。 今天分两步讲下: 第一步讲下OSS云存储开通与使用。 首先登陆阿里云,首页...
  • 文章目录商城品牌管理新建品牌管理菜单对显示状态进行优化阿里云对象存储OSS什么是对象存储 OSS相关概念存储类型(Storage Class)存储空间(Bucke...
  • 对象存储OSS介绍

    2018-11-21 11:40:40
    阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以通过调用 API,在任何应用、任何时间、任何地点上传和下载数据,也可以通过 Web 控制台对...
  • 1. 服务接口定义/*** 文件上传 1:头像 2:显示图片 3:个人封面 :4:基础图片* @param request* @param response* @param uid 用户id* @param userType ...@param files 上传的文件对象* @return* @throws Except...
  • 一、开通“对象存储OSS”服务 为了解决海量数据存储与弹性扩容,项目中我们采用云存储的解决方案- 阿里云OSS。 1、开通“对象存储OSS”服务 2、进入管理控制台 二、控制台使用 1、创建Bucket 命名:srb-file 读写...
  • 对象存储 OSS 文档来源于阿里云对象存储 OSS,Minio也是对象存储 OSS,很多概念都是相通的,所以了解下。实际企业应用使用阿里OSS是一个很不错的选择。 对象存储服务(Object Storage Service,OSS)是一种海量、...
  • 产品选型主要从OSS和NAS中选择一款,满足文档存储的需求。 二、NAS优缺点 NAS 是一种采用直接与网络介质相连的特殊设备实现数据存储的机制。由于这些设备都分配有 IP 地址,所以客户机通过充当数据网关的服务器...
  • 对象存储OSS提供标准、低频访问、归档、冷归档四种存储类型,全面覆盖从热到冷的各种数据存储场景。 说明 冷归档存储目前仅在华北2(北京)地域邀测中。 各存储类型的定价信息请参见OSS详细价格信息。具体的计费...
  • 日志文件存储方式采用对象存储OSS 解析日志文件增加redis分布式锁 详情 客户端上报的日志分为两种,1是手动回捞的日志,2是客户端奔溃上报日志。日志文件是加密的压缩文件,上传到服务端以后,需要进行解压解密,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,891
精华内容 2,356
关键字:

分布式对象存储oss