1+ """Benchmark shard transfer speed between Qdrant cluster nodes.
2+
3+ Uploads a dataset to a Qdrant cluster, then repeatedly replicates a shard
4+ between two peers to measure transfer throughput (points/s and MB/s).
5+ """
6+
17import json
28import os
39import statistics
410import sys
511import time
12+ from collections import Counter
613from pathlib import Path
714
815import numpy as np
@@ -28,12 +35,14 @@ def __init__(self, uris: list[str]):
2835 }
2936 self .primary = self .clients [uris [0 ]]
3037
31- def cluster_info (self , client = None ):
32- return (
38+ def cluster_info (self , client = None ) -> models . CollectionClusterInfo :
39+ result = (
3340 (client or self .primary )
3441 .http .distributed_api .collection_cluster_info (COLLECTION )
35- .dict ()[ " result" ]
42+ .result
3643 )
44+ assert result
45+ return result
3746
3847 def setup (self , dims : int ):
3948 try :
@@ -81,46 +90,25 @@ def wait_green(self, timeout=1800):
8190 return
8291 raise TimeoutError (f"Collection not green after { timeout } s" )
8392
84- def storage_types (self , uri : str ) -> dict :
93+ def storage_types (self , uri : str ) -> Counter :
8594 try :
86- r = requests .get (f"{ uri } /telemetry?details_level=6" , timeout = 10 )
87- if not r .ok :
88- print (f" Telemetry request failed: { r .status_code } " )
89- return {}
90- data = r .json ()
91- collections = (
92- data .get ("result" , {}).get ("collections" , {}).get ("collections" , [])
93- )
94- if not collections :
95- print (
96- f" No collections in telemetry, keys: { list (data .get ('result' , {}).keys ())} "
97- )
98- return {}
99- for coll in collections :
100- if coll .get ("id" ) == COLLECTION :
101- types = {}
102- for shard in coll .get ("shards" , []):
103- local = shard .get ("local" )
104- if not local :
105- continue
106- for seg in local .get ("segments" , []):
107- for vec in (
108- seg .get ("config" , {}).get ("vector_data" , {}).values ()
109- ):
110- st = vec .get ("storage_type" , "unknown" )
111- types [st ] = types .get (st , 0 ) + 1
112- return types
113- print (
114- f" Collection '{ COLLECTION } ' not found, available: { [c .get ('id' ) for c in collections ]} "
95+ data = requests .get (f"{ uri } /telemetry?details_level=6" , timeout = 10 ).json ()
96+ return Counter (
97+ vec ["storage_type" ]
98+ for coll in data ["result" ]["collections" ]["collections" ]
99+ if coll .get ("id" ) == COLLECTION
100+ for shard in coll ["shards" ]
101+ for seg in (shard ["local" ] or {}).get ("segments" , [])
102+ for vec in seg ["config" ]["vector_data" ].values ()
115103 )
116104 except Exception as e :
117105 print (f" Telemetry error: { e } " )
118- return {}
106+ return Counter ()
119107
120108 def wait_mmap (self , uri : str , timeout = 180 ):
121109 print ("Waiting for Mmap segments..." )
122110 start = time .time ()
123- types = {}
111+ types = Counter ()
124112 while time .time () - start < timeout :
125113 types = self .storage_types (uri )
126114 mmap = types .get ("Mmap" , 0 )
@@ -134,7 +122,7 @@ def wait_mmap(self, uri: str, timeout=180):
134122 def wait_transfer (self , timeout = 600 ):
135123 start = time .time ()
136124 while time .time () - start < timeout :
137- if not self .cluster_info ().get ( " shard_transfers" ) :
125+ if not self .cluster_info ().shard_transfers :
138126 return
139127 time .sleep (0.5 )
140128 raise TimeoutError ("Transfer timeout" )
@@ -165,15 +153,15 @@ def run(self, vectors: np.ndarray, runs: int) -> dict:
165153 self .wait_mmap (list (self .clients .keys ())[0 ])
166154
167155 info = self .cluster_info ()
168- from_peer = info [ " peer_id" ]
169- shard_id = info [ " local_shards" ] [0 ][ " shard_id" ]
156+ from_peer = info . peer_id
157+ shard_id = info . local_shards [0 ]. shard_id
170158
171159 to_peer = None
172160 for client in self .clients .values ():
173161 node = self .cluster_info (client )
174- if node [ " peer_id" ] != from_peer :
175- to_peer = node [ " peer_id" ]
176- if shard_id in {s [ " shard_id" ] for s in node .get ( " local_shards" , []) }:
162+ if node . peer_id != from_peer :
163+ to_peer = node . peer_id
164+ if shard_id in {s . shard_id for s in node .local_shards }:
177165 self .drop_replica (shard_id , to_peer )
178166 time .sleep (2 )
179167 break
0 commit comments