Overview
The LoadBalancingPolicy trait defines how the driver selects nodes and shards for query execution. The policy constructs a load balancing plan - an ordered list of targets (node + optional shard) that the driver will attempt to contact.
Most users should use the DefaultPolicy which provides token-aware routing with DC awareness.
Source: scylla/src/policies/load_balancing/mod.rs:80
Trait Definition
pub trait LoadBalancingPolicy: Send + Sync + std::fmt::Debug {
fn pick<'a>(
&'a self,
request: &'a RoutingInfo,
cluster: &'a ClusterState,
) -> Option<(NodeRef<'a>, Option<Shard>)>;
fn fallback<'a>(
&'a self,
request: &'a RoutingInfo,
cluster: &'a ClusterState,
) -> FallbackPlan<'a>;
fn on_request_success(&self, _request: &RoutingInfo, _latency: Duration, _node: NodeRef<'_>) {}
fn on_request_failure(
&self,
_request: &RoutingInfo,
_latency: Duration,
_node: NodeRef<'_>,
_error: &RequestAttemptError,
) {}
fn name(&self) -> String;
}
Methods
pick
Returns the first (preferred) node to contact for a request.
fn pick<'a>(
&'a self,
request: &'a RoutingInfo,
cluster: &'a ClusterState,
) -> Option<(NodeRef<'a>, Option<Shard>)>
Information about the request (consistency, token, table)
Current cluster state with node information
target
Option<(NodeRef, Option<Shard>)>
The preferred node and optional shard to contact, or None if no node is available
The shard is a hint - the driver may use a different shard if the suggested one is unavailable or out of bounds.
fallback
Returns all remaining nodes in the load balancing plan.
fn fallback<'a>(
&'a self,
request: &'a RoutingInfo,
cluster: &'a ClusterState,
) -> FallbackPlan<'a>
Information about the request
Iterator over remaining (node, shard) targets
This is called when:
pick() returns None
- The request to
pick()ed node fails
- Speculative execution is triggered
on_request_success
Callback invoked after successful request completion.
fn on_request_success(&self, request: &RoutingInfo, latency: Duration, node: NodeRef<'_>)
The node that successfully handled the request
Useful for implementing latency-aware policies.
on_request_failure
Callback invoked after request failure.
fn on_request_failure(
&self,
request: &RoutingInfo,
latency: Duration,
node: NodeRef<'_>,
error: &RequestAttemptError,
)
error
&RequestAttemptError
required
The error that caused the request to fail
name
Returns the policy name for debugging and logging.
Supporting Types
RoutingInfo
Information about a request used by load balancing policies.
pub struct RoutingInfo<'a> {
pub consistency: Consistency,
pub serial_consistency: Option<SerialConsistency>,
pub token: Option<Token>,
pub table: Option<&'a TableSpec<'a>>,
pub is_confirmed_lwt: bool,
}
Request consistency level
serial_consistency
Option<SerialConsistency>
Serial consistency for LWT operations
Partition token for token-aware routing
Whether this is a confirmed LWT (ScyllaDB-specific optimization)
FallbackPlan
pub type FallbackPlan<'a> = Box<dyn Iterator<Item = (NodeRef<'a>, Option<Shard>)> + Send + Sync + 'a>;
An iterator over fallback targets (node + optional shard).
NodeRef
Reference to a cluster node (includes host ID, address, datacenter, etc.).
Shard
Shard number for ScyllaDB’s shard-aware routing.
DefaultPolicy
The recommended load balancing policy with token-aware routing and DC awareness.
pub struct DefaultPolicy {
// ... internal fields
}
Creation
use scylla::policies::load_balancing::{DefaultPolicy, DefaultPolicyBuilder};
let policy = DefaultPolicyBuilder::new()
.prefer_datacenter("us-east".to_string())
.token_aware(true)
.permit_dc_failover(true)
.build();
Builder Methods
prefer_datacenter
Sets the preferred datacenter.
pub fn prefer_datacenter(self, datacenter: String) -> Self
Name of the preferred datacenter
token_aware
Enables or disables token-aware routing.
pub fn token_aware(self, token_aware: bool) -> Self
true to enable token-aware routing (default: true)
permit_dc_failover
Allows fallback to other datacenters.
pub fn permit_dc_failover(self, permit: bool) -> Self
true to allow DC failover (default: false)
enable_shuffling
Shuffles replicas within preferred datacenter.
pub fn enable_shuffling(self, enable: bool) -> Self
true to shuffle replicas (default: true)
latency_awareness
Configures latency-aware routing.
pub fn latency_awareness(self, builder: LatencyAwarenessBuilder) -> Self
Latency Awareness
use scylla::policies::load_balancing::LatencyAwarenessBuilder;
let latency_aware = LatencyAwarenessBuilder::new()
.minimum_measurements(100)
.update_rate_ms(100)
.retry_period_ms(10_000)
.exclusion_threshold(2.0)
.build();
let policy = DefaultPolicyBuilder::new()
.latency_awareness(latency_aware)
.build();
Builder Methods
minimum_measurements
pub fn minimum_measurements(self, measurements: usize) -> Self
Minimum number of measurements before excluding nodes (default: 50)
update_rate_ms
pub fn update_rate_ms(self, rate_ms: u64) -> Self
How often to recalculate node latencies in milliseconds (default: 100)
retry_period_ms
pub fn retry_period_ms(self, period_ms: u64) -> Self
Time before retrying excluded nodes in milliseconds (default: 10000)
exclusion_threshold
pub fn exclusion_threshold(self, threshold: f64) -> Self
Latency multiplier for excluding slow nodes (default: 2.0)
Nodes with latency > (threshold * min_latency) are excluded.
SingleTargetLoadBalancingPolicy
A policy that always routes to a specific node (useful for testing or special cases).
pub struct SingleTargetLoadBalancingPolicy {
// ... internal fields
}
Creation
use scylla::policies::load_balancing::
{SingleTargetLoadBalancingPolicy, NodeIdentifier};
let policy = SingleTargetLoadBalancingPolicy::new(
NodeIdentifier::Address("127.0.0.1:9042".parse()?)
);
NodeIdentifier
pub enum NodeIdentifier {
Address(SocketAddr),
Hostname(String),
}
Examples
Basic DefaultPolicy
use scylla::{SessionBuilder, policies::load_balancing::DefaultPolicyBuilder};
let policy = DefaultPolicyBuilder::new()
.prefer_datacenter("us-east".to_string())
.token_aware(true)
.build();
let session = SessionBuilder::new()
.known_node("127.0.0.1:9042")
.load_balancing(Arc::new(policy))
.build()
.await?;
DC-Aware with Failover
let policy = DefaultPolicyBuilder::new()
.prefer_datacenter("us-west".to_string())
.permit_dc_failover(true) // Allow other DCs if preferred DC is down
.token_aware(true)
.build();
Latency-Aware Policy
use scylla::policies::load_balancing::
{DefaultPolicyBuilder, LatencyAwarenessBuilder};
let latency_aware = LatencyAwarenessBuilder::new()
.minimum_measurements(100)
.exclusion_threshold(2.0)
.update_rate_ms(100)
.retry_period_ms(10_000)
.build();
let policy = DefaultPolicyBuilder::new()
.prefer_datacenter("us-east".to_string())
.latency_awareness(latency_aware)
.build();
Single Node Policy
use scylla::policies::load_balancing::
{SingleTargetLoadBalancingPolicy, NodeIdentifier};
use std::sync::Arc;
let policy = SingleTargetLoadBalancingPolicy::new(
NodeIdentifier::Address("127.0.0.1:9042".parse()?)
);
let session = SessionBuilder::new()
.known_node("127.0.0.1:9042")
.load_balancing(Arc::new(policy))
.build()
.await?;
Custom Load Balancing Policy
use scylla::policies::load_balancing::{
LoadBalancingPolicy, RoutingInfo, FallbackPlan
};
use scylla::cluster::{ClusterState, NodeRef};
use scylla::routing::Shard;
use std::time::Duration;
#[derive(Debug)]
struct RoundRobinPolicy {
counter: std::sync::atomic::AtomicUsize,
}
impl RoundRobinPolicy {
fn new() -> Self {
Self {
counter: std::sync::atomic::AtomicUsize::new(0),
}
}
}
impl LoadBalancingPolicy for RoundRobinPolicy {
fn pick<'a>(
&'a self,
_request: &'a RoutingInfo,
cluster: &'a ClusterState,
) -> Option<(NodeRef<'a>, Option<Shard>)> {
let nodes: Vec<_> = cluster.get_working_nodes().collect();
if nodes.is_empty() {
return None;
}
let idx = self.counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let node = nodes[idx % nodes.len()];
Some((node, None))
}
fn fallback<'a>(
&'a self,
_request: &'a RoutingInfo,
cluster: &'a ClusterState,
) -> FallbackPlan<'a> {
Box::new(
cluster
.get_working_nodes()
.map(|node| (node, None))
)
}
fn name(&self) -> String {
"RoundRobinPolicy".to_string()
}
}
See Also