无论如何,是否有小文件作为实时流写入S3

时间:2018-11-27 13:11:29

标签: java multithreading amazon-web-services amazon-s3

我在一分钟内得到1万到3 kb大小的2万个小型xml文件。 我必须将所有文件写入目录中。

有时,传入文件的速度提高到每分钟100k。 java或aws api中是否有什么可以帮助我匹配传入的速度?

我正在使用uploadFileList() API上传所有文件。 我也尝试过监视事件,以便每当文件到达文件夹时,它都会将该文件上传到S3中,但是与传入文件相比,它是如此之慢,并且会产生大量积压。

我也尝试了多线程,但是如果我增加了更多线程,则会从S3 reduce you request rate error.中获取错误 有时候我也低于错误

  

AmazonServiceException:   com.amazonaws.services.s3.model.AmazonS3Exception:您的套接字   未从服务器中读取或写入与服务器的连接   超时时间。空闲连接将关闭。

但是当我使用线程时,我没有得到这个错误

我也尝试过的另一种方法是创建一个大文件,然后上传到S3,然后在S3中,我再次将其拆分为小文件,这很好,但是此解决方案延迟了文件上传到S3的速度,并影响了访问此文件的用户S3中的文件。

我知道将小文件上传到S3是不合适的,但是我有这样的用例。

我注意到的速度是在一分钟内上传5k个文件。

有人可以建议其他方法,这样我的文件上传速度每分钟至少增加1.5万。

我正在共享我尝试使用多线程应用程序上传的完整代码

我创建要放入线程的文件的类

public class FileProcessThreads {

    public  ArrayList process(String fileLocation)  {

        File dir = new File(fileLocation);
        File[] directoryListing = dir.listFiles();
        ArrayList<File> files = new ArrayList<File>();
        if (directoryListing.length > 0) {
            for (File path : directoryListing) {
                files.add(path);
            }
        }
        return files;
    }
}

我在其中创建线程池和执行程序的类2

public class UploadExecutor {
private static String fileLocation = "C:\\Users\\u6034690\\Desktop\\ONEFILE";
// private static String fileLocation="D:\\TRFAudits_Moved\\";
private static final String _logFileName = "s3FileUploader.log";
private static Logger _logger = Logger.getLogger(UploadExecutor.class);

@SuppressWarnings("unchecked")
public static void main(String[] args) {
    _logger.info("----------Stating application's  main method----------------- ");
    AWSCredentials credential = new ProfileCredentialsProvider("TRFAuditability-Prod-ServiceUser").getCredentials();
    final ClientConfiguration config = new ClientConfiguration();

    AmazonS3Client s3Client = (AmazonS3Client) AmazonS3ClientBuilder.standard().withRegion("us-east-1")
            .withCredentials(new AWSStaticCredentialsProvider(credential)).withForceGlobalBucketAccessEnabled(true)
            .build();

    s3Client.getClientConfiguration().setMaxConnections(100);

    TransferManager tm = new TransferManager(s3Client);
    while (true) {
        FileProcessThreads fp = new FileProcessThreads();
        List<File> records = fp.process(fileLocation);
        while (records.size() <= 0) {
            try {
                _logger.info("No records found willl wait for 10 Seconds");
                TimeUnit.SECONDS.sleep(10);
                records = fp.process(fileLocation);
            } catch (InterruptedException e) {
                _logger.error("InterruptedException: " + e.toString());
            }
        }
        _logger.info("Total no of Audit files = " + records.size());
        ExecutorService es = Executors.newFixedThreadPool(2);
        int recordsInEachThread = (int) (records.size() / 2);
        _logger.info("No of records in each thread = " + recordsInEachThread);
        UploadObject my1 = new UploadObject(records.subList(0, recordsInEachThread), tm);
        UploadObject my2 = new UploadObject(records.subList(recordsInEachThread, records.size()), tm);

        es.execute(my1);
        es.execute(my2);
        es.shutdown();
        try {
            boolean finshed = es.awaitTermination(1, TimeUnit.MINUTES);
            if (!finshed) {
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            _logger.error("InterruptedException: " + e.toString());
        }
    }
}

}

上次课,我将文件上传到S3

public class UploadObject implements Runnable{
static String bucketName = "a205381-auditxml/S3UPLOADER";
private String fileLocation="C:\\Users\\u6034690\\Desktop\\ONEFILE";
//private String fileLocation="D:\\TRFAudits\\";
//static String bucketName = "a205381-auditxml/S3UPLOADER"; 

private static Logger _logger;

List<File> records;
TransferManager tm;

UploadObject(List<File> list,TransferManager tm){
    this.records = list;
    this.tm=tm;
    _logger = Logger.getLogger(UploadObject.class);
}
public void run(){
        System.out.println(Thread.currentThread().getName() + " : ");
        uploadToToS3();
}

public  void uploadToToS3() {

    _logger.info("Number of record to be processed in current thread: : "+records.size());
    MultipleFileUpload xfer = tm.uploadFileList(bucketName, "TEST",new File(fileLocation), records);
    try {
        xfer.waitForCompletion();
        TransferState xfer_state = xfer.getState();
        _logger.info("Upload status -----------------" + xfer_state);

        for (File file : records) {
            try {
                Files.delete(FileSystems.getDefault().getPath(file.getAbsolutePath()));
            } catch (IOException e) {
                System.exit(1);
                _logger.error("IOException: "+e.toString());
            }
        }

        _logger.info("Successfully completed file cleanse");

    } catch (AmazonServiceException e) {
        _logger.error("AmazonServiceException: "+e.toString());
        System.exit(1);
    } catch (AmazonClientException e) {
        _logger.error("AmazonClientException: "+e.toString());
        System.exit(1);
    } catch (InterruptedException e) {
        _logger.error("InterruptedException: "+e.toString());
        System.exit(1);
    }

    System.out.println("Completed");
    _logger.info("Upload completed");
    _logger.info("Calling Transfer manager shutdown");
    //tm.shutdownNow();

}

}

2 个答案:

答案 0 :(得分:2)

这听起来像是您在破坏S3的内置保护功能(在下面引用文档)。我还在下面列出了一些类似的问题。其中一些建议使用SQS进行重新配置,以平衡并分配S3上的负载。

除了引入更多可移动的片段外,您还可以重复使用S3ClientTransferManager。将它们从可运行对象中移出并将它们传递到其构造函数中。 TransferManager本身根据Javadoc使用多线程。

  

在可能的情况下,TransferManager尝试使用多个线程一次上载单个上载的多个部分。当处理较大的内容大小和高带宽时,这可以显着提高吞吐量。

您还可以增加S3Client使用的max number of simultaneous connections

也许:

s3Client.getClientConfiguration().setMaxConnections(75)甚至更高。

DEFAULT_MAX_CONNECTIONS is set to 50

最后,您可以尝试将其上传到存储桶下的其他前缀/文件夹,如下所述,以实现更高的请求率。

当前的AWS Request Rate and Performance Guidelines

  

Amazon S3自动扩展到高请求率。例如,您的应用程序每个存储桶中的每个前缀每秒至少可以实现3500个PUT / POST / DELETE和5500个GET请求。存储桶中的前缀数量没有限制。很容易以指数方式提高您的读写性能。例如,如果您在Amazon S3存储桶中创建10个前缀来并行化读取,则可以将读取性能扩展到每秒55,000个读取请求。

当前的AWS S3 Error Best Practices

  

为重复的SlowDown错误调整应用程序

     与任何分布式系统一样,S3具有保护机制,可检测有意或无意的资源过度消耗并做出相应的反应。当高请求率触发这些机制之一时,可能会发生SlowDown错误。降低请求率将减少或消除此类错误。一般而言,大多数用户不会定期遇到这些错误。但是,如果您想了解更多信息,或者遇到严重或意外的SlowDown错误,请发布到我们的Amazon S3开发人员论坛https://forums.aws.amazon.com/或注册AWS高级支持https://aws.amazon.com/premiumsupport/

类似的问题:

S3 SlowDown: Please reduce your request rate exception

Amazon Web Services S3 Request Limit

AWS Forums - Maximizing Connection Reuse for S3 getObjectMetadata() Calls

答案 1 :(得分:0)

S3传输加速不一定提供更快的上载速度。从同一地区使用时,有时会比正常上传速度慢。 Amazon S3 Transfer Acceleration使用他们在世界各地拥有的AWS边缘基础架构,以更快地将数据传输到AWS骨干网。当您使用Amazon S3 Transfer Acceleration时,您的请求将根据延迟路由到最佳的AWS边缘位置。然后,Transfer Acceleration将使用优化的网络协议,从边缘到源的持久连接,完全打开的发送和接收窗口等,通过AWS管理的骨干网将您的上载发送回S3。因为您已经在该区域内,所以使用此功能不会有任何好处。但是,最好从https://s3-accelerate-speedtest.s3-accelerate.amazonaws.com/en/accelerate-speed-comparsion.html

测试速度