public class DefaultOptimalSizeExploringResizer extends java.lang.Object implements OptimalSizeExploringResizer, scala.Product, scala.Serializable
This resizer works best when you expect the pool size to performance function to be a convex function.
For example, when you have a CPU bound tasks, the optimal size is bound to the number of CPU cores. When your task is IO bound, the optimal size is bound to optimal number of concurrent connections to that IO service - e.g. a 4 node elastic search cluster may handle 4-8 concurrent requests at optimal speed.
It achieves this by keeping track of message throughput at each pool size and performing the following three resizing operations (one at a time) periodically:
* Downsize if it hasn't seen all routees ever fully utilized for a period of time. * Explore to a random nearby pool size to try and collect throughput metrics. * Optimize to a nearby pool size with a better (than any other nearby sizes) throughput metrics.
When the pool is fully-utilized (i.e. all routees are busy), it randomly choose between exploring and optimizing. When the pool has not been fully-utilized for a period of time, it will downsize the pool to the last seen max utilization multiplied by a configurable ratio.
By constantly exploring and optimizing, the resizer will eventually walk to the optimal size and remain nearby. When the optimal size changes it will start walking towards the new one.
It keeps a performance log so it's stateful as well as
having a larger memory footprint than the default Resizer
.
The memory usage is O(n) where n is the number of sizes
you allow, i.e. upperBound - lowerBound.
For documentation about the parameters, see the reference.conf - akka.actor.deployment.default.optimal-size-exploring-resizer
OptimalSizeExploringResizer.ResizeRecord, OptimalSizeExploringResizer.ResizeRecord$, OptimalSizeExploringResizer.UnderUtilizationStreak, OptimalSizeExploringResizer.UnderUtilizationStreak$
Constructor and Description |
---|
DefaultOptimalSizeExploringResizer(int lowerBound,
int upperBound,
double chanceOfScalingDownWhenFull,
scala.concurrent.duration.Duration actionInterval,
int numOfAdjacentSizesToConsiderDuringOptimization,
double exploreStepSize,
double downsizeRatio,
scala.concurrent.duration.Duration downsizeAfterUnderutilizedFor,
double explorationProbability,
double weightOfLatestMetric) |
Modifier and Type | Method and Description |
---|---|
scala.concurrent.duration.Duration |
actionInterval() |
abstract static boolean |
canEqual(java.lang.Object that) |
double |
chanceOfScalingDownWhenFull() |
scala.concurrent.duration.Duration |
downsizeAfterUnderutilizedFor() |
double |
downsizeRatio() |
abstract static boolean |
equals(java.lang.Object that) |
double |
explorationProbability() |
double |
exploreStepSize() |
boolean |
isTimeForResize(long messageCounter)
Is it time for resizing.
|
int |
lowerBound() |
int |
numOfAdjacentSizesToConsiderDuringOptimization() |
scala.collection.immutable.Map<java.lang.Object,scala.concurrent.duration.Duration> |
performanceLog()
Leave package accessible for testing purpose
|
abstract static int |
productArity() |
abstract static java.lang.Object |
productElement(int n) |
static scala.collection.Iterator<java.lang.Object> |
productIterator() |
static java.lang.String |
productPrefix() |
OptimalSizeExploringResizer.ResizeRecord |
record()
Leave package accessible for testing purpose
|
void |
reportMessageCount(scala.collection.immutable.IndexedSeq<Routee> currentRoutees,
long messageCounter)
Report the messageCount as well as current routees so that the
it can collect metrics.
|
int |
resize(scala.collection.immutable.IndexedSeq<Routee> currentRoutees)
Decide if the capacity of the router need to be changed.
|
boolean |
stopExploring()
Leave package accessible for testing purpose
|
scala.Tuple2<scala.collection.immutable.Map<java.lang.Object,scala.concurrent.duration.Duration>,OptimalSizeExploringResizer.ResizeRecord> |
updatedStats(scala.collection.immutable.IndexedSeq<Routee> currentRoutees,
long messageCounter) |
int |
upperBound() |
double |
weightOfLatestMetric() |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
public DefaultOptimalSizeExploringResizer(int lowerBound, int upperBound, double chanceOfScalingDownWhenFull, scala.concurrent.duration.Duration actionInterval, int numOfAdjacentSizesToConsiderDuringOptimization, double exploreStepSize, double downsizeRatio, scala.concurrent.duration.Duration downsizeAfterUnderutilizedFor, double explorationProbability, double weightOfLatestMetric)
public abstract static boolean canEqual(java.lang.Object that)
public abstract static boolean equals(java.lang.Object that)
public abstract static java.lang.Object productElement(int n)
public abstract static int productArity()
public static scala.collection.Iterator<java.lang.Object> productIterator()
public static java.lang.String productPrefix()
public int lowerBound()
public int upperBound()
public double chanceOfScalingDownWhenFull()
public scala.concurrent.duration.Duration actionInterval()
public int numOfAdjacentSizesToConsiderDuringOptimization()
public double exploreStepSize()
public double downsizeRatio()
public scala.concurrent.duration.Duration downsizeAfterUnderutilizedFor()
public double explorationProbability()
public double weightOfLatestMetric()
public scala.collection.immutable.Map<java.lang.Object,scala.concurrent.duration.Duration> performanceLog()
public OptimalSizeExploringResizer.ResizeRecord record()
public boolean stopExploring()
public boolean isTimeForResize(long messageCounter)
Resizer
CAUTION: this method is invoked from the thread which tries to send a message to the pool, i.e. the ActorRef.!() method, hence it may be called concurrently.
isTimeForResize
in interface Resizer
messageCounter
- (undocumented)public void reportMessageCount(scala.collection.immutable.IndexedSeq<Routee> currentRoutees, long messageCounter)
OptimalSizeExploringResizer
reportMessageCount
in interface OptimalSizeExploringResizer
public scala.Tuple2<scala.collection.immutable.Map<java.lang.Object,scala.concurrent.duration.Duration>,OptimalSizeExploringResizer.ResizeRecord> updatedStats(scala.collection.immutable.IndexedSeq<Routee> currentRoutees, long messageCounter)
public int resize(scala.collection.immutable.IndexedSeq<Routee> currentRoutees)
Resizer
isTimeForResize
returns true and no other resize is in progress.
Return the number of routees to add or remove. Negative value will remove that number of routees. Positive value will add that number of routees. 0 will not change the routees.
This method is invoked only in the context of the Router actor.