快速入门案例描述图片上传配置环境pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.oss</groupId> <artifactId>oss-project01</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.8.0</version> </dependency> </dependencies> </project>图片上传代码实现package com.oss; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; public class FileUpLoad { public static void main(String[] args) throws FileNotFoundException { // Endpoint以杭州为例，其它Region请按实际情况填写。 //String endpoint = "http://oss-cn-hangzhou.aliyuncs.com"; String endpoint = "http://oss-cn-beijing.aliyuncs.com"; // 云账号AccessKey有所有API访问权限，建议遵循阿里云安全最佳实践 创建并使用RAM子账号进行API访问或日常运维， String accessKeyId = "LTAI4GD1XcQgrQuvkKnZYhhA"; String accessKeySecret = "1n2i3VNxd5gWr9YPYuJbVMophsXUQr"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 上传文件流。 InputStream inputStream = new FileInputStream(new File("src\\main\\resources\\1.png")); ossClient.putObject("test-imgs", "1.png", inputStream); // 关闭OSSClient。 ossClient.shutdown(); } }java API操作需求描述1）创建Bucket2）把字符串存入OSS，Object的名称为firstKey3）下载文件4）文件存储入OSS5）查看Bucket中的Object6）删除Object功能实现pom.xml 同上一个例子代码实现package com.oss; import java.io.*; import java.util.List; import java.util.Properties; import com.aliyun.oss.ClientException; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.OSSException; import com.aliyun.oss.model.BucketInfo; import com.aliyun.oss.model.OSSObject; import com.aliyun.oss.model.OSSObjectSummary; import com.aliyun.oss.model.ObjectListing; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; public class HelloOSS { static Logger logger = Logger.getLogger(HelloOSS.class); // endpoint是访问OSS的域名。如果您已经在OSS的控制台上 创建了Bucket，请在控制台上查看域名。 // 如果您还没有创建Bucket，endpoint选择请参看文档中心的“开发人员指南 > 基本概念 > 访问域名”， // 链接地址是：https://help.aliyun.com/document_detail/oss/user_guide/oss_concept/endpoint.html?spm=5176.docoss/user_guide/endpoint_region // endpoint的格式形如“http://oss-cn-hangzhou.aliyuncs.com/”，注意http://后不带bucket名称， // 比如“http://bucket-name.oss-cn-hangzhou.aliyuncs.com”，是错误的endpoint，请去掉其中的“bucket-name”。 private static String endpoint = "http://oss-cn-beijing.aliyuncs.com"; // accessKeyId和accessKeySecret是OSS的访问密钥，您可以在控制台上创建和查看， // 创建和查看访问密钥的链接地址是：https://ak-console.aliyun.com/#/。 // 注意：accessKeyId和accessKeySecret前后都没有空格，从控制台复制时请检查并去除多余的空格。 private static String accessKeyId = "LTAI4GD1XcQgrQuvkKnZYhhA"; private static String accessKeySecret = "1n2i3VNxd5gWr9YPYuJbVMophsXUQr"; // Bucket用来管理所存储Object的存储空间，详细描述请参看“开发人员指南 > 基本概念 > OSS基本概念介绍”。 // Bucket命名规范如下：只能包括小写字母，数字和短横线（-），必须以小写字母或者数字开头，长度必须在3-63字节之间。 private static String bucketName = "test-imgs"; // Object是OSS存储数据的基本单元，称为OSS的对象，也被称为OSS的文件。详细描述请参看“开发人员指南 > 基本概念 > OSS基本概念介绍”。 // Object命名规范如下：使用UTF-8编码，长度必须在1-1023字节之间，不能以“/”或者“\”字符开头。 private static String firstKey = "my-first-key"; public static void main(String[] args) throws IOException { // 日志配置，OSS Java SDK使用log4j记录错误信息。示例程序会在工程目录下生成“ossdemo.log”日志文件，默认日志级别是INFO。 // 日志的配置文件是“conf/log4j.properties”，如果您不需要日志，可以没有日志配置文件和下面的日志配置。 // PropertyConfigurator.configure("conf/log4j.properties"); InputStream in = HelloOSS.class.getClassLoader().getResourceAsStream("log4j.properties"); Properties properties = new Properties(); properties.load(in); PropertyConfigurator.configure(properties); logger.info("Started"); // 生成OSSClient，您可以指定一些参数，详见“SDK手册 > Java-SDK > 初始化”， // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/init.html?spm=5176.docoss/sdk/java-sdk/get-start OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); try { // 判断Bucket是否存在。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/ manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init if (ossClient.doesBucketExist(bucketName)) { System.out.println("您已经创建Bucket：" + bucketName + "。"); } else { System.out.println("您的Bucket不存在，创建Bucket：" + bucketName + "。"); // 创建Bucket。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init ossClient.createBucket(bucketName); } // 查看Bucket信息。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init BucketInfo info = ossClient.getBucketInfo(bucketName); System.out.println("Bucket " + bucketName + "的信息如下："); System.out.println("\t数据中心：" + info.getBucket().getLocation()); System.out.println("\t创建时间：" + info.getBucket().getCreationDate()); System.out.println("\t用户标志：" + info.getBucket().getOwner()); // 把字符串存入OSS，Object的名称为firstKey。详细请参看“SDK手册 > Java-SDK > 上传文件”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/upload_object.html?spm=5176.docoss/user_guide/upload_object InputStream is = new ByteArrayInputStream("Hello OSS".getBytes()); ossClient.putObject(bucketName, firstKey, is); System.out.println("Object：" + firstKey + "存入OSS成功。"); // 下载文件。详细请参看“SDK手册 > Java-SDK > 下载文件”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/download_object.html?spm=5176.docoss/sdk/java-sdk/manage_object OSSObject ossObject = ossClient.getObject(bucketName, firstKey); InputStream inputStream = ossObject.getObjectContent(); StringBuilder objectContent = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); while (true) { String line = reader.readLine(); if (line == null) break; objectContent.append(line); } inputStream.close(); System.out.println("Object：" + firstKey + "的内容是：" + objectContent); // 文件存储入OSS，Object的名称为fileKey。详细请参看“SDK手册 > Java-SDK > 上传文件”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/upload_object.html?spm=5176.docoss/user_guide/upload_object String fileKey = "README.md"; ossClient.putObject(bucketName, fileKey, new File("src\\main\\resources\\README.md")); System.out.println("Object：" + fileKey + "存入OSS成功。"); // 查看Bucket中的Object。详细请参看“SDK手册 > Java-SDK > 管理文件”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/manage_object.html?spm=5176.docoss/sdk/java-sdk/manage_bucket ObjectListing objectListing = ossClient.listObjects(bucketName); List<OSSObjectSummary> objectSummary = objectListing.getObjectSummaries(); System.out.println("您有以下Object："); for (OSSObjectSummary object : objectSummary) { System.out.println("\t" + object.getKey()); } // 删除Object。详细请参看“SDK手册 > Java-SDK > 管理文件”。 // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/javasdk/manage_object.html?spm=5176.docoss/sdk/java-sdk/manage_bucket ossClient.deleteObject(bucketName, firstKey); System.out.println("删除Object：" + firstKey + "成功。"); ossClient.deleteObject(bucketName, fileKey); System.out.println("删除Object：" + fileKey + "成功。"); } catch (OSSException oe) { oe.printStackTrace(); } catch (ClientException ce) { ce.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { ossClient.shutdown(); } logger.info("Completed"); } }log4j.propertieslog4j.rootLogger=INFO, RFA ossdemo.log.dir=. ossdemo.log.file=oss-demo.log # Logging Threshold log4j.threshold=ALL # Null Appender log4j.appender.NullAppender=org.apache.log4j.varia.NullAppender # # Rolling File Appender - cap space usage at 5gb. # ossdemo.log.maxfilesize=256MB ossdemo.log.maxbackupindex=20 log4j.appender.RFA=org.apache.log4j.RollingFileAppender log4j.appender.RFA.File=${ossdemo.log.dir}/${ossdemo.log.file} log4j.appender.RFA.MaxFileSize=${ossdemo.log.maxfilesize} log4j.appender.RFA.MaxBackupIndex=${ossdemo.log.maxbackupindex} log4j.appender.RFA.layout=org.apache.log4j.PatternLayout # Pattern format: Date LogLevel LoggerName LogMessage log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n # Debugging Pattern format #log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n # # Daily Rolling File Appender # log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender log4j.appender.DRFA.File=${ossdemo.log.dir}/${ossdemo.log.file} # Rollver at midnight log4j.appender.DRFA.DatePattern=.yyyy-MM-dd # 30-day backup #log4j.appender.DRFA.MaxBackupIndex=30 log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout # Pattern format: Date LogLevel LoggerName LogMessage log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n # Debugging Pattern format #log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n # # console # Add "console" to rootlogger above if you want to use this # log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.target=System.err log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}:%m%nSpringBoot整合OSS上传需求描述使用SpringBoot完成上传图片配置文件pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.oss</groupId> <artifactId>oss-project02</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>2.8.3</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.9.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>application.properties# Spring boot application #server.servlet.context-path=/oss-server server.port = 8999 #logging.level.root=DEBUGaliyun.propertiesaliyun.endpoint=http://oss-cn-beijing.aliyuncs.com aliyun.accessKeyId=LTAI4GD1XcQgrQuvkKnZYhhA aliyun.accessKeySecret=1n2i3VNxd5gWr9YPYuJbVMophsXUQr aliyun.bucketName=test-imgs aliyun.urlPrefix=https://test-imgs.oss-cn-beijing.aliyuncs.com/编码实现AliyunConfigpackage com.oss.config; import com.aliyun.oss.OSSClient; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource("classpath:aliyun.properties") @ConfigurationProperties(prefix = "aliyun") @Data public class AliyunConfig { private String endpoint; private String accessKeyId; private String accessKeySecret; private String bucketName; private String urlPrefix; @Bean public OSSClient oSSClient() { return new OSSClient(endpoint, accessKeyId, accessKeySecret); } }实体对象package com.oss.bean; import lombok.Data; @Data public class UpLoadResult { // 文件唯一标识 private String uid; // 文件名 private String name; // 状态有：uploading done error removed private String status; // 服务端响应内容，如：'{"status": "success"}' private String response; }FileUpLoadServicepackage com.oss.service; import com.aliyun.oss.OSSClient; import com.oss.bean.UpLoadResult; import com.oss.config.AliyunConfig; import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayInputStream; import java.io.IOException; @Service public class FileUpLoadService { @Autowired private AliyunConfig aliyunConfig; @Autowired private OSSClient ossClient; // 允许上传的格式 private static final String[] IMAGE_TYPE = new String[]{".bmp", ".jpg", ".jpeg", ".gif", ".png"}; public UpLoadResult upload(MultipartFile uploadFile) { // 校验图片格式 boolean isLegal = false; for (String type : IMAGE_TYPE) { if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), type)) { isLegal = true; break; } } UpLoadResult uploadResult = new UpLoadResult(); if (!isLegal) { uploadResult.setStatus("error"); return uploadResult; } String fileName = uploadFile.getOriginalFilename(); String filePath = getFilePath(fileName); try { ossClient.putObject(aliyunConfig.getBucketName(),filePath, new ByteArrayInputStream(uploadFile.getBytes())); } catch (IOException e) { e.printStackTrace(); //上传失败 uploadResult.setStatus("error"); return uploadResult; } uploadResult.setStatus("done"); uploadResult.setName(this.aliyunConfig.getUrlPrefix() + filePath); uploadResult.setUid(String.valueOf(System.currentTimeMillis())); return uploadResult; } private String getFilePath(String sourceFileName) { DateTime dateTime = new DateTime(); return "images/" + dateTime.toString("yyyy") + "/" + dateTime.toString("MM") + "/" + dateTime.toString("dd") + "/" + UUID.randomUUID().toString() + "." + StringUtils.substringAfterLast(sourceFileName, "."); } }UpLoadController 控制器package com.oss.controller; import com.oss.bean.UpLoadResult; import com.oss.service.FileUpLoadService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; @RequestMapping("/pic") @Controller public class UpLoadController { @Autowired private FileUpLoadService fileUpLoadService; @PostMapping("/upload") @ResponseBody public UpLoadResult upload(@RequestParam("file") MultipartFile multipartFile) { return this.fileUpLoadService.upload(multipartFile); } }ApplicationBoot 启动引导package com.oss; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ApplicationBoot { public static void main(String[] args) { SpringApplication.run(ApplicationBoot.class, args); } }测试数据处理介绍阿里云OSS为在云上的数据打通了一个处理与使用的快速通道。通过简单的 RESTful 接口，可以在任何时间、任何地点、任何互联网设备上对存储在OSS中的数据进行分析处理。数据处理包含以下两种：阿里云OSS原生处理服务阿里云OSS原生处理服务包括图片处理和视频截帧，其中图片处理包括图片的缩略、剪裁、参数调节等。 OSS原生处理服务无需开通，默认集成在OSS中，创建完Bucket后即可使用。产生的数据处理费用直接在OSS上结算。智能媒体管理服务阿里云OSS与智能媒体管理（IMM）深度结合，支持文档预览、文档格式转换、人脸识别、图片分析、二维码识别等丰富的数据分析处理操作。图片处理本文档介绍如何快速使用OSS图片处理服务。您可以通过三种方式处理图片：为图片URL添加参数进行单次处理、使用图片样式对不同图片进行相同处理，或使用OSS SDK对图片进行处理。处理操作说明文档图片缩放对图片进行等比缩放或固定宽高缩放。图片缩放图片裁剪使用内切圆裁剪图片。内切圆通过指定范围的方式裁剪图片。 自定义裁剪将图片在x或y轴上等分为多个区域，然后取出指定区域。 索引切割使用圆角矩形裁剪图片。 圆角矩形图片旋转设置是否对图片进行自动旋转自适应方向对图片进行指定角度的顺时针旋转。 旋转图片效果为图片添加模糊效果。模糊效果调整图片的亮度。 亮度对图片进行锐化。 锐化调整图片的对比度。 对比度格式转换将图片转换为指定的格式。格式转换可以对保存为JPG或WebP格式的图片进行图片质量转换。 质量变换指定图片的呈现方式。 渐进显示获取图片信息获取图片的平均色调。获取图片主色调获取图片的宽度、长度、文件大小、格式、EXIF信息等。 获取信息图片水印为图片添加图片、文字或混合水印。图片水印视频截祯注意事项当前仅支持对视频编码格式为H264的视频文件进行视频截帧。OSS当前没有默认保存视频截帧的操作，视频截帧的图片需手动下载到本地。参数说明操作名称：snapshot参数描述取值范围t指定截图时间。[0,视频时长] 单位：msw指定截图宽度，如果指定为0，则自动计算。[0,视频宽度] 单位：像素（px）h指定截图高度，如果指定为0，则自动计算；如果w和h都为0，则输出为原视频宽高。[0,视频高度] 单位：像素（px）m指定截图模式，不指定则为默认模式，根据时间精确截图。如果指定为fast，则截取该时间点之前的最近的一个关键帧。枚举值：fastf指定输出图片的格式。枚举值：jpg、pngar指定是否根据视频信息自动旋转图片。如果指定为auto，则会在截图生成之后根据视频旋转信息进行自动旋转。枚举值：autohttps://help.aliyun.com/document_detail/64555.html音视频处理存储在OSS上的多媒体音视频数据，可以通过经济、弹性、高扩展的阿里云媒体转码服务，转换成适合在移动端、PC、TV上播放的格式。媒体转码核心能力包括：转换媒体格式，支持多平台播放。保证相同画质质量的前提下，调整视频码率、提高视频压缩效率、减小文件体积，从而减少播放卡顿并节省存储空间和流量费用。添加水印logo，突出品牌，增加产品识别度。对视频进行剪辑/拼接等二次创作。针对画质较差的视频，去除画面中的毛刺、马赛克等，修复为高清晰版本。音视频转码智能媒体管理（IMM）阿里云 OSS 能够与智能媒体管理（IMM）深度结合，支持文档预览、文档格式转换、人脸识别、图片分析、二维码识别等丰富的数据分析处理操作。下面介绍如何在 OSS 控制台中使用 IMM 的功能。前提条件要在 OSS 中使用 IMM 功能，您需要开通 IMM 服务并进行授权。有关开通服务及授权的详细步骤，请参见开通产品及创建项目中的前提条件部分。如果您使用 RAM 子账号进行本文中的操作，需要同时开通对应存储空间的访问权限和 AliyunIMMFullAccess 权限。创建 IMM Project 及使用 IMM 功能会产生一定的费用，如果您不需要使用 IMM 的功能，请及时解绑 IMM。详细费用请参见计费说明。https://test-imgs.oss-cn-beijing.aliyuncs.com/1.png?x-ossprocess=imm/detecfacehttps://test-imgs.oss-cn-beijing.aliyuncs.com/1.png?x-ossprocess=imm/tagimageCDN 加速 (阿里 网宿 微软 亚马逊 akmai)对象存储OSS与阿里云CDN服务结合，可优化静态热点文件下载加速的场景（即同一地区大量用户同时下载同一个静态文件的场景）。您可以将OSS的存储空间（Bucket）作为源站，利用阿里云CDN将源内容发布到边缘节点。当大量终端用户重复访问同一文件时，可以直接从边缘节点获取已缓存的数据，提高访问的响应速度。适用场景：静态文件访问量大，服务器负载高，I/O问题导致用户访问卡顿。静态文件数量大，服务器存储空间不够。静态文件用户访问分布在各地，同一个地区客户，会成千上万次重复下载同一文件。https://www.aliyun.com/product/cdn
开放接口规范开发者在发送请求给 OSS 时，既可以使用 带签名认证的请求，也可以使用匿名访问。OSS提供的相关API接口如下:关于Service操作API描述getService (listBuckets)返回请求者拥有的所有Bucket关于Bucket的操作API描述createBucket创建BucketputBucketACL设置Bucket访问权限putBucketLogging开启Bucket日志putBucketWebsite设置Bucket为静态网站托管模式putBucketReferer设置Bucket的防盗链规则putBucketLifecycle设置Bucket中Object的生命周期规则getBucket(ListObject)列出Bucket中所有Object的信息getBucketAcl获得Bucket访问权限getBucketLocation获得Bucket所属的数据中心位置信息getBucketInfo获取Bucket信息getBucketLogging查看Bucket的访问日志配置情况getBucketWebsite查看Bucket的静态网站托管状态getBucketReferer查看Bucket的防盗链规则getBucketLifecycle查看Bucket中Object的生命周期规则deleteBucket删除BucketdeleteBucketLogging关闭Bucket访问日志记录功能deleteBucketWebsite关闭Bucket的静态网站托管模式deleteBucketLifecycle删除Bucket中Object的生命周期规则putBucketEncryption配置Bucket的加密规则getBucketEncryption获取Bucket的加密规则deleteBucketEncryption删除Bucket的加密规则关于Object的操作API描述putObject上传ObjectcopyObject拷贝一个Object成另外一个ObjectgetObject获取ObjectappendObject在Object尾追加上传数据deleteObject删除ObjectdeleteMultipleObjects删除多个ObjectheadObject只返回某个Object的meta信息，不返回文件内容getObjectMeta返回Object的基本meta信息，包括该Object的ETag、Size（文件大小）、LastModified，不返回文件内容postObject使用Post上传ObjectputObjectACL设置ObjectACLgetObjectACL获取ObjectACL信息callback上传回调putSymlink创建软链接getSymlink获取软链接restoreObject解冻文件selectObject用SQL语法查询Object内容putObjectTagging设置或更新对象标签getObjectTagging获取对象标签信息deleteObjectTagging删除指定的对象标签关于Multipart Upload的操作API描述InitiateMultipartUpload初始化MultipartUpload事件uploadPart分块上传文件uploadPartCopy分块复制上传文件completeMultipartUpload完成整个文件的MultipartUpload上传abortMultipartUpload取消MultipartUpload事件listMultipartUploads罗列出所有执行中的MultipartUpload事件listParts罗列出指定UploadID所属的所有已经上传成功Part跨域资源共享（CORS）API描述putBucketcors在指定Bucket设定一个CORS的规则getBucketcors获取指定的Bucket目前的CORS规则deleteBucketcors关闭指定Bucket对应的CORS功能并清空所有规则optionObject跨域访问preflight请求关于Live Channel的操作API描述putLiveChannelStatus切换LiveChannel的状态putLiveChannel创建LiveChannelgetVodPlaylist获取播放列表postVodPlaylist生成播放列表get LiveChannelStat获取LiveChannel的推流状态信息getLiveChannelInfo获取LiveChannel的配置信息getLiveChannelHistory获取LiveChannel的推流记录listLiveChannel列举LiveChanneldeleteLiveChannel删除LiveChannel案例剖析从上面的请求中 挑选任意接口分析createBucket 创建BucketputObject 上传ObjectgetObject 下载ObjectOSS云存储错误响应当用户访问OSS出现错误时，OSS会返回给用户相应的错误码和错误信息，便于用户定位问题，并做出适当的处理。OSS的错误响应格式当用户访问OSS出错时，OSS会返回给用户一个合适的3xx，4xx或者5xx的HTTP状态码；以及一个application/xml格式的消息体。错误响应的消息体例子：<?xml version="1.0" ?> <Error xmlns=”http://doc.oss.aliyuncs.com”> <Code> AccessDenied <Message> Query-string authentication requires the Signature, Expires and OSSAccessKeyId parameters </Message> <RequestId> 1D842BC5425544BB </RequestId> <HostId> oss.aliyuncs.com </HostId> </Error>所有错误的消息体中都包括以下几个元素：Code：OSS返回给用户的错误码。Message：OSS给出的详细错误信息。RequestId：用于唯一标识该次请求的UUID；当你无法解决问题时，可以凭这个RequestId来请求OSS开发工程师的帮助。HostId：用于标识访问的OSS集群（目前统一为oss.aliyuncs.com）OSS的错误码OSS的错误码列表如下：错误码描述HTTP状态码AccessDenied拒绝访问403BucketAlreadyExistsBucket已经存在409BucketNotEmptyBucket不为空409EntityTooLarge实体过大400EntityTooSmall实体过小400FileGroupTooLarge文件组过大400FilePartNotExist文件Part不存在400FilePartStale文件Part过时400InvalidArgument参数格式错误400InvalidAccessKeyIdAccess Key ID不存在403InvalidBucketName无效的Bucket名字400InvalidDigest无效的摘要400InvalidObjectName无效的Object名字400InvalidPart无效的Part400InvalidPartOrder无效的part顺序400InvalidTargetBucketForLoggingLogging操作中有无效的目标bucket400InternalErrorOSS内部发生错误500MalformedXMLXML格式非法400MethodNotAllowed不支持的方法405MissingArgument缺少参数411MissingContentLength缺少内容长度411NoSuchBucketBucket不存在404NoSuchKey文件不存在404NoSuchUploadMultipart Upload ID不存在404NotImplemented无法处理的方法501PreconditionFailed预处理错误412RequestTimeTooSkewed发起请求的时间和服务器时间超出15分钟403RequestTimeout请求超时400SignatureDoesNotMatch签名错误403TooManyBuckets用户的Bucket数目超过限制400请求一个需要Referer字段的Objecthttps://test000000000000001.oss-cn-beijing.aliyuncs.com/1.pngOSS参数不支持的操作如果在OSS合法的操作中，添加了OSS不支持的请求头参数（例如在PUT的时候，加入If-Modified-Since参数），OSS会返回501 Not Implemented错误错误请求示例：PUT /my-image.jpg HTTP/1.1 Host:oss-example. oss.aliyuncs.com Date: Wed, 28 May 2011 22:32:00 GMT If-Modified-Since: Wed, 06 Apr 2011 10:02:46 GMT返回示例：501 Not Implemented x-oss-request-id: 77E534EBF90372BE Content-Type: application/xml Transfer-Encoding: chunked Date: Thu, 28 Apr 2011 08:03:07 GMT Connection: close Server: AliyunOSS <?xml version="1.0" ?> <Error xmlns=”http://doc.oss.aliyuncs.com”> <Code> NotImplemented <Message> A header you provided implies functionality that is not implemented. </Message> If-Modified-Since <RequestId> 77E534EBF90372BE </RequestId> <HostId> oss.aliyuncs.com </HostId> </Error>OSS不支持的操作如果试图以OSS不支持的操作来访问某个资源，返回405 Method Not Allowed错误。错误请求示例：abc / HTTP/1.1 Host:oss-example. oss.aliyuncs.com Date: date Authorization: signatureValue返回示例：x-oss-request-id: 2403382433A2EDA8 Allow: GET, DELETE, HEAD, PUT Content-Type: application/xml Transfer-Encoding: chunked Date: Thu, 31 Mar 2011 10:01:52 GMT Server: AliyunOSS <?xml version="1.0" ?> <Error xmlns=”http://doc.oss.aliyuncs.com”> <Code> MethodNotAllowed <Message> The specified method is not allowed against this resource. </Message> <ResourceType> BUCKET </ResourceType> <Method> abc </Method> <RequestId> 2403382433A2EDA8 </RequestId> <HostId> oss.aliyuncs.com </HostId> </Error>
权限控制方式针对存放在 Bucket 的 Object 的访问，OSS 提供了多种权限控制方式，包括 ACL、RAM Policy 和 Bucket Policy。ACL：OSS 为权限控制提供访问控制列表（ACL）。ACL是基于资源的授权策略，可授予 Bucket 和 Object 访问权限。 可以在创建 Bucket 或上传 Object 时设置ACL，也可以在创建 Bucket 或上传Object 后的任意时间内修改 ACL。RAM Policy：RAM （Resource Access Management）是阿里云提供的资源访问控制服务。RAM Policy 是基于用户的授权策略。Bucket Policy：Bucket Policy 是基于资源的授权策略。相比于 RAM Policy，Bucket Policy 操作简单，支持在控制台直接进行图形化配置。ACLBucket ACLBucket ACL是 Bucket 级别的权限访问控制。目前有三种访问权限：public-read-write，publicread 和 private，含义如下：权限值中文名称权限对访问者的限制public-read-write公共读写任何人（包括匿名访问）都可以对该 Bucket 中的 Object 进行读/写/删除操作；所有这些操作产生的费用由该 Bucket 的 Owner 承担，请慎用该权限。public-read公共读，私有写只有该 Bucket 的 Owner 或者授权对象可以对存放在其中的 Object 进行写/删除操作；任何人（包括匿名访问）可以对 Object 进行读操作。private私有读写只有该 Bucket 的 Owner 或者授权对象可以对存放在其中的 Object 进行读/写/删除操作；其他人在未经授权的情况下无法访问该 Bucket 内的 Object。操作方式:操作方式特点控制台Web应用程序，直观易用图形化工具ossbrowser图形化工具，易操作Java SDK丰富、完整的各类语言SDK demoObject ACLObject ACL是Object 级别的权限访问控制。目前有四种访问权限：private、public-read、publicread-write、default。PutObjectACL 操作通过 Put 请求中的x-oss-object-acl 头来设置，这个操作只有 Bucket Owner 有权限执行。Object ACL 的四种访问权限含义如下：权限值中文名称权限对访问者的限制public-read-write公共读写该 ACL 表明某个 Object 是公共读写资源，即所有用户拥有对该 Object 的读写权限。public-read公共读，私有写该 ACL 表明某个 Object 是公共读资源，即非 Object Owner 只有该 Object 的读权限，而 Object Owner 拥有该 Object 的读写权限。private私有读写该 ACL 表明某个 Object 是私有资源，即只有该 Object 的 Owner 拥有该 Object 的读写权限，其他的用户没有权限操作该 Object。default默认权限该 ACL 表明某个 Object 是遵循 Bucket 读写权限的资源，即 Bucket 是什么权限，Object 就是什么权限。操作方式和上面类似 参考官方文档即可https://help.aliyun.com/document_detail/100676.html?spm=a2c4g.11186623.2.9.695b5a5bnz0mcm#concept-blw-yqm-2gbRAM PolicyRAM（Resource Access Management）是阿里云提供的资源访问控制服务，RAM Policy是基于用户的授权策略。使用RAM，您可以创建、管理RAM用户，并可以控制这些RAM用户对资源的操作权限。当您的企业存在多用户协同操作资源时，使用RAM可以让您避免与其他用户共享云账号密钥，按需为用户分配最小权限，管理更加方便，权限更加明确，信息更加安全。注意如果您选择使用RAM Policy，建议您通过官方工具RAM策略编辑器快速生成所需的RAM Policy。RAM Policy操作比较复杂，强烈推荐您使用简单易用的图形化配置方式Bucket Policy。https://help.aliyun.com/document_detail/102600.html?spm=a2c4g.11186623.6.693.143258f6f33HSTBucket PolicyBucket Policy是基于资源的授权策略。相比于RAM Policy，Bucket Policy支持在控制台直接进行图形化配置操作，并且Bucket拥有者直接可以进行访问授权。Bucket Policy常见的应用场景如下：向其他账号的RAM用户授权访问。您可以授予其他账号的RAM用户访问您的OSS资源的权限。向匿名用户授予带特定IP条件限制的访问权限。某些场景下，您需要向匿名用户授予带IP限制的访问策略。例如，企业内部的机密文档，只允许在企业内部访问，不允许在其他区域访问。由于企业内部人员较多，如果针对每个人配置RAM Policy，工作量非常大。此时，您可以基于Bucket Policy设置带IP限制的访问策略，从而高效方便地进行授权。Bucket Policy的配置方法和教程视频请参见使用Bucket Policy授权其他用户访问OSS资源。
基本功能使用阿里云管理控制台来完成 OSS 基本操作的流程如下：开通OSS服务器前提条件在使用阿里云 OSS 服务之前，请确保您已经注册了阿里云账号并完成实名认证。如果您还没有创建阿里云账号，系统会在您开通 OSS 时提示您注册账号。操作步骤1）登录阿里云官网。2）将鼠标移至产品，单击对象存储 OSS，打开 OSS 产品详情页面。3）在 OSS 产品详情页，单击立即开通。1）开通服务后，在 OSS 产品详情页单击管理控制台直接进入 OSS 管理控制台界面。您也可以单击位于官网首页右上方菜单栏的控制台，进入阿里云管理控制台首页，然后单击左侧的对象存储 OSS 菜单进入 OSS 管理控制台界面。创建存储空间1）登录OSS管理控制台。2）单击Bucket列表，之后单击创建Bucket。您也可以单击概览，之后单击右侧的创建Bucket。3）在创建Bucket页面配置Bucket参数。上传文件1）登录OSS管理控制台。2）单击Bucket列表，之后单击目标Bucket名称。3）单击文件管理 > 上传文件。4）在上传文件页面，设置上传文件的参数。5）在上传任务页面等待任务完成，之后关闭对话框。下载文件1）登录OSS管理控制台。2）进入目标Bucket。单击Bucket列表，之后单击目标Bucket名称。3）单击文件管理页签，您可以进行以下操作：删除文件1）登录OSS管理控制台。2）进入目标Bucket。单击Bucket列表，之后单击目标Bucket名称。3）选择一个或多个文件，选择批量操作 > 删除。您也可以选择目标文件右侧删除来删除单个文件。4）在删除文件对话框中，单击确定。删除存储空间进入OSS管理控制台界面。进入目标Bucket，找到删除Bucket按钮。单击基础设置页签，找到Bucket管理区域。3. 单击删除Bucket。在弹出的对话框中，单击确定。Object外链地址的构成规则如果一个bucket设置成公开读权限，意味着允许其他用户来访问属于你的object。你的object的外链地址构成规则如下：http://<你的bucket名字>.<数据库中心服务域名>/<你的object名字>构成规则的示意图如下：假设 oss-example 这个 bucket 在青岛数据中心，这个 object 的外链 URL 为：http://oss-example.oss-cn-qingdao.aliyuncs.com/aliyun-logo.png用户可以直接该URL链接放入HTML中使用： OSS 的短域名（oss.aliyuncs.com）作为 OSS 杭州数据中心的另一个域名仍然可以使用，但只能处理 bucket 属于杭州数据中心的请求。 为了统一起见，本 文接下来章节的例子中， 都将以 oss-cnhangzhou 域名为例。 请用户根据自己 bucket 所属的数据中心自行替换请求所访问的 Host。注意:在使用 OSS 时，请一直使用 OSS 服务域名，而不要使用固定的 IP 地址。OSS防盗链OSS 是按使用收费的服务， 为了防止用户在 OSS 上的数据被其他人盗链， OSS 支持基于 HTTP header 中表头字段 referer 的防盗链方法。通过 OSS 的控制台--权限管理--防盗链,可以对一个 bucket 设置 referer 字段的白名单和是否允许 referer 字段为空的请求访问。例如， 对于一个名为 ossexample的 bucket，设置其referer 白名单为 http://www.aliyun.com。则所有 referer 为 http://www.aliyun.com 的请求才能访问 oss-example 这个 bucket 中的 Object。细节分析：1) 用户只有通过 URL 签名或者匿名访问 Object 时，才会做防盗链验证。请求 的 Header 中有“Authorization”字段的，不会做防盗链验证。2) 一个 bucket 可以支持多个 referer 参数，这些参数之间由“，”号分隔。oss控制台配置时 使用换行3) Referer 参数支持通配符“*”和“？”。4) 用户可以设置是否允许 referer 字段为空的请求访问。5) 白名单为空时，不会检查 referer 字段是否为空（不然所有的请求都会被拒绝）。6) 白名单不为空，且设置了不允许 referer 字段为空的规则；则只有 referer 属于 白名单的请求被允许，其他请求（包括 referer 为空的请求）会被拒绝。7) 如果白名单不为空，但设置了允许 referer 字段为空的规则；则 referer 为空的 请求和符合白名单的请求会被允许；其他请求都会被拒绝。8) Bucket 的三种权限（private， public-read， public-read-write）都会检查 referer 字段。自定义域名绑定(CNAME)OSS 支持用户将自定义的域名绑定在属于自己的 bucket 上面，这个操作必 须通过 OSS 控制台（http://oss.aliyun.com） -“Bucket 属性 传输管理 ” -“绑定域名”页面 配置来实现。按照中国《互联网管理条例》的要求，所有需要开通这项功能的用 户，必须提供阿里云备案号，域名持有者身份证等有效资料，经由阿里云审批通 过后才可以使用。在开通 CNAME 功能后， OSS 将自动处理对该域名的访问请求。CNAME 应用场景例子：用户 A 拥有一个域名为 abc.com 的网站；这个网站的所有图片存储在 img.abc.com 这个子域名下；为了应对日益增长的图片流量压力， 用户 A 在 OSS 上创建了一个名为 abc-img 的 bucket， 并将所有图片存在 OSS 上；通过 OSS 控制台，提交将 img.abc.com CNAME 成 abc-img.oss-cnhangzhou.aliyuncs.com 的申请，并提供相应的材料通过阿里云审核后，在自己的域名服务器上，添加一条 CNAME 规则（https://dns.console.aliyun.com/？spm=a2c4g.11186623.2.12.70c759cbsvcLcR#/dns/domainList），将 img.abc.com 映射成 abc-img.oss-cn-hangzhou.aliyuncs.com，这样所有对 img.abc.com 的访问都将变成访问 abc-img 这个 bucket。例如：一个对 http://img.abc.com/logo.png 的访问，实际上访问的是 http://abc-img.oss-cn-hangzhou.aliyuncs.com/logo.png访问日志记录(Server_Access_Logging)OSS为用户提供自动保存访问日志记录功能。Bucket的拥有者可以通过OSS控制台（http://oss.aliyun.com）日志管理，为其所拥有的bucket开启访问日志记录功能。当一个bucket（源Bucket，Source Bucket）开启访问日志记录功能后，OSS自动将访问这个bucket的请求日志，以小时为单位，按照固定的命名规则，生成一个Object写入用户指定的bucket（目标Bucket，Target Bucket）。存储访问日志记录的object命名规则：-YYYY-mm-DD-HH-MM-SS-UniqueString命名规则中，TargetPrefix由用户指定；YYYY, mm, DD, HH, MM和SS分别是该Object被创建时的阿拉伯数字的年，月，日，小时，分钟和秒（注意位数）；UniqueString为OSS系统生成的字符串。一个实际的用于存储OSS访问日志的Object名称例子如下：MyLog-oss-example-2012-09-10-04-00-00-0000上例中，“MyLog-”是用户指定的Object前缀；“oss-example”是源bucket的名称；“2012-09-10-04-00-00”是该Object被创建时的北京时间；“0000” 是OSS系统生成的字符串。LOG文件格式（从左至右，以空格分隔）：名称例子含义Remote IP119.140.142.11请求发起的IP地址（Proxy代理或用户防火墙可能会屏蔽该字段）Reserved-保留字段Time[02/May/2012:00:00:04+0800]OSS收到请求的时间Request-URI“GET /aliyun-logo.png HTTP/1.1“用户请求的URI（包括query-string）HTTP Status200OSS返回的HTTP状态码SentBytes5576用户从OSS下载的流量RequestTime(ms)71完成本次请求的时间（毫秒）Referrerhttp://oss.aliyun.com请求的HTTP ReferrerUser-Agentcurl/7.15.5HTTP的User-Agent头HostNameoss-example.oss.aliyuncs.com请求访问域名Request ID505B01695037C2AF032593A4用于唯一标示该请求的UUIDLoggingFlagtrue是否开启了访问日志功能Requester Aliyun ID1657136103983691请求者的阿里云ID；匿名访问为“-”OperationGetObject请求类型Bucketoss-example请求访问的Bucket名字Key/aliyun-logo.png用户请求的KeyObjectSize5576Object大小Server Cost Time (ms)17OSS服务器处理本次请求所花的时间（毫秒）Error CodeNoSuchBucketOSS返回的错误码UserID1657136103983691Bucket拥有者IDDelta DataSize280Bucket大小的变化量；若没有变化为“-”细节分析：1) 源Bucket和目标Bucket必须属于同一个用户。2) “TargetPrefix”表示存储访问日志记录的object名字前缀，可以为空。3) 源bucket和目标bucket可以是同一个Bucket，也可以是不同的Bucket；用户也可以将多个的源bucket的LOG都保存在同一个目标bucket内（建议指定不同的TargetPrefix）。4) OSS以小时为单位生成bucket访问的Log文件，但并不表示这个小时的所有请求都记录在这个小时的LOG文件内，也有可能出现在上一个或者下一个LOG文件中。5) OSS生成的Log文件命名规则中的“UniqueString”仅仅是OSS为其生成的UUID，用于唯一标识该文件。6) OSS生成一个bucket访问的Log文件，算作一次PUT操作，并记录其占用的空间，但不会记录产生的流量。LOG生成后，用户可以按照普通的Object来操作这些LOG文件。7) OSS会忽略掉所有以“x-”开头的query-string参数，但这个query-string会被记录在访问LOG中。如果你想从海量的访问日志中，标示一个特殊的请求，可以在URL中添加一个“x-”开头的query-string参数。如下:http://oss-example.oss.aliyuncs.com/aliyun-logo.pnghttp://oss-example.oss.aliyuncs.com/aliyun-logo.png?x-user=adminOSS处理上面两个请求，结果是一样的。但是在访问LOG中，你可以通过搜索“x-user=admin”，很方便地定位 出经过标记的这个请求。8) OSS的LOG中的任何一个字段，都可能出现“-”，用于表示未知数据或对于当前请求该字段无效。9) 根据需求，OSS的LOG格式将来会在尾部添加一些字段，请开发者开发Log处理工具时考虑兼容性的问题。
存储空间（Bucket）存储空间是用户用于存储对象（Object）的容器，所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性，包括地域、访问权限、存储类型等。用户可以根据实际需求，创建不同类型的存储空间来存储不同的数据。同一个存储空间的内部是扁平的，没有文件系统目录的概念，所有的对象都直接隶属于其对应的存储空间。每个用户可以拥有多个存储空间。存储空间的名称在 OSS 范围内必须是全局唯一的，一旦创建之后无法修改名称。存储空间内部的对象数目没有限制。存储空间的命名规范如下：只能包括小写字母、数字和短横线（-）。必须以小写字母或者数字开头和结尾。长度必须在 3–63 字节之间。对象/文件（Object）对象是 OSS 存储数据的基本单元，也被称为 OSS 的文件。对象由元信息（Object Meta），用户数据（Data）和文件名（Key）组成。对象由存储空间内部唯一的 Key 来标识。对象元信息是一组键值对，表示了对象的一些属性，比如最后修改时间、大小等信息，同时用户也可以在元信息中存储一些自定义的信息。对象的生命周期是从上传成功到被删除为止。在整个生命周期内，只有通过追加上传的 Object 可以继续通过追加上传写入数据，其他上传方式上传的 Object 内容无法编辑，您可以通过重复上传同名的对象来覆盖之前的对象。对象的命名规范如下：使用 UTF-8 编码。长度必须在 1–1023 字节之间。不能以正斜线（/）或者反斜线（\）开头。Region（地域）Region 表示 OSS 的数据中心所在物理位置。用户可以根据费用、请求来源等选择合适的地域创建Bucket。一般来说，距离用户更近的 Region 访问速度更快。Region 是在创建 Bucket 的时候指定的，一旦指定之后就不允许更改。该 Bucket 下所有的 Object 都存储在对应的数据中心，目前不支持 Object 级别的 Region 设置。Endpoint（访问域名）Endpoint 表示 OSS 对外服务的访问域名。OSS 以 HTTP RESTful API 的形式对外提供服务，当访问不同的 Region 的时候，需要不同的域名。通过内网和外网访问同一个 Region 所需要的 Endpoint 也是不同的。例如杭州 Region 的外网 Endpoint 是 oss-cn-hangzhou.aliyuncs.com，内网 Endpoint 是 osscn-hangzhou-internal.aliyuncs.com。AccessKey（访问密钥）AccessKey（简称 AK）指的是访问身份验证中用到的 AccessKeyId 和 AccessKeySecret。OSS 通过使用 AccessKeyId 和 AccessKeySecret 对称加密的方法来验证某个请求的发送者身份。AccessKeyId 用于标识用户；AccessKeySecret 是用户用于加密签名字符串和 OSS 用来验证签名字符串的密钥，必须保密。对于 OSS 来说，AccessKey 的来源有：Bucket 的拥有者申请的 AccessKey。被 Bucket 的拥有者通过 RAM 授权给第三方请求者的 AccessKey。被 Bucket 的拥有者通过 STS 授权给第三方请求者的 AccessKey。注意:可以登录阿里云官网-“用户中心” -“我的帐户” -“安全认证” 获取 Access Key ID 和 Access Key Secret，一个阿里云帐号可以生成 5 对 Access Key ID 和 Access Key Secret。并支持启用/禁用设置。ServiceOSS 提供给用户的虚拟存储空间，在这个虚拟空间中，每个用户可拥有一个到多个 Bucket。
阿里云OSS云存储简介阿里云对象存储服务（Object Storage Service，简称 OSS），是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于99.9999999999%（12 个 9），服务设计可用性（或业务连续性）不低于 99.995%。可以使用阿里云提供的 API、SDK 接口或者 OSS 迁移工具轻松地将海量数据移入或移出阿里云 OSS。数据存储到阿里云 OSS 以后，可以选择标准存储（Standard）作为移动应用、大型网站、图片分享或热点音视频的主要存储方式，也可以选择成本更低、存储期限更长的低频访问存储（Infrequent Access）和归档存储（Archive）作为不经常访问数据的存储方式。OSS 具有与平台无关的 RESTful API 接口，可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。OSS与自建存储对比的优势对比项对象存储OSS自建服务器存储可靠性OSS作为阿里巴巴全集团数据存储的核心基础设施，多年支撑双11业务高峰，历经高可用与高可靠的严苛考验。OSS的多重冗余架构设计，为数据持久存储提供可靠保障。同时，OSS基于高可用架构设计，消除单节故障，确保数据业务的持续性。服务设计可用性不低于99.995%。数据设计持久性不低于99.9999999999%（12个9）。规模自动扩展，不影响对外服务。数据自动多重冗余备份。受限于硬件可靠性，易出问题，一旦出现磁盘坏道，容易出现不可逆转的数据丢失。人工数据恢复困难、耗时、耗力。 安全提供企业级多层次安全防护，包括服务端加密、客户端加密、防盗链、IP黑白名单、细粒度权限管控、日志审计、WORM特性等。多用户资源隔离机制，支持异地容灾机制。获得多项合规认证，包括SEC和FINRA 等，满足企业数据安全与合规要求。需要另外购买清洗和黑洞设备。需要单独实现安全机制。成本多线BGP骨干网络，无带宽限制，上行流量免费。无需运维人员与托管费用，0成本运维。存储受硬盘容量限制，需人工扩容。单线或双线接入速度慢，有带宽限制，峰值时期需人工扩容。需专人运维，成本高。智能存储提供多种数据处理能力，如图片处理、视频截帧、文档预览、图片场景识别、人脸识别、SQL就地查询等，并无缝对接Hadoop生态、以及阿里云函数计算、EMR、DataLakeAnalytics、BatchCompute、MaxCompute、DBS等产品，满足企业数据分析与管理的需求。需要额外采购，单独部署。应用场景图片和音视频等应用的海量存储网页或者移动应用的静态和动态资源分离云端数据处理计量计费阿里云对象存储 OSS 服务费用的各项组成部分及计费方式分为按量计费和包年包月两种。按量付费：按实际使用量*单价的方式计费，每小时统计前一小时的实际用量并从账户余额中扣除实际消费金额。例如当前时间是 9:30，结算的是 8:00-9:00 产生的费用。包年包月：预先购买指定资源包，之后使用资源时，扣除相应的额度。一般情况下，包年包月比按量付费更加优惠。资源包目前仅提供标准（LRS）存储包、低频（LRS）存储包、归档（LRS）存储包、标准（ZRS）存储包、低频（ZRS）存储包、下行流量包、 回源流量包、传输加速包，可购买地域请参见购买对象存储 OSS 资源包。这个看一个实际的计费案例即可：https://help.aliyun.com/document_detail/109686.html?spm=a2c4g.11186623.6.562.4bbd7c28AAnl9D
SpringBoot访问FastDFS引入jar依赖<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.1-RELEASE</version> </dependency> </dependencies>配置文件application.ymlfdfs: connectTimeout: 600 trackerList: - 192.168.211.130:22122 - 192.168.211.135:22122 - 192.168.211.136:22122 server: port: 8899编写上传下载文件的服务类package com.fastdfs.service; import com.github.tobato.fastdfs.domain.StorePath; import com.github.tobato.fastdfs.proto.storage.DownloadByteArray; import com.github.tobato.fastdfs.service.FastFileStorageClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.IOException; @Component public class FastDFSClientService { @Autowired private FastFileStorageClient fastFileStorageClient; /* * 文件上传 * * @param bytes 文件字节 * @param fileSize 文件大小 * @param extension 文件扩展名 * @return fastDfs路径 */ public String uploadFile(byte[] bytes, long fileSize, String extension) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); StorePath storePath = fastFileStorageClient.uploadFile(byteArrayInputStream, fileSize, extension, null); System.out.println(storePath.getGroup() + ":" + storePath.getPath() + ":" + storePath.getFullPath()); return storePath.getFullPath(); } /* * 下载文件 * * @param fileUrl 文件URL * @return 文件字节 * @throws IOException */ public byte[] downloadFile(String fileUrl) throws IOException { String group = fileUrl.substring(0, fileUrl.indexOf("/")); String path = fileUrl.substring(fileUrl.indexOf("/") + 1); DownloadByteArray downloadByteArray = new DownloadByteArray(); byte[] bytes = fastFileStorageClient.downloadFile(group, path, downloadByteArray); return bytes; } }控制器类package com.fastdfs.controller; import com.fastdfs.service.FastDFSClientService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; @RestController @RequestMapping("/fastdfs") public class FastDFSController { @Autowired private FastDFSClientService fastDFSClientService; @RequestMapping("/upload") public String uploadFile(MultipartFile file) throws IOException { byte[] bytes = file.getBytes(); String originalFileName = file.getOriginalFilename(); String extension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1); String fileName = file.getName(); long fileSize = file.getSize(); System.out.println(originalFileName + ":" + fileName + ":" + fileSize + ":" + extension + ":" + bytes.length); return fastDFSClientService.uploadFile(bytes, fileSize, extension); } @RequestMapping("/download") public void downloadFile(String fileUrl, HttpServletResponse response) throws IOException { byte[] bytes = fastDFSClientService.downloadFile(fileUrl); response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileUrl, "UTF-8")); response.setCharacterEncoding("UTF-8"); ServletOutputStream outputStream = null; try { outputStream = response.getOutputStream(); outputStream.write(bytes); } catch (IOException e) { e.printStackTrace(); } finally { try { outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }编写启动类package com.fastdfs; import com.github.tobato.fastdfs.FdfsClientConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableMBeanExport; import org.springframework.context.annotation.Import; import org.springframework.jmx.support.RegistrationPolicy; //解决jmx重复注册bean的问题 @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) //只需要一行注解就可以拥有带有连接池的FastDFS Java客户端了 @Import(FdfsClientConfig.class) @SpringBootApplication public class FastDfsApplicationMain { public static void main(String[] args) { SpringApplication.run(FastDfsApplicationMain.class, args); } }使用postman 进行测试业务场景头像上传nginx头像缩略图处理思路:上传图片时，直接处理成缩略图，不是很灵活，业务很确定可以使用先存储图片，使用时，实时计算附件上传附件下载附件思考：是使用直接的url，还是需要写一个处理请求避免重复解决方案：上传成功后计算文件对应的MD5然后存入MySQL，添加文件时把文件MD5和之前存入MYSQL中的存储的信息对比。参考:DigestUtils.md5DigestAsHex(bytes)。
FastDFS集群架构设置3台CentOS 7 虚拟机3个tracker 3个storage192.168.211.130192.168.211.136192.168.211.135trackertrackertrackerstorage（group1）storage（group1）storage（group2）nginxnginxnginx按照之前的单机方式先进行安装FastDFS集群架构详细配置配置tracker集群 三台相同vi /etc/fdfs/tracker.conf# 0是轮询，1是指定组，2是剩余存储空间多的group优先 store_lookup=0 配置storage集群并启动vi /etc/fdfs/storage.conftracker_server=192.168.211.130:22122 tracker_server=192.168.211.136:22122 tracker_server=192.168.211.135:22122 #注意组名 192.168.211.135 配置是 group2 group_name=group1 #storage 的端口号，同一个组的 storage 端口号必须相同 port=23000 /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart查看storage的日志和查看tracker集群信息cat /home/fastdfs/logs/storaged.log访问FastDFS时 可以把Tracker 理解成对等的,但实际底层多个Tracker时在运行过程中会选择其中一个作为Leader，由该Leader执行一些唯一性的操作。在早期版本中Tracker-Leader有两个作用，分别是：为新加入的Storage分配一个源Storage；为开启合并存储的Group选择Trunk-Server。但是在最新的版本中实际上只有第二个作用，也就是选择Trunk-Server。查看之后，如果连接不上，注意关闭防火墙（或开放通信端口）systemctl stop firewalld查看存储集群信息/usr/bin/fdfs_monitor /etc/fdfs/storage.conf测试上传vim /etc/fdfs/client.conftracker_server=192.168.211.130:22122 tracker_server=192.168.211.136:22122 tracker_server=192.168.211.135:22122/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /root/fastdfs/1.png find / -name group*/*/*/*/xxx.png使用Nginx和FastDFS集群结合vi /etc/fdfs/mod_fastdfs.conftracker_server=192.168.211.130:22122 tracker_server=192.168.211.136:22122 tracker_server=192.168.211.135:22122 #注意组名 如果是group2 则一定要改 group_name=group1 vim /usr/local/nginx/conf/nginx.conf#添加如下配置 server { listen 8888; server_name localhost; location ~/group[0-9]/ { ngx_fastdfs_module; } }启动nginx/usr/local/nginx/sbin/nginx测试文件服务器通过任意一台nginx访问http://192.168.211.130/group1/M00/00/00/xxx.pnghttp://192.168.211.135/group1/M00/00/00/xxx.pngFastDFS配置优化最大连接数设置配置文件：tracker.conf 和 storage.conf参数名：max_connections缺省值：256说明：FastDFS为一个连接分配一个task buffer，为了提升分配效率，FastDFS采用内存池的做法。FastDFS老版本直接事先分配 max_connections 个buffer，这个做法显然不是太合理，在 max_connections 设置过大的情况下太浪费内存。v5.04对预分配采用增量方式，tracker一次预分配1024个，storage一次预分配256个。define ALLOC_CONNECTIONS_ONCE 1024总的task buffer初始内存占用情况测算如下改进前：max_connections * buffer_size改进后：max_connections和预分配的连接中那个小 * buffer_size使用v5.04及后续版本，可以根据实际需要将 max_connections 设置为一个较大的数值，比如 10240 甚至更大。注意此时需要将一个进程允许打开的最大文件数调大到超过max_connections否则FastDFS server启动会报错。vi /etc/security/limits.conf soft nofile 65535hard nofile 65535重启系统生效 另外，对于32位系统，请注意使用到的内存不要超过3GB ## 工作线程数设置 配置文件：tracker.conf 和 storage.conf 参数名： work_threads 缺省值：4 说明：为了避免CPU上下文切换的开销，以及不必要的资源消耗，不建议将本参数设置得过大。为了发挥出多个CPU的效能，系统中的线程数总和，应等于CPU总数。 对于tracker server，公式为：work_threads + 1 = CPU数 对于storage，公式为： work_threads + 1 + (disk_reader_threads + disk_writer_threads) * store_path_count = CPU数 ## storage目录数设置 配置文件： storage.conf 参数名：subdir_count_per_path 缺省值：256 说明：FastDFS采用二级目录的做法，目录会在FastDFS初始化时自动创建。存储海量小文件，打开了trunk存储方式的情况下，建议将本参数适当改小，比如设置为32，此时存放文件的目录数为 32 * 32 = 1024。假如trunk文件大小采用缺省值64MB，磁盘空间为2TB，那么每个目录下存放的trunk文件数均值为：2TB/(1024 * 64MB) = 32个 ## storage磁盘读写线程设置 配置文件： storage.conf 参数名:disk_rw_separated：磁盘读写是否分离 参数名:disk_reader_threads：单个磁盘读线程数 参数名:disk_writer_threads：单个磁盘写线程数 如果磁盘读写混合，单个磁盘读写线程数为读线程数和写线程数之和，对于单盘挂载方式，磁盘读写线程分别设置为1即可 如果磁盘做了RAID，那么需要酌情加大读写线程数，这样才能最大程度地发挥磁盘性能 ## storage同步延迟相关设置 配置文件： storage.conf 参数名:sync_binlog_buff_interval：将binlog buffer写入磁盘的时间间隔，取值大于0，缺省值为60s 参数名:sync_wait_msec：如果没有需要同步的文件，对binlog进行轮询的时间间隔，取值大于0，缺省值为200ms 参数名: sync_interval：同步完一个文件后，休眠的毫秒数，缺省值为0
架构详解storage server：存储服务器（又称存储节点或数据服务器），文件和文件属性（meta data）都保存到存储服务器上。Storage server直接利用OS的文件系统调用管理文件。Storage server（后简称storage）以组（卷，group或volume）为单位组织，一个group内包含多台storage机器，数据互为备份，存储空间以group内容量最小的storage为准，所以建议group内的多个storage尽量配置相同，以免造成存储空间的浪费。以group为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制（group内storage server数量即为该group的副本数），比如将不同应用数据存到不同的group就能隔离应用数据，同时还可根据应用的访问特性来将应用分配到不同的group来做负载均衡；缺点是group的容量受单机存储容量的限制，同时当group内有机器坏掉时，数据恢复只能依赖group内的其它机器，使得恢复时间会很长。group内每个storage的存储依赖于本地文件系统，storage可配置多个数据存储目录，比如有10块磁盘，分别挂载在/data/disk1-/data/disk10 ，则可将这10个目录都配置为storage的数据存储目录。storage接受到写文件请求时，会根据配置好的规则，选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多，在storage第一次启动时，会在每个数据存储目录里创建2级子目录，默认每级256个，总共65536个文件，新写的文件会以hash的方式被路由到其中某个子目录下，然后将文件数据直接作为一个本地文件存储到该目录中。group：组，也可称为卷。同组内服务器上的文件是完全相同的，同一组内的storage server之间是对等的，文件上传、删除等操作可以在任意一台storage server上进行。meta data：文件相关属性，键值对（ Key Value Pair）方式，如：width: 1118。tracker server：跟踪服务器，主要做调度工作，起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息，是客户端和数据服务器交互的枢纽。因为不记录文件索引信息，所以占用的内存量很少。Tracker是FastDFS的协调者，负责管理所有的storage server和group，每个storage在启动后会连接Tracker，告知自己所属的group等信息，并保持周期性的心跳，tracker根据storage的心跳信息，建立group==>[storage server list]的映射表。Tracker需要管理的元信息很少，会全部存储在内存中；另外tracker上的元信息都是由storage汇报的信息生成的，本身不需要持久化任何数据，这样使得tracker非常容易扩展，直接增加tracker机器即可扩展为tracker cluster来服务，cluster里每个tracker之间是完全对等的，所有的tracker都接受stroage的心跳信息，生成元数据信息来提供读写服务。client：客户端，作为业务请求的发起方，通过专有接口，使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。FastDFS向使用者提供基本文件访问接口，比如upload、download、append、delete等，以客户端库的方式提供给用户使用。设计理念轻量级FastDFS服务端只有两个角色：Tracker server和Storage server。Tracker server在内存中记录分组和Storage server的状态等信息，不记录文件索引信息，占用的内存量很少。另外，客户端（应用）和Storage server访问Tracker server时，Tracker server扫描内存中的分组和Storage server状态信息，然后给出应答。由此可以看出Tracker server非常轻量化，不会成为系统瓶颈。FastDFS中的Storage server直接利用OS的文件系统存储文件。FastDFS不会对文件进行分块存储，客户端上传的文件和Storage server上的文件一一对应。对于互联网应用，文件分块存储没有多大的必要。它既没有带来多大的好处，又增加了系统的复杂性。FastDFS不对文件进行分块存储，与支持文件分块存储的DFS相比，更加简洁高效，并且完全能满足绝大多数互联网应用的实际需要。在FastDFS中，客户端上传文件时，文件ID不是由客户端指定，而是由Storage server生成后返回给客户端的。文件ID中包含了组名、文件相对路径和文件名，Storage server可以根据文件ID直接定位到文件。因此FastDFS集群中根本不需要存储文件索引信息，这是FastDFS比较轻量级的一个例证。而其他文件系统则需要存储文件索引信息，这样的角色通常称作NameServer。其中mogileFS采用MySQL数据库来存储文件索引以及系统相关的信息，其局限性显而易见，MySQL将成为整个系统的瓶颈。FastDFS轻量级的另外一个体现是代码量较小。最新的V2.0包括了C客户端API、FastDHT客户端API和PHP extension等，代码行数不到5.2万行。分组存储FastDFS采用了分组存储方式。集群由一个或多个组构成，集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成，同组内的多台Storage server之间是对等的互备关系。文件上传、下载、删除等操作可以在组内任意一台Storage server上进行。类似木桶短板效应，一个组的存储容量为该组内存储服务器容量最小的那个，由此可见组内存储服务器的软硬件配置最好是一致的。用分组存储方式的好处是灵活、可控性较强。比如上传文件时，可以由客户端直接指定上传到的组。一个分组的存储服务器访问压力较大时，可以在该组增加存储服务器来扩充服务能力（纵向扩容）。当系统容量不足时，可以增加组来扩充存储容量（横向扩容）。采用这样的分组存储方式，可以使用FastDFS对文件进行管理，使用主流的Web server如Apache、nginx等进行文件下载。对等结构FastDFS集群中的Tracker server也可以有多台，Tracker server和Storage server均不存在单点问题。Tracker server之间是对等关系，组内的Storage server之间也是对等关系。传统的Master-Slave结构中的Master是单点，写操作仅针对Master。如果Master失效，需要将Slave提升为Master，实现逻辑会比较复杂。和Master-Slave结构相比，对等结构中所有结点的地位是相同，每个结点都是Master，不存在单点问题。FastDFS 功能原理文件上传文件上传流程文件上传内部原理选择tracker server和group当集群中不止一个tracker server时，由于tracker之间是完全对等的关系，客户端在upload文件时可以任意选择一个trakcer。 当tracker接收到upload_file的请求时，会为该文件分配一个可以存储该文件的group，使用store_lookup选择group的规则：0、Round robin，所有的group间轮询1、Specified group，指定某一个确定的group2、Load balance，剩余存储空间多的group优先选择storage server当选定group后，tracker会在group内选择一个storage server给客户端，使用store_server选择storage的规则：0、Round robin，在group内的所有storage间轮询1、First server ordered by ip，按ip排序2、First server ordered by priority，按优先级排序（优先级在storage上配置）选择storage path当分配好storage server后，客户端将向storage发送写文件请求，storage将会为文件分配一个数据存储目录 storage server可以有多个存放文件的存储路径（可以理解为多个磁盘），store_path支持如下规则：0、Round robin，多个存储目录间轮询2、剩余存储空间最多的优先生成文件名选定存储目录之后，storage会为文件生一个文件名，由storage server ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成，然后将这个二进制串进行base64编码，转换为可打印的字符串。选择两级目录 当选定存储目录之后，storage会为文件分配一个文件名，每个存储目录下有两级256*256的子目录，storage会按文件fileid进行两次hash，路由到其中一个子目录，然后将文件以这个文件标示为文件名存储到该子目录下。返回文件id当文件存储到某个子目录后，即认为该文件存储成功，接下来会为该文件返回一个文件id，由group、存储目录、两级子目录、内部文件名、文件后缀名（由客户端指定，主要用于区分文件类型）拼接而成。group1/M00/00/00/xxx.png组名：文件上传后所在的存储组名称，在文件上传成功后有存储服务器返回，需要客户端自行保存。虚拟磁盘路径：存储服务器配置的虚拟路径，与磁盘选项store_path*对应。数据两级目录：存储服务器在每个虚拟磁盘路径下创建的两级目录，用于存储数据文件。文件名：与文件上传时不同。是由存储服务器根据特定信息生成，文件名包含：源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。文件下载客户端带上文件名信息请求Tracker服务获取到存储服务器的ip地址和端口，然后客户端根据返回的IP地址和端口号请求下载文件，存储服务器接收到请求后返回文件给客户端。跟upload_file一样，在download_file时客户端可以选择任意tracker server。客户端发送download请求给某个tracker，必须带上文件名信息，tracke从文件名中解析出文件的group、大小、创建时间等信息，然后为该请求选择一个storage用来服务读请求。选择哪个 storage server 作为下载服务器 使用download_server 规则如下:0: 轮询方式，可以下载当前文件的任意一个 storage server进行轮询1: 哪个为源storage server 就用哪个由于group内的文件同步时在后台异步进行的，所以有可能出现在读到时候，文件还没有同步到某些storage server,为了尽量避免访问到这样的storage，会有相应的文件同步规则。文件同步文件同步原理写文件时，客户端将文件写至group内一个storage server即认为写文件成功，storage server写完文件后，会由后台线程将文件同步至同group内其他的storage server。每个storage写文件后，同时会写一份binlog，binlog里不包含文件数据，只包含文件名等元信息，这份binlog用于后台同步，storage会记录向group内其他storage同步的进度，以便重启后能接上次的进度继续同步。进度以时间戳的方式进行记录，所以最好能保证集群内所有server的时钟保持同步。storage的同步进度会作为元数据的一部分汇报到tracker上，tracke在选择storage的时候会以同步进度作为参考。比如一个group内有A、B、C 三个storage server，A向C同步到进度为T1 ，B向C同步到时间戳为T2（T2 > T1)，tracker接收到这些同步进度信息时，就会进行整理，将最小的那个做为C的同步时间戳，本例中T1即为C的同步时间戳（即所有T1以前写的数据都已经同步到C上了）。同理，根据上述规则，tracker会为A、B生成一个同步时间戳。tracker选择group内可用的storage的规则该文件上传到的源头storage源头storage只要存活着，肯定包含这个文件，源头的地址被编码在文件名中。文件创建时间戳==storage被同步到的时间戳 且(当前时间-文件创建时间戳) > 文件同步最大时间（如5分钟)文件创建后，认为经过最大同步时间后，肯定已经同步到其他storage了。文件创建时间戳 < storage被同步到的时间戳。同步时间戳之前的文件确定已经同步了(当前时间 - 文件创建时间戳) > 同步延迟阀值。经过同步延迟阈值时间，认为文件肯定已经同步了。文件删除删除处理流程与文件下载类似：Client询问Tracker server可以删除指定文件的Storage server，参数为文件ID（包含组名和文件名）。Tracker server返回一台可用的Storage server。Client直接和该Storage server建立连接，完成文件删除。文件删除API：delete_file断点续传提供appender file的支持，通过upload_appender_file接口完成，appender file允许在创建后，对该文件进行append操作。实际上，appender file与普通文件的存储方式是相同的，不同的是，appender file不能被合并存储到trunk file。续传涉及到的文件大小MD5不会改变。续传流程与文件上传类似，先定位到源storage，完成完整或部分上传，再通过binlog进行同group内server文件同步。断点续传的API:upload_appender_file文件HTTP访问支持FastDFS的tracker和storage都内置了http协议的支持，客户端可以通过http协议来下载文件，tracker在接收到请求时，通过http的redirect机制将请求重定向至文件所在的storage上。除了内置的http协议外，FastDFS还提供了通过apache或nginx扩展模块下载文件的支持。
为什么要有分布式文件系统单机时代优点：文件访问比较便利，项目直接引用，实现起来简单，无需任何复杂技术，保存文件和访问文件都很方便。缺点：一方面，文件和代码耦合在一起，文件越多存放越混乱。另一方面，如果流量比较大，静态文件访问会占据一定的资源，影响正常业务进行，不利于网站快速发展。独立文件服务器优点：Web/App服务器可以更专注发挥动态处理的能力。独立存储，更方便做扩容、容灾和数据迁移；方便做图片等资源请求的负载均衡，方便应用各种缓存策略（HTTP Header、Proxy Cache等），也更加方便迁移到CDN。缺点：单机存在性能瓶颈，容灾、垂直扩展性稍差分布式文件系统优点：扩展能力: 毫无疑问，扩展能力是一个分布式文件系统最重要的特点；高可用性: 在分布式文件系统中，高可用性包含两层，一是整个文件系统的可用性，二是数据的完整和一致性；弹性存储: 可以根据业务需要灵活地增加或缩减数据存储以及增删存储池中的资源，而不需要中断系统运行。缺点：系统复杂度稍高，需要更多服务器。分布式存储解决方案对比指标适合类型文件分布复杂度FUSEPOSIX备份机制通讯协议接口社区支持开发语言FastDFS4KB~500MB小文件合并存储不分片处理简单不支持不支持组内冗余备份Api http国内用户群CTFS所有文件小文件合并，以block组织分片复杂不支持不支持Block存储多份，主辅灾备Api http少C++MFS大于64K分片存储复杂支持支持多点备份动态冗余使用fuse较多PerlHDFS大文件大文件分片分块存储简单支持支持多副本原生api较多JavaCeph对象文件块OSD一主多从复杂支持支持多副本原生api较少C++MogileFS海量小图片不分片存储复杂可以支持不支持动态冗余http原生api文档少Perl什么是FastDFSFastDFS是用C语言编写的一款开源的轻量级分布式文件系统。它对文件进行管理，功能包括：文件存储、文件同步、文件访问（文件上传、文件下载）等，解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务，如相册网站、视频网站等等。FastDFS为互联网量身定制，充分考虑了冗余备份、负载均衡、线性扩容等机制，并注重高可用、高性能等指标，使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。FastDFS特性分组存储，灵活简洁、对等结构，不存在单点文件不分块存储，上传的文件和OS文件系统中的文件一一对应文件ID由FastDFS生成，作为文件访问凭证，FastDFS不需要传统的name server和流行的web server无缝衔接，FastDFS已提供apache和nginx扩展模块中、小文件均可以很好支持，支持海量小文件存储支持多块磁盘，支持单盘数据恢复支持相同内容的文件只保存一份，节约磁盘空间支持在线扩容 支持主从文件存储服务器上可以保存文件属性（meta-data）V2.0网络通信采用libevent，支持大并发访问，整体性能更好下载文件支持多线程方式，支持断点续传FastDFS的构成FastDFS由客户端(Client)、 跟踪服务器(Tracker Server)和存储服务器(Storage Server)构成。客户端（client）客户端（client），作为业务请求的发起方，通过专有接口，使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。跟踪器（tracker）Trackerserver作用是负载均衡和调度，通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。跟踪器在访问上起负载均衡的作用。可以随时增加或下线而不会影响线上服务。存储节点（storage）Storageserver作用是文件存储，客户端上传的文件最终存储在Storage服务器上，Storage server没有实现自己的文件系统而是利用操作系统的文件系统来管理文件。可以将storage称为存储服务器。存储节点中的服务器均可以随时增加或下线而不会影响线上服务。Linux下FastDFS 安装安装编译环境yum install git gcc gcc-c++ make automake vim wget libevent -y安装libfastcommon 基础库mkdir /root/fastdfs cd /root/fastdfs git clone https://github.com/happyfish100/libfastcommon.git --depth 1 cd libfastcommon/ ./make.sh && ./make.sh install安装FastDFScd /root/fastdfs wget https://github.com/happyfish100/fastdfs/archive/V5.11.tar.gz tar -zxvf V5.11.tar.gz cd fastdfs-5.11 ./make.sh && ./make.sh install配置文件准备cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf cp /root/fastdfs/fastdfs-5.11/conf/http.conf /etc/fdfs cp /root/fastdfs/fastdfs-5.11/conf/mime.types /etc/fdfs修改tracker.conf配置文件vim /etc/fdfs/tracker.conf需要修改的内容如下port=22122 base_path=/home/fastdfs修改storage.conf配置文件vim /etc/fdfs/storage.conf需要修改的内容如下port=23000 # 数据和日志文件存储根目录 base_path=/home/fastdfs # 第一个存储目录，可以有多个 store_path0=/home/fastdfs tracker_server=192.168.211.136:22122 # http访问文件的端口(默认8888,看情况修改,和nginx中保持一致) http.server_port=8888启动mkdir /home/fastdfs -p /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart为了检查是否启动，查看所有运行的端口netstat -ntlp测试上传修改client.conf配置文件vim /etc/fdfs/client.conf需要修改的内容如下base_path=/home/fastdfs #tracker服务器IP和端口 tracker_server=192.168.211.136:22122 #保存后测试，返回ID表示成功 如：group1/M00/00/00/xxx.png /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /root/fastdfs/1.png安装fastdfs-nginx-modulecd /root/fastdfs wget https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.20.tar.gz tar -xvf V1.20.tar.gz修改配置文件cd fastdfs-nginx-module-1.20/src vim config需要修改的内容如下修改第5 行 和 15 行 修改成 ngx_module_incs="/usr/include/fastdfs /usr/include/fastcommon/" CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"复制配置文件cp mod_fastdfs.conf /etc/fdfs/修改mod_fastdfs.conf配置文件vim /etc/fdfs/mod_fastdfs.conf需要修改的内容如下tracker_server=192.168.211.136:22122 url_have_group_name=true store_path0=/home/fastdfs创建文件夹mkdir -p /var/temp/nginx/client安装nginxcd /root/fastdfs wget http://nginx.org/download/nginx-1.15.6.tar.gz tar -zxvf nginx-1.15.6.tar.gz cd nginx-1.15.6/ yum -y install pcre-devel openssl openssl-devel # 添加fastdfs-nginx-module模块 ./configure --add-module=/root/fastdfs/fastdfs-nginx-module-1.20/src # 编译安装 make && make install # 查看模块是否安装上 /usr/local/nginx/sbin/nginx -V修改nginx配置文件vim /usr/local/nginx/conf/nginx.conf添加如下配置server { listen 8888; server_name localhost; location ~/group[0-9]/ { ngx_fastdfs_module; } }启动nginx/usr/local/nginx/sbin/nginx测试下载# 关闭防火墙或打开通信端口 systemctl stop firewalldhttp://192.168.211.136:8888/group1/M00/00/00/xxx.pngjava访问FastDFS可以参考官方案例 https://github.com/happyfish100/fastdfs-client-java建立maven 工程 引入jar包 <dependency> <groupId>cn.bestwu</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27</version> </dependency>引入配置文件fastdfs-client.propertiesfastdfs.connect_timeout_in_seconds = 5 fastdfs.network_timeout_in_seconds = 30 fastdfs.charset = UTF-8 fastdfs.tracker_servers = 192.168.211.136:22122编写测试类@Test public void testUpload() { try { //加载配置文件 ClientGlobal.initByProperties("fastdfs-client.properties"); //创建tracker客户端 TrackerClient tc = new TrackerClient(); //根据tracker客户端创建连接 获取到跟踪服务器对象 TrackerServer ts = tc.getConnection(); StorageServer ss = null; //定义storage客户端 StorageClient1 client = new StorageClient1(ts, ss); //文件元信息 NameValuePair[] list = new NameValuePair[1]; list[0] = new NameValuePair("fileName", "1.png"); //上传，返回fileId String fileId = client.upload_file1("****.png", "png", list); System.out.println(fileId); } catch (Exception e) { e.printStackTrace(); } }@Test public void testQuery() { try { //加载配置文件 ClientGlobal.initByProperties("fastdfs-client.properties"); // 创建tracker客户端 TrackerClient tc = new TrackerClient(); // 根据tracker客户端创建连接 获取到跟踪服务器对象 TrackerServer ts = tc.getConnection(); StorageServer ss = null; //定义storage客户端 StorageClient1 client = new StorageClient1(ts, ss); // 查询文件信息 FileInfo fileInfo = client.query_file_info1("group1/M00/00/00/****.png"); System.out.println(fileInfo); } catch (Exception e) { e.printStackTrace(); } }@Test public void testDownload() { try { //加载配置文件 ClientGlobal.initByProperties("config/fastdfs-client.properties"); // 创建tracker客户端 TrackerClient tc = new TrackerClient(); // 根据tracker客户端创建连接 TrackerServer ts = tc.getConnection(); StorageServer ss = null; // 定义storage客户端 StorageClient1 client = new StorageClient1(ts, ss); // 下载 byte[] bs = client.download_file1("group1/M00/00/00/****.png"); FileOutputStream fos = new FileOutputStream(new File("xxxx.png")); fos.write(bs); fos.close(); } catch (Exception e) { e.printStackTrace(); } }