Skip to content

Commit a1fa8c2

Browse files
krithika369Krithika Sundararajan
andauthored
Add UserContainerLimitRequestFactor config to determine resource limit from request (#146)
* Set resource limit = request * Add Knative config UserContainerLimitRequestFactor to control the resource limit fraction Co-authored-by: Krithika Sundararajan <[email protected]>
1 parent 5bb6c15 commit a1fa8c2

14 files changed

+182
-116
lines changed

api/turing/cluster/knative_service.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,13 @@ type KnativeService struct {
3535
ContainerPort int32 `json:"containerPort"`
3636

3737
// Autoscaling properties
38-
MinReplicas int `json:"minReplicas"`
39-
MaxReplicas int `json:"maxReplicas"`
40-
TargetConcurrency int `json:"targetConcurrency"`
41-
QueueProxyResourcePercentage int `json:"queueProxyResourcePercentage"`
38+
MinReplicas int `json:"minReplicas"`
39+
MaxReplicas int `json:"maxReplicas"`
40+
TargetConcurrency int `json:"targetConcurrency"`
41+
42+
// Resource properties
43+
QueueProxyResourcePercentage int `json:"queueProxyResourcePercentage"`
44+
UserContainerLimitRequestFactor float64 `json:"userContainerLimitRequestFactor"`
4245
}
4346

4447
// Creates a new config object compatible with the knative serving API, from
@@ -101,7 +104,7 @@ func (cfg *KnativeService) buildSvcSpec(
101104
revisionName := fmt.Sprintf("%s-0", cfg.Name)
102105

103106
// Build resource requirements for the user container
104-
resourceReqs := cfg.buildResourceReqs()
107+
resourceReqs := cfg.buildResourceReqs(cfg.UserContainerLimitRequestFactor)
105108

106109
// Build container spec
107110
container := corev1.Container{

api/turing/cluster/knative_service_test.go

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ func TestBuildKnativeServiceConfig(t *testing.T) {
9090
var timeout int64 = 30
9191
resources := corev1.ResourceRequirements{
9292
Limits: map[corev1.ResourceName]resource.Quantity{
93-
corev1.ResourceCPU: resource.MustParse("800m"),
94-
corev1.ResourceMemory: resource.MustParse("1024Mi"),
93+
corev1.ResourceCPU: resource.MustParse("600m"),
94+
corev1.ResourceMemory: resource.MustParse("768Mi"),
9595
},
9696
Requests: map[corev1.ResourceName]resource.Quantity{
9797
corev1.ResourceCPU: resource.MustParse("400m"),
@@ -159,13 +159,14 @@ func TestBuildKnativeServiceConfig(t *testing.T) {
159159
}{
160160
"basic": {
161161
serviceCfg: KnativeService{
162-
BaseService: baseSvc,
163-
ContainerPort: 8080,
164-
MinReplicas: 1,
165-
MaxReplicas: 2,
166-
IsClusterLocal: true,
167-
TargetConcurrency: 1,
168-
QueueProxyResourcePercentage: 30,
162+
BaseService: baseSvc,
163+
ContainerPort: 8080,
164+
MinReplicas: 1,
165+
MaxReplicas: 2,
166+
IsClusterLocal: true,
167+
TargetConcurrency: 1,
168+
QueueProxyResourcePercentage: 30,
169+
UserContainerLimitRequestFactor: 1.5,
169170
},
170171
expectedSpec: knservingv1.Service{
171172
ObjectMeta: metav1.ObjectMeta{
@@ -203,12 +204,13 @@ func TestBuildKnativeServiceConfig(t *testing.T) {
203204
},
204205
"annotations": {
205206
serviceCfg: KnativeService{
206-
BaseService: baseSvc,
207-
ContainerPort: 8080,
208-
MinReplicas: 5,
209-
MaxReplicas: 6,
210-
IsClusterLocal: false,
211-
TargetConcurrency: 4,
207+
BaseService: baseSvc,
208+
ContainerPort: 8080,
209+
MinReplicas: 5,
210+
MaxReplicas: 6,
211+
IsClusterLocal: false,
212+
TargetConcurrency: 4,
213+
UserContainerLimitRequestFactor: 1.5,
212214
},
213215
expectedSpec: knservingv1.Service{
214216
ObjectMeta: metav1.ObjectMeta{

api/turing/cluster/kubernetes_service.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import (
77
"k8s.io/apimachinery/pkg/util/intstr"
88
)
99

10+
// defaultLimitRequestFactor is the default multiplication factor applied to the resource request,
11+
// to be set as resource limit
12+
const defaultLimitRequestFactor = 1.0
13+
1014
// KubernetesService defines the properties for Kubernetes services
1115
type KubernetesService struct {
1216
*BaseService
@@ -57,7 +61,7 @@ func (cfg *KubernetesService) buildDeployment(labels map[string]string) *appsv1.
5761
Args: cfg.Command,
5862
Ports: cfg.buildContainerPorts(),
5963
Env: cfg.Envs,
60-
Resources: cfg.buildResourceReqs(),
64+
Resources: cfg.buildResourceReqs(defaultLimitRequestFactor),
6165
VolumeMounts: cfg.VolumeMounts,
6266
LivenessProbe: cfg.buildContainerProbe(livenessProbeType, int(cfg.ProbePort)),
6367
ReadinessProbe: cfg.buildContainerProbe(readinessProbeType, int(cfg.ProbePort)),

api/turing/cluster/kubernetes_service_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ func TestBuildKubernetesServiceConfig(t *testing.T) {
109109
corev1.ResourceMemory: resource.MustParse("1"),
110110
},
111111
Limits: map[corev1.ResourceName]resource.Quantity{
112-
corev1.ResourceCPU: resource.MustParse("2"),
113-
corev1.ResourceMemory: resource.MustParse("2"),
112+
corev1.ResourceCPU: resource.MustParse("1"),
113+
corev1.ResourceMemory: resource.MustParse("1"),
114114
},
115115
},
116116
VolumeMounts: svcConf.VolumeMounts,

api/turing/cluster/models.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cluster
22

33
import (
4+
"math"
5+
46
corev1 "k8s.io/api/core/v1"
57
"k8s.io/apimachinery/pkg/api/resource"
68
"k8s.io/apimachinery/pkg/util/intstr"
@@ -64,20 +66,16 @@ type BaseService struct {
6466
VolumeMounts []corev1.VolumeMount `json:"volume_mounts"`
6567
}
6668

67-
func (cfg *BaseService) buildResourceReqs() corev1.ResourceRequirements {
69+
func (cfg *BaseService) buildResourceReqs(userContainerLimitRequestFactor float64) corev1.ResourceRequirements {
6870
reqs := map[corev1.ResourceName]resource.Quantity{
6971
corev1.ResourceCPU: cfg.CPURequests,
7072
corev1.ResourceMemory: cfg.MemoryRequests,
7173
}
7274

73-
// Set resource limits to twice the request
74-
cpuLimit := cfg.CPURequests.DeepCopy()
75-
cpuLimit.Add(cpuLimit)
76-
memoryLimit := cfg.MemoryRequests.DeepCopy()
77-
memoryLimit.Add(memoryLimit)
75+
// Set resource limits to request * userContainerLimitRequestFactor
7876
limits := map[corev1.ResourceName]resource.Quantity{
79-
corev1.ResourceCPU: cpuLimit,
80-
corev1.ResourceMemory: memoryLimit,
77+
corev1.ResourceCPU: computeResource(cfg.CPURequests, userContainerLimitRequestFactor),
78+
corev1.ResourceMemory: computeResource(cfg.MemoryRequests, userContainerLimitRequestFactor),
8179
}
8280

8381
return corev1.ResourceRequirements{
@@ -130,3 +128,22 @@ type ConfigMap struct {
130128
FileName string `json:"file_name"`
131129
Data string `json:"data"`
132130
}
131+
132+
// Ref:
133+
// https://github.com/knative/serving/blob/release-0.14/pkg/reconciler/revision/resources/queue.go#L115
134+
func computeResource(resourceQuantity resource.Quantity, fraction float64) resource.Quantity {
135+
scaledValue := resourceQuantity.Value()
136+
scaledMilliValue := int64(math.MaxInt64 - 1)
137+
if scaledValue < (math.MaxInt64 / 1000) {
138+
scaledMilliValue = resourceQuantity.MilliValue()
139+
}
140+
141+
percentageValue := float64(scaledMilliValue) * fraction
142+
newValue := int64(math.MaxInt64)
143+
if percentageValue < math.MaxInt64 {
144+
newValue = int64(percentageValue)
145+
}
146+
147+
newquantity := resource.NewMilliQuantity(newValue, resource.BinarySI)
148+
return *newquantity
149+
}

api/turing/cluster/servicebuilder/router.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func (sb *clusterSvcBuilder) NewRouterService(
9090
sentryDSN string,
9191
knativeTargetConcurrency int,
9292
knativeQueueProxyResourcePercentage int,
93+
userContainerLimitRequestFactor float64,
9394
) (*cluster.KnativeService, error) {
9495
// Create service name
9596
name := sb.GetRouterServiceName(routerVersion)
@@ -124,12 +125,13 @@ func (sb *clusterSvcBuilder) NewRouterService(
124125
Volumes: volumes,
125126
VolumeMounts: volumeMounts,
126127
},
127-
IsClusterLocal: false,
128-
ContainerPort: routerPort,
129-
MinReplicas: routerVersion.ResourceRequest.MinReplica,
130-
MaxReplicas: routerVersion.ResourceRequest.MaxReplica,
131-
TargetConcurrency: knativeTargetConcurrency,
132-
QueueProxyResourcePercentage: knativeQueueProxyResourcePercentage,
128+
IsClusterLocal: false,
129+
ContainerPort: routerPort,
130+
MinReplicas: routerVersion.ResourceRequest.MinReplica,
131+
MaxReplicas: routerVersion.ResourceRequest.MaxReplica,
132+
TargetConcurrency: knativeTargetConcurrency,
133+
QueueProxyResourcePercentage: knativeQueueProxyResourcePercentage,
134+
UserContainerLimitRequestFactor: userContainerLimitRequestFactor,
133135
}
134136
return sb.validateKnativeService(svc)
135137
}

api/turing/cluster/servicebuilder/router_test.go

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,12 @@ func TestNewRouterService(t *testing.T) {
147147
},
148148
},
149149
},
150-
ContainerPort: 8080,
151-
MinReplicas: 2,
152-
MaxReplicas: 4,
153-
TargetConcurrency: 1,
154-
QueueProxyResourcePercentage: 20,
150+
ContainerPort: 8080,
151+
MinReplicas: 2,
152+
MaxReplicas: 4,
153+
TargetConcurrency: 1,
154+
QueueProxyResourcePercentage: 20,
155+
UserContainerLimitRequestFactor: 1.5,
155156
},
156157
success: true,
157158
},
@@ -243,11 +244,12 @@ func TestNewRouterService(t *testing.T) {
243244
},
244245
},
245246
},
246-
ContainerPort: 8080,
247-
MinReplicas: 2,
248-
MaxReplicas: 4,
249-
TargetConcurrency: 1,
250-
QueueProxyResourcePercentage: 20,
247+
ContainerPort: 8080,
248+
MinReplicas: 2,
249+
MaxReplicas: 4,
250+
TargetConcurrency: 1,
251+
QueueProxyResourcePercentage: 20,
252+
UserContainerLimitRequestFactor: 1.5,
251253
},
252254
success: true,
253255
},
@@ -342,11 +344,12 @@ func TestNewRouterService(t *testing.T) {
342344
},
343345
},
344346
},
345-
ContainerPort: 8080,
346-
MinReplicas: 2,
347-
MaxReplicas: 4,
348-
TargetConcurrency: 1,
349-
QueueProxyResourcePercentage: 20,
347+
ContainerPort: 8080,
348+
MinReplicas: 2,
349+
MaxReplicas: 4,
350+
TargetConcurrency: 1,
351+
QueueProxyResourcePercentage: 20,
352+
UserContainerLimitRequestFactor: 1.5,
350353
},
351354
success: true,
352355
},
@@ -441,11 +444,12 @@ func TestNewRouterService(t *testing.T) {
441444
},
442445
},
443446
},
444-
ContainerPort: 8080,
445-
MinReplicas: 2,
446-
MaxReplicas: 4,
447-
TargetConcurrency: 1,
448-
QueueProxyResourcePercentage: 20,
447+
ContainerPort: 8080,
448+
MinReplicas: 2,
449+
MaxReplicas: 4,
450+
TargetConcurrency: 1,
451+
QueueProxyResourcePercentage: 20,
452+
UserContainerLimitRequestFactor: 1.5,
449453
},
450454
success: true,
451455
},
@@ -473,7 +477,7 @@ func TestNewRouterService(t *testing.T) {
473477
Team: "test-team",
474478
}
475479
svc, err := sb.NewRouterService(&routerVersion, project, "test-env", "service-account",
476-
data.expRawConfig, "fluentd-tag", "jaeger-endpoint", true, "sentry-dsn", 1, 20)
480+
data.expRawConfig, "fluentd-tag", "jaeger-endpoint", true, "sentry-dsn", 1, 20, 1.5)
477481

478482
if data.success {
479483
require.Nil(t, err)

api/turing/cluster/servicebuilder/service_builder.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ type ClusterServiceBuilder interface {
5757
secretName string,
5858
knativeTargetConcurrency int,
5959
knativeQueueProxyResourcePercentage int,
60+
userContainerLimitRequestFactor float64,
6061
) (*cluster.KnativeService, error)
6162
NewEnsemblerService(
6263
ver *models.RouterVersion,
@@ -65,6 +66,7 @@ type ClusterServiceBuilder interface {
6566
secretName string,
6667
knativeTargetConcurrency int,
6768
knativeQueueProxyResourcePercentage int,
69+
userContainerLimitRequestFactor float64,
6870
) (*cluster.KnativeService, error)
6971
NewRouterService(
7072
ver *models.RouterVersion,
@@ -78,6 +80,7 @@ type ClusterServiceBuilder interface {
7880
sentryDSN string,
7981
knativeTargetConcurrency int,
8082
knativeQueueProxyResourcePercentage int,
83+
userContainerLimitRequestFactor float64,
8184
) (*cluster.KnativeService, error)
8285
NewFluentdService(
8386
routerVersion *models.RouterVersion,
@@ -129,6 +132,7 @@ func (sb *clusterSvcBuilder) NewEnricherService(
129132
secretName string,
130133
knativeTargetConcurrency int,
131134
knativeQueueProxyResourcePercentage int,
135+
userContainerLimitRequestFactor float64,
132136
) (*cluster.KnativeService, error) {
133137
// Get the enricher reference
134138
enricher := routerVersion.Enricher
@@ -188,12 +192,13 @@ func (sb *clusterSvcBuilder) NewEnricherService(
188192
Volumes: volumes,
189193
VolumeMounts: volumeMounts,
190194
},
191-
IsClusterLocal: true,
192-
ContainerPort: int32(enricher.Port),
193-
MinReplicas: enricher.ResourceRequest.MinReplica,
194-
MaxReplicas: enricher.ResourceRequest.MaxReplica,
195-
TargetConcurrency: knativeTargetConcurrency,
196-
QueueProxyResourcePercentage: knativeQueueProxyResourcePercentage,
195+
IsClusterLocal: true,
196+
ContainerPort: int32(enricher.Port),
197+
MinReplicas: enricher.ResourceRequest.MinReplica,
198+
MaxReplicas: enricher.ResourceRequest.MaxReplica,
199+
TargetConcurrency: knativeTargetConcurrency,
200+
QueueProxyResourcePercentage: knativeQueueProxyResourcePercentage,
201+
UserContainerLimitRequestFactor: userContainerLimitRequestFactor,
197202
})
198203
}
199204

@@ -206,6 +211,7 @@ func (sb *clusterSvcBuilder) NewEnsemblerService(
206211
secretName string,
207212
knativeTargetConcurrency int,
208213
knativeQueueProxyResourcePercentage int,
214+
userContainerLimitRequestFactor float64,
209215
) (*cluster.KnativeService, error) {
210216
// Get the ensembler reference
211217
ensembler := routerVersion.Ensembler
@@ -266,12 +272,13 @@ func (sb *clusterSvcBuilder) NewEnsemblerService(
266272
Volumes: volumes,
267273
VolumeMounts: volumeMounts,
268274
},
269-
IsClusterLocal: true,
270-
ContainerPort: int32(docker.Port),
271-
MinReplicas: docker.ResourceRequest.MinReplica,
272-
MaxReplicas: docker.ResourceRequest.MaxReplica,
273-
TargetConcurrency: knativeTargetConcurrency,
274-
QueueProxyResourcePercentage: knativeQueueProxyResourcePercentage,
275+
IsClusterLocal: true,
276+
ContainerPort: int32(docker.Port),
277+
MinReplicas: docker.ResourceRequest.MinReplica,
278+
MaxReplicas: docker.ResourceRequest.MaxReplica,
279+
TargetConcurrency: knativeTargetConcurrency,
280+
QueueProxyResourcePercentage: knativeQueueProxyResourcePercentage,
281+
UserContainerLimitRequestFactor: userContainerLimitRequestFactor,
275282
})
276283
}
277284

0 commit comments

Comments
 (0)