AmazonS3客户端跨域转存方案
·
背景
本人日常工作中使用比较多的就是对象存储,用到过阿里云的、腾讯云的、字节云的等等,每家的对象存储协议都大同小异,并且都支持AmazonS3协议;所以只要吃透AmazonS3,基本全部可以搞定,在使用AmazonS3进行处理过程中存在一个需求:
如何实现AmazonS3支持客户端SDK进行两个跨域桶之间的文件拷贝?
可能有的同学知道:官方文档有提供跨域拷贝的ACL命令,何必自己在客户端捣鼓呢?
其实还是业务场景问题,客户端更加灵活,方便业务操作处理,不一定只是单出的CV操作,但是目前的AmazonS3只能支持先下载,后上传,存在落盘的额外时间,性能非常慢,故需要想办法进行优化,怎么可以做到直接的内存转发拷贝呢?
问题分析解决
【不支持原因分析】
经过研究发现,S3是通过http协议获取流进行交互的,流本身不支持mark的;但是S3在进行数据上传时需要进行签名验证,签名过程会读取流数据,然后签名ok后才进行上传,此时会发生reset操作;由此导致下载流不能支持直接上传。
【支持方案】
基于S3的签名后上传的特性,触发reset时必定是流读完重置到pos=0,那么为了实现下载流支持reset,可以通过FilterInputStream进行封装重写reset方法,触发时,关闭当前流,重新建立一个下载流,如下图

S3Object s3Object = amazonS3.getObject(srcBucket, srcKey);
ObjectMetadata metadata = s3Object.getObjectMetadata();
InputStream inp = new FilterInputStream(s3Object.getObjectContent()) {
public boolean markSupported() {
return true;
}
public synchronized void reset() throws IOException {
this.close();
S3Object newObj = amazonS3.getObject(srcBucket, srcKey);
this.in = newObj.getObjectContent();
}
};
PutObjectRequest putObjectRequest = new PutObjectRequest(descBucket, descKey, inp, metadata);
int readLimitInBytes = 1024 * 1024 * 100;
putObjectRequest.getRequestClientOptions().setReadLimit(readLimitInBytes);
amazonS3.putObject(putObjectRequest);
方案对比
| 操作方案 | 优点 | 缺点 | 图示 |
|---|---|---|---|
| 落盘后上传 | 1、仅一次网络下载 2、内存可控 3、支持大文件 |
1、多了1次写盘和2次读盘 2、磁盘IO影响转发速度 |
下图:落盘方案 |
| 流式不落盘上传 | 1、支持大文件 2、不用落地 3、内存可控 4、转发速度快 |
1、占用双倍的下载流量 2、容易受到网络干扰导致转移失败 |
下图:流处理方案 |
| byte数组中转 | 1、仅一次网络下载 2、转发速度快 3、不用落地 |
1、最大仅支持4G以下的文件 2、内存不可控,需要考虑服务内存限制 |
下图:byte数组方案 |
建议根据实际情况,配合使用以上三种改方案。
更多推荐


所有评论(0)