Sol RPC Router uses a weighted random algorithm to distribute requests across healthy backends. The selection logic filters out unhealthy backends and respects optional method-specific routing overrides.
pub fn select_backend(&self, rpc_method: Option<&str>) -> Option<(String, String)> { let state = self.state.load(); // Check method-specific routing first if let Some(method) = rpc_method { if let Some(backend_label) = state.method_routes.get(method) { if let Some(backend) = state .backends .iter() .find(|b| b.config.label == *backend_label) { if backend.healthy.load(Ordering::Relaxed) { debug!("Method {} routed to label={}", method, backend_label); return Some((backend.config.label.clone(), backend.config.url.clone())); } else { info!( "Method {} target label={} is unhealthy, falling back to weighted selection", method, backend_label ); } } } } // Filter out unhealthy backends (lock-free) let healthy_backends: Vec<&RuntimeBackend> = state .backends .iter() .filter(|b| b.healthy.load(Ordering::Relaxed)) .collect(); if healthy_backends.is_empty() { return None; // No healthy backends available } // Calculate total weight of healthy backends let healthy_total_weight: u32 = healthy_backends.iter().map(|b| b.config.weight).sum(); if healthy_total_weight == 0 { return healthy_backends .first() .map(|b| (b.config.label.clone(), b.config.url.clone())); } // Weighted random selection among healthy backends let mut rng = rand::thread_rng(); let mut random_weight = rng.gen_range(0..healthy_total_weight); for backend in &healthy_backends { if random_weight < backend.config.weight { return Some((backend.config.label.clone(), backend.config.url.clone())); } random_weight -= backend.config.weight; } // Fallback (should never reach here if weights are valid) healthy_backends .first() .map(|b| (b.config.label.clone(), b.config.url.clone()))}
With all backends healthy, the expected traffic split is:
Backend
Weight
Probability
Approximate Traffic
mainnet-primary
10
10/17
~58.8%
backup-rpc
5
5/17
~29.4%
local-node
2
2/17
~11.8%
The weighted random algorithm provides probabilistic distribution. Over time, traffic converges to the expected ratios, but individual requests are randomly distributed.
Exact Match: If the RPC method matches a route and the target backend is healthy, route directly
Fallback: If the target backend is unhealthy, fall back to weighted selection
Unknown Methods: Methods not in the routing table use weighted selection
Example from src/state.rs:49-67:
src/state.rs
if let Some(method) = rpc_method { if let Some(backend_label) = state.method_routes.get(method) { // Find the backend by label to check its atomic health if let Some(backend) = state .backends .iter() .find(|b| b.config.label == *backend_label) { if backend.healthy.load(Ordering::Relaxed) { debug!("Method {} routed to label={}", method, backend_label); return Some((backend.config.label.clone(), backend.config.url.clone())); } else { info!( "Method {} target label={} is unhealthy, falling back to weighted selection", method, backend_label ); } } }}
Method routing only applies to healthy backends. If the target backend is unhealthy, requests fall back to weighted selection across all healthy backends.
# Total requests per backendsum by (backend) (rpc_requests_total)# Request rate per backendrate(rpc_requests_total{backend="mainnet-primary"}[5m])# Traffic distribution (percentage)sum by (backend) (rate(rpc_requests_total[5m])) / ignoring(backend) group_leftsum(rate(rpc_requests_total[5m]))