Problem – Shard Rebalancing Timeout After Autoscaling Nodes
In an inference‑serving deployment of Weaviate, automatic scaling of worker nodes frequently triggers a cascade of errors:
- Search requests return
504 Gateway Timeoutor stale vectors. - Cluster logs contain repeated messages such as:
rebalance_timeout: shard "shard-7" could not be moved within the configured timeout - Metrics show CPU > 90 % and memory pressure on the original nodes while newly added nodes report
shard not found. - Post‑scale queries sometimes return duplicate or missing vector IDs, e.g.:
vector_retrieval_error: inconsistent vector data detected for ID 3f9c2a1b‑e4d5‑4a6b‑9c1f‑7d2e5f8a9b0c after rebalancing
The impact is twofold: latency spikes break SLA for low‑latency inference, and data inconsistency jeopardizes model correctness.
Root Cause Analysis
Weaviate’s sharding model distributes vector data across nodes based on the shard_id hash. When the autoscaling controller adds new nodes, the cluster coordinator initiates a rebalance operation that moves a subset of shards to the fresh capacity.
Key configuration points (from the official Cluster sharding and replication guide and the Configuration reference) are:
| Parameter | Default | Purpose |
|---|---|---|
rebalance_timeout |
30 s | Maximum time allowed for a single shard move. |
max_shard_load |
80 % | Upper bound of CPU+memory load a node may accept new shards. |
replication_factor |
2 | Number of replicas per shard. |
During heavy inference traffic the source nodes already operate near max_shard_load. When the coordinator attempts to stream shards to a node that is still initializing (see Autoscaling and node management), the following sequence occurs:
- The new node reports
state=INITIALIZING, but the coordinator proceeds because the autoscaling policy assumes readiness after a fixed health‑check interval. - Shard transfer RPCs start; however, the source node cannot allocate additional network buffers and CPU cycles, causing the RPC to exceed
rebalance_timeout. - The coordinator aborts the move, logs
rebalance_timeout, and leaves the shard on the overloaded node. - Because the shard remains on a node that is now >95 % loaded, subsequent queries experience timeouts and the replica set becomes inconsistent, leading to
vector_retrieval_error.
In multi‑region setups the cross‑region latency adds to the RPC duration, further increasing the chance of hitting the 30‑second default.
Investigation and Debugging
Below is a reproducible debugging workflow that isolates the failure path.
1. Verify Autoscaling Event
# kubectl get nodes -w
NAME STATUS ROLES AGE VERSION
weaviate-1 Ready 12d v1.24.3
weaviate-2 Ready 12d v1.24.3
# Autoscaler adds two nodes
weaviate-3 NotReady 1m v1.24.3
weaviate-4 NotReady 1m v1.24.3
2. Inspect Cluster Coordinator Logs
rebalance_timeout: shard “shard-7” could not be moved within the configured timeout
node_overload: cannot allocate new shard, current load 96% exceeds max_shard_load
3. Check Per‑Node Resource Utilization
# kubectl top pod -n weaviate
NAME CPU(cores) MEMORY(bytes)
weaviate-1-0c9f7d9c9-8kz9b 950m 7.8Gi
weaviate-2-5d2f6a9e2-1xv4l 910m 7.5Gi
weaviate-3-7e8a1b2c3-9q2p 120m 1.2Gi # still initializing
4. Capture RPC Timing with tcpdump
# tcpdump -i eth0 -nn -s 0 -w rebalance.pcap port 50051
# After capture, inspect with wireshark:
# Observe that the SYN‑ACK handshake to weaviate-3 takes ~18 s due to node boot.
5. Validate Shard Allocation State
# curl -s http://weaviate-1:8080/v1/shards | jq .
{
"shards": [
{"id":"shard-7","node":"weaviate-1","replicas":["weaviate-2"]},
{"id":"shard-8","node":"weaviate-2","replicas":["weaviate-1"]},
...
]
}
Notice that shard-7 remains on weaviate-1 despite the intended move to weaviate-3.
Resolution – Tuning Rebalance and Autoscaling Parameters
The fix consists of three coordinated changes:
1. Increase rebalance_timeout to accommodate node boot latency
# before (weaviate.yaml)
rebalance_timeout: 30s
max_shard_load: 80%
# after
rebalance_timeout: 120s # 2 minutes for cold‑start nodes
max_shard_load: 85% # slight headroom for inference spikes
2. Delay shard movement until the target node reports READY
Modify the autoscaling health‑check script (refer to the Autoscaling and node management guide) to poll the /v1/.well-known/ready endpoint and only mark the node as eligible after the gRPC server is fully up.
# health-check.sh
#!/usr/bin/env bash
URL="http://localhost:8080/v1/.well-known/ready"
for i in {1..30}; do
if curl -s $URL | grep -q "ready":true; then
exit 0
fi
sleep 5
done
exit 1
3. Adjust replication_factor for inference workloads
Increasing replicas reduces the load on any single node during rebalancing. For high‑throughput inference, a factor of 3 is recommended.
# before (class schema)
{
"class": "Document",
"vectorizer": "text2vec-contextionary",
"replication_factor": 2
}
# after
{
"class": "Document",
"vectorizer": "text2vec-contextionary",
"replication_factor": 3
}
4. Apply the configuration and restart the coordinator
# kubectl rollout restart deployment/weaviate-coordinator -n weaviate
After the restart, the coordinator respects the new timeout and waits for node readiness before issuing shard moves.
Validation – Verifying the Fix
- Re‑trigger an autoscaling event (e.g., increase CPU target threshold).
- Confirm that new nodes reach
Readystate before anyrebalance_timeoutentries appear in the logs. - Run a high‑concurrency inference benchmark (e.g.,
hey -c 200 -n 5000 http://weaviate:8080/v1/graphql) and monitor latency. - Check shard distribution:
# curl -s http://weaviate-1:8080/v1/shards | jq '.shards[] | select(.node=="weaviate-3")'The output should list the newly assigned shards.
- Validate vector consistency:
# weaviate-cli get --class Document --id# Compare vector length and values across replicas; no "vector_retrieval_error" should appear.
Operational Experience – Lessons Learned
- Misleading symptom: Initial 504 errors were attributed to the inference model, but the root cause was the stalled shard move.
- Assumption failure: The autoscaler assumed a node is ready after a fixed 30‑second health check, ignoring cold‑start latency of the vector index.
- Edge case: In multi‑region clusters, cross‑region latency doubled the effective RPC time, making the default 30 s timeout insufficient.
- Practical tip: Enable the
rebalance_debugflag (see the configuration reference) to emit detailed timing metrics for each shard transfer.
Best Practices and Prevention
- Set
rebalance_timeoutto at least2×the longest node boot time observed in your environment. - Use a readiness probe that checks both the HTTP health endpoint and the gRPC server state before marking a node as eligible for shard allocation.
- Keep
max_shard_loadbelow 85 % for inference workloads; consider a separate “burst” node pool that can absorb temporary spikes. - Monitor the
weaviate_shard_rebalance_duration_secondsmetric; alert if it exceeds 60 seconds. - During rolling upgrades, pause autoscaling or set
rebalance_enabled: falseuntil all nodes reportREADY.
Related Topic Hub: Vector Databases Troubleshooting Hub
FAQ
- Why does the rebalance timeout only appear after scaling up?
Because the coordinator initiates shard moves only when new capacity is detected. If the new node is not yet ready, the RPC exceeds the default 30 s limit, triggering the timeout. - Can I keep the default
rebalance_timeoutand still avoid failures?
Only if your node startup time plus network latency is consistently under 30 seconds. In most inference clusters with large vector indexes, a longer timeout is required. - Do I need to increase the replication factor for every class?
For classes that serve high‑throughput inference, increasing to 3 improves fault tolerance during rebalancing. For low‑traffic metadata classes, the default of 2 is sufficient. - How do I know if a node is still initializing?
Query the readiness endpoint:curl http://. The JSON field:8080/v1/.well-known/ready "ready":falseindicates the node is not yet eligible for shard allocation. - What metric should I watch to detect a stuck rebalance?
Watchweaviate_shard_rebalance_errors_totalandweaviate_shard_rebalance_duration_seconds. A sudden spike in errors combined with durations >rebalance_timeoutsignals a problem.