Skip to content

Commit 8726690

Browse files
authored
HADOOP-19729. [ABFS][Perf] Network Profiling for Tailing Requests and Killing Bad Connections Proactively (#8043)
Contributed by Anuj Modi
1 parent 7696764 commit 8726690

24 files changed

+1453
-7
lines changed

hadoop-tools/hadoop-azure/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@
199199
<scope>compile</scope>
200200
</dependency>
201201

202+
<dependency>
203+
<groupId>org.hdrhistogram</groupId>
204+
<artifactId>HdrHistogram</artifactId>
205+
<version>2.1.12</version>
206+
<scope>compile</scope>
207+
</dependency>
208+
202209
<!--com.fasterxml.jackson is used by WASB, not ABFS-->
203210
<!--transitive dependency from Azure SDK-->
204211
<dependency>

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AbfsConfiguration.java

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,43 @@ public class AbfsConfiguration{
601601
DefaultValue = DEFAULT_FS_AZURE_ENABLE_CREATE_BLOB_IDEMPOTENCY)
602602
private boolean enableCreateIdempotency;
603603

604+
@BooleanConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_ENABLE_TAIL_LATENCY_TRACKER,
605+
DefaultValue = DEFAULT_FS_AZURE_ENABLE_TAIL_LATENCY_TRACKER)
606+
private boolean isTailLatencyTrackerEnabled;
607+
608+
@BooleanConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_ENABLE_TAIL_LATENCY_REQUEST_TIMEOUT,
609+
DefaultValue = DEFAULT_FS_AZURE_ENABLE_TAIL_LATENCY_REQUEST_TIMEOUT)
610+
private boolean isTailLatencyRequestTimeoutEnabled;
611+
612+
@IntegerConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_TAIL_LATENCY_PERCENTILE,
613+
DefaultValue = DEFAULT_FS_AZURE_TAIL_LATENCY_PERCENTILE)
614+
private int tailLatencyPercentile;
615+
616+
@IntegerConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_TAIL_LATENCY_MIN_DEVIATION,
617+
DefaultValue = DEFAULT_FS_AZURE_TAIL_LATENCY_MIN_DEVIATION)
618+
private int tailLatencyMinDeviation;
619+
620+
@IntegerConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_TAIL_LATENCY_MIN_SAMPLE_SIZE,
621+
DefaultValue = DEFAULT_FS_AZURE_TAIL_LATENCY_MIN_SAMPLE_SIZE)
622+
private int tailLatencyMinSampleSize;
623+
624+
@IntegerConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_MILLIS,
625+
DefaultValue = DEFAULT_FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_MILLIS)
626+
private int tailLatencyAnalysisWindowInMillis;
627+
628+
@IntegerConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_GRANULARITY,
629+
DefaultValue = DEFAULT_FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_GRANULARITY,
630+
MinValue = MIN_FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_GRANULARITY)
631+
private int tailLatencyAnalysisWindowGranularity;
632+
633+
@IntegerConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_TAIL_LATENCY_PERCENTILE_COMPUTATION_INTERVAL_MILLIS,
634+
DefaultValue = DEFAULT_FS_AZURE_TAIL_LATENCY_PERCENTILE_COMPUTATION_INTERVAL_MILLIS)
635+
private int tailLatencyPercentileComputationIntervalInMillis;
636+
637+
@IntegerConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_TAIL_LATENCY_MAX_RETRY_COUNT,
638+
DefaultValue = DEFAULT_FS_AZURE_TAIL_LATENCY_MAX_RETRY_COUNT)
639+
private int tailLatencyMaxRetryCount;
640+
604641
private String clientProvidedEncryptionKey;
605642
private String clientProvidedEncryptionKeySHA;
606643

@@ -1970,4 +2007,80 @@ public int getBlobRenameDirConsumptionParallelism() {
19702007
public int getBlobDeleteDirConsumptionParallelism() {
19712008
return blobDeleteDirConsumptionParallelism;
19722009
}
2010+
2011+
/**
2012+
* Checks if the tail latency tracker is enabled.
2013+
* @return true if enabled, false otherwise.
2014+
*/
2015+
public boolean isTailLatencyTrackerEnabled() {
2016+
return isTailLatencyTrackerEnabled;
2017+
}
2018+
2019+
/**
2020+
* Checks if the tail latency request timeout feature is enabled.
2021+
* @return true if enabled, false otherwise.
2022+
*/
2023+
public boolean isTailLatencyRequestTimeoutEnabled() {
2024+
return isTailLatencyTrackerEnabled && isTailLatencyRequestTimeoutEnabled
2025+
&& getPreferredHttpOperationType().equals(HttpOperationType.APACHE_HTTP_CLIENT);
2026+
}
2027+
2028+
/**
2029+
* Gets the tail latency percentile to be tracked.
2030+
* @return the tail latency percentile.
2031+
*/
2032+
public int getTailLatencyPercentile() {
2033+
return tailLatencyPercentile;
2034+
}
2035+
2036+
/**
2037+
* Gets the minimum deviation for tail latency tracking.
2038+
* @return the minimum deviation.
2039+
*/
2040+
public int getTailLatencyMinDeviation() {
2041+
return tailLatencyMinDeviation;
2042+
}
2043+
2044+
/**
2045+
* Gets the minimum sample size for tail latency reporting.
2046+
* @return the minimum sample size.
2047+
*/
2048+
public int getTailLatencyMinSampleSize() {
2049+
return tailLatencyMinSampleSize;
2050+
}
2051+
2052+
/**
2053+
* Gets the tail latency analysis window in milliseconds.
2054+
* @return the analysis window in milliseconds.
2055+
*/
2056+
public int getTailLatencyAnalysisWindowInMillis() {
2057+
return tailLatencyAnalysisWindowInMillis;
2058+
}
2059+
2060+
/**
2061+
* Gets the interval for tail latency percentile computation in milliseconds.
2062+
* @return the computation interval in milliseconds.
2063+
*/
2064+
public int getTailLatencyComputationIntervalInMillis() {
2065+
return tailLatencyPercentileComputationIntervalInMillis;
2066+
}
2067+
2068+
/**
2069+
* Gets the granularity of the tail latency analysis window.
2070+
* @return the analysis window granularity.
2071+
*/
2072+
public int getTailLatencyAnalysisWindowGranularity() {
2073+
if (tailLatencyAnalysisWindowGranularity <= 0) {
2074+
return MIN_FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_GRANULARITY;
2075+
}
2076+
return tailLatencyAnalysisWindowGranularity;
2077+
}
2078+
2079+
/**
2080+
* Gets the maximum retry count for tail latency requests.
2081+
* @return the maximum retry count.
2082+
*/
2083+
public int getTailLatencyMaxRetryCount() {
2084+
return tailLatencyMaxRetryCount;
2085+
}
19732086
}

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AzureBlobFileSystemStore.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
import org.apache.hadoop.fs.azurebfs.services.ListingSupport;
114114
import org.apache.hadoop.fs.azurebfs.services.SharedKeyCredentials;
115115
import org.apache.hadoop.fs.azurebfs.services.StaticRetryPolicy;
116+
import org.apache.hadoop.fs.azurebfs.services.TailLatencyRequestTimeoutRetryPolicy;
116117
import org.apache.hadoop.fs.azurebfs.services.VersionedFileStatus;
117118
import org.apache.hadoop.fs.azurebfs.utils.Base64;
118119
import org.apache.hadoop.fs.azurebfs.utils.CRC64;
@@ -1817,6 +1818,8 @@ private AbfsClientContext populateAbfsClientContext() {
18171818
new ExponentialRetryPolicy(abfsConfiguration))
18181819
.withStaticRetryPolicy(
18191820
new StaticRetryPolicy(abfsConfiguration))
1821+
.withTailLatencyRequestTimeoutRetryPolicy(
1822+
new TailLatencyRequestTimeoutRetryPolicy(abfsConfiguration))
18201823
.withAbfsCounters(abfsCounters)
18211824
.withAbfsPerfTracker(abfsPerfTracker)
18221825
.build();

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/ConfigurationKeys.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,5 +530,60 @@ public static String containerProperty(String property, String fsName, String ac
530530
/**Flag to enable/disable create idempotency during create operation: {@value}*/
531531
public static final String FS_AZURE_ENABLE_CREATE_BLOB_IDEMPOTENCY = "fs.azure.enable.create.blob.idempotency";
532532

533+
/**
534+
* Flag to enable/disable tail latency tracker for AbfsRestOperation.
535+
* When enabled, Client observed E2E latency will be tracked by a histogram.
536+
* Regular p50, p99 and configured percentile latencies will be reported.
537+
*/
538+
public static final String FS_AZURE_ENABLE_TAIL_LATENCY_TRACKER = "fs.azure.enable.tail.latency.tracker";
539+
540+
/**
541+
* Flag to enable/disable tail latency based timeout for AbfsRestOperation.
542+
* When enabled, if an operation's latency exceeds the currently reported tail
543+
* latency by the tracker, the ongoing socket connection will be closed and
544+
* the operation will be retried, up to the configured max retry count: {@value}
545+
*/
546+
public static final String FS_AZURE_ENABLE_TAIL_LATENCY_REQUEST_TIMEOUT = "fs.azure.enable.tail.latency.timeout";
547+
548+
/**
549+
* The percentile value to be considered as tail latency value.
550+
* Default is 99.0 (99th percentile): {@value}
551+
*/
552+
public static final String FS_AZURE_TAIL_LATENCY_PERCENTILE = "fs.azure.tail.latency.percentile";
553+
554+
/**
555+
* The minimum deviation (in percentage) between p50 and tail latency
556+
* percentile to trigger tail latency based request timeout: {@value}
557+
*/
558+
public static final String FS_AZURE_TAIL_LATENCY_MIN_DEVIATION = "fs.azure.tail.latency.min.deviation";
559+
560+
/**
561+
* The minimum sample size required before the histogram starts reporting latency data: {@value}
562+
*/
563+
public static final String FS_AZURE_TAIL_LATENCY_MIN_SAMPLE_SIZE = "fs.azure.tail.latency.min.sample.size";
564+
565+
/**
566+
* The time window (in milliseconds) over which the tail latency analysis is performed.
567+
* Until the whole window is filled, the histogram will not report any latency data: {@value}
568+
*/
569+
public static final String FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_MILLIS = "fs.azure.tail.latency.analysis.window.millis";
570+
571+
/**
572+
* The granularity (in milliseconds) at which the tail latency analysis window is divided.
573+
* This is to make sliding window calculations efficient and robust: {@value}
574+
*/
575+
public static final String FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_GRANULARITY = "fs.azure.tail.latency.analysis.window.granularity";
576+
577+
/**
578+
* Interval (in milliseconds) at which the tail latency percentile is computed
579+
* and updated by the background thread for each operation type: {@value}
580+
*/
581+
public static final String FS_AZURE_TAIL_LATENCY_PERCENTILE_COMPUTATION_INTERVAL_MILLIS = "fs.azure.tail.latency.percentile.computation.interval.millis";
582+
583+
/**
584+
* Maximum number of retries for an operation when tail latency based timeout occur: {@value}
585+
*/
586+
public static final String FS_AZURE_TAIL_LATENCY_MAX_RETRY_COUNT = "fs.azure.tail.latency.max.retry.count";
587+
533588
private ConfigurationKeys() {}
534589
}

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/constants/FileSystemConfigurations.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ public final class FileSystemConfigurations {
241241
public static final int RATE_LIMIT_DEFAULT = 1_000;
242242

243243
public static final int ZERO = 0;
244+
public static final double ZERO_D = 0.0;
244245
public static final int HUNDRED = 100;
245246
public static final double HUNDRED_D = 100.0;
246247
public static final long THOUSAND = 1000L;
@@ -392,5 +393,16 @@ public final class FileSystemConfigurations {
392393

393394
public static final boolean DEFAULT_FS_AZURE_ENABLE_CREATE_BLOB_IDEMPOTENCY = true;
394395

396+
public static final boolean DEFAULT_FS_AZURE_ENABLE_TAIL_LATENCY_TRACKER = false;
397+
public static final boolean DEFAULT_FS_AZURE_ENABLE_TAIL_LATENCY_REQUEST_TIMEOUT = false;
398+
public static final int DEFAULT_FS_AZURE_TAIL_LATENCY_PERCENTILE = 99;
399+
public static final int DEFAULT_FS_AZURE_TAIL_LATENCY_MIN_DEVIATION = 200;
400+
public static final int DEFAULT_FS_AZURE_TAIL_LATENCY_MIN_SAMPLE_SIZE = 100;
401+
public static final int DEFAULT_FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_MILLIS = 60_000;
402+
public static final int DEFAULT_FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_GRANULARITY = 10;
403+
public static final int MIN_FS_AZURE_TAIL_LATENCY_ANALYSIS_WINDOW_GRANULARITY = 1;
404+
public static final int DEFAULT_FS_AZURE_TAIL_LATENCY_PERCENTILE_COMPUTATION_INTERVAL_MILLIS = 500;
405+
public static final int DEFAULT_FS_AZURE_TAIL_LATENCY_MAX_RETRY_COUNT = 1;
406+
395407
private FileSystemConfigurations() {}
396408
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.fs.azurebfs.contracts.exceptions;
20+
21+
import java.util.concurrent.TimeoutException;
22+
import static org.apache.hadoop.fs.azurebfs.services.AbfsErrors.ERR_TAIL_LATENCY_REQUEST_TIMEOUT;
23+
24+
/**
25+
* Thrown when a request takes more time than the current reported tail latency.
26+
*/
27+
public class TailLatencyRequestTimeoutException extends AzureBlobFileSystemException {
28+
29+
/**
30+
* Constructs a TailLatencyRequestTimeoutException with TimeoutException as the cause.
31+
* @param innerException the TimeoutException that caused this exception
32+
*/
33+
public TailLatencyRequestTimeoutException(TimeoutException innerException) {
34+
super(ERR_TAIL_LATENCY_REQUEST_TIMEOUT, innerException);
35+
}
36+
37+
/**
38+
* Constructs a TailLatencyRequestTimeoutException without a cause.
39+
*/
40+
public TailLatencyRequestTimeoutException() {
41+
super(ERR_TAIL_LATENCY_REQUEST_TIMEOUT);
42+
}
43+
}

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsAHCHttpOperation.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,19 @@ public class AbfsAHCHttpOperation extends AbfsHttpOperation {
9191
*/
9292
private final AbfsApacheHttpClient abfsApacheHttpClient;
9393

94+
/**
95+
* Timeout in milliseconds that defines maximum allowed time to execute operation.
96+
* This timeout starts when execution starts and includes E2E processing time of request.
97+
* This is based on tail latency observed in the system.
98+
*/
99+
private final long tailLatencyTimeout;
100+
94101
public AbfsAHCHttpOperation(final URL url,
95102
final String method,
96103
final List<AbfsHttpHeader> requestHeaders,
97104
final Duration connectionTimeout,
98105
final Duration readTimeout,
106+
final long tailLatencyTimeout,
99107
final AbfsApacheHttpClient abfsApacheHttpClient,
100108
final AbfsClient abfsClient) throws IOException {
101109
super(LOG, url, method, requestHeaders, connectionTimeout, readTimeout,
@@ -104,6 +112,7 @@ public AbfsAHCHttpOperation(final URL url,
104112
|| HTTP_METHOD_PATCH.equals(method)
105113
|| HTTP_METHOD_POST.equals(method);
106114
this.abfsApacheHttpClient = abfsApacheHttpClient;
115+
this.tailLatencyTimeout = tailLatencyTimeout;
107116
LOG.debug("Creating AbfsAHCHttpOperation for URL: {}, method: {}",
108117
url, method);
109118

@@ -159,6 +168,10 @@ AbfsManagedHttpClientContext getHttpClientContext() {
159168
return new AbfsManagedHttpClientContext();
160169
}
161170

171+
long getTailLatencyTimeout() {
172+
return tailLatencyTimeout;
173+
}
174+
162175
/**{@inheritDoc}*/
163176
@Override
164177
protected InputStream getErrorStream() throws IOException {
@@ -273,7 +286,7 @@ HttpResponse executeRequest() throws IOException {
273286
try {
274287
LOG.debug("Executing request: {}", httpRequestBase);
275288
HttpResponse response = abfsApacheHttpClient.execute(httpRequestBase,
276-
abfsHttpClientContext, getConnectionTimeout(), getReadTimeout());
289+
abfsHttpClientContext, getConnectionTimeout(), getReadTimeout(), getTailLatencyTimeout());
277290
setConnectionTimeMs(abfsHttpClientContext.getConnectTime());
278291
setSendRequestTimeMs(abfsHttpClientContext.getSendTime());
279292
setRecvResponseTimeMs(abfsHttpClientContext.getReadTime());

0 commit comments

Comments
 (0)