Distributed Vector Search — Configuration Reference
Settings, flags and defaults for Distributed Vector Search: the controller in the master leader, the weed-vector-worker engines, and the query router in every S3 gateway.
Controller ([master.vector] in master.toml)
The controller runs in whichever master leads. It reads [master.vector] from that master’s own master.toml, so keep the section identical on every master. An invalid value stops the master at startup.
| Key | Default | Meaning |
|---|---|---|
min_width |
1 |
Smallest W: engines per replica group. |
max_fanout |
32 |
Largest W. No query touches more engines than this. |
max_scan_mb |
64 |
W grows until an even split leaves each engine at most this many MiB of the index to scan per query, as long as min_replicas groups still fit the engines. 0 sizes W by memory only. |
min_replicas |
2 |
Fewest replica groups per index. |
max_replicas |
16 |
Most replica groups per index. |
qps_per_group |
200 |
Queries per second one group serves before R grows. |
replica_cooldown |
10m |
R falls only after the load has asked for fewer groups this long. |
warmup_timeout |
10m |
Queries move to a new placement after this long even if its engines are not warm yet. |
restart_grace |
2m |
An engine whose session is lost keeps its slots this long. |
idle_timeout |
1h |
An index with no subscribers and no stats this long is forgotten. Its next stats report brings it back. |
stats_ttl |
2m |
A gateway’s last stats report counts until it is this old. |
leader_settle |
10s |
A new leader waits this long for engines to rejoin before it places anything. |
warmups_per_engine |
4 |
Slots one engine warms at the same time. |
warmups_per_cluster |
256 |
Slots warming at the same time across all engines. |
Rules: 1 ≤ min_width ≤ max_fanout, 1 ≤ min_replicas ≤ max_replicas, max_scan_mb ≥ 0, qps_per_group > 0, and positive warm-up limits and durations. replica_cooldown and leader_settle may be 0.
Per-index bounds
[[master.vector.index]]
key = "s3://bucket/vector/index" # the index's table URI
min_width = 4
max_width = 8
min_replicas = 2
max_replicas = 4
key is required. An S3 Vectors index’s table URI is s3://<vector bucket>/vector/<index name>. Each bound is optional, must be a positive integer, and replaces the cluster default for that index. A minimum may not exceed its maximum, and max_fanout still caps max_width.
Sizing
On every tick, for each index:
resident: the largest index size reported by a gateway withinstats_ttl: its segments plus its unsegmented tail.budget: the median--capacity-bytesof the engines that are not draining.E: the number of engines that are not draining.
W_mem = clamp(ceil(resident / (0.8 × budget)), min_width, max_width)
W_scan = clamp(max(W_mem, ceil(resident / max_scan_mb)), min_width, max_width)
W = max(W_mem, min(W_scan, floor(E / min_replicas)))
R = clamp(ceil(peak QPS / qps_per_group), min_replicas, max_replicas)
Here max_width is the per-index bound, capped by max_fanout. R rises at once and falls to the peak seen during replica_cooldown. When R × W is more than E, the later groups get fewer engines or are dropped.
Placement
- Level 1, controller only. Each index gets R groups of up to W engines. Zones are ordered per index by hash, and group g takes zone g mod (number of zones). Within a zone, engines are ranked by weighted rendezvous score
-w / ln(h), where w is the engine’s capacity. A group fills from its own zone first, then from any zone. Each group ranks engines by its own key, so an engine joining or leaving moves few others. Groups that share a zone still interact: when a group replaces a lost member with an engine that a later group held, the later group picks a replacement too. - Level 2, gateways and engines. Within a group, segments are assigned in id order. Each goes to the member with the highest hash whose load stays within 1.25× the group’s average bytes, otherwise to the least loaded member. Each tail fragment is placed the same way, as a segment with an equal share of the tail’s bytes. Level 2 uses integer arithmetic only, so the Go router and the Rust engines compute the same mapping; shared test vectors pin the two together.
- Make-before-break. The controller keeps a serving and a target placement for each index. Engines warm the target. Serving switches to the target once every new owner reports warm, or after
warmup_timeout.
Engines (weed-vector-worker)
| Flag | Env | Default | Meaning |
|---|---|---|---|
--masters |
VECTOR_MASTERS |
— | Comma-separated master addresses. gRPC is the HTTP port + 10000 unless given as host:port.grpcPort. |
--listen |
VECTOR_LISTEN |
0.0.0.0:18888 |
gRPC listen address. |
--state-dir |
VECTOR_STATE_DIR |
<tmp>/weed-vector-<port> |
Keeps the engine’s id, so a restart within restart_grace gets its slots back. Use a directory that survives reboots. |
--zone |
VECTOR_ZONE |
default |
Failure domain (data center, or data center/rack). An index’s groups go to different zones. |
--capacity-bytes |
VECTOR_CAPACITY_BYTES |
75% of RAM, or of the cgroup limit | Segment memory budget, and the engine’s placement weight. |
--storage-option |
VECTOR_STORAGE_OPTIONS |
— | key=value object store option for opening assigned tables (endpoint, region, credentials). Repeatable; comma-separated in the env var. |
--table-root |
VECTOR_TABLE_ROOT |
unset | URI prefix every table must live under. Requests for other URIs are denied. Unset, the engine opens any URI a caller names, so keep engine ports on a private network. |
--max-warmups |
VECTOR_MAX_WARMUPS |
4 |
Slots warmed at the same time. |
--drain-timeout |
VECTOR_DRAIN_TIMEOUT |
2m |
How long SIGTERM waits for the controller to move queries off this engine before the server stops. |
--search-threads |
VECTOR_SEARCH_THREADS |
one per CPU core | Searches running at once. |
--search-queue |
VECTOR_SEARCH_QUEUE |
2 × search threads | Searches waiting for a thread. Beyond that, new searches get RESOURCE_EXHAUSTED at once. |
--dataset-cache |
VECTOR_DATASET_CACHE |
256 |
Opened (table, version) datasets kept in memory. |
--index-cache-bytes |
VECTOR_INDEX_CACHE_BYTES |
the capacity, else 6 GiB | Byte budget for cached index data, shared by every table. |
--read-cache-mb |
VECTOR_READ_CACHE_MB |
512 |
Memory for caching reads of write-once table files. 0 disables it. |
Engine states: joining (registered, not serving), warming (loading its target slots), serving, draining (planned removal: still serving until queries move off). An engine whose session stays lost past restart_grace is gone, and its slots are placed elsewhere.
Query router (every S3 gateway)
The router needs no flags. It finds the controller through the gateway’s masters and uses the gateway’s -dataCenter as its zone.
- Resolve the index’s latest version. The version is cached, and writes through the gateway invalidate it.
- List the version’s segments from any serving engine. The list is cached per version, because versions are immutable.
- Watch the index’s placement, and pick a group: the gateway’s own zone first, then the group with fewer outstanding requests.
- Map segments and tail fragments to the group’s members. A member that is down or shedding load hands its share to its owner in another group (warm), or else to another member (cold).
- Send one
SearchSegmentsper engine, with the query’s remaining deadline. - Merge the partial top-k lists into the global top-k.
With no placement (no controller, or no serving engine), the query goes to the single weed-vector. Only QueryVectors takes the distributed path. Writes and index management go to the single engine.
| Policy | Default |
|---|---|
| Outstanding requests per engine | 32 |
| Hedge | After the engine’s p95 latency, to the owner in another group, once 20 of that engine’s latencies have been seen. Budget: 5% of sub-requests. |
| Retry | Once, on another owner, after RESOURCE_EXHAUSTED or a broken connection. Budget: 10% of sub-requests plus 1 per second. |
| Engine that failed or shed load | Avoided for 1 s, doubling with each consecutive failure up to 32 s. |
| Queries in flight per gateway | Adaptive between 16 and 1024, starting at 64. A query waits up to 20 ms for room. |
| Widest plan | 64 engines. Wider plans are refused. |
Errors
| Cause | S3 Vectors error |
|---|---|
| Engines are shedding load or unreachable, after the one retry | ServiceUnavailableException (503) |
| The gateway’s in-flight limit is still reached after the 20 ms wait | ServiceUnavailableException (503) |
| The plan would span more than 64 engines | ServiceUnavailableException (503) |
An engine that sheds load means the cluster is short of capacity, not that the caller is sending too fast, so the gateway never reports it as TooManyRequestsException.
Versions
Index versions are immutable. Engines keep opened versions in an LRU. There is no per-query lease: version cleanup keeps every version that was the latest at any point in the last hour, however old its commit, and no query runs that long.