Skip to content

Commit 0487340

Browse files
boyang9527rohitsharma04
authored andcommitted
enable memoryutil based scaling (cloudfoundry#53)
* enable memoryutil based scaling - bump latest app-autoscaler code - bosh release code change accordingly - add acceptance test for memoryutil based scaling - refactor other acceptance tests * sync package specs
1 parent e467c5e commit 0487340

20 files changed

+169
-35
lines changed

example/property-overrides.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ api_server_properties:
2020
ca_cert: (( app_autoscaler_ca_cert ))
2121
client_cert: (( scheduler_client_cert ))
2222
client_key: (( scheduler_client_key ))
23+
scaling_engine:
24+
ca_cert: (( app_autoscaler_ca_cert ))
25+
client_cert: (( scalingengine_client_cert ))
26+
client_key: (( scalingengine_client_key ))
2327

2428
service_broker_properties:
2529
db_config:

jobs/apiserver/spec

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ templates:
99
apiserver_ca.crt.erb: config/certs/apiserver/ca.crt
1010
apiserver_server.crt.erb: config/certs/apiserver/server.crt
1111
apiserver_server.key.erb: config/certs/apiserver/server.key
12+
scalingengine_ca.crt.erb: config/certs/scalingengine/ca.crt
13+
scalingengine_client.crt.erb: config/certs/scalingengine/client.crt
14+
scalingengine_client.key.erb: config/certs/scalingengine/client.key
1215
scheduler_ca.crt.erb: config/certs/scheduler/ca.crt
1316
scheduler_client.crt.erb: config/certs/scheduler/client.crt
1417
scheduler_client.key.erb: config/certs/scheduler/client.key
@@ -30,6 +33,7 @@ properties:
3033
description: "PEM-encoded server certificate"
3134
api_server.server_key:
3235
description: "PEM-encoded server key"
36+
3337
api_server.scheduler.host:
3438
description: "Host where scheduler is running"
3539
default: "scheduler.service.cf.internal"
@@ -42,6 +46,23 @@ properties:
4246
description: "PEM-encoded client certificate"
4347
api_server.scheduler.client_key:
4448
description: "PEM-encoded client key"
49+
50+
51+
api_server.scaling_engine.host:
52+
description: "Host where scalingengine is running"
53+
default: "scalingengine.service.cf.internal"
54+
api_server.scaling_engine.port:
55+
description: "Port where scalingengine will listen"
56+
default: 6104
57+
api_server.scaling_engine.ca_cert:
58+
description: "PEM-encoded CA certificate"
59+
api_server.scaling_engine.client_cert:
60+
description: "PEM-encoded client certificate"
61+
api_server.scaling_engine.client_key:
62+
description: "PEM-encoded client key"
63+
64+
65+
4566
api_server.db_config.max_connections:
4667
description: "Maximum number of connections that may be held in the apiserver db pool"
4768
api_server.db_config.min_connections:

jobs/apiserver/templates/config.json.erb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
database = p_arr('policy_db.databases').find { |database| database['tag'] == 'policydb' or database['tag'] == 'default'}
1212
scheduler_host = p('api_server.scheduler.host')
1313
scheduler_port = p('api_server.scheduler.port')
14+
scaling_engine_host = p('api_server.scaling_engine.host')
15+
scaling_engine_port = p('api_server.scaling_engine.port')
16+
1417
params = {
1518
'port' => p('api_server.port'),
1619
'db' => {
@@ -27,6 +30,14 @@
2730
'caCertFile' => "/var/vcap/jobs/apiserver/config/certs/scheduler/ca.crt"
2831
},
2932
},
33+
'scalingEngine' => {
34+
'uri' => "https://" + scaling_engine_host + ":" + scaling_engine_port.to_s,
35+
'tls' => {
36+
'keyFile' => "/var/vcap/jobs/apiserver/config/certs/scalingengine/client.key",
37+
'certFile' => "/var/vcap/jobs/apiserver/config/certs/scalingengine/client.crt",
38+
'caCertFile' => "/var/vcap/jobs/apiserver/config/certs/scalingengine/ca.crt"
39+
},
40+
},
3041
'tls' => {
3142
'keyFile' => "/var/vcap/jobs/apiserver/config/certs/apiserver/server.key",
3243
'certFile' => "/var/vcap/jobs/apiserver/config/certs/apiserver/server.crt",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<% if_p("api_server.scaling_engine.ca_cert") do |value| %>
2+
<%= value %>
3+
<% end %>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<% if_p("api_server.scaling_engine.client_cert") do |value| %>
2+
<%= value %>
3+
<% end %>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<% if_p("api_server.scaling_engine.client_key") do |value| %>
2+
<%= value %>
3+
<% end %>

jobs/metricscollector/spec

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,12 @@ properties:
6969
description: "the time interval to refresh app policies from policy database"
7070
default: 60s
7171
metricscollector.collector.poll_interval:
72-
description: "the time interval to poll container metrics from loggregator"
72+
description: "the time interval to collect container metrics from loggregator"
7373
default: 30s
74+
metricscollector.collector.collect_method:
75+
description: "the method to collect metrics from loggregator"
76+
default: "polling"
77+
7478

7579
metricscollector.lock.lock_ttl:
7680
description: "consul lock ttl duration"

jobs/metricscollector/templates/metricscollector.yml.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ db:
4545
collector:
4646
refresh_interval: <%= p("metricscollector.collector.refresh_interval") %>
4747
poll_interval: <%= p("metricscollector.collector.poll_interval") %>
48+
collect_method: <%= p("metricscollector.collector.collect_method") %>
4849

4950
lock:
5051
lock_ttl: <%= p("metricscollector.lock.lock_ttl") %>

jobs/scheduler/spec

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ properties:
3535
description: "Maximum no of jobs can be re-scheduled"
3636
scheduler.notification_reschedule_maxcount:
3737
description: "Maximum number of notification sent to scaling engine for job re-schedule"
38+
3839
scheduler.scaling_engine.host:
3940
description: "URL where Scaling-engine is running"
4041
default: "scalingengine.service.cf.internal"
@@ -47,9 +48,11 @@ properties:
4748
description: "PEM-encoded client certificate"
4849
scheduler.scaling_engine.client_key:
4950
description: "PEM-encoded client key"
51+
5052
scheduler.consul.ttl:
5153
description: "TTL timeout seconds"
5254
default: 20
55+
5356
scheduler_db.address:
5457
description: "IP address on which the schedulerdb server will listen"
5558
default: "postgres.service.cf.internal"
@@ -60,4 +63,16 @@ properties:
6063
scheduler_db.port:
6164
description: "Port on which the schedulerdb server will listen"
6265
scheduler_db.roles:
63-
description: "The list of database roles used in schedulerdb database including name/password"
66+
description: "The list of database roles used in schedulerdb database including name/password"
67+
68+
policy_db.address:
69+
description: "IP address on which the policydb server will listen"
70+
default: "postgres.service.cf.internal"
71+
policy_db.databases:
72+
description: "The list of databases used in policydb database including name"
73+
policy_db.db_scheme:
74+
description: "Database scheme to be used to access policydb"
75+
policy_db.port:
76+
description: "Port on which the policydb server will listen"
77+
policy_db.roles:
78+
description: "The list of database roles used in policydb database including name/password"

jobs/scheduler/templates/application.properties.erb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,27 @@
66
p(property,nil) || []
77
end
88

9-
role = p_arr('scheduler_db.roles').find { |role| role['tag'] == 'schedulerdb' or role['tag'] == 'default' }
10-
database = p_arr('scheduler_db.databases').find { |database| database['tag'] == 'schedulerdb' or database['tag'] == 'default' }
9+
schedulerdb_role = p_arr('scheduler_db.roles').find { |role| role['tag'] == 'schedulerdb' or role['tag'] == 'default' }
10+
schedulerdb_database = p_arr('scheduler_db.databases').find { |database| database['tag'] == 'schedulerdb' or database['tag'] == 'default' }
11+
12+
policydb_role = p_arr('policy_db.roles').find { |role| role['tag'] == 'policydb' or role['tag'] == 'default' }
13+
policydb_database = p_arr('policy_db.databases').find { |database| database['tag'] == 'policydb' or database['tag'] == 'default' }
14+
1115
%>
1216
#datasource for application and quartz
1317

1418
spring.datasource.driverClassName=org.postgresql.Driver
15-
spring.datasource.url=jdbc:postgresql://<%=p('scheduler_db.address')%>:<%=p('scheduler_db.port') %>/<%=database['name'] %>
16-
spring.datasource.username=<%=role['name'] %>
17-
spring.datasource.password=<%=role['password'] %>
19+
spring.datasource.url=jdbc:postgresql://<%=p('scheduler_db.address')%>:<%=p('scheduler_db.port') %>/<%=schedulerdb_database['name'] %>
20+
spring.datasource.username=<%=schedulerdb_role['name'] %>
21+
spring.datasource.password=<%=schedulerdb_role['password'] %>
22+
23+
#datasource for policy
24+
25+
spring.policyDbDataSource.driverClassName=org.postgresql.Driver
26+
spring.policyDbDataSource.url=jdbc:postgresql://<%=p('policy_db.address')%>:<%=p('policy_db.port') %>/<%=policydb_database['name'] %>
27+
spring.policyDbDataSource.password=<%=policydb_role['name'] %>
28+
spring.policyDbDataSource.username=<%=policydb_role['password'] %>
29+
1830

1931
#quartz job
2032
scalingenginejob.reschedule.interval.millisecond=<%=p('scheduler.job_reschedule_interval_millisecond') %>

packages/metricscollector/spec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ files:
1616
- app-autoscaler/src/autoscaler/metricscollector/fakes/*.go # gosub
1717
- app-autoscaler/src/autoscaler/metricscollector/noaa/*.go # gosub
1818
- app-autoscaler/src/autoscaler/metricscollector/server/*.go # gosub
19+
- app-autoscaler/src/autoscaler/metricscollector/testhelpers/*.go # gosub
1920
- app-autoscaler/src/autoscaler/models/*.go # gosub
2021
- app-autoscaler/src/autoscaler/routes/*.go # gosub
2122
- app-autoscaler/src/code.cloudfoundry.org/cfhttp/*.go # gosub

src/acceptance/app/app_suite_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ func averageMemoryUsedByInstance(appGUID string, timeout time.Duration) uint64 {
205205
return memSum / uint64(len(memoryUsedArray))
206206
}
207207

208-
func generateDynamicScaleOutPolicy(instanceMin, instanceMax int, threshold int64) string {
208+
func generateDynamicScaleOutPolicy(instanceMin, instanceMax int, metricName string, threshold int64) string {
209209
scalingOutRule := ScalingRule{
210-
MetricType: "memoryused",
210+
MetricType: metricName,
211211
StatWindowSeconds: interval,
212212
BreachDurationSeconds: interval,
213213
Threshold: threshold,
@@ -227,9 +227,9 @@ func generateDynamicScaleOutPolicy(instanceMin, instanceMax int, threshold int64
227227
return string(bytes)
228228
}
229229

230-
func generateDynamicScaleInPolicy(instanceMin, instanceMax int, threshold int64) string {
230+
func generateDynamicScaleInPolicy(instanceMin, instanceMax int, metricName string, threshold int64) string {
231231
scalingInRule := ScalingRule{
232-
MetricType: "memoryused",
232+
MetricType: metricName,
233233
StatWindowSeconds: interval,
234234
BreachDurationSeconds: interval,
235235
Threshold: threshold,

src/acceptance/app/dynamic_policy_test.go

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ var _ = Describe("AutoScaler dynamic policy", func() {
3838
Expect(guid).To(Exit(0))
3939
appGUID = strings.TrimSpace(string(guid.Out.Contents()))
4040

41-
Expect(cf.Cf("start", appName).Wait(cfg.DefaultTimeoutDuration() * 3)).To(Exit(0))
41+
Expect(cf.Cf("start", appName).Wait(cfg.CfPushTimeoutDuration())).To(Exit(0))
4242
waitForNInstancesRunning(appGUID, initialInstanceCount, cfg.DefaultTimeoutDuration())
4343
})
4444

@@ -49,7 +49,7 @@ var _ = Describe("AutoScaler dynamic policy", func() {
4949
Expect(deleteService).To(Exit(0))
5050
})
5151

52-
Context("when scale by memoryused", func() {
52+
Context("when scaling by memoryused", func() {
5353

5454
JustBeforeEach(func() {
5555
bindService := cf.Cf("bind-service", appName, instanceName, "-c", policy).Wait(cfg.DefaultTimeoutDuration())
@@ -63,12 +63,12 @@ var _ = Describe("AutoScaler dynamic policy", func() {
6363

6464
Context("when memory used is greater than scaling out threshold", func() {
6565
BeforeEach(func() {
66-
policy = generateDynamicScaleOutPolicy(1, 2, 30)
66+
policy = generateDynamicScaleOutPolicy(1, 2, "memoryused", 30)
6767
initialInstanceCount = 1
6868
})
6969

7070
It("should scale out", func() {
71-
totalTime := time.Duration(interval*2)*time.Second + 2*time.Minute
71+
totalTime := time.Duration(interval*2)*time.Second + 3*time.Minute
7272
finishTime := time.Now().Add(totalTime)
7373

7474
Eventually(func() uint64 {
@@ -82,11 +82,11 @@ var _ = Describe("AutoScaler dynamic policy", func() {
8282

8383
Context("when memory used is lower than scaling in threshold", func() {
8484
BeforeEach(func() {
85-
policy = generateDynamicScaleInPolicy(1, 2, 80)
85+
policy = generateDynamicScaleInPolicy(1, 2, "memoryused", 80)
8686
initialInstanceCount = 2
8787
})
8888
It("should scale in", func() {
89-
totalTime := time.Duration(interval*2)*time.Second + 2*time.Minute
89+
totalTime := time.Duration(interval*2)*time.Second + 3*time.Minute
9090
finishTime := time.Now().Add(totalTime)
9191

9292
Eventually(func() uint64 {
@@ -98,4 +98,54 @@ var _ = Describe("AutoScaler dynamic policy", func() {
9898
})
9999

100100
})
101+
102+
Context("when scaling by memoryutil", func() {
103+
104+
JustBeforeEach(func() {
105+
bindService := cf.Cf("bind-service", appName, instanceName, "-c", policy).Wait(cfg.DefaultTimeoutDuration())
106+
Expect(bindService).To(Exit(0), "failed binding service to app with a policy ")
107+
})
108+
109+
AfterEach(func() {
110+
unbindService := cf.Cf("unbind-service", appName, instanceName).Wait(cfg.DefaultTimeoutDuration())
111+
Expect(unbindService).To(Exit(0), "failed unbinding service from app")
112+
})
113+
114+
Context("when memoryutil is greater than scaling out threshold", func() {
115+
BeforeEach(func() {
116+
policy = generateDynamicScaleOutPolicy(1, 2, "memoryutil", 20)
117+
initialInstanceCount = 1
118+
})
119+
120+
It("should scale out", func() {
121+
totalTime := time.Duration(interval*2)*time.Second + 3*time.Minute
122+
finishTime := time.Now().Add(totalTime)
123+
124+
Eventually(func() uint64 {
125+
return averageMemoryUsedByInstance(appGUID, totalTime)
126+
}, totalTime, 15*time.Second).Should(BeNumerically(">=", 26*MB))
127+
128+
waitForNInstancesRunning(appGUID, 2, finishTime.Sub(time.Now()))
129+
})
130+
131+
})
132+
133+
Context("when memoryutil is lower than scaling in threshold", func() {
134+
BeforeEach(func() {
135+
policy = generateDynamicScaleInPolicy(1, 2, "memoryutil", 80)
136+
initialInstanceCount = 2
137+
})
138+
It("should scale in", func() {
139+
totalTime := time.Duration(interval*2)*time.Second + 3*time.Minute
140+
finishTime := time.Now().Add(totalTime)
141+
142+
Eventually(func() uint64 {
143+
return averageMemoryUsedByInstance(appGUID, totalTime)
144+
}, totalTime, 15*time.Second).Should(BeNumerically("<", 115*MB))
145+
146+
waitForNInstancesRunning(appGUID, 1, finishTime.Sub(time.Now()))
147+
})
148+
})
149+
150+
})
101151
})

src/acceptance/app/recurring_schedule_policy_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ var _ = Describe("AutoScaler recurring schedule policy", func() {
4848
Expect(deleteService).To(Exit(0))
4949
})
5050

51-
Context("when scale out by recurring schedule", func() {
51+
Context("when scaling by recurring schedule", func() {
5252

5353
JustBeforeEach(func() {
5454

55-
Expect(cf.Cf("start", appName).Wait(cfg.DefaultTimeoutDuration() * 3)).To(Exit(0))
55+
Expect(cf.Cf("start", appName).Wait(cfg.CfPushTimeoutDuration())).To(Exit(0))
5656
waitForNInstancesRunning(appGUID, initialInstanceCount, cfg.DefaultTimeoutDuration())
5757

5858
location, err := time.LoadLocation("GMT")
@@ -75,12 +75,12 @@ var _ = Describe("AutoScaler recurring schedule policy", func() {
7575
})
7676

7777
It("should scale", func() {
78-
waitTime := startTime.Sub(time.Now()) + 1*time.Minute
7978
By("setting to initial_min_instance_count")
80-
waitForNInstancesRunning(appGUID, 3, waitTime)
79+
jobRunTime := startTime.Add(1 * time.Minute).Sub(time.Now())
80+
waitForNInstancesRunning(appGUID, 3, jobRunTime)
8181

8282
By("setting schedule's instance_min_count")
83-
jobRunTime := endTime.Sub(time.Now())
83+
jobRunTime = endTime.Sub(time.Now())
8484
Eventually(func() int {
8585
return runningInstances(appGUID, jobRunTime)
8686
}, jobRunTime, 15*time.Second).Should(Equal(2))
@@ -102,13 +102,12 @@ var _ = Describe("AutoScaler recurring schedule policy", func() {
102102
})
103103

104104
It("should scale", func() {
105-
waitTime := startTime.Sub(time.Now()) + 1*time.Minute
106-
107105
By("setting to initial_min_instance_count")
108-
waitForNInstancesRunning(appGUID, 3, waitTime)
106+
jobRunTime := startTime.Add(1 * time.Minute).Sub(time.Now())
107+
waitForNInstancesRunning(appGUID, 3, jobRunTime)
109108

110109
By("setting schedule's instance_min_count")
111-
jobRunTime := endTime.Sub(time.Now())
110+
jobRunTime = endTime.Sub(time.Now())
112111
Eventually(func() int {
113112
return runningInstances(appGUID, jobRunTime)
114113
}, jobRunTime, 15*time.Second).Should(Equal(2))

0 commit comments

Comments
 (0)