-
Notifications
You must be signed in to change notification settings - Fork 904
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
fix deep equal check failure in CreateOrUpdateWork(), by replace the marshaler #5939
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #5939 +/- ##
=======================================
Coverage 48.37% 48.37%
=======================================
Files 666 666
Lines 54831 54831
=======================================
Hits 26524 26524
Misses 26590 26590
Partials 1717 1717
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Hi @zach593, I am trying to use this issue to design a performance monitoring case, my case is as follows:
Do you think there are better optimization opportunities for my case? |
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, the current pr resolves the deepcopy failure issue and dose not introduce new performance risks.
About the kind/bug
label. do you expect to sync the current pr to the previous release versions? If we don't need to, maybe we can modify the label.
@chaosi-zju As we discussed in zoom, for the performance optimization, this PR is not enough, I may need another 2 PRs to complete this goal. Since I need more than one PR, I created #6017 to track it, and we can have further discussion in that issue. |
Sure, can you help with that? I'm not familiar with commands with |
BTW, I think we could consider use |
/remove-kind bug |
ok, thanks, I think this PR can move forward first /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.
/assign
I will take a look this week.
pkg/util/helper/work.go
Outdated
@@ -54,7 +55,7 @@ func CreateOrUpdateWork(ctx context.Context, client client.Client, workMeta meta | |||
} | |||
} | |||
|
|||
workloadJSON, err := resource.MarshalJSON() | |||
workloadJSON, err := json.Marshal(resource) |
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.
Is there any difference between encoding/json.Marshal
and unstructured.MarshalJSON
other than the /n
?
I am mostly curious about functionality and performance.
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.
In addition, I think we need to check all of the places where using the unstructured.MarshalJSON
.
PS: I don't mean to check and fix them all in this PR. Just remind me.
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.
Tracked this on #6031, please correct me if anyone feels this is unnecessary.
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.
Is there any difference between
encoding/json.Marshal
andunstructured.MarshalJSON
other than the/n
?
I am mostly curious about functionality and performance.
I did a benchmark test to compare different json marshal function, my test code is as:
benchmark test code
func BenchmarkMarshalJSON(b *testing.B) {
resource := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "test-deployment",
"namespace": "default",
},
"spec": map[string]interface{}{
"replicas": 3,
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"app": "test",
},
},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"app": "test",
},
},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "test-container",
"image": "nginx:latest",
},
},
},
},
},
},
}
b.Run("resource.MarshalJSON", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = resource.MarshalJSON()
}
})
b.Run("json.Marshal", func(b *testing.B) {
for i := 0; i < b.N; i++ {
// "encoding/json"
_, _ = json.Marshal(resource)
}
})
b.Run("jsoniter.Marshal", func(b *testing.B) {
for i := 0; i < b.N; i++ {
// jsoniter "github.com/json-iterator/go"
_, _ = jsoniter.Marshal(resource)
}
})
}
the result is:
goos: windows
goarch: amd64
pkg: github.com/karmada-io/karmada/pkg/controllers/ctrlutil
cpu: Intel(R) Core(TM) i5-14600KF
BenchmarkMarshalJSON
BenchmarkMarshalJSON/resource.MarshalJSON
BenchmarkMarshalJSON/resource.MarshalJSON-20 398614 2835 ns/op
BenchmarkMarshalJSON/json.Marshal
BenchmarkMarshalJSON/json.Marshal-20 307854 4004 ns/op
BenchmarkMarshalJSON/jsoniter.Marshal
BenchmarkMarshalJSON/jsoniter.Marshal-20 393528 3019 ns/op
PASS
and
goos: windows
goarch: amd64
pkg: github.com/karmada-io/karmada/pkg/util/helper
cpu: Intel(R) Xeon(R) Gold 6278C CPU @ 2.60GHz
BenchmarkMarshalJSON
BenchmarkMarshalJSON/resource.MarshalJSON
BenchmarkMarshalJSON/resource.MarshalJSON-4 95715 13065 ns/op
BenchmarkMarshalJSON/json.Marshal
BenchmarkMarshalJSON/json.Marshal-4 68590 16391 ns/op
BenchmarkMarshalJSON/jsoniter.Marshal
BenchmarkMarshalJSON/jsoniter.Marshal-4 79052 13281 ns/op
PASS
seems previous unstructured.MarshalJSON
perform better, while encoding/json.Marshal
worst
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.
resource.MarshalJSON()
is specifically optimized for the unstructured.Unstructured
type, potentially offering significant performance improvements when handling large numbers of Kubernetes resources.
besides, Kubernetes resources may contain fields that require special treatment during serialization, which can be handled by the custom method, for example:
- Timestamp fields like
creationTimestamp
may need to be formatted in a particular way. - Some fields might need to be omitted entirely when they're empty, rather than being serialized as null.
- Certain fields may require custom serialization rules to maintain backward compatibility with older API versions.
- Resource-specific fields (like status in various resources) might need special treatment during serialization.
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.
json.Marshal()
also calls x.MarshalJSON()
inside because unstructured.Unstructured
implemented the json.Marshaler
interface by implemented MarshalJSON()
function.
…marshaler Signed-off-by: zach593 <[email protected]>
afc1a3c
to
ce1ca99
Compare
New changes are detected. LGTM label has been removed. |
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What type of PR is this?
/kind bug
What this PR does / why we need it:
see #5938
Which issue(s) this PR fixes:
Fixes #5938
Special notes for your reviewer:
Does this PR introduce a user-facing change?: