429 Слишком много запросов при генерации предопределенных URL-адресов для объектов s3 с использованием aws-sdk
У меня есть приложение, которое представляет собой систему управления цифровыми активами. Он отображает эскизы. У меня есть эти миниатюры, настроенные для обслуживания с предварительно назначенными 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-адреса в пакетах.
0 ответов
Проблема не связана с созданием предварительно подписанных URL-адресов. Это делается без взаимодействия со службой, поэтому нет никакого способа, которым это могло бы быть ограничено скоростью. Предварительно подписанный URL-адрес использует алгоритм HMAC-SHA, чтобы доказать службе, что объект, обладающий учетными данными, разрешил конкретный запрос. Односторонний (необратимый) характер HMAC-SHA позволяет создавать эти URL-адреса полностью на компьютере, на котором выполняется код, без взаимодействия со службой.
Тем не менее, вполне вероятно, что повторная загрузка учетных данных является действительной причиной исключения - и вы, кажется, делаете это излишне снова и снова.
Это дорогая операция:
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(clientRegion)
.withCredentials(new ContainerCredentialsProvider())
.build();
Каждый раз, когда вы вызываете это снова, учетные данные должны быть получены снова. Это на самом деле предел, который вы бьете.
Создайте свой s3client
только один раз и рефакторинг s3SignedUrl()
ожидать, что этот объект будет передан, так что вы можете использовать его повторно.
Вы должны увидеть заметное улучшение производительности, в дополнение к решению 429
ошибка.