429 Слишком много запросов при генерации предопределенных URL-адресов для объектов s3 с использованием aws-sdk - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть приложение, которое представляет собой систему управления цифровыми активами.Он отображает эскизы.У меня есть эти миниатюры, настроенные для обслуживания с предварительно назначенными URL-адресами AWS S3: https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURLJavaSDK.html. Этот фрагмент кода работает, пока я не изменю количество элементов, обрабатываемых в запросе.Приложение имеет выбор для 25, 50, 100, 200. Если я выберу 100 или 200, процесс завершится с ошибкой «Ошибка: com.amazonaws.AmazonServiceException: слишком много запросов (Служба: пусто; Код состояния: 429; Код ошибки: пусто»; Идентификатор запроса: null) "

В данный момент процесс выглядит следующим образом: Выполните поиск>, запустите каждый ключ объекта с помощью метода, который возвращает предопределенный URL-адрес для этого объекта.

Мы запускаем этоприложение через Elastic Container Service, которое позволяет нам вводить учетные данные через ContainerCredentialsProvider.

Соответствующий код для обзора:

String s3SignedUrl(String objectKeyUrl) {
    // Environment variables for S3 client.
    String clientRegion = System.getenv("REGION");
    String bucketName = System.getenv("S3_BUCKET");

    try {
        // S3 credentials get pulled in from AWS via ContainerCredentialsProvider.
        AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                .withRegion(clientRegion)
                .withCredentials(new ContainerCredentialsProvider())
                .build();

        // Set the pre-signed URL to expire after one hour.
        java.util.Date expiration = new java.util.Date();
        long expTimeMillis = expiration.getTime();
        expTimeMillis += 1000 * 60 * 60;
        expiration.setTime(expTimeMillis);

        // Generate the presigned URL.
        GeneratePresignedUrlRequest generatePresignedUrlRequest =
                new GeneratePresignedUrlRequest(bucketName, objectKeyUrl)
                        .withMethod(HttpMethod.GET)
                        .withExpiration(expiration);

        return s3Client.generatePresignedUrl(generatePresignedUrlRequest).toString();

    } catch (AmazonServiceException e) {
        throw new AssetException(FAILED_TO_GET_METADATA, "The call was transmitted successfully, but Amazon " +
                "S3 couldn't process it, so it returned an error response. Error: " + e);
    } catch (SdkClientException e) {
        throw new AssetException(FAILED_TO_GET_METADATA, "Amazon S3 couldn't be contacted for a response, or " +
                "the client couldn't parse the response from Amazon S3. Error: " + e);
    }
}

И это та часть, где мы обрабатываем элементы:

// Overwrite the url, it's nested deeply in maps of maps.
    for (Object anAssetList : assetList) {
        String assetId = ((Map) anAssetList).get("asset_id").toString();
        if (renditionAssetRecordMap.containsKey(assetId)) {
            String s3ObjectKey = renditionAssetRecordMap.get(assetId).getThumbObjectLocation();
            ((Map) ((Map) ((Map) anAssetList)
                    .getOrDefault("rendition_content", new HashMap<>()))
                    .getOrDefault("thumbnail_content", new HashMap<>()))
                    .put("url", s3SignedUrl(s3ObjectKey));
        }
    }

Любое руководство будет оценено.Хотелось бы получить решение, простое и, надеюсь, настраиваемое на стороне AWS.В противном случае, сейчас я смотрю на добавление процесса для этого, чтобы генерировать URL в пакетах.

1 Ответ

0 голосов
/ 03 декабря 2018

Проблема не связана с созданием предварительно подписанных URL-адресов.Это делается без взаимодействия со службой, поэтому нет никакого способа, которым это могло бы быть ограничено скоростью.Предварительно подписанный URL-адрес использует алгоритм HMAC-SHA, чтобы доказать службе, что объект, обладающий учетными данными, разрешил конкретный запрос.Односторонняя (необратимая) природа HMAC-SHA позволяет полностью генерировать эти URL-адреса на компьютере, на котором выполняется код, без взаимодействия со службой.

Однако представляется весьма вероятным, что повторная выборкаучетные данные являются действительной причиной исключения - и вы, кажется, делаете это излишне снова и снова.

Это дорогостоящая операция:

    AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
            .withRegion(clientRegion)
            .withCredentials(new ContainerCredentialsProvider())
            .build();

Каждый раз, когда вы вызываете это снова, учетные данные должны выбираться снова.Это на самом деле предел, которого вы достигаете.

Создайте свой s3client только один раз, и рефакторинг s3SignedUrl() ожидает, что этот объект будет передан, так что вы можете использовать его повторно.

В дополнение к устранению ошибки 429 вы увидите заметное улучшение производительности.

...