Skip to content

Commit 5ab5ce0

Browse files
authored
xds/resolver: Optimize Interceptor Chain Construction (#8641)
#### Existing behavior: - At routing time, when an RPC matches a route and a cluster is selected, the interceptor chain for that specific RPC is built. - This chain is built on a per-RPC basis. - A subsequent RPC that matches the exact same route and cluster will trigger the entire chain reconstruction again, even if no configuration has changed. #### New behavior: - The interceptor chain is now pre-built for every route and every pickable cluster associated with that route. - The chains are constructed once when the config selector is built. #### Other changes: - Existing unit tests have been converted to be more e2e style tests. - This lays the necessary groundwork for upcoming changes to the filter API, specifically to support filter state retention RELEASE NOTES: NONE
1 parent 9c2cd38 commit 5ab5ce0

File tree

4 files changed

+712
-452
lines changed

4 files changed

+712
-452
lines changed

internal/xds/resolver/serviceconfig.go

Lines changed: 37 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -97,28 +97,23 @@ func serviceConfigJSON(activeClusters map[string]*clusterInfo) []byte {
9797
}
9898

9999
type virtualHost struct {
100-
// map from filter name to its config
101-
httpFilterConfigOverride map[string]httpfilter.FilterConfig
102100
// retry policy present in virtual host
103101
retryConfig *xdsresource.RetryConfig
104102
}
105103

106104
// routeCluster holds information about a cluster as referenced by a route.
107105
type routeCluster struct {
108-
name string
109-
// map from filter name to its config
110-
httpFilterConfigOverride map[string]httpfilter.FilterConfig
106+
name string // Name of the cluster.
107+
interceptor iresolver.ClientInterceptor // HTTP filters to run for RPCs matching this route.
111108
}
112109

113110
type route struct {
114111
m *xdsresource.CompositeMatcher // converted from route matchers
115112
actionType xdsresource.RouteActionType // holds route action type
116113
clusters wrr.WRR // holds *routeCluster entries
117114
maxStreamDuration time.Duration
118-
// map from filter name to its config
119-
httpFilterConfigOverride map[string]httpfilter.FilterConfig
120-
retryConfig *xdsresource.RetryConfig
121-
hashPolicies []*xdsresource.HashPolicy
115+
retryConfig *xdsresource.RetryConfig
116+
hashPolicies []*xdsresource.HashPolicy
122117
}
123118

124119
func (r route) String() string {
@@ -200,11 +195,6 @@ func (cs *configSelector) SelectConfig(rpcInfo iresolver.RPCInfo) (*iresolver.RP
200195
ref := &cs.clusters[cluster.name].refCount
201196
atomic.AddInt32(ref, 1)
202197

203-
interceptor, err := cs.newInterceptor(rt, cluster)
204-
if err != nil {
205-
return nil, annotateErrorWithNodeID(err, cs.xdsNodeID)
206-
}
207-
208198
lbCtx := clustermanager.SetPickedCluster(rpcInfo.Context, cluster.name)
209199
lbCtx = iringhash.SetXDSRequestHash(lbCtx, cs.generateHash(rpcInfo, rt.hashPolicies))
210200

@@ -220,7 +210,7 @@ func (cs *configSelector) SelectConfig(rpcInfo iresolver.RPCInfo) (*iresolver.RP
220210
cs.sendNewServiceConfig()
221211
}
222212
},
223-
Interceptor: interceptor,
213+
Interceptor: cluster.interceptor,
224214
}
225215

226216
if rt.maxStreamDuration != 0 {
@@ -310,35 +300,6 @@ func (cs *configSelector) generateHash(rpcInfo iresolver.RPCInfo, hashPolicies [
310300
return rand.Uint64()
311301
}
312302

313-
func (cs *configSelector) newInterceptor(rt *route, cluster *routeCluster) (iresolver.ClientInterceptor, error) {
314-
if len(cs.httpFilterConfig) == 0 {
315-
return nil, nil
316-
}
317-
interceptors := make([]iresolver.ClientInterceptor, 0, len(cs.httpFilterConfig))
318-
for _, filter := range cs.httpFilterConfig {
319-
override := cluster.httpFilterConfigOverride[filter.Name] // cluster is highest priority
320-
if override == nil {
321-
override = rt.httpFilterConfigOverride[filter.Name] // route is second priority
322-
}
323-
if override == nil {
324-
override = cs.virtualHost.httpFilterConfigOverride[filter.Name] // VH is third & lowest priority
325-
}
326-
ib, ok := filter.Filter.(httpfilter.ClientInterceptorBuilder)
327-
if !ok {
328-
// Should not happen if it passed xdsClient validation.
329-
return nil, fmt.Errorf("filter does not support use in client")
330-
}
331-
i, err := ib.BuildClientInterceptor(filter.Config, override)
332-
if err != nil {
333-
return nil, fmt.Errorf("error constructing filter: %v", err)
334-
}
335-
if i != nil {
336-
interceptors = append(interceptors, i)
337-
}
338-
}
339-
return &interceptorList{interceptors: interceptors}, nil
340-
}
341-
342303
// stop decrements refs of all clusters referenced by this config selector.
343304
func (cs *configSelector) stop() {
344305
// The resolver's old configSelector may be nil. Handle that here.
@@ -363,6 +324,38 @@ func (cs *configSelector) stop() {
363324
}
364325
}
365326

327+
// newInterceptor builds a chain of client interceptors for the given filters
328+
// and override configuration. The cluster override has the highest priority,
329+
// followed by the route override, and finally the virtual host override.
330+
func newInterceptor(filters []xdsresource.HTTPFilter, clusterOverride, routeOverride, virtualHostOverride map[string]httpfilter.FilterConfig) (iresolver.ClientInterceptor, error) {
331+
if len(filters) == 0 {
332+
return nil, nil
333+
}
334+
interceptors := make([]iresolver.ClientInterceptor, 0, len(filters))
335+
for _, filter := range filters {
336+
override := clusterOverride[filter.Name]
337+
if override == nil {
338+
override = routeOverride[filter.Name]
339+
}
340+
if override == nil {
341+
override = virtualHostOverride[filter.Name]
342+
}
343+
ib, ok := filter.Filter.(httpfilter.ClientInterceptorBuilder)
344+
if !ok {
345+
// Should not happen if it passed xdsClient validation.
346+
return nil, fmt.Errorf("filter %q does not support use in client", filter.Name)
347+
}
348+
i, err := ib.BuildClientInterceptor(filter.Config, override)
349+
if err != nil {
350+
return nil, fmt.Errorf("error constructing filter: %v", err)
351+
}
352+
if i != nil {
353+
interceptors = append(interceptors, i)
354+
}
355+
}
356+
return &interceptorList{interceptors: interceptors}, nil
357+
}
358+
366359
type interceptorList struct {
367360
interceptors []iresolver.ClientInterceptor
368361
}

0 commit comments

Comments
 (0)