Skip to content
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

Feature/auto scaling with usage #47

Merged
merged 26 commits into from
Sep 13, 2018
Merged

Conversation

lftakakura
Copy link
Contributor

@lftakakura lftakakura commented Aug 28, 2018

No description provided.

@coveralls
Copy link

coveralls commented Aug 28, 2018

Coverage Status

Coverage increased (+0.4%) to 82.017% when pulling 0a4d73b on feature/auto-scaling-with-usage into b67fa88 on master.

Copy link
Contributor

@henrod henrod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, just some changes

@@ -600,75 +588,208 @@ func (w *Watcher) checkState(
roomCount *models.RoomsStatusCount,
scheduler *models.Scheduler,
nowTimestamp int64,
) (bool, bool, bool, error) { //shouldScaleUp, shouldScaleDown, changedState
) (int, bool, bool, bool, error) { //delta, shouldScaleUp, shouldScaleDown, changedState
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 returns is too much, better create a new struct that contains the int and the three bools, then you return that struct and the error

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't scaleup/down be inferred from the delta sign? if positive we should scaleup and if negative we should scaledown

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree


// If usage is above limit, scale up.
if isDown == false && 100*roomCount.Occupied >= roomCount.Total()*trigger.Limit {
w.Logger.Debug("Usage is above limit. Should scale up")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be extracted to another function. The idea is reduce the size of this function and simplify it

if 100*roomCount.Occupied >= roomCount.Total()*autoScalingInfo.Up.Trigger.Limit {
scaleInfo.SendUsage(
w.SchedulerName,
"legacy", point, roomCount.Total(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to put "legacy" on constants to avoid typos

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

words of wisdom

Copy link
Contributor

@cscatolini cscatolini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few comments

dev-room/app.py Outdated
@@ -37,6 +48,7 @@ def ping():
except Exception as ex:
print(str(ex))
pass
break
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the pass and the break?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it shouldn't have break. Forgot to take it off =/

watcher/utils.go Outdated
roomCount *models.RoomsStatusCount,
) int { // delta
usageThreshold := float32(metricTrigger.Usage) / 100
return int(float32(float32(roomCount.Occupied)-float32(usageThreshold*float32(roomCount.Total()))) / usageThreshold)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we round up instead of just converting to int?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

@@ -600,75 +588,208 @@ func (w *Watcher) checkState(
roomCount *models.RoomsStatusCount,
scheduler *models.Scheduler,
nowTimestamp int64,
) (bool, bool, bool, error) { //shouldScaleUp, shouldScaleDown, changedState
) (int, bool, bool, bool, error) { //delta, shouldScaleUp, shouldScaleDown, changedState
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't scaleup/down be inferred from the delta sign? if positive we should scaleup and if negative we should scaledown

} else if inSync == true { // always send current usage
if len(autoScalingInfo.Down.MetricsTrigger) > 0 {
for _, trigger := range autoScalingInfo.Down.MetricsTrigger {
w.ScaleDownInfo.SendUsage(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find any sendUsage for scale up, it this intended? or am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On scaleUp it will call SendUsageAndReturnStatus(). SendUsage() is called here because checkMetricsTrigger will not be called for down scaling if up scaling is needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we have two separate usage metrics, one for scaling up and another for scaling down?

if 100*roomCount.Occupied >= roomCount.Total()*autoScalingInfo.Up.Trigger.Limit {
scaleInfo.SendUsage(
w.SchedulerName,
"legacy", point, roomCount.Total(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

words of wisdom

Copy link
Contributor

@cscatolini cscatolini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will these changes be backwards compatible? I don't think so but I'm not sure it will be a big problem.

watcher/utils.go Outdated
@@ -30,6 +31,12 @@ func roomDynamicDelta(
metricTrigger *models.ScalingPolicyMetricsTrigger,
roomCount *models.RoomsStatusCount,
) int { // delta
usageThreshold := float32(metricTrigger.Usage) / 100
return int(float32(float32(roomCount.Occupied)-float32(usageThreshold*float32(roomCount.Total()))) / usageThreshold)
// [Occupied / (Total + Delta)] = Usage/100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much clearer 😌

@lftakakura
Copy link
Contributor Author

lftakakura commented Aug 31, 2018

The changes should be backwards compatible. The only issue is with the redis set that now is the same for both up and down scaling.

watcher/utils.go Outdated
)

func dynamicDelta(
metricTrigger *models.ScalingPolicyMetricsTrigger,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use ScalingPolicyMetricsTrigger as an interface actually, with the methods Metric() and Usage(). Or with the method DynamicDelta(). That way you won't need a switch/case statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do

) (bool, bool, bool, error) { //shouldScaleUp, shouldScaleDown, changedState
var shouldScaleUp, shouldScaleDown, changedState bool
inSync := true
) (*scaling, error) { //delta, shouldScaleUp, shouldScaleDown, changedState
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this comment anymore ;)

usage := float32(autoScalingInfo.Up.Trigger.Usage) / 100
capacity := autoScalingInfo.Up.Trigger.Time / w.AutoScalingPeriod
// Send current usage
if len(autoScalingInfo.Down.MetricsTrigger) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is too long. You could separate the ifs into methods whose names are their intention.

return scaling, nil
}

func (w *Watcher) checkLegacyTrigger(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is too much duplicated code with checkMetricsTrigger. Couldn't you merge them? For example, The for loop on checkMetricsTrigger could be extracted and receive the same parameters checkLegacyTrigger uses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do

func getMemUsageAndRequests(usage, requests v1.ResourceList) (float32, float32) {
resourceRequests := float32(requests.Memory().ScaledValue(0))
resourceUsage := float32(usage.Memory().ScaledValue(0))
fmt.Printf("\nrequests: %v | usage: %v\n", requests.Memory().Value(), usage.Memory().Value())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debug logs?

usageRatio := currentUtilization / float32(trigger.Usage) / 100
delta := int(math.Ceil(float64(usageRatio)*float64(roomCount.Available()))) - roomCount.Available()

fmt.Printf("\ncurrentUtilization: %v | usageRatio: %v | roomCount: %v | delta: %v\n", currentUtilization, usageRatio, roomCount.Available(), delta)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same


for _, pod := range podList.Items {
for i, container := range pod.Containers {
if container.Name == pod.Name { // Get game room container
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably this is not the best way to check

api/app.go Outdated
@@ -56,6 +57,7 @@ type App struct {
DBClient *pg.Client
RedisClient *redis.Client
KubernetesClient kubernetes.Interface
KubernetesMetricsClient metricsClient.Interface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

linter should align this

@lftakakura lftakakura force-pushed the feature/auto-scaling-with-usage branch from 9ef73ac to 5289a40 Compare September 13, 2018 13:38
@lftakakura lftakakura changed the title WIP: Feature/auto scaling with usage Feature/auto scaling with usage Sep 13, 2018
@@ -538,6 +644,98 @@ portRange:
})
})

FIt("should return error if autoscaling min > max", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All tests must be It()

@lftakakura lftakakura merged commit 5f1bd55 into master Sep 13, 2018
@lftakakura lftakakura deleted the feature/auto-scaling-with-usage branch September 13, 2018 22:57
@@ -0,0 +1,32 @@
import falcon
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lftakakura this is the best file in the project 🤣

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants