Altinity / Altinity/clickhouse-operator

Operator throttles itself at scale with >400 CHI pods — reconcile concurrency and the K8s client rate limiter aren't linked

Open
#2,045 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

big deployment planned for review research required
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.