You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After a training workload is submitted under a compute domain, all compute-domain-associated daemons must negotiate a unique index for each daemon. This index is used to generate DNS configuration. Only after that can the imex process start in each daemon, and the daemon pod becomes Ready.
Only when all daemons associated with the compute domain are Ready can the PrepareResourceClaims phase of the compute-domain-kubelet-plugin complete, allowing the training pods to start.
In large-scale training scenarios, we have observed slow pod startup times. The main bottleneck is the negotiation process described above. The negotiation is based on optimistic locking: each daemon updates the status of the same compute domain object, which leads to a large number of conflicts and update requests.
This high request volume triggers API server APF throttling (code 429) and Retry-After: 30s, while update conflicts (code 409) further amplify the problem.
This PR moved the logic for negotiating indexes and updating the compute domain from distributed daemons to a centralized compute domain controller. The expectation was to avoid conflicts and reduce request volume.
However, this issue points out implementation problems in Move CD status updates to centralized controller #810. The controller workqueue suffered from backlog accumulation. In testing, a 256-pod training job required 8 minutes to start.
This PR still used distributed negotiation, but replaced update with server-side apply (SSA). During implementation, we found that naive SSA could result in two nodes being assigned the same index, which is invalid.
As a result, we had to re-check index assignment after SSA and re-patch any conflicting nodes. In other words, retries were still required.
This PR introduced the ComputeDomainClique(CDC) object, dividing one compute domain into multiple isolated domains. Index negotiation was then scoped to a single clique (at most 18 nodes).
This proved to be highly effective. We ported the relevant DRA logic into fake-kubelet for stress testing. The results showed that at a scale of 5k+ nodes, DRA time was reduced to approximately 1 minute.
However, during stress testing, we still observed 429 responses even after increasing some APF-related parameters. This indicates that the request volume is still too high and there is further room for optimization.
In addition, fake-kubelet has a simpler control flow than the real kubelet, so the measured latency is optimistic. Our goal is to reduce DRA latency to the second level.
This draft PR proposes using SSA to update clique objects. Unfortunately, we ran into the same problem as in CD daemon: use SSA for conflict-free nodes list updates #822. To mitigate it, we again had to apply the same workaround: re-check after SSA and re-patch if conflicts were detected.
Proposed Solution
Based on the lessons learned so far, we can draw the following conclusions:
Compared with update, SSA merely shifts conflict detection from the API server to the daemon. It does not eliminate redundant update requests, so it provides limited benefit for our problem.
Centralized index allocation and status updates are expected to reduce the number of update requests and avoid APF issues. In addition, after introducing CDC, we can parallelize across CDCs, which means multiple workqueues and may help avoid the backlog issue seen in Move CD status updates to centralized controller #810.
I suggest revisiting the centralized index allocation approach, with the help of CDC.
Component Changes
Compute Domain Kubelet Plugin
The DRA plugin needs to add an additional cliqueID label to each node, which helps the controller build clique domains.
Compute Domain Daemon
The daemon no longer needs to manage CDC lifecycle operations such as creation, update, deletion, or index registration logic (currently handled by DaemonInfoManager in the code).
The daemon only needs to watch the CDC object associated with itself, read the assigned index from it, generate DNS configuration, and start the imex process. When an ipset change is observed, it should regenerate the configuration and restart imex.
Compute Domain Controller
The controller will now be responsible for allocating indexes and updating CDC and CD status. Concretely, the controller will watch cd, node, daemonset, and pods.
When the controller starts, it watches nodes and builds both the clique domains and the node -> index mapping. The node -> index mapping is mostly stable and is only updated when nodes are added or removed.
cliqueID
nodeName
index
clique-1
node-1
0
clique-1
node-2
1
clique-1
node-3
2
clique-2
node-4
0
clique-2
node-5
1
When allocating mappings, a simple first-fit strategy is used. On restart, the controller first reconstructs the clique domains and mappings from existing CDC objects.
The controller spawns one cdcWorker per CDC. Workers across different CDCs run in parallel, while within each cdcWorker, events are processed serially via a workqueue.
Taking the lessons from #810 into account, daemon pod events are dispatched to the corresponding cdcWorker based on a nodeName → clique mapping. This is a fast, lightweight operation and therefore will not cause backlog accumulation at the controller.
Tasks handled by cdcWorker include:
Updating the daemon pod IP received from events into the CDC
Watching the corresponding daemonset, and when Ready = DESIRED, updating the CDC status to Ready
After all CDCs are Ready, the controller updates the CD status to Ready.
Batch Update
In the centralized update design, we can further reduce request volume by using batch updates. Given the structure of CDC, each individual update request is essentially updating or appending one entry in the daemons slice. We can merge multiple update requests inside the controller and flush them in batches.
Estimated Optimization Impact
Using a 5k-node scenario as an example, and consider using a batch size of 5 in the new design.:
Scenario
Step
Request Count
Total
Current
Update CDC to register DNS index
5000 * 3~5 retries = 15000~25000
25000~40000
Current
Update CDC status = Ready
5000 * 2~3 retries = 10000~15000
25000~40000
Optimized
Update CDC to register DNS index
5000 * 0.2~1 = 1000~5000
2000~10000
Optimized
Update CDC status = Ready
5000 * 0.2~1 = 1000~5000
2000~10000
Alternatives Considered
No response
Scope
Large: New feature gate, API change, or multi-component change
Component
compute-domain-controller
Problem Statement
After a training workload is submitted under a compute domain, all compute-domain-associated daemons must negotiate a unique index for each daemon. This index is used to generate DNS configuration. Only after that can the
imexprocess start in each daemon, and the daemon pod becomesReady.Only when all daemons associated with the compute domain are
Readycan thePrepareResourceClaimsphase of thecompute-domain-kubelet-plugincomplete, allowing the training pods to start.In large-scale training scenarios, we have observed slow pod startup times. The main bottleneck is the negotiation process described above. The negotiation is based on optimistic locking: each daemon updates the status of the same compute domain object, which leads to a large number of conflicts and update requests.
This high request volume triggers API server APF throttling (code 429) and
Retry-After: 30s, while update conflicts (code 409) further amplify the problem.Related Progress
Move CD status updates to centralized controller #810
This PR moved the logic for negotiating indexes and updating the compute domain from distributed daemons to a centralized compute domain controller. The expectation was to avoid conflicts and reduce request volume.
If the number of pod replicas for the job associated with ComputeDomain is large, the pod startup will be very slow. #816
However, this issue points out implementation problems in Move CD status updates to centralized controller #810. The controller workqueue suffered from backlog accumulation. In testing, a 256-pod training job required 8 minutes to start.
CD daemon: use SSA for conflict-free nodes list updates #822
This PR still used distributed negotiation, but replaced
updatewith server-side apply (SSA). During implementation, we found that naive SSA could result in two nodes being assigned the same index, which is invalid.As a result, we had to re-check index assignment after SSA and re-patch any conflicting nodes. In other words, retries were still required.
Maintain CD daemon info in a new per-CD, per-clique ComputeDomainClique object #826
This PR introduced the
ComputeDomainClique(CDC)object, dividing one compute domain into multiple isolated domains. Index negotiation was then scoped to a single clique (at most 18 nodes).This proved to be highly effective. We ported the relevant DRA logic into fake-kubelet for stress testing. The results showed that at a scale of 5k+ nodes, DRA time was reduced to approximately 1 minute.
However, during stress testing, we still observed
429responses even after increasing some APF-related parameters. This indicates that the request volume is still too high and there is further room for optimization.In addition,
fake-kubelethas a simpler control flow than the real kubelet, so the measured latency is optimistic. Our goal is to reduce DRA latency to the second level.CDClique: SSA per-node status, conflict retry on cleanup, scoped pod selection #1101
This draft PR proposes using SSA to update clique objects. Unfortunately, we ran into the same problem as in CD daemon: use SSA for conflict-free nodes list updates #822. To mitigate it, we again had to apply the same workaround: re-check after SSA and re-patch if conflicts were detected.
Proposed Solution
Based on the lessons learned so far, we can draw the following conclusions:
update, SSA merely shifts conflict detection from the API server to the daemon. It does not eliminate redundant update requests, so it provides limited benefit for our problem.I suggest revisiting the centralized index allocation approach, with the help of CDC.
Component Changes
Compute Domain Kubelet Plugin
The DRA plugin needs to add an additional
cliqueIDlabel to each node, which helps the controller build clique domains.Compute Domain Daemon
The daemon no longer needs to manage CDC lifecycle operations such as creation, update, deletion, or index registration logic (currently handled by
DaemonInfoManagerin the code).The daemon only needs to watch the CDC object associated with itself, read the assigned index from it, generate DNS configuration, and start the
imexprocess. When anipsetchange is observed, it should regenerate the configuration and restartimex.Compute Domain Controller
The controller will now be responsible for allocating indexes and updating CDC and CD status. Concretely, the controller will watch
cd,node,daemonset, andpods.When the controller starts, it watches nodes and builds both the clique domains and thenode -> indexmapping. Thenode -> indexmapping is mostly stable and is only updated when nodes are added or removed.When allocating mappings, a simple first-fit strategy is used. On restart, the controller first reconstructs the clique domains and mappings from existing CDC objects.The controller spawns one cdcWorker per CDC. Workers across different CDCs run in parallel, while within each cdcWorker, events are processed serially via a workqueue.
Taking the lessons from #810 into account, daemon pod events are dispatched to the corresponding cdcWorker based on a nodeName → clique mapping. This is a fast, lightweight operation and therefore will not cause backlog accumulation at the controller.
Tasks handled by
cdcWorkerinclude:Ready = DESIRED, updating the CDC status toReadyAfter all CDCs are
Ready, the controller updates the CD status toReady.Batch Update
In the centralized update design, we can further reduce request volume by using batch updates. Given the structure of CDC, each individual update request is essentially updating or appending one entry in the
daemonsslice. We can merge multiple update requests inside the controller and flush them in batches.Estimated Optimization Impact
Using a 5k-node scenario as an example, and consider using a batch size of 5 in the new design.:
5000 * 3~5 retries = 15000~2500025000~40000status = Ready5000 * 2~3 retries = 10000~1500025000~400005000 * 0.2~1 = 1000~50002000~10000status = Ready5000 * 0.2~1 = 1000~50002000~10000Alternatives Considered
No response
Scope
Large: New feature gate, API change, or multi-component change
Upstream Kubernetes Dependencies
No response
Additional Context
No response