Skip to main content

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>)>
request
&RoutingInfo
required
Information about the request (consistency, token, table)
cluster
&ClusterState
required
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>
request
&RoutingInfo
required
Information about the request
cluster
&ClusterState
required
Current cluster state
plan
FallbackPlan
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<'_>)
request
&RoutingInfo
required
The request information
latency
Duration
required
Request completion time
node
NodeRef
required
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.
fn name(&self) -> String

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,
}
consistency
Consistency
Request consistency level
serial_consistency
Option<SerialConsistency>
Serial consistency for LWT operations
token
Option<Token>
Partition token for token-aware routing
table
Option<&TableSpec>
Keyspace and table name
is_confirmed_lwt
bool
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

pub type Shard = u16;
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
datacenter
String
required
Name of the preferred datacenter

token_aware

Enables or disables token-aware routing.
pub fn token_aware(self, token_aware: bool) -> Self
token_aware
bool
required
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
permit
bool
required
true to allow DC failover (default: false)

enable_shuffling

Shuffles replicas within preferred datacenter.
pub fn enable_shuffling(self, enable: bool) -> Self
enable
bool
required
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
measurements
usize
required
Minimum number of measurements before excluding nodes (default: 50)
update_rate_ms
pub fn update_rate_ms(self, rate_ms: u64) -> Self
rate_ms
u64
required
How often to recalculate node latencies in milliseconds (default: 100)
retry_period_ms
pub fn retry_period_ms(self, period_ms: u64) -> Self
period_ms
u64
required
Time before retrying excluded nodes in milliseconds (default: 10000)
exclusion_threshold
pub fn exclusion_threshold(self, threshold: f64) -> Self
threshold
f64
required
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

Build docs developers (and LLMs) love