Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Cassandra Driver Policies

Driver policies control how the application interacts with the Cassandra cluster during normal operation and failure scenarios. These policies are the primary mechanism through which developers configure failure handling behavior.


Developer Responsibility for Failure Handling

Section titled “Developer Responsibility for Failure Handling”

Unlike traditional databases where failure handling is largely abstracted away, Cassandra drivers expose failure scenarios directly to the application. The developer is responsible for configuring appropriate responses to failures.

This design is intentional: Cassandra's distributed architecture means that "failure" is nuanced. A node being slow is different from a node being down. A write timeout does not mean the write failed—it may have succeeded on some replicas. The driver cannot make assumptions about what the application considers acceptable behavior.

Failure TypeWhat HappenedDriver's QuestionDeveloper Must Decide
Read timeoutSome replicas didn't respond in timeRetry or fail?Is stale data acceptable? Retry elsewhere?
Write timeoutCoordinator didn't get enough acknowledgmentsRetry or fail?Is duplicate write acceptable? Is operation idempotent?
UnavailableNot enough replicas alive to satisfy CLRetry or fail?Lower consistency acceptable? Wait and retry?
Node downNode unreachableWhere to route? When to retry connection?Failover strategy? Recovery timing?

Default policies exist but are generic. Production applications must evaluate each policy against their specific requirements for consistency, latency, and availability.


PolicyQuestion It AnswersDefault Behavior
Load BalancingWhich node should handle this request?Round-robin across local datacenter, token-aware
RetryShould a failed request be retried?Retry read timeouts once, don't retry write timeouts
ReconnectionHow quickly to reconnect after node failure?Exponential backoff (driver-specific defaults)
Speculative ExecutionShould redundant requests be sent?Disabled

Understanding default behavior is essential before customizing policies.

PolicyConfigurationBehavior
Load Balancingbasic.load-balancing-policyToken-aware, prefers local DC, round-robin within replicas
RetryDefaultRetryPolicyRetry read timeout if enough replicas responded; never retry write timeout
ReconnectionExponentialReconnectionPolicyBase: 1 second, Max: 60 seconds (verify for specific version)
Speculative ExecutionNoneDisabled—must explicitly enable
PolicyDefault ImplementationBehavior
Load BalancingTokenAwarePolicy(DCAwareRoundRobinPolicy())Token-aware wrapping DC-aware round-robin
RetryRetryPolicyRetry read timeout once on same host; retry unavailable once on next host
ReconnectionExponentialReconnectionPolicyBase: 1 second, Max: 600 seconds
Speculative ExecutionNoneDisabled

Understanding common failure scenarios helps in selecting appropriate policies.

Driver failing over to another replica after a node connection failureApplicationDriverNode1Node2Node3ApplicationApplicationDriverDriverNode1Node1Node2Node2Node3Node3Node1 failsExecute queryRequest [token owner]Connection failedLoad balancer selects next nodeRequest [replica]SuccessResult

Policy involvement:

  • Load Balancing: Provides fallback nodes when primary fails
  • Retry: Determines if connection failure triggers retry
  • Reconnection: Schedules background reconnection to Node1

Scenario 2: Read Timeout (Partial Response)

Section titled “Scenario 2: Read Timeout (Partial Response)”
Read timeout when replicas do not answer a QUORUM readApplicationDriverCoordinatorReplica1Replica2Replica3ApplicationApplicationDriverDriverCoordinatorCoordinatorReplica1Replica1Replica2Replica2Replica3Replica3SELECT [QUORUM]QueryRead requestRead requestRead requestDataSlow or unresponsiveTimeout waiting for quorumReadTimeoutException[received=1, required=2]Retry policy consultedRetry or throw?

Policy involvement:

  • Retry: Decides whether to retry based on how many replicas responded
  • Speculative Execution: Could have sent parallel request to avoid timeout
Write timeout leaving the outcome on a slow replica unknownApplicationDriverCoordinatorReplica1Replica2ApplicationApplicationDriverDriverCoordinatorCoordinatorReplica1Replica1Replica2Replica2INSERT [QUORUM]WriteWrite requestWrite requestACKSlow - no responseTimeout [received=1, required=2]WriteTimeoutExceptionDid R2 receive the write?Retry could cause duplicate!

Critical consideration: Write may have succeeded on R2 but acknowledgment was lost. Retrying non-idempotent writes risks data corruption.

Application reachability of nodes during a network partitionApplication reachability of nodes during a network partitionReachablePartitionedApplicationNode1Node2Node3Node4Node5blocked

Policy involvement:

  • Load Balancing: Must route only to reachable nodes
  • Reconnection: Attempts to reconnect to partitioned nodes
  • Retry: Unavailable exceptions if CL cannot be met with reachable nodes

Multi-DC deployments require careful policy configuration to ensure correct behavior during normal operation and DC failures.

Always configure the local datacenter explicitly. This is the most critical setting for multi-DC deployments.

// Java - REQUIRED for multi-DC
CqlSession session = CqlSession.builder()
.withLocalDatacenter("dc1")
.build();
# Python - REQUIRED for multi-DC
from cassandra.policies import DCAwareRoundRobinPolicy
cluster = Cluster(
load_balancing_policy=DCAwareRoundRobinPolicy(local_dc='dc1')
)
Multi-datacenter routing preferring local nodes with remote nodes used only for failoverMulti-datacenter routing preferring local nodes with remote nodes used only for failoverApplication in DC1DC1 (Local)DC2 (Remote)ApplicationNode1Node2Node3Node4Node5Node6PRIMARY(low latency)PRIMARYPRIMARYFAILOVER ONLYFAILOVER ONLY
ConfigurationNormal OperationLocal DC Down
LOCAL_QUORUM + local DC onlyRoutes to local DCAll requests fail
LOCAL_QUORUM + remote DC allowedRoutes to local DCStill fails (LOCAL_* CLs only count local replicas)
QUORUM + remote DC allowedMay route anywhereContinues if global quorum available

Configure multi-DC failover via application.conf:

datastax-java-driver {
basic.load-balancing-policy {
local-datacenter = "dc1"
}
advanced.load-balancing-policy {
# Allow failover to remote DC (requires non-LOCAL consistency levels)
dc-failover.max-nodes-per-remote-dc = 2
}
}

LOCAL consistency levels

Allowing remote DC nodes in the load balancing policy does not enable failover for LOCAL_* consistency levels. These levels only count replicas in the coordinator's datacenter regardless of where the request originates.

Consistency LevelMulti-DC BehaviorDC Failure Impact
LOCAL_ONELocal DC onlyFails if local DC down
LOCAL_QUORUMLocal DC onlyFails if local DC down
QUORUMGlobal quorumMay succeed with one DC down
EACH_QUORUMQuorum in every DCFails if any DC down
ALLEvery replicaFails if any node down

Recommendation: Use LOCAL_QUORUM for most operations. Configure load balancer to allow remote DC failover only when acceptable for the use case.


Default policies are designed for general use cases but may not match specific application requirements:

ScenarioDefault BehaviorProblem
Multi-DC deploymentMay route to remote DCHigh latency if local DC not configured
Heterogeneous hardwareEqual distributionOverloads weaker nodes
Batch analyticsToken-aware routingOptimal for OLTP, but analytics may prefer round-robin
ScenarioDefault BehaviorProblem
Non-idempotent writesMay retry on timeoutPotential duplicate writes
Overloaded clusterRetry immediatelyAmplifies load, worsens situation
Read timeoutRetry same nodeNode may still be slow
ScenarioDefault BehaviorProblem
Brief network blipExponential backoffSlow recovery for transient issues
Node replacementStandard reconnectionMay attempt reconnection to decommissioned node
Rolling restartBackoff after each nodeCascading delays

Policies do not operate in isolation—they interact during request execution:

Interaction of load balancing and retry policies during request executionInteraction of load balancing and retry policies during request executionApplication executes queryLoad Balancing PolicySend to Node1Response?Return resultRetry PolicySend to Node3Return errorResponse?Continue or failReturns node order:[N1, N3, N2]SuccessFailureRetry allowedNo retrySuccessFailure

If speculative execution is enabled, requests are sent concurrently:

Speculative execution sending a concurrent request to a second nodeApplicationDriverNode1Node3ApplicationApplicationDriverDriverNode1Node1Node3Node3Execute queryRequestStart 50ms timerSpeculative requestResponse [fast]Return resultOriginal still pendingResponse [ignored]

Do not rely on defaults for production deployments. Configure each policy explicitly via application.conf (preferred) or programmatically:

# application.conf - Recommended approach for Java Driver 4.x
datastax-java-driver {
basic {
load-balancing-policy.local-datacenter = "dc1"
}
advanced {
reconnection-policy {
class = ExponentialReconnectionPolicy
base-delay = 1 second
max-delay = 5 minutes
}
speculative-execution-policy {
class = ConstantSpeculativeExecutionPolicy
max-executions = 2
delay = 100 milliseconds
}
}
}
// Load configuration from application.conf
CqlSession session = CqlSession.builder()
.withConfigLoader(DriverConfigLoader.fromClasspath("application.conf"))
.build();

Some policies can be overridden per statement:

// Override retry policy for specific query
Statement statement = SimpleStatement.builder("SELECT * FROM users WHERE id = ?")
.addPositionalValue(userId)
.setRetryPolicy(FallthroughRetryPolicy.INSTANCE) // No retries
.build();

This allows different behavior for different query types (e.g., strict no-retry for non-idempotent writes).


Use CaseLoad BalancingRetryReconnectionSpeculative Execution
OLTP (low latency)Token-aware, local DCConservative (reads only)Fast base (500ms)Enable for reads
Batch/AnalyticsRound-robin or token-awareAggressive retryStandardDisable
Multi-DC Active-ActiveToken-aware, local DC, failover enabledPer-DC retryStandardLocal DC only
Write-heavyToken-awareNo retry for writesStandardDisable
Read-heavyToken-awareRetry readsStandardEnable
# application-oltp.conf
datastax-java-driver {
basic.load-balancing-policy.local-datacenter = "dc1"
advanced {
load-balancing-policy.slow-replica-avoidance = true
reconnection-policy {
class = ExponentialReconnectionPolicy
base-delay = 500 milliseconds
max-delay = 2 minutes
}
speculative-execution-policy {
class = ConstantSpeculativeExecutionPolicy
max-executions = 2
delay = 50 milliseconds
}
}
}
# application-multi-dc.conf
datastax-java-driver {
basic.load-balancing-policy.local-datacenter = "dc1"
advanced {
load-balancing-policy {
# Allow failover to remote DC (requires non-LOCAL consistency levels)
dc-failover.max-nodes-per-remote-dc = 2
}
reconnection-policy {
class = ExponentialReconnectionPolicy
base-delay = 1 second
max-delay = 5 minutes
}
# No speculative execution across DCs (latency difference too high)
}
}