-
Notifications
You must be signed in to change notification settings - Fork 113
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
OCPBUGS-26498: Make ingressConditionsEqual more efficient #588
OCPBUGS-26498: Make ingressConditionsEqual more efficient #588
Conversation
Add missing key to log statement and log when a worker becomes elected to leader or demoted to a follower for better clarity in router logs.
@gcs278: This pull request references Jira Issue OCPBUGS-26498, which is valid. 3 validation(s) were run on this bug
Requesting review from QA contact: The bug has been updated to refer to the pull request using the external bug tracker. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
Introduces verbose (level 10) logging to trace plugin chain execution. A bug was identified where the plugin chain halted unexpectedly, and logging the plugin chain steps aids in debugging.
Add verbose logging to help indicate the router is attempting to update a route status. This is helpful for debugging racy router status logic.
27cfb9a
to
b1bea4d
Compare
pkg/router/controller/contention.go
Outdated
// Sort both slices by Type to ensure they are in the same order for comparison. | ||
sort.Slice(a, func(i, j int) bool { return a[i].Type < a[j].Type }) | ||
sort.Slice(b, func(i, j int) bool { return b[i].Type < b[j].Type }) |
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.
Have you done benchmarks on this code? sort.Slice
uses reflection, albeit the lighter-weight reflectlite
rather than the standard reflect
package, and even without that, the underlying quicksort algorithm implementation is probably slower than a nested loop for the expected number of items (namely 0 or 1 in the usual case, 2 in the exceptional case). If benchmarks show that sort.Slice
is fast enough, though, then it doesn't really matter. (If you do write a benchmark, consider using testing.B
and adding the benchmark to pkg/router/controller/status_test.go
.)
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.
Good point. I need to back this up with some data. I added a benchmark function (first time I've ever done that) and provided various results in the PR description.
The benchmark with sort.Slice
results show it's ~500x faster (I'm comparing ns/op
). I stopped there.
BUT I just tried out nested loops, and I see it's ~5000-7000x faster. You are right, where 2 conditions are our max, nested loops are faster than sort.Slice
..
b1bea4d
to
c97331f
Compare
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Miciah The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
A suggestion for improved performance: % git diff
diff --git a/pkg/router/controller/contention.go b/pkg/router/controller/contention.go
index 0d866406..0f159bf7 100644
--- a/pkg/router/controller/contention.go
+++ b/pkg/router/controller/contention.go
@@ -263,10 +263,10 @@ func ingressConditionsEqual(a, b []routev1.RouteIngressCondition) bool {
// Compare each condition in a with every condition in b.
// Given the current max of only two conditions, nested loops are more efficient than sorting.
- for _, condA := range a {
+ for i := 0; i < len(a); i++ {
matchFound := false
- for _, condB := range b {
- if conditionsEqual(condA, condB) {
+ for j := 0; j < len(b); j++ {
+ if conditionsEqual(&a[i], &b[j]) {
matchFound = true
break
}
@@ -280,7 +280,7 @@ func ingressConditionsEqual(a, b []routev1.RouteIngressCondition) bool {
}
// conditionsEqual compares two RouteIngressConditions, ignoring LastTransitionTime.
-func conditionsEqual(a, b routev1.RouteIngressCondition) bool {
+func conditionsEqual(a, b *routev1.RouteIngressCondition) bool {
return a.Type == b.Type &&
a.Status == b.Status &&
a.Reason == b.Reason && Benchmarking shows: % go test -bench=. -run=Benchmark_ingressConditionsEqual ./... -benchtime=10s
goos: linux
goarch: amd64
pkg: github.com/openshift/router/pkg/router/controller
cpu: 11th Gen Intel(R) Core(TM) i9-11900 @ 2.50GHz
Benchmark_ingressConditionsEqual/single-16 1000000000 3.422 ns/op
Benchmark_ingressConditionsEqual/mismatch_length-16 1000000000 1.487 ns/op
Benchmark_ingressConditionsEqual/double-16 880706917 13.74 ns/op |
}, | ||
}, | ||
} | ||
for _, tc := range testCases { |
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.
Although there's very minimal setup here you could call b.ResetTimer()
to take any current or future setup costs out of the numbers.
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.
Done.
We found that the router's contention tracker was slower after updates were made to support the UnservableInFutureVersions condition. This lag sometimes causes routers to update the route status before the contention tracker detected an update, leading to the per-route contention logic not activating. In such scenarios, the maxContentions logic eventually activates, temporarily preventing the router from making any updates to the routes. This commit improves the efficiency of the ingressConditionsEqual function to help mitigate this type of issues.
c97331f
to
44f217f
Compare
Done, thanks @frobware |
/lgtm |
/hold cancel |
I see something funny in my origin E2E test, just going to hold out of precaution until I understand. |
Never mind, I mistakenly was testing with the wrong router image and thought there was a regression... |
@gcs278: The following test failed, say
Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
b6f7c63
into
openshift:master
@gcs278: Jira Issue OCPBUGS-26498: Some pull requests linked via external trackers have merged: The following pull requests linked via external trackers have not merged: These pull request must merge or be unlinked from the Jira bug in order for it to move to the next state. Once unlinked, request a bug refresh with Jira Issue OCPBUGS-26498 has not been moved to the MODIFIED state. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
[ART PR BUILD NOTIFIER] This PR has been included in build ose-haproxy-router-base-container-v4.17.0-202404302014.p0.gb6f7c63.assembly.stream.el9 for distgit ose-haproxy-router-base. |
We found that the router's contention tracker was slower after updates were made to support the UnservableInFutureVersions condition. This lag sometimes causes routers to update the route status before the contention tracker detected an update, leading to the per-route contention logic not activating.
In such scenarios, the maxContentions logic eventually activates, temporarily preventing the router from making any updates to the routes. This commit improves the efficiency of the ingressConditionsEqual function to help mitigate this type of issues.
Related slack thread.
Current PR Benchmark Results (Nested Loops):
Using
sort.Slice
Benchmark Results (Previous PR Revision b1bea4d):Post-#555 Benchmark Results (Not this PR):
Pre-#555 Benchmark Results:
Also, I have included some trivial logging improvements that will help debugging racy conditions.