-
Notifications
You must be signed in to change notification settings - Fork 39.8k
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
Share a single etcd3 client logger across all clients #111477
Conversation
This logger is responsible for 20% of the API server's memory usage when many CRDs are installed. See the below issue for more context. kubernetes#111476 Signed-off-by: Nic Cope <nicc@rk0n.org>
|
Hi @negz. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. 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. |
re: viability: Sounds like you're already thinking in this direction-- I'm relatively certain there is information being logged that would be sorely missed by cluster administrators when diagnosing etcd issues. Any idea what the current log level is and what volume of data was being logged in the 1k+ CRD case? |
I don't see anything being logged, but I just have a toy kind cluster with the CRDs loaded and no controllers or real clients. I imagine there might be interesting logs on a real cluster. Per #111476 (comment) this is almost certainly happening because we have one etcd client (and thus one logger) per CRD installed. I imagine we should probably share a client or pool of clients to etcd, but I'd love to get a fix for this memory usage into 1.25 and I believe the code freeze is days away. Perhaps a reasonable quick fix for this logger issue would be to create one logger and pass it into all newly created etcd clients? |
Currently the API server creates one etcd client per CRD. If clients aren't provided a logger they'll each create their own. These loggers can account for ~20% of API server memory consumption on a cluster with hundreds of CRDs. Signed-off-by: Nic Cope <nicc@rk0n.org>
|
Just pushed a commit and edited the PR description to have clients share one logger rather than each creating their own. |
staging/src/k8s.io/apiserver/pkg/storage/storagebackend/factory/etcd3.go
Outdated
Show resolved
Hide resolved
|
/ok-to-test |
|
The way the initialization of the default etcd logger is recreated here to have a shared logger looks right to me. |
|
/test pull-kubernetes-e2e-kind-ipv6 |
Draft started in #111559 |
|
I don't think I'll personally be confident enough in #111559 to get it done by the freeze tomorrow. Do folks feel like this one is ready to merge as a stop-gap? |
|
Related discussion about one etcd client per API Kind. https://kubernetes.slack.com/archives/C0EG7JC6T/p1618439560231400
|
@jqmichael that sounds similar to what I've done in #111559 - I believe in this case one transport is roughly equivalent to one etcd database? |
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: lavalamp, negz 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 |
…-upstream-release-1.22 Automated cherry pick of #111477: Share a single etcd3 client logger across all clients
…-upstream-release-1.24 Automated cherry pick of #111477: Share a single etcd3 client logger across all clients
…-upstream-release-1.23 Automated cherry pick of #111477: Share a single etcd3 client logger across all clients
Currently, the etcd client logger is not explicitly configured when a new etcd client is initialized, which means that a new one gets created for every client. Yet, this comes with a significant memory cost, which can be avoided explicitly initializing and configuring a shared logger. This change mimics a similar one implemented for the kubernetes apiserver: kubernetes/kubernetes#111477 The following reports the top 3 nodes from the heap pprof profile of an idle process after initializing 1K etcd clients through `kvstore.NewClient`. * Without the patch: Showing nodes accounting for 268.62MB, 88.75% of 302.68MB total Dropped 124 nodes (cum <= 1.51MB) Showing top 3 nodes out of 60 flat flat% sum% cum cum% 224.33MB 74.11% 74.11% 224.33MB 74.11% go.uber.org/zap/zapcore.newCounters 32.45MB 10.72% 84.83% 32.45MB 10.72% google.golang.org/grpc/internal/transport.newBufWriter 11.85MB 3.91% 88.75% 11.85MB 3.91% bufio.NewReaderSize * With the patch: Showing nodes accounting for 65.20MB, 69.19% of 94.23MB total Showing top 3 nodes out of 137 flat flat% sum% cum cum% 43.62MB 46.29% 46.29% 43.62MB 46.29% google.golang.org/grpc/internal/transport.newBufWriter 19.08MB 20.25% 66.54% 19.08MB 20.25% bufio.NewReaderSize 2.50MB 2.65% 69.19% 3MB 3.19% time.NewTimer Co-authored-by: yougjiahe <yongjiahe@tuputech.com> Signed-off-by: Marco Iorio <marco.iorio@isovalent.com>
Currently, the etcd client logger is not explicitly configured when a new etcd client is initialized, which means that a new one gets created for every client. Yet, this comes with a significant memory cost, which can be avoided explicitly initializing and configuring a shared logger. This change mimics a similar one implemented for the kubernetes apiserver: kubernetes/kubernetes#111477 The following reports the top 3 nodes from the heap pprof profile of an idle process after initializing 1K etcd clients through `kvstore.NewClient`. * Without the patch: Showing nodes accounting for 268.62MB, 88.75% of 302.68MB total Dropped 124 nodes (cum <= 1.51MB) Showing top 3 nodes out of 60 flat flat% sum% cum cum% 224.33MB 74.11% 74.11% 224.33MB 74.11% go.uber.org/zap/zapcore.newCounters 32.45MB 10.72% 84.83% 32.45MB 10.72% google.golang.org/grpc/internal/transport.newBufWriter 11.85MB 3.91% 88.75% 11.85MB 3.91% bufio.NewReaderSize * With the patch: Showing nodes accounting for 65.20MB, 69.19% of 94.23MB total Showing top 3 nodes out of 137 flat flat% sum% cum cum% 43.62MB 46.29% 46.29% 43.62MB 46.29% google.golang.org/grpc/internal/transport.newBufWriter 19.08MB 20.25% 66.54% 19.08MB 20.25% bufio.NewReaderSize 2.50MB 2.65% 69.19% 3MB 3.19% time.NewTimer Co-authored-by: yougjiahe <yongjiahe@tuputech.com> Signed-off-by: Marco Iorio <marco.iorio@isovalent.com>
What type of PR is this?
/kind bug
What this PR does / why we need it:
Currently the API server creates one etcd client per CRD. If clients aren't provided a logger they'll each create their own. These loggers can account for ~20% of API server memory consumption on a cluster with hundreds of CRDs.
Which issue(s) this PR fixes:
Fixes #111476
Special notes for your reviewer:
With this single logger and ~1,900 CRDs loaded I'm seeing the API server using from 5.5 to 6.5 GiB RSS as garbage collection sawtooths. That's a saving of at least 1GiB.
Profile no longer shows the logger:
Note that I don't really know how to make this logger actually log anything so it's hard to confirm whether this change has any performance or observability impact.
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: