Skip to content

Commit 27e5d26

Browse files
committed
HADOOP-16792: Make S3 client request timeout configurable
1 parent f206b73 commit 27e5d26

6 files changed

Lines changed: 100 additions & 0 deletions

File tree

hadoop-common-project/hadoop-common/src/main/resources/core-default.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,6 +1919,23 @@
19191919
</description>
19201920
</property>
19211921

1922+
<property>
1923+
<name>fs.s3a.connection.request.timeout</name>
1924+
<value>0</value>
1925+
<description>
1926+
Time out on HTTP requests to the AWS service; 0 means no timeout.
1927+
Measured in seconds; the usual time suffixes are all supported
1928+
1929+
Important: this is the maximum duration of any AWS service call,
1930+
including upload and copy operations. If non-zero, it must be larger
1931+
than the time to upload multi-megabyte blocks to S3 from the client,
1932+
and to rename many-GB files. Use with care.
1933+
1934+
Values that are larger than Integer.MAX_VALUE milliseconds are
1935+
converged to Integer.MAX_VALUE milliseconds
1936+
</description>
1937+
</property>
1938+
19221939
<property>
19231940
<name>fs.s3a.etag.checksum.enabled</name>
19241941
<value>false</value>

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/Constants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ private Constants() {
187187
public static final String SOCKET_TIMEOUT = "fs.s3a.connection.timeout";
188188
public static final int DEFAULT_SOCKET_TIMEOUT = 200000;
189189

190+
// milliseconds until a request is timed-out
191+
public static final String REQUEST_TIMEOUT =
192+
"fs.s3a.connection.request.timeout";
193+
public static final int DEFAULT_REQUEST_TIMEOUT = 0;
194+
190195
// socket send buffer to be used in Amazon client
191196
public static final String SOCKET_SEND_BUFFER = "fs.s3a.socket.send.buffer";
192197
public static final int DEFAULT_SOCKET_SEND_BUFFER = 8 * 1024;

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AUtils.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import java.util.Optional;
8383
import java.util.Set;
8484
import java.util.concurrent.ExecutionException;
85+
import java.util.concurrent.TimeUnit;
8586

8687
import static org.apache.commons.lang3.StringUtils.isEmpty;
8788
import static org.apache.hadoop.fs.s3a.Constants.*;
@@ -1284,6 +1285,15 @@ public static void initConnectionSettings(Configuration conf,
12841285
DEFAULT_SOCKET_SEND_BUFFER, 2048);
12851286
int sockRecvBuffer = intOption(conf, SOCKET_RECV_BUFFER,
12861287
DEFAULT_SOCKET_RECV_BUFFER, 2048);
1288+
long requestTimeoutMillis = conf.getTimeDuration(REQUEST_TIMEOUT,
1289+
DEFAULT_REQUEST_TIMEOUT, TimeUnit.SECONDS, TimeUnit.MILLISECONDS);
1290+
1291+
if (requestTimeoutMillis > Integer.MAX_VALUE) {
1292+
LOG.debug("Request timeout is too high({} ms). Setting to {} ms instead",
1293+
requestTimeoutMillis, Integer.MAX_VALUE);
1294+
requestTimeoutMillis = Integer.MAX_VALUE;
1295+
}
1296+
awsConf.setRequestTimeout((int) requestTimeoutMillis);
12871297
awsConf.setSocketBufferSizeHints(sockSendBuffer, sockRecvBuffer);
12881298
String signerOverride = conf.getTrimmed(SIGNING_ALGORITHM, "");
12891299
if (!signerOverride.isEmpty()) {

hadoop-tools/hadoop-aws/src/site/markdown/tools/hadoop-aws/index.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,23 @@ options are covered in [Testing](./testing.md).
983983
<description>Select which version of the S3 SDK's List Objects API to use.
984984
Currently support 2 (default) and 1 (older API).</description>
985985
</property>
986+
987+
<property>
988+
<name>fs.s3a.connection.request.timeout</name>
989+
<value>0</value>
990+
<description>
991+
Time out on HTTP requests to the AWS service; 0 means no timeout.
992+
Measured in seconds; the usual time suffixes are all supported
993+
994+
Important: this is the maximum duration of any AWS service call,
995+
including upload and copy operations. If non-zero, it must be larger
996+
than the time to upload multi-megabyte blocks to S3 from the client,
997+
and to rename many-GB files. Use with care.
998+
999+
Values that are larger than Integer.MAX_VALUE milliseconds are
1000+
converged to Integer.MAX_VALUE milliseconds
1001+
</description>
1002+
</property>
9861003
```
9871004

9881005
## <a name="retry_and_recovery"></a>Retry and Recovery

hadoop-tools/hadoop-aws/src/site/markdown/tools/hadoop-aws/troubleshooting_s3a.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,3 +1384,41 @@ For this reason, the number of retry events are limited.
13841384
</description>
13851385
</property>
13861386
```
1387+
1388+
### <a name="aws-timeouts"></a> Tuning AWS request timeouts
1389+
1390+
It is possible to configure a global timeout for AWS service calls using following property:
1391+
1392+
```xml
1393+
<property>
1394+
<name>fs.s3a.connection.request.timeout</name>
1395+
<value>0</value>
1396+
<description>
1397+
Time out on HTTP requests to the AWS service; 0 means no timeout.
1398+
Measured in seconds; the usual time suffixes are all supported
1399+
1400+
Important: this is the maximum duration of any AWS service call,
1401+
including upload and copy operations. If non-zero, it must be larger
1402+
than the time to upload multi-megabyte blocks to S3 from the client,
1403+
and to rename many-GB files. Use with care.
1404+
1405+
Values that are larger than Integer.MAX_VALUE milliseconds are
1406+
converged to Integer.MAX_VALUE milliseconds
1407+
</description>
1408+
</property>
1409+
```
1410+
1411+
If this value is configured too low, user may encounter `SdkClientException`s due to many requests
1412+
timing-out.
1413+
1414+
```
1415+
com.amazonaws.SdkClientException: Unable to execute HTTP request: Request did not complete before the request timeout configuration.: Unable to execute HTTP request: Request did not complete before the request timeout configuration.
1416+
at org.apache.hadoop.fs.s3a.S3AUtils.translateException(S3AUtils.java:205)
1417+
at org.apache.hadoop.fs.s3a.Invoker.once(Invoker.java:112)
1418+
at org.apache.hadoop.fs.s3a.Invoker.lambda$retry$4(Invoker.java:315)
1419+
at org.apache.hadoop.fs.s3a.Invoker.retryUntranslated(Invoker.java:407)
1420+
at org.apache.hadoop.fs.s3a.Invoker.retry(Invoker.java:311)
1421+
```
1422+
1423+
When this happens, try to set `fs.s3a.connection.request.timeout` to a larger value or disable it
1424+
completely by setting it to `0`.

hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/ITestS3AConfiguration.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,19 @@ public void testCustomUserAgent() throws Exception {
390390
awsConf.getUserAgentPrefix());
391391
}
392392

393+
@Test
394+
public void testRequestTimeout() throws Exception {
395+
conf = new Configuration();
396+
conf.set(REQUEST_TIMEOUT, "120");
397+
fs = S3ATestUtils.createTestFileSystem(conf);
398+
AmazonS3 s3 = fs.getAmazonS3ClientForTesting("Request timeout (ms)");
399+
ClientConfiguration awsConf = getField(s3, ClientConfiguration.class,
400+
"clientConfiguration");
401+
assertEquals("Configured " + REQUEST_TIMEOUT +
402+
" is different than what AWS sdk configuration uses internally",
403+
120000, awsConf.getRequestTimeout());
404+
}
405+
393406
@Test
394407
public void testCloseIdempotent() throws Throwable {
395408
conf = new Configuration();

0 commit comments

Comments
 (0)