Chr*_*ein 6 java amazon-s3 spring-boot aws-sdk
我们有一个 Spring Boot 应用程序,可将多媒体文件(最大 100 MB)存储在 S3 兼容的云存储中。应用程序通过 REST 调用或 AMQP 消息代理 (RabbitMQ) 接收这些文件。
通常系统的负载是中等的,所以根本不会有问题。然而,当系统负载较重时,我们会遇到访问 S3 的问题。目前,我们正在通过使用随机分配给调用进程的 10 个 AmazonS3Client 池来解决此问题。这实际上改善了问题,但并没有解决问题。当负载太高(意味着大量的写入和读取操作)时,我们会遇到此类异常:
com.amazonaws.AmazonClientException:无法执行 HTTP 请求:连接超时
在 com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:299)
在 com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:170)
在 com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:2648)
在 com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1049)
在 com.amazonaws.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:924)
我们使用的是 1.3.8 版本的 aws-java-sdk,由于较新版本中的区域设置,无法轻松更新到较新版本。签名算法阻止我们在最新版本中正确访问我们的存储桶。
实现如下:
初始化(在构造函数级别):
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setConnectionTimeout(AWS_CONNECTION_TIMEOUT);
clientConfiguration.setMaxConnections(AWS_MAX_CONNECTIONS);
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
for (int i = 0; i < AWS_MAX_CLIENTS; i++) {
s3[i] = new AmazonS3Client(credentials, clientConfiguration);
s3[i].setEndpoint(endpoint);
}
Run Code Online (Sandbox Code Playgroud)
放:
int i = getRandomClient();
s3[i].putObject(bucketName, key, file);
Run Code Online (Sandbox Code Playgroud)
得到:
ReadableByteChannel channel;
try {
int i = getRandomClient();
S3Object object = s3[i].getObject(bucketName, addPrefix(fileId, prefix));
S3ObjectInputStream stream = object.getObjectContent();
channel = Channels.newChannel(stream);
File file = File.createTempFile(fileId, "");
try (WritableByteChannel outChannel = Channels.newChannel(new FileOutputStream(file))) {
ByteBuffer buffer = ByteBuffer.allocate(8192);
int read;
while ((read = channel.read(buffer)) > 0) {
buffer.rewind();
buffer.limit(read);
while (read > 0) {
read -= outChannel.write(buffer);
}
buffer.clear();
}
IOUtils.closeQuietly(stream);
return file;
}
}
catch (AmazonClientException e) {
if (!isMissingKey(e)) {
throw new IOException(e);
}
}
finally {
if (channel != null) {
channel.close();
}
}
Run Code Online (Sandbox Code Playgroud)
很明显,有限的连接和客户端数量是瓶颈。我们可以通过多种方法调整实现以使其正常工作。我们当然可以限制监听消息代理的消费者数量。我们还可以增加AWS客户端的超时、数量和连接,或者限制服务层的吞吐量。然而,我们正在寻找一种更复杂的方法来处理这里的事情。
有什么办法可以判断指定的客户端当前是否可以使用或者打开的连接过多?有什么办法可以让客户端等待下一个空闲连接吗?
增加客户端数量与增加单个客户端的连接池大小没有什么不同,只不过现在您必须担心使用getRandomClient(). 此外,创建多个客户端和维护不必要数量的连接池会产生巨大的开销。你正试图重新发明轮子。
您可以做的一件事是捕获超时期间引发的异常,如下所示:
try {
... do s3 read/write ...
} catch (AmazonClientException ace) {
if (ace.getCause() instanceof org.apache.http.conn.ConnectionPoolTimeoutException) {
log.error("S3 connection pool timeout!");
}
}
Run Code Online (Sandbox Code Playgroud)
使用它来帮助调整连接池大小。基本上只是继续扩大规模,直到这不再是你的瓶颈。
| 归档时间: |
|
| 查看次数: |
10437 次 |
| 最近记录: |