Skip to content

Commit 908b627

Browse files
committed
Run watch serving in separate groutine
Signed-off-by: Eric Lin <[email protected]>
1 parent 91cecde commit 908b627

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

Diff for: staging/src/k8s.io/apiserver/pkg/endpoints/handlers/get.go

+22-6
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141
"k8s.io/apiserver/pkg/endpoints/request"
4242
"k8s.io/apiserver/pkg/features"
4343
"k8s.io/apiserver/pkg/registry/rest"
44+
genericfilters "k8s.io/apiserver/pkg/server/filters"
4445
utilfeature "k8s.io/apiserver/pkg/util/feature"
4546
"k8s.io/component-base/tracing"
4647
"k8s.io/klog/v2"
@@ -259,7 +260,7 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatc
259260
}
260261
klog.V(3).InfoS("Starting watch", "path", req.URL.Path, "resourceVersion", opts.ResourceVersion, "labels", opts.LabelSelector, "fields", opts.FieldSelector, "timeout", timeout)
261262
ctx, cancel := context.WithTimeout(ctx, timeout)
262-
defer cancel()
263+
defer func() { cancel() }()
263264
watcher, err := rw.Watch(ctx, &opts)
264265
if err != nil {
265266
scope.err(err, w, req)
@@ -270,11 +271,26 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatc
270271
scope.err(err, w, req)
271272
return
272273
}
273-
requestInfo, _ := request.RequestInfoFrom(ctx)
274-
metrics.RecordLongRunning(req, requestInfo, metrics.APIServerComponent, func() {
275-
defer watcher.Stop()
276-
handler.ServeHTTP(w, req)
277-
})
274+
// Invalidate cancel() to defer until serve() is complete.
275+
deferredCancel := cancel
276+
cancel = func() {}
277+
278+
serve := func() {
279+
defer deferredCancel()
280+
requestInfo, _ := request.RequestInfoFrom(ctx)
281+
metrics.RecordLongRunning(req, requestInfo, metrics.APIServerComponent, func() {
282+
defer watcher.Stop()
283+
handler.ServeHTTP(w, req)
284+
})
285+
}
286+
287+
// Run watch serving in a separate goroutine to allow freeing current stack memory
288+
t := genericfilters.TaskFrom(req.Context())
289+
if t != nil {
290+
t.Func = serve
291+
} else {
292+
serve()
293+
}
278294
return
279295
}
280296

Diff for: staging/src/k8s.io/apiserver/pkg/features/kube_features.go

+8
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ const (
9090
// Add support for distributed tracing in the API Server
9191
APIServerTracing featuregate.Feature = "APIServerTracing"
9292

93+
// owner: @linxiulei
94+
// beta: v1.30
95+
//
96+
// Enables serving watch requests in separate goroutines.
97+
APIServingWithRoutine featuregate.Feature = "APIServingWithRoutine"
98+
9399
// owner: @cici37 @jpbetz
94100
// kep: http://kep.k8s.io/3488
95101
// alpha: v1.26
@@ -278,6 +284,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
278284

279285
APIServerTracing: {Default: true, PreRelease: featuregate.Beta},
280286

287+
APIServingWithRoutine: {Default: true, PreRelease: featuregate.Beta},
288+
281289
ValidatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Beta},
282290

283291
CustomResourceValidationExpressions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31

Diff for: staging/src/k8s.io/apiserver/pkg/server/config.go

+5
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,11 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
10381038
handler = genericapifilters.WithTracing(handler, c.TracerProvider)
10391039
}
10401040
handler = genericapifilters.WithLatencyTrackers(handler)
1041+
// WithRoutine will execute future handlers in a separate goroutine and serving
1042+
// handler in current goroutine to minimize the stack memory usage.
1043+
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServingWithRoutine) {
1044+
handler = genericfilters.WithRoutine(handler, c.LongRunningFunc)
1045+
}
10411046
handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver)
10421047
handler = genericapifilters.WithRequestReceivedTimestamp(handler)
10431048
handler = genericapifilters.WithMuxAndDiscoveryComplete(handler, c.lifecycleSignals.MuxAndDiscoveryComplete.Signaled())

0 commit comments

Comments
 (0)