-
Notifications
You must be signed in to change notification settings - Fork 2k
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
ThroughputControl-Global #19183
ThroughputControl-Global #19183
Conversation
# Throughput control part 1 -- local # refactor # refactor # refactor class name Throughput control part 1 -- Local control
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run java - cosmos - tests |
Azure Pipelines successfully started running 1 pipeline(s). |
...src/main/java/com/azure/cosmos/implementation/throughputControl/LinkedCancellationToken.java
Outdated
Show resolved
Hide resolved
sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/GlobalThroughputControlConfig.java
Outdated
Show resolved
Hide resolved
...cosmos/azure-cosmos/src/main/java/com/azure/cosmos/GlobalThroughputControlConfigBuilder.java
Outdated
Show resolved
Hide resolved
...cosmos/azure-cosmos/src/main/java/com/azure/cosmos/GlobalThroughputControlConfigBuilder.java
Outdated
Show resolved
Hide resolved
sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/GlobalThroughputControlConfig.java
Show resolved
Hide resolved
...a/com/azure/cosmos/implementation/throughputControl/config/ThroughputGlobalControlGroup.java
Outdated
Show resolved
Hide resolved
...va/com/azure/cosmos/implementation/throughputControl/config/ThroughputLocalControlGroup.java
Outdated
Show resolved
Hide resolved
sdk/cosmos/azure-cosmos/src/samples/java/com/azure/cosmos/ThroughputControlCodeSnippet.java
Show resolved
Hide resolved
.../src/main/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlStore.java
Show resolved
Hide resolved
private final RxPartitionKeyRangeCache partitionKeyRangeCache; | ||
|
||
private final LinkedCancellationTokenSource cancellationTokenSource; | ||
private final ConcurrentHashMap<String, LinkedCancellationToken> cancellationTokenMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto, on the thread-safely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will discuss offline for this one.
.../src/main/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlStore.java
Outdated
Show resolved
Hide resolved
.../src/main/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlStore.java
Outdated
Show resolved
Hide resolved
.../main/java/com/azure/cosmos/implementation/throughputControl/ThroughputRequestThrottler.java
Show resolved
Hide resolved
.../src/test/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlTests.java
Show resolved
Hide resolved
.../src/test/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlTests.java
Outdated
Show resolved
Hide resolved
if (request.requestContext != null) { | ||
BridgeInternal.setResourceAddress(requestRateTooLargeException, request.requestContext.resourcePhysicalAddress); | ||
try { | ||
this.throughputReadLock.lock(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here mixing the readLock pattern with reactor Mono is interesting, and I am not sure if it does what you intended to do. thinking ...
Think about this,
- let's say you acquire the read lock
this.throughputReadLock.lock()
and then we checkif (this.availableThroughput.get() > 0)
- then we are returning a
Mono
from theprocessRequest(.)
method. which means as we go out of the scope of this method the finally block andthis.throughputReadLock.unlock();
will be invoked. so now the lock is released. - now
trackRequestCharge
andtrackRequestCharge
won't be invoked till we go out of the scope ofprocessRequest
and someone subscribes to the returnedMono
.
I checked the trackRequestCharge
and trackRequestCharge
implementation I noticed that you are re-accquiring the read lock.
Now please consider this scenario: does this cause any problem?
processRequest
acquires the lock this.throughputReadLock.lock()and read the value of
availableThroughput`processRequest
returns a Mono and release thethis.throughputReadLock.lock()
lock in the finally block- now let's say some other thread acquires the write lock and updates the throughputs
- someone subsctibes to the Mono returned in step 2, and now
trackRequestCharge
andtrackRequestCharge
will be invoked, they will attempt to accquire readLock but because of the step 3. in between the throughput values they see is not the same value that the if branch ofprocessRequest
observed.
Does this cause any problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@moderakh @FabianMeiswinkel @kushagraThapar
I think this is one of the consequences of we only track the RU usage based on the response compared to pre-calculation.
The consequences of it :
a. could be some requests actually happened in the previous cycle their response will be tracked in the next cycle and eat some throughput from the next cycle.
b. The throughput usage for previous cycle is lower than the real usage.
It can be improved if we do some operation RU predication later on.
Or we can do some stuff like: for each operation, it can be attached to a certain cycle version. and we only track the response if it matches to the current cycle version. Maybe this is a better way?
The reason I introduced the read write lock is mainly to keep ScheduledThroughput and availableThroughput to be in sync, since if we are going to return 429, then we depends on those two values to calculate the backoff time.
Any throughputs for this one?
.../src/test/java/com/azure/cosmos/implementation/throughputControl/ThroughputControlTests.java
Outdated
Show resolved
Hide resolved
/azp run java - cosmos - tests |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run java - cosmos - tests |
Azure Pipelines successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work @xinlian12
Looks great. This is done very well.
I added a few comments around thread-safety, your usage of locks, and also I think you need to more frequently update the document associated with each client (as discussed at least every ttl -1 / 2
to ensure your document doesn't get ttl due to slight shift in task scheduling, etc)
other than these looks great.
|
||
public void cancel() { | ||
if (this.cancellationRequested.compareAndSet(false, true)) { | ||
for (LinkedCancellationTokenSource childTokenSource : this.childTokenSourceList) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non thread-safe access to the this.childTokenSourceList
...com/azure/cosmos/implementation/throughputControl/config/ThroughputControlGroupInternal.java
Show resolved
Hide resolved
} | ||
}) | ||
.doOnSuccess(requestController -> { | ||
if (requestController != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
per reactor-stream spec, null values are never allowed. hence requestController
always will be non null. you don't need to check.
per reactive-streams/reactive-streams-jvm#209
it is guaranteed you will never receive a null value here.
sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java
Show resolved
Hide resolved
/azp run java - cosmos - tests |
Azure Pipelines successfully started running 1 pipeline(s). |
This is the second PR of the throughput control.
Compared to local control mode, the throughput control group is shared among different clients.
TODO:
Benchmark tests results:
