Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
616ba4ea
Commit
616ba4ea
authored
Sep 07, 2015
by
k8s-merge-robot
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #13261 from mwielgus/hpa_formula
Auto commit by PR queue bot
parents
06b251e7
02c30c5d
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
49 additions
and
26 deletions
+49
-26
horizontal-pod-autoscaler.md
docs/proposals/horizontal-pod-autoscaler.md
+11
-11
horizontalpodautoscaler_controller.go
...ntroller/autoscaler/horizontalpodautoscaler_controller.go
+38
-15
No files found.
docs/proposals/horizontal-pod-autoscaler.md
View file @
616ba4ea
...
@@ -200,16 +200,20 @@ and adjust the count of the Scale if needed to match the target
...
@@ -200,16 +200,20 @@ and adjust the count of the Scale if needed to match the target
The target number of pods will be calculated from the following formula:
The target number of pods will be calculated from the following formula:
```
```
TargetNumOfPods =
sum(CurrentPodsConsumption) / Target
TargetNumOfPods =
ceil(sum(CurrentPodsConsumption) / Target)
```
```
To make scaling more stable, scale-up will happen only when the floor of ```
TargetNumOfPods
``` is higher than
Starting and stopping pods may introduce noise to the metrics (for instance starting may temporarily increase
the current number, while scale-down will happen only when the ceiling of ```
TargetNumOfPods
``` is lower than
CPU and decrease average memory consumption) so, after each action, the autoscaler should wait some time for reliable data.
the current number.
The decision to scale-up will be executed instantly.
Scale-up will happen if there was no rescaling within the last 3 minutes.
However, we will execute scale-down only if the sufficient time has passed from the last scale-up (e.g.: 10 minutes).
Scale-down will wait for 10 minutes from the last rescaling. Moreover any scaling will only be made if
Such approach has two benefits:
```
avg(CurrentPodsConsumption) / Target
```
drops below 0.9 or increases above 1.1 (10% tolerance). Such approach has two benefits:
* Autoscaler works in a conservative way.
* Autoscaler works in a conservative way.
If new user load appears, it is important for us to rapidly increase the number of pods,
If new user load appears, it is important for us to rapidly increase the number of pods,
...
@@ -218,10 +222,6 @@ Such approach has two benefits:
...
@@ -218,10 +222,6 @@ Such approach has two benefits:
* Autoscaler avoids thrashing, i.e.: prevents rapid execution of conflicting decision if the load is not stable.
* Autoscaler avoids thrashing, i.e.: prevents rapid execution of conflicting decision if the load is not stable.
As the CPU consumption of a pod immediately after start may be highly variable due to initialization/startup,
autoscaler will skip metrics from the first minute of pod lifecycle.
## Relative vs. absolute metrics
## Relative vs. absolute metrics
The question arises whether the values of the target metrics should be absolute (e.g.: 0.6 core, 100MB of RAM)
The question arises whether the values of the target metrics should be absolute (e.g.: 0.6 core, 100MB of RAM)
...
...
pkg/controller/autoscaler/horizontalpodautoscaler_controller.go
View file @
616ba4ea
...
@@ -18,6 +18,7 @@ package autoscalercontroller
...
@@ -18,6 +18,7 @@ package autoscalercontroller
import
(
import
(
"fmt"
"fmt"
"math"
"time"
"time"
"github.com/golang/glog"
"github.com/golang/glog"
...
@@ -30,6 +31,15 @@ import (
...
@@ -30,6 +31,15 @@ import (
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util"
)
)
const
(
heapsterNamespace
=
"kube-system"
heapsterService
=
"monitoring-heapster"
// Usage shoud exceed the tolerance before we start downscale or upscale the pods.
// TODO: make it a flag or HPA spec element.
tolerance
=
0.1
)
type
HorizontalPodAutoscalerController
struct
{
type
HorizontalPodAutoscalerController
struct
{
client
client
.
Interface
client
client
.
Interface
expClient
client
.
ExperimentalInterface
expClient
client
.
ExperimentalInterface
...
@@ -79,38 +89,51 @@ func (a *HorizontalPodAutoscalerController) reconcileAutoscalers() error {
...
@@ -79,38 +89,51 @@ func (a *HorizontalPodAutoscalerController) reconcileAutoscalers() error {
continue
continue
}
}
// if the ratio is 1.2 we want to have 2 replicas
usageRatio
:=
float64
(
currentConsumption
.
Quantity
.
MilliValue
())
/
float64
(
hpa
.
Spec
.
Target
.
Quantity
.
MilliValue
())
desiredReplicas
:=
1
+
int
((
currentConsumption
.
Quantity
.
MilliValue
()
*
int64
(
currentReplicas
))
/
hpa
.
Spec
.
Target
.
Quantity
.
MilliValue
(
))
desiredReplicas
:=
int
(
math
.
Ceil
(
usageRatio
*
float64
(
currentReplicas
)
))
if
desiredReplicas
<
hpa
.
Spec
.
MinCount
{
if
desiredReplicas
<
hpa
.
Spec
.
MinCount
{
desiredReplicas
=
hpa
.
Spec
.
MinCount
desiredReplicas
=
hpa
.
Spec
.
MinCount
}
}
// TODO: remove when pod ideling is done.
if
desiredReplicas
==
0
{
desiredReplicas
=
1
}
if
desiredReplicas
>
hpa
.
Spec
.
MaxCount
{
if
desiredReplicas
>
hpa
.
Spec
.
MaxCount
{
desiredReplicas
=
hpa
.
Spec
.
MaxCount
desiredReplicas
=
hpa
.
Spec
.
MaxCount
}
}
now
:=
time
.
Now
()
now
:=
time
.
Now
()
rescale
:=
false
rescale
:=
false
if
desiredReplicas
!=
currentReplicas
{
if
desiredReplicas
!=
currentReplicas
{
// Going down
// Going down only if the usageRatio dropped significantly below the target
if
desiredReplicas
<
currentReplicas
&&
(
hpa
.
Status
==
nil
||
hpa
.
Status
.
LastScaleTimestamp
==
nil
||
// and there was no rescaling in the last downscaleForbiddenWindow.
hpa
.
Status
.
LastScaleTimestamp
.
Add
(
downscaleForbiddenWindow
)
.
Before
(
now
))
{
if
desiredReplicas
<
currentReplicas
&&
usageRatio
<
(
1
-
tolerance
)
&&
(
hpa
.
Status
==
nil
||
hpa
.
Status
.
LastScaleTimestamp
==
nil
||
hpa
.
Status
.
LastScaleTimestamp
.
Add
(
downscaleForbiddenWindow
)
.
Before
(
now
))
{
rescale
=
true
rescale
=
true
}
}
// Going up
// Going up only if the usage ratio increased significantly above the target
if
desiredReplicas
>
currentReplicas
&&
(
hpa
.
Status
==
nil
||
hpa
.
Status
.
LastScaleTimestamp
==
nil
||
// and there was no rescaling in the last upscaleForbiddenWindow.
hpa
.
Status
.
LastScaleTimestamp
.
Add
(
upscaleForbiddenWindow
)
.
Before
(
now
))
{
if
desiredReplicas
>
currentReplicas
&&
usageRatio
>
(
1
+
tolerance
)
&&
(
hpa
.
Status
==
nil
||
hpa
.
Status
.
LastScaleTimestamp
==
nil
||
hpa
.
Status
.
LastScaleTimestamp
.
Add
(
upscaleForbiddenWindow
)
.
Before
(
now
))
{
rescale
=
true
rescale
=
true
}
}
}
if
rescale
{
if
rescale
{
scale
.
Spec
.
Replicas
=
desiredReplicas
scale
.
Spec
.
Replicas
=
desiredReplicas
_
,
err
=
a
.
expClient
.
Scales
(
hpa
.
Namespace
)
.
Update
(
hpa
.
Spec
.
ScaleRef
.
Kind
,
scale
)
_
,
err
=
a
.
expClient
.
Scales
(
hpa
.
Namespace
)
.
Update
(
hpa
.
Spec
.
ScaleRef
.
Kind
,
scale
)
if
err
!=
nil
{
if
err
!=
nil
{
glog
.
Warningf
(
"Failed to rescale %s: %v"
,
reference
,
err
)
glog
.
Warningf
(
"Failed to rescale %s: %v"
,
reference
,
err
)
continue
continue
}
}
}
}
else
{
desiredReplicas
=
currentReplicas
}
}
status
:=
expapi
.
HorizontalPodAutoscalerStatus
{
status
:=
expapi
.
HorizontalPodAutoscalerStatus
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment