使用jclouds在S3上分段上传

1.目标

在上一篇文章中 ,我们研究了如何使用jclouds中的通用Blob API将内容上传到S3。 在本文中,我们将使用jcloudsS3特定的异步API上传内容并利用S3提供的分段上传功能。

2.准备


2.1。 设置自定义API

上传过程的第一部分是创建jclouds API-这是针对Amazon S3的自定义API:

public AWSS3AsyncClient s3AsyncClient() {String identity = ...String credentials = ...BlobStoreContext context = ContextBuilder.newBuilder('aws-s3').credentials(identity, credentials).buildView(BlobStoreContext.class);RestContext<AWSS3Client, AWSS3AsyncClient> providerContext = context.unwrap();return providerContext.getAsyncApi();
}

2.2。 确定内容的零件数

Amazon S3对于要上传的每个部分都有5 MB的限制。 因此,我们需要做的第一件事就是确定可以分割内容的适当数量的部分,以使我们没有低于5 MB限制的部分:

public static int getMaximumNumberOfParts(byte[] byteArray) {int numberOfParts= byteArray.length / fiveMB; // 5*1024*1024if (numberOfParts== 0) {return 1;}return numberOfParts;
}

2.3。 将内容分成几部分

将把字节数组分成一定数量的部分:

public static List<byte[]> breakByteArrayIntoParts(byte[] byteArray, int maxNumberOfParts) {List<byte[]> parts = Lists.<byte[]> newArrayListWithCapacity(maxNumberOfParts);int fullSize = byteArray.length;long dimensionOfPart = fullSize / maxNumberOfParts;for (int i = 0; i < maxNumberOfParts; i++) {int previousSplitPoint = (int) (dimensionOfPart * i);int splitPoint = (int) (dimensionOfPart * (i + 1));if (i == (maxNumberOfParts - 1)) {splitPoint = fullSize;}byte[] partBytes = Arrays.copyOfRange(byteArray, previousSplitPoint, splitPoint);parts.add(partBytes);}return parts;
}

我们将测试将字节数组分成多个部分的逻辑–我们将生成一些字节,将字节数组拆分,使用Guava将其重新组合在一起,并验证是否可以获取原始字节:

@Test
public void given16MByteArray_whenFileBytesAreSplitInto3_thenTheSplitIsCorrect() {byte[] byteArray = randomByteData(16);int maximumNumberOfParts = S3Util.getMaximumNumberOfParts(byteArray);List<byte[]> fileParts = S3Util.breakByteArrayIntoParts(byteArray, maximumNumberOfParts);assertThat(fileParts.get(0).length + fileParts.get(1).length + fileParts.get(2).length,equalTo(byteArray.length));byte[] unmultiplexed = Bytes.concat(fileParts.get(0), fileParts.get(1), fileParts.get(2));assertThat(byteArray, equalTo(unmultiplexed));
}

要生成数据,我们只需使用Random的支持:

byte[] randomByteData(int mb) {byte[] randomBytes = new byte[mb * 1024 * 1024];new Random().nextBytes(randomBytes);return randomBytes;
}

2.4。 创建有效载荷

既然我们已经为内容确定了正确的部分数量,并且设法将内容分解为多个部分,那么我们需要为jclouds API 生成Payload对象

public static List<Payload> createPayloadsOutOfParts(Iterable<byte[]> fileParts) {List<Payload> payloads = Lists.newArrayList();for (byte[] filePart : fileParts) {byte[] partMd5Bytes = Hashing.md5().hashBytes(filePart).asBytes();Payload partPayload = Payloads.newByteArrayPayload(filePart);partPayload.getContentMetadata().setContentLength((long) filePart.length);partPayload.getContentMetadata().setContentMD5(partMd5Bytes);payloads.add(partPayload);}return payloads;
}

3.上载

上传过程是一个灵活的多步骤过程–这意味着:

  • 可以在拥有所有数据之前开始上载–可以在输入数据时上载数据
  • 数据分上传-如果这些操作之一失败,则可以简单地将其检索
  • 块可以并行上传–这可以大大提高上传速度,尤其是在大文件的情况下

3.1。 启动上传操作

上传操作的第一步是启动该过程 。 对S3的请求必须包含标准的HTTP标头–特别是内容MD5标头。 我们将在这里使用Guava哈希函数支持:

Hashing.md5().hashBytes(byteArray).asBytes();

这是整个字节数组(而不是各个部分)的md5哈希

为了启动上载以及与S3的所有进一步交互,我们将使用AWSS3AsyncClient –我们之前创建的异步API:

ObjectMetadata metadata = ObjectMetadataBuilder.create().key(key).contentMD5(md5Bytes).build();
String uploadId = s3AsyncApi.initiateMultipartUpload(container, metadata).get();

密钥是分配给对象的句柄–它必须是客户端指定的唯一标识符。

还要注意,即使我们使用的是异步版本的API, 我们也阻止了该操作的结果–这是因为我们需要初始化的结果才能继续前进。

操作的结果是S3返回的上传ID –这将在整个生命周期中识别上传,并将出现在所有后续的上传操作中。

3.2。 上载零件

下一步是上传零件 。 我们的目标是并行发送这些请求,因为上载零件操作代表了大部分上载过程:

List<ListenableFuture<String>> ongoingOperations = Lists.newArrayList();
for (int partNumber = 0; partNumber < filePartsAsByteArrays.size(); partNumber++) {ListenableFuture<String> future = s3AsyncApi.uploadPart(container, key, partNumber + 1, uploadId, payloads.get(partNumber));ongoingOperations.add(future);
}

零件编号必须是连续的,但发送请求的顺序无关紧要。

提交所有上传零件请求后,我们需要等待它们的响应,以便我们可以收集每个零件的单独ETag值:

Function<ListenableFuture<String>, String> getEtagFromOp =new Function<ListenableFuture<String>, String>() {public String apply(ListenableFuture<String> ongoingOperation) {try {return ongoingOperation.get();} catch (InterruptedException | ExecutionException e) {throw new IllegalStateException(e);}}
};
List<String> etagsOfParts = Lists.transform(ongoingOperations, getEtagFromOp);

如果由于某种原因,上载部分操作之一失败, 则可以重试该操作,直到成功为止。 上面的逻辑不包含重试机制,但是建立它应该足够简单。

3.3。 完成上传操作

上传过程的最后一步是完成分段操作 。 S3 API要求以Map的形式上传来自先前零件的响应,现在我们可以轻松地从上面获得的ETag列表中创建这些响应:

Map<Integer, String> parts = Maps.newHashMap();
for (int i = 0; i < etagsOfParts.size(); i++) {parts.put(i + 1, etagsOfParts.get(i));
}

最后,发送完整的请求:

s3AsyncApi.completeMultipartUpload(container, key, uploadId, parts).get();

这将返回完成对象的最终ETag,并完成整个上传过程。

4。结论

在本文中,我们使用自定义S3 jclouds API构建了一个支持多部分的,完全并行的S3上传操作。 此操作可以按原样使用,但是可以通过几种方法进行改进 。 首先,应在上传操作周围添加重试逻辑,以更好地处理故障。 接下来,对于非常大的文件,即使该机制正在并行发送所有上载的多部分请求, 限制机制仍应限制发送的并行请求的数量。 这既可以避免带宽成为瓶颈,又可以确保Amazon本身不会将上传过程标记为超过每秒允许的请求限制– Guava RateLimiter可能非常适合此操作。

参考:来自baeldung博客的JCG合作伙伴 Eugen Paraschiv的jclouds在S3上进行了分段上传 。

翻译自: https://www.javacodegeeks.com/2013/04/multipart-upload-on-s3-with-jclouds.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ichart】简单的统计图表ichart.js的使用

1、首先下载&#xff0c;点击下载 2、只需要这一个js&#xff0c;粘贴赋值到自己项目中即可。 3、引入js <script type"text/javascript" src"../js/ichart.1.2.min.js"></script> <script type"text/javascript" src"..…

java单击切换div_[Java教程]点击同一按钮实现div的隐藏与现实切换

[Java教程]点击同一按钮实现div的隐藏与现实切换0 2016-01-16 21:00:12点击同一按钮实现div的隐藏与现实切换:在很多应用中&#xff0c;都有这样的功能&#xff0c;点击同一个按钮可以实现div的隐藏或者现实&#xff0c;当然操作的并非必须是按钮或者div&#xff0c;不过原理是…

python链表的实现,有注释

class Node(): #node实现,每个node分为两部分:一部分含有链表元素,成数据域;另一部分为指针,指向下一个 __slots__[_item,_next] #限定node实例的属性??? 这个元素就是有两部分组成,,,一个指针一个数据,,,但是链表头就不是这样了 def __init__(self…

ActiveMQ——activemq的使用java代码实例(精选)

ActiveMQ 在java中的使用&#xff0c;通过单例模式、工厂实现 Jms规范里的两种message传输方式Topic和Queue&#xff0c;两者的对比如下表()&#xff1a; TopicQueue概要Publish Subscribe messaging 发布订阅消息Point-to-Point 点对点有无状态topic数据默认不落地&#xff…

Java 8:正在运行的CompletableFuture

在Java 8中全面研究了CompletableFuture API之后&#xff0c;我们准备编写一个简单的Web搜寻器。 我们已经使用ExecutorCompletionService &#xff0c; Guava ListenableFuture和Scala / Akka解决了类似的问题。 我选择了相同的问题&#xff0c;以便轻松比较方法和实现技术。 …

java能不能修改文件大小信息_java上机考试3

考号: 000128000091 姓名: 张天義 学号: 1040610329 班级: 本科(计算机、微电、电工、经管)->计算机科学与技术 00:13:25一、单选(共80分)1. int count1;for(int i1;i<5;i){countcounti;}System.out.println(count);上述代码执行后的输出结果是A、15B、1C、16D、5标记此题…

(网页)中的简单的遮罩层

html: <div id"test"></div><div id"log_window"> <!--<a href"javascript:cancel_shield()">关闭</a>--> <!--<img src"assets/css/images/loading.gif" />--> <p style"fo…

即使在jdk中也有错误的代码

Java 7&#xff0c;TreeSet和NullPointerException。 最近&#xff0c;我尝试用Java 7编译一个用Java 6开发的项目。在执行测试过程中发生了很多有趣的事情&#xff0c;在Java 6中使用Java 7平稳运行的测试失败了&#xff01; 因此&#xff0c;我必须理解为什么&#xff0c;这就…

Eclipse+GitHub 提交代码错误 -“rejected - non-fast-forward”

Eclipse Push出现rejected - non-fast-forward错误 在 Push到服务器时有时会出现 rejected - non-fast-forward 错误&#xff0c;这是由于远端发生改变&#xff0c;此时再提交之前你需要将远端的改变合并到本地上错误原因&#xff1a;文件冲突&#xff0c;本地的代码和远程Repo…

两天学会css基础(一)

什么是css&#xff1f;css的作用是什么&#xff1f; CSS 指层叠样式表 (Cascading Style Sheets)主要作用就是给HTML结构添加样式&#xff0c;搭建页面结构&#xff0c;比如设置元素的宽高大小&#xff0c;颜色&#xff0c;位置等等。 学习css之前先了解一下css代码在HTML中的…

在Android项目中使用AspectJ

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 转载请表明出处&#xff1a;http://www.cnblogs.com/cavalier-/p/8888459.html 什么是AOP AOP是 Aspect Oriented Programming 的缩写&#xff0c;即面向切面编程&#xff0c;和平常遇到的面向对象O…

LVM 逻辑卷 (logica volume manager)

逻辑卷轴管理员 (Logical Volume Manager) 想像一个情况&#xff0c;你在当初规划主机的时候将 /home 只给他 50G &#xff0c;等到使用者众多之后导致这个 filesystem 不够大&#xff0c; 此时你能怎么作&#xff1f; 多数的朋友都是这样&#xff1a;再加一颗新硬盘&#xff0…

java中u怎么用_Java中interrupt的使用

通常我们会有这样的需求&#xff0c;即停止一个线程。在java的api中有stop、suspend等方法可以达到目的&#xff0c;但由于这些方法在使用上存在不安全性&#xff0c;会带来不好的副作用&#xff0c;不建议被使用。具体原因可以参考Why is Thread.stop deprecated。在本文中&am…

当Maven依赖插件位于

问题&#xff1a; 我们进行了一个集成测试&#xff0c;该测试创建了一个Spring ClassPathXmlApplicationContext &#xff0c;同时这样做导致NoSuchMethodError爆炸。 事实证明&#xff0c;我们对Spring构件的依赖版本存在冲突。 这本身不是一个不寻常的问题-使用Maven依赖插件…

sql查询语句for xml path语法

【原地址】 for xml path作用&#xff1a;将多行的查询结果&#xff0c;根据某一些条件合并到一行。 例&#xff1a;现有一张表 执行下面语句 select Department,(SELECT Employee, FROM People b WHERE b.Departmenta.Department For XML Path()) Student from People as a g…

css高度已知,左右定宽,中间自适应三栏布局

css高度已知&#xff0c;左右定宽&#xff0c;中间自适应三栏布局&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale…

java使用impala存放多条sql_Impala基于内存的SQL引擎的详细介绍

数据存储使用相同的存储数据池都支持把数据存储于HDFS, HBase。元数据&#xff1a;两者使用相同的元数据SQL解释处理&#xff1a;比较相似都是通过词法分析生成执行计划。执行计划&#xff1a;Hive: 依赖于MapReduce执行框架&#xff0c;执行计划分成 map->shuffle->redu…

Android Studio打包以及Gradle配置构建

本文转载 郭霖公众号 https://mp.weixin.qq.com/s?__bizMzA5MzI3NjE2MA&mid2650241610&idx1&snb8af73f6c288b6617d9fe0ab3618118d&pass_ticketQK4j37kpmGNlsYcECWMb64HxKHEVJG5mSJubQEQguKI%3D 生成签名文件手动打包 首先生成签名文件&#xff0c;点击 Build…

去除inline-block间隙的几种方法

为什么会产生间隙&#xff1f; 由于编写代码时的美观和可读性&#xff0c;在代码中添加回车或空格而产生的间隙。 html代码&#xff1a; <ul class"container"><li></li><li></li><li></li><li></li><li&…

java重载方法math_Java语言程序设计(十二)Math数学类,方法重载及变量作用域...

1.重载方法上一篇文章用到的max方法只能用于int型数据类型&#xff0c;但是如果需要决定两个浮点数中哪个较大&#xff0c;解决方法是创建另一个方法名相同但参数不同的方法&#xff0c;代码如下&#xff1a;public static double max(double num1, double num2){if(num1>nu…