-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Performance enhancements for the rules matchers. #3563
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution @ShaneSaww.
First review
middlewares/reqHost.go
Outdated
|
||
var reqHostKey struct{} | ||
|
||
// ReqHostMiddleware is the struct for the middleware that adds the CanonicalDomain of the requst Host into a context for later use. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please replace requst
by request
middlewares/reqHost.go
Outdated
// ReqHostMiddleware is the struct for the middleware that adds the CanonicalDomain of the requst Host into a context for later use. | ||
type ReqHostMiddleware struct{} | ||
|
||
// NewReqHostMiddleware is a middleware that adds the CanonicalDomain of the requst Host into a context for later use. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please replace requst
by request
middlewares/reqHost.go
Outdated
} | ||
} | ||
|
||
// GetCannonHost plucks the cannonized host key from the requst of a context that was put through the middleware |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please replace requst
by request
and cannonized
by canonized
middlewares/reqHost.go
Outdated
} | ||
|
||
// GetCannonHost plucks the cannonized host key from the requst of a context that was put through the middleware | ||
func GetCannonHost(ctx context.Context) (string, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should maybe rename into GetCanonHost
middlewares/reqHost.go
Outdated
var reqHostKey struct{} | ||
|
||
// ReqHostMiddleware is the struct for the middleware that adds the CanonicalDomain of the requst Host into a context for later use. | ||
type ReqHostMiddleware struct{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you rename ReqHostMiddleware
by ReqHost
please
middlewares/reqHost.go
Outdated
type ReqHostMiddleware struct{} | ||
|
||
// NewReqHostMiddleware is a middleware that adds the CanonicalDomain of the requst Host into a context for later use. | ||
func NewReqHostMiddleware() *ReqHostMiddleware { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is not necessary, you could directly use &ReqHostMiddleware{}
instead of creating a function for that. Like it is done for Compress
or AddPrefix
middlewares
middlewares/reqHost.go
Outdated
return &ReqHostMiddleware{} | ||
} | ||
|
||
func (rhm *ReqHostMiddleware) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could maybe rename rhm
with rh
middlewares/reqHost.go
Outdated
} | ||
|
||
func (rhm *ReqHostMiddleware) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { | ||
reqHost := r.Host |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could maybe simplify like that
func (rh *ReqHostMiddleware) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
reqHost := types.CanonicalDomain(parseHost(r.Host))
if next != nil {
next.ServeHTTP(rw, r.WithContext(context.WithValue(r.Context(), reqHostKey, reqHost)))
}
}
func parseHost(addr string) string {
if !strings.Contains(addr, ":") {
return addr
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
return addr
}
return host
}
WDYT?
And you should be able to test parseHost
function
The code freeze happen today, so I will do the change to be able to merge your PR today before the code freeze |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
2a2c370
to
3b19e92
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is another way to optimize.
I will do tests
833b7de
to
c80d5bd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really happy to add a middleware that call CanonicalDomain
for all requests.
But for now LGTM
This commit works towards calling types.CannonicalDomain less and reducing the amount of calls that are in the hotpath for a request. The big change here is moving the cannon'd request Host header into a middleware so it only has be cannonized once per request.
This commit works towards calling
types.CannonicalDomain
less and reducing the amount of calls that are in the hotpath for a request.The big change here is moving the cannon'd request Host header into a middleware so it only has be cannonized once per request.
What does this PR do?
This PR creates a middleware that gets hit early on in the request lifecycle and puts then
CanonicalDomain
request host into a context to be read during the route Matcher funcs.Along with that this re-works the matcherFuncs to call
CanonicalDomain
less by using the context, and callingCanonicalDomain
for the hosts at the initialization of the matcherFunc not inside the matcher func where it's expensive.Motivation
Performance tuning in our production environment showed that
CanonicalDomain
was using a good chunk of CPU time.See the include flameGraph photos of the
matcherFunc
section.Before:
After:
More
Additional Notes