Altinity / Altinity/clickhouse-operator
Operator throttles itself at scale with >400 CHI pods — reconcile concurrency and the K8s client rate limiter aren't linked
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 2.6k
- Forks
- 574
- Avg merge
- 8d 6h
- Merged PRs (30d)
- 6
Description
We ran into this on the large CHI in production. It took a while to find because the operator doesn't surface it anywhere.
The operator has two settings that don't know about each other: how much it reconciles in parallel, and how many requests per second it's allowed to send to the Kubernetes API. Turning up concurrency doesn't help if the request rate is low, because all the parallel work still waits on the same rate limit.
The request rate is controlled by OPERATOR_K8S_CLIENT_QPS_LIMIT and OPERATOR_K8S_CLIENT_BURST_LIMIT. If those aren't set, the operator falls back to the Kubernetes client defaults of 5 requests per second with a burst of 10. That's 5 requests per second for the whole operator regardless of how many hosts it manages.
Concurrency is configured separately, through the reconcile thread and shard-concurrency settings. Nothing compares the two. You can tell the operator to reconcile several hundreds shards in parallel while it's still capped at 5 requests per second, and it won't warn you that the two are in conflict.
The impact shows up at scale. A few hundred hosts at roughly ten API calls each is thousands of calls per reconcile, and at 5 requests per second that's about ten minutes of waiting on the rate limit before any useful work happens. With host >400 there was almost no progress in deployment. The only evidence is an info-level log line from the Kubernetes client, which most people aren't watching:
Waited for 9.99s due to client-side throttling, not priority and fairness, request: GET:https://.../api/v1/namespaces/<ns>/pods/<pod>
Confirmed on 0.27.2 (latest upstream) and on our internal 0.25.x builds.
Fix ideas
The goal is to stop the two settings from drifting apart without anyone noticing.
- Check it at startup: if the configured concurrency implies a request rate above the limit, log a warning (or refuse to start) that names both values and the settings to raise.
- Make the throttling visible: raise it to a log level operators see, or expose it as a metric.
- Set defaults that scale with host count instead of inheriting the client's 5/10.
Workaround today
Raise OPERATOR_K8S_CLIENT_QPS_LIMIT and OPERATOR_K8S_CLIENT_BURST_LIMIT on the operator. We used 200/400, which unblocked the internal cluster.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing OPERATOR_K8S_CLIENT_QPS_LIMIT, OPERATOR_K8S_CLIENT_BURST_LIMIT, and the reconcile thread and shard-concurrency settings into the Kubernetes client configuration. Reproduce the client-side throttling behavior on a large workload, then define and implement one approach for linking or surfacing the conflicting limits; done means the conflict is visible or prevented and the relevant behavior is verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kubernetes
- Domain
- devops, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100