AmazonS3:收到警告:S3AbortableInputStream:Not 所有字节均已从 S3ObjectInputStream 读取,中止 HTTP 连接
AmazonS3: Getting warning: S3AbortableInputStream:Not all bytes were read from the S3ObjectInputStream, aborting HTTP connection
这是我收到的警告:
S3AbortableInputStream:Not all bytes were read from the S3ObjectInputStream, aborting HTTP connection. This is likely an error and may result in sub-optimal behavior. Request only the bytes you need via a ranged GET or drain the input stream after use.
我尝试对资源使用 try,但 S3ObjectInputStream 似乎无法通过此方法关闭。
try (S3Object s3object = s3Client.getObject(new GetObjectRequest(bucket, key));
S3ObjectInputStream s3ObjectInputStream = s3object.getObjectContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(s3ObjectInputStream, StandardCharsets.UTF_8));
){
//some code here blah blah blah
}
我也试过下面的代码并明确关闭,但这也不起作用:
S3Object s3object = s3Client.getObject(new GetObjectRequest(bucket, key));
S3ObjectInputStream s3ObjectInputStream = s3object.getObjectContent();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(s3ObjectInputStream, StandardCharsets.UTF_8));
){
//some code here blah blah
s3ObjectInputStream.close();
s3object.close();
}
如有任何帮助,我们将不胜感激。
PS: 我只从 S3 读取文件的两行,文件有更多数据。
通过其他媒介得到答案。在这里分享:
该警告表明您在未读取整个文件的情况下调用了 close()。这是有问题的,因为 S3 仍在尝试发送数据,而您让连接处于不正常状态。
这里有两个选项:
- 从输入流中读取其余数据,以便重新使用连接。
- 调用s3ObjectInputStream.abort()关闭连接而不读取数据。该连接不会被重用,因此您在下一个重新创建连接的请求中会受到一些性能影响。如果需要很长时间才能阅读文件的其余部分,这可能是值得的。
要在 Chirag Sejpal 的回答中添加一个示例(详细说明选项 #1),可以使用以下方法在关闭输入流之前从输入流中读取其余数据:
S3Object s3object = s3Client.getObject(new GetObjectRequest(bucket, key));
try (S3ObjectInputStream s3ObjectInputStream = s3object.getObjectContent()) {
try {
// Read from stream as necessary
} catch (Exception e) {
// Handle exceptions as necessary
} finally {
while (s3ObjectInputStream != null && s3ObjectInputStream.read() != -1) {
// Read the rest of the stream
}
}
// The stream will be closed automatically by the try-with-resources statement
}
我运行进入同样的错误。
正如其他人所指出的,lambda 中的 /tmp space 限制为 512 MB。
如果 lambda 上下文被重新用于新的调用,那么 /tmp space 已经半满了。
因此,当读取 S3 对象并将所有文件写入 /tmp 目录时(就像我所做的那样),
我 运行 out disk space 介于两者之间。
Lambda 因错误退出,但并未读取 S3ObjectInputStream 中的所有字节。
因此,需要记住两件事:
1) 如果第一次执行导致问题,请吝啬你的 /tmp space。
我们只有 512 MB
2) 如果第二次执行导致问题,那么可以通过攻击根本问题来解决。
无法删除 /tmp 文件夹。
所以,执行完后把/tmp文件夹下的文件全部删除。
在java中,这是我所做的,成功解决了问题。
public String handleRequest(Map < String, String > keyValuePairs, Context lambdaContext) {
try {
// All work here
} catch (Exception e) {
logger.error("Error {}", e.toString());
return "Error";
} finally {
deleteAllFilesInTmpDir();
}
}
private void deleteAllFilesInTmpDir() {
Path path = java.nio.file.Paths.get(File.separator, "tmp", File.separator);
try {
if (Files.exists(path)) {
deleteDir(path.toFile());
logger.info("Successfully cleaned up the tmp directory");
}
} catch (Exception ex) {
logger.error("Unable to clean up the tmp directory");
}
}
public void deleteDir(File dir) {
File[] files = dir.listFiles();
if (files != null) {
for (final File file: files) {
deleteDir(file);
}
}
dir.delete();
}
我 运行 遇到了同样的问题,以下 class 帮助了我
@Data
@AllArgsConstructor
public class S3ObjectClosable implements Closeable {
private final S3Object s3Object;
@Override
public void close() throws IOException {
s3Object.getObjectContent().abort();
s3Object.close();
}
}
现在您可以在没有警告的情况下使用
try (final var s3ObjectClosable = new S3ObjectClosable(s3Client.getObject(bucket, key))) {
//same code
}
根据 Chirag Sejpal 的回答的选项 #1,我使用以下语句耗尽 S3AbortableInputStream 以确保可以重用连接:
com.amazonaws.util.IOUtils.drainInputStream(s3ObjectInputStream);
这是我的解决方案。我正在使用 spring 启动 2.4.3
创建一个 amazon s3 客户端
AmazonS3 amazonS3Client = AmazonS3ClientBuilder
.standard()
.withRegion("your-region")
.withCredentials(
new AWSStaticCredentialsProvider(
new BasicAWSCredentials("your-access-key", "your-secret-access-key")))
.build();
创建一个亚马逊转账客户端。
TransferManager transferManagerClient = TransferManagerBuilder.standard()
.withS3Client(amazonS3Client)
.build();
在/tmp/{your-s3-key}中创建一个临时文件,这样我们就可以把我们下载的文件放在这个文件。
File file = new File(System.getProperty("java.io.tmpdir"), "your-s3-key");
try {
file.createNewFile(); // Create temporary file
} catch (IOException e) {
e.printStackTrace();
}
file.mkdirs(); // Create the directory of the temporary file
然后,我们使用transfer manager client
从s3下载文件
// Note that in this line the s3 file downloaded has been transferred in to the temporary file that we created
Download download = transferManagerClient.download(
new GetObjectRequest("your-s3-bucket-name", "your-s3-key"), file);
// This line blocks the thread until the download is finished
download.waitForCompletion();
现在s3文件已经成功传输到我们创建的临时文件中。我们可以得到临时文件.
的InputStream
InputStream input = new DataInputStream(new FileInputStream(file));
因为临时文件不再需要了,我们直接删除。
file.delete();
这是我收到的警告:
S3AbortableInputStream:Not all bytes were read from the S3ObjectInputStream, aborting HTTP connection. This is likely an error and may result in sub-optimal behavior. Request only the bytes you need via a ranged GET or drain the input stream after use.
我尝试对资源使用 try,但 S3ObjectInputStream 似乎无法通过此方法关闭。
try (S3Object s3object = s3Client.getObject(new GetObjectRequest(bucket, key));
S3ObjectInputStream s3ObjectInputStream = s3object.getObjectContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(s3ObjectInputStream, StandardCharsets.UTF_8));
){
//some code here blah blah blah
}
我也试过下面的代码并明确关闭,但这也不起作用:
S3Object s3object = s3Client.getObject(new GetObjectRequest(bucket, key));
S3ObjectInputStream s3ObjectInputStream = s3object.getObjectContent();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(s3ObjectInputStream, StandardCharsets.UTF_8));
){
//some code here blah blah
s3ObjectInputStream.close();
s3object.close();
}
如有任何帮助,我们将不胜感激。
PS: 我只从 S3 读取文件的两行,文件有更多数据。
通过其他媒介得到答案。在这里分享:
该警告表明您在未读取整个文件的情况下调用了 close()。这是有问题的,因为 S3 仍在尝试发送数据,而您让连接处于不正常状态。
这里有两个选项:
- 从输入流中读取其余数据,以便重新使用连接。
- 调用s3ObjectInputStream.abort()关闭连接而不读取数据。该连接不会被重用,因此您在下一个重新创建连接的请求中会受到一些性能影响。如果需要很长时间才能阅读文件的其余部分,这可能是值得的。
要在 Chirag Sejpal 的回答中添加一个示例(详细说明选项 #1),可以使用以下方法在关闭输入流之前从输入流中读取其余数据:
S3Object s3object = s3Client.getObject(new GetObjectRequest(bucket, key));
try (S3ObjectInputStream s3ObjectInputStream = s3object.getObjectContent()) {
try {
// Read from stream as necessary
} catch (Exception e) {
// Handle exceptions as necessary
} finally {
while (s3ObjectInputStream != null && s3ObjectInputStream.read() != -1) {
// Read the rest of the stream
}
}
// The stream will be closed automatically by the try-with-resources statement
}
我运行进入同样的错误。
正如其他人所指出的,lambda 中的 /tmp space 限制为 512 MB。 如果 lambda 上下文被重新用于新的调用,那么 /tmp space 已经半满了。
因此,当读取 S3 对象并将所有文件写入 /tmp 目录时(就像我所做的那样), 我 运行 out disk space 介于两者之间。 Lambda 因错误退出,但并未读取 S3ObjectInputStream 中的所有字节。
因此,需要记住两件事:
1) 如果第一次执行导致问题,请吝啬你的 /tmp space。 我们只有 512 MB
2) 如果第二次执行导致问题,那么可以通过攻击根本问题来解决。 无法删除 /tmp 文件夹。 所以,执行完后把/tmp文件夹下的文件全部删除。
在java中,这是我所做的,成功解决了问题。
public String handleRequest(Map < String, String > keyValuePairs, Context lambdaContext) {
try {
// All work here
} catch (Exception e) {
logger.error("Error {}", e.toString());
return "Error";
} finally {
deleteAllFilesInTmpDir();
}
}
private void deleteAllFilesInTmpDir() {
Path path = java.nio.file.Paths.get(File.separator, "tmp", File.separator);
try {
if (Files.exists(path)) {
deleteDir(path.toFile());
logger.info("Successfully cleaned up the tmp directory");
}
} catch (Exception ex) {
logger.error("Unable to clean up the tmp directory");
}
}
public void deleteDir(File dir) {
File[] files = dir.listFiles();
if (files != null) {
for (final File file: files) {
deleteDir(file);
}
}
dir.delete();
}
我 运行 遇到了同样的问题,以下 class 帮助了我
@Data
@AllArgsConstructor
public class S3ObjectClosable implements Closeable {
private final S3Object s3Object;
@Override
public void close() throws IOException {
s3Object.getObjectContent().abort();
s3Object.close();
}
}
现在您可以在没有警告的情况下使用
try (final var s3ObjectClosable = new S3ObjectClosable(s3Client.getObject(bucket, key))) {
//same code
}
根据 Chirag Sejpal 的回答的选项 #1,我使用以下语句耗尽 S3AbortableInputStream 以确保可以重用连接:
com.amazonaws.util.IOUtils.drainInputStream(s3ObjectInputStream);
这是我的解决方案。我正在使用 spring 启动 2.4.3
创建一个 amazon s3 客户端
AmazonS3 amazonS3Client = AmazonS3ClientBuilder
.standard()
.withRegion("your-region")
.withCredentials(
new AWSStaticCredentialsProvider(
new BasicAWSCredentials("your-access-key", "your-secret-access-key")))
.build();
创建一个亚马逊转账客户端。
TransferManager transferManagerClient = TransferManagerBuilder.standard()
.withS3Client(amazonS3Client)
.build();
在/tmp/{your-s3-key}中创建一个临时文件,这样我们就可以把我们下载的文件放在这个文件。
File file = new File(System.getProperty("java.io.tmpdir"), "your-s3-key");
try {
file.createNewFile(); // Create temporary file
} catch (IOException e) {
e.printStackTrace();
}
file.mkdirs(); // Create the directory of the temporary file
然后,我们使用transfer manager client
从s3下载文件// Note that in this line the s3 file downloaded has been transferred in to the temporary file that we created
Download download = transferManagerClient.download(
new GetObjectRequest("your-s3-bucket-name", "your-s3-key"), file);
// This line blocks the thread until the download is finished
download.waitForCompletion();
现在s3文件已经成功传输到我们创建的临时文件中。我们可以得到临时文件.
的InputStreamInputStream input = new DataInputStream(new FileInputStream(file));
因为临时文件不再需要了,我们直接删除。
file.delete();