-
Notifications
You must be signed in to change notification settings - Fork 9.2k
HADOOP-18457. ABFS: Support for account level throttling #5034
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
steveloughran
merged 38 commits into
apache:trunk
from
anmolanmol1234:HADOOP-18457_temp
Nov 30, 2022
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
0de876e
Enable throttling at account level
anmolasrani123 7faec72
Resolving PR comments
anmolasrani123 09602b0
Unused import remove
anmolasrani123 4412a54
Merge branch 'apache:trunk' into HADOOP-18457
anmolanmol1234 934f00f
Fix for null pointer exception
anmolasrani123 5cd2a2b
Fixed naming for intercept
anmolasrani123 487f65b
Addressing PR
anmolasrani123 35a82da
Merge branch 'apache:trunk' into HADOOP-18457
anmolanmol1234 e3c5de4
Changes
anmolasrani123 008e447
Changes for timer
anmolasrani123 31368bf
Changes for account idle
anmolasrani123 ae244eb
Enable account level throttling
anmolasrani123 dde4604
Adding tests
anmolasrani123 2445dc9
adding tests
anmolasrani123 09019f2
Changes for throttling with idle time as config
anmolasrani123 939a6b9
Fixed imports
anmolasrani123 a124975
Merge branch 'apache:trunk' into HADOOP-18457_temp
anmolanmol1234 62f0427
Adding back files
anmolasrani123 cbd96e3
Adding back files
anmolasrani123 a9b6d6d
Adding back files
anmolasrani123 47d306d
Individual operation timeout
anmolasrani123 bdf2686
Changes for operation level idle timeout
anmolasrani123 996a212
Checkstyle fixes
anmolasrani123 6121a6d
Interface for throttling
anmolasrani123 6a6e288
Test added for interface for intercept
anmolasrani123 7db57ac
Double checking fix
anmolasrani123 448b236
addressed PR comments
anmolasrani123 6a39779
Fix try finally
anmolasrani123 bfbc3c0
Fix for synchronization
anmolasrani123 98d3110
Added enum for timer functionality
anmolasrani123 499db63
Merge branch 'apache:trunk' into HADOOP-18457_temp
anmolanmol1234 29fe5b1
Merge branch 'HADOOP-18457_temp' of https://github.com/anmolanmol1234…
anmolasrani123 c552e0b
Fix for lost reference
anmolasrani123 a4764d6
Fix for mock client
anmolasrani123 ece0552
Addressing PR comments
anmolasrani123 b3546d3
Made the class final
anmolasrani123 d4a5a93
Merge branch 'apache:trunk' into HADOOP-18457_temp
anmolanmol1234 f819e15
Merge branch 'apache:trunk' into HADOOP-18457_temp
anmolanmol1234 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,20 +20,23 @@ | |
|
|
||
| import java.util.Timer; | ||
| import java.util.TimerTask; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
| import java.util.concurrent.atomic.AtomicLong; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
|
|
||
| import org.apache.hadoop.classification.VisibleForTesting; | ||
| import org.apache.hadoop.fs.azurebfs.AbfsConfiguration; | ||
| import org.apache.hadoop.util.Preconditions; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import static org.apache.hadoop.util.Time.now; | ||
|
|
||
| class AbfsClientThrottlingAnalyzer { | ||
| private static final Logger LOG = LoggerFactory.getLogger( | ||
| AbfsClientThrottlingAnalyzer.class); | ||
| private static final int DEFAULT_ANALYSIS_PERIOD_MS = 10 * 1000; | ||
| private static final int MIN_ANALYSIS_PERIOD_MS = 1000; | ||
| private static final int MAX_ANALYSIS_PERIOD_MS = 30000; | ||
| private static final double MIN_ACCEPTABLE_ERROR_PERCENTAGE = .1; | ||
|
|
@@ -50,42 +53,38 @@ class AbfsClientThrottlingAnalyzer { | |
| private String name = null; | ||
| private Timer timer = null; | ||
| private AtomicReference<AbfsOperationMetrics> blobMetrics = null; | ||
| private AtomicLong lastExecutionTime = null; | ||
| private final AtomicBoolean isOperationOnAccountIdle = new AtomicBoolean(false); | ||
| private AbfsConfiguration abfsConfiguration = null; | ||
| private boolean accountLevelThrottlingEnabled = true; | ||
|
|
||
| private AbfsClientThrottlingAnalyzer() { | ||
| // hide default constructor | ||
| } | ||
|
|
||
| /** | ||
| * Creates an instance of the <code>AbfsClientThrottlingAnalyzer</code> class with | ||
| * the specified name. | ||
| * | ||
| * @param name a name used to identify this instance. | ||
| * @throws IllegalArgumentException if name is null or empty. | ||
| */ | ||
| AbfsClientThrottlingAnalyzer(String name) throws IllegalArgumentException { | ||
| this(name, DEFAULT_ANALYSIS_PERIOD_MS); | ||
| } | ||
|
|
||
| /** | ||
| * Creates an instance of the <code>AbfsClientThrottlingAnalyzer</code> class with | ||
| * the specified name and period. | ||
| * | ||
| * @param name A name used to identify this instance. | ||
| * @param period The frequency, in milliseconds, at which metrics are | ||
| * analyzed. | ||
| * @param abfsConfiguration The configuration set. | ||
| * @throws IllegalArgumentException If name is null or empty. | ||
| * If period is less than 1000 or greater than 30000 milliseconds. | ||
| */ | ||
| AbfsClientThrottlingAnalyzer(String name, int period) | ||
| AbfsClientThrottlingAnalyzer(String name, AbfsConfiguration abfsConfiguration) | ||
| throws IllegalArgumentException { | ||
| Preconditions.checkArgument( | ||
| StringUtils.isNotEmpty(name), | ||
| "The argument 'name' cannot be null or empty."); | ||
| int period = abfsConfiguration.getAnalysisPeriod(); | ||
| Preconditions.checkArgument( | ||
| period >= MIN_ANALYSIS_PERIOD_MS && period <= MAX_ANALYSIS_PERIOD_MS, | ||
| "The argument 'period' must be between 1000 and 30000."); | ||
| this.name = name; | ||
| this.analysisPeriodMs = period; | ||
| this.abfsConfiguration = abfsConfiguration; | ||
| this.accountLevelThrottlingEnabled = abfsConfiguration.accountThrottlingEnabled(); | ||
| this.analysisPeriodMs = abfsConfiguration.getAnalysisPeriod(); | ||
| this.lastExecutionTime = new AtomicLong(now()); | ||
| this.blobMetrics = new AtomicReference<AbfsOperationMetrics>( | ||
| new AbfsOperationMetrics(System.currentTimeMillis())); | ||
| this.timer = new Timer( | ||
|
|
@@ -95,6 +94,47 @@ private AbfsClientThrottlingAnalyzer() { | |
| analysisPeriodMs); | ||
| } | ||
|
|
||
| /** | ||
| * Resumes the timer if it was stopped. | ||
| */ | ||
| private void resumeTimer() { | ||
| blobMetrics = new AtomicReference<AbfsOperationMetrics>( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: use |
||
| new AbfsOperationMetrics(System.currentTimeMillis())); | ||
| timer.schedule(new TimerTaskImpl(), | ||
| analysisPeriodMs, | ||
| analysisPeriodMs); | ||
| isOperationOnAccountIdle.set(false); | ||
| } | ||
|
|
||
| /** | ||
| * Synchronized method to suspend or resume timer. | ||
| * @param timerFunctionality resume or suspend. | ||
| * @param timerTask The timertask object. | ||
| * @return true or false. | ||
| */ | ||
| private synchronized boolean timerOrchestrator(TimerFunctionality timerFunctionality, | ||
| TimerTask timerTask) { | ||
| switch (timerFunctionality) { | ||
| case RESUME: | ||
| if (isOperationOnAccountIdle.get()) { | ||
| resumeTimer(); | ||
| } | ||
| break; | ||
| case SUSPEND: | ||
| if (accountLevelThrottlingEnabled && (System.currentTimeMillis() | ||
| - lastExecutionTime.get() >= getOperationIdleTimeout())) { | ||
| isOperationOnAccountIdle.set(true); | ||
| timerTask.cancel(); | ||
| timer.purge(); | ||
| return true; | ||
| } | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Updates metrics with results from the current storage operation. | ||
| * | ||
|
|
@@ -104,19 +144,22 @@ private AbfsClientThrottlingAnalyzer() { | |
| public void addBytesTransferred(long count, boolean isFailedOperation) { | ||
| AbfsOperationMetrics metrics = blobMetrics.get(); | ||
| if (isFailedOperation) { | ||
| metrics.bytesFailed.addAndGet(count); | ||
| metrics.operationsFailed.incrementAndGet(); | ||
| metrics.addBytesFailed(count); | ||
| metrics.incrementOperationsFailed(); | ||
| } else { | ||
| metrics.bytesSuccessful.addAndGet(count); | ||
| metrics.operationsSuccessful.incrementAndGet(); | ||
| metrics.addBytesSuccessful(count); | ||
| metrics.incrementOperationsSuccessful(); | ||
| } | ||
| blobMetrics.set(metrics); | ||
| } | ||
|
|
||
| /** | ||
| * Suspends the current storage operation, as necessary, to reduce throughput. | ||
| * @return true if Thread sleeps(Throttling occurs) else false. | ||
| */ | ||
| public boolean suspendIfNecessary() { | ||
| lastExecutionTime.set(now()); | ||
| timerOrchestrator(TimerFunctionality.RESUME, null); | ||
| int duration = sleepDuration; | ||
| if (duration > 0) { | ||
| try { | ||
|
|
@@ -134,19 +177,27 @@ int getSleepDuration() { | |
| return sleepDuration; | ||
| } | ||
|
|
||
| int getOperationIdleTimeout() { | ||
| return abfsConfiguration.getAccountOperationIdleTimeout(); | ||
| } | ||
|
|
||
| AtomicBoolean getIsOperationOnAccountIdle() { | ||
| return isOperationOnAccountIdle; | ||
| } | ||
|
|
||
| private int analyzeMetricsAndUpdateSleepDuration(AbfsOperationMetrics metrics, | ||
| int sleepDuration) { | ||
| final double percentageConversionFactor = 100; | ||
| double bytesFailed = metrics.bytesFailed.get(); | ||
| double bytesSuccessful = metrics.bytesSuccessful.get(); | ||
| double operationsFailed = metrics.operationsFailed.get(); | ||
| double operationsSuccessful = metrics.operationsSuccessful.get(); | ||
| double bytesFailed = metrics.getBytesFailed().get(); | ||
| double bytesSuccessful = metrics.getBytesSuccessful().get(); | ||
| double operationsFailed = metrics.getOperationsFailed().get(); | ||
| double operationsSuccessful = metrics.getOperationsSuccessful().get(); | ||
| double errorPercentage = (bytesFailed <= 0) | ||
| ? 0 | ||
| : (percentageConversionFactor | ||
| * bytesFailed | ||
| / (bytesFailed + bytesSuccessful)); | ||
| long periodMs = metrics.endTime - metrics.startTime; | ||
| long periodMs = metrics.getEndTime() - metrics.getStartTime(); | ||
|
|
||
| double newSleepDuration; | ||
|
|
||
|
|
@@ -238,10 +289,13 @@ public void run() { | |
| } | ||
|
|
||
| long now = System.currentTimeMillis(); | ||
| if (now - blobMetrics.get().startTime >= analysisPeriodMs) { | ||
| if (timerOrchestrator(TimerFunctionality.SUSPEND, this)) { | ||
| return; | ||
| } | ||
| if (now - blobMetrics.get().getStartTime() >= analysisPeriodMs) { | ||
| AbfsOperationMetrics oldMetrics = blobMetrics.getAndSet( | ||
| new AbfsOperationMetrics(now)); | ||
| oldMetrics.endTime = now; | ||
| oldMetrics.setEndTime(now); | ||
| sleepDuration = analyzeMetricsAndUpdateSleepDuration(oldMetrics, | ||
| sleepDuration); | ||
| } | ||
|
|
@@ -252,24 +306,4 @@ public void run() { | |
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Stores Abfs operation metrics during each analysis period. | ||
| */ | ||
| static class AbfsOperationMetrics { | ||
| private AtomicLong bytesFailed; | ||
| private AtomicLong bytesSuccessful; | ||
| private AtomicLong operationsFailed; | ||
| private AtomicLong operationsSuccessful; | ||
| private long endTime; | ||
| private long startTime; | ||
|
|
||
| AbfsOperationMetrics(long startTime) { | ||
| this.startTime = startTime; | ||
| this.bytesFailed = new AtomicLong(); | ||
| this.bytesSuccessful = new AtomicLong(); | ||
| this.operationsFailed = new AtomicLong(); | ||
| this.operationsSuccessful = new AtomicLong(); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.