Skip to content

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

Cassandra Driver Speculative Execution Policy

Speculative execution reduces tail latency by sending redundant requests to multiple nodes. When one node is slow, another may respond faster, improving perceived latency without waiting for timeouts.


Instead of waiting for a single request to complete or timeout, speculative execution sends the same request to additional nodes after a delay:

Without speculative execution:

ClientNode 1ClientClientNode 1Node 1Request (t=0ms)Slow processing...Response (t=150ms, P99)

With speculative execution (delay = 50ms):

ClientNode 1Node 2ClientClientNode 1Node 1Node 2Node 2Request (t=0ms)Slow processing...Speculative request (t=50ms)Response (t=80ms)Use first response(Node 2)Response (t=150ms, ignored)

The application receives the response in 80ms instead of 150ms.


Speculative execution is effective when:

ConditionBenefit
High P99 latency due to outliersReduces tail latency significantly
Individual node slowdownsOther replicas compensate
GC pauses on specific nodesRequest completes on non-GC node
Network congestion to specific nodesAlternate path may be faster

Speculative execution is less effective when:

ConditionLimitation
All nodes uniformly slowBoth requests are slow
Coordinator overhead dominatesProblem is client-side, not server
Query requires cross-partition coordinationComplexity is inherent

Speculative execution particularly helps with tail latencies. P50 and P90 remain largely unchanged, but P99 improves significantly as the slower replica is bypassed:

PercentileWithout Speculative ExecutionWith Speculative Execution
P50~2ms~2ms
P90~8ms~8ms
P99~100ms~10ms

Send speculative request after fixed delay:

// Java driver
ConstantSpeculativeExecutionPolicy policy =
ConstantSpeculativeExecutionPolicy.builder()
.withMaxExecutions(2) // Original + 1 speculative
.withDelay(Duration.ofMillis(100))
.build();
ParameterDescriptionTypical Value
Max executionsTotal requests (including original)2-3
DelayTime before sending speculative requestP50-P90 latency

Send speculative request when original exceeds observed percentile:

// Send speculative if original takes longer than P95
PercentileSpeculativeExecutionPolicy policy =
PercentileSpeculativeExecutionPolicy.builder()
.withMaxExecutions(2)
.withPercentile(95.0)
.build();

This adapts to actual latency distribution, avoiding unnecessary speculative requests when the cluster is fast.


Speculative execution trades increased cluster load for reduced latency:

ConfigurationApplication RateCluster LoadOverhead
No speculative execution1000 req/sec1000 req/sec0%
Speculative, 10% trigger rate1000 req/sec1100 req/sec+10%
Speculative, 50% trigger rate1000 req/sec1500 req/sec+50%
ScenarioProblem
High trigger rate (>50%)Significant load increase with diminishing returns
Already saturated clusterExtra load makes all requests slower
Non-idempotent operationsDuplicate execution may corrupt data

Speculative execution must only be used with idempotent operations.

Both the original and speculative requests may execute:

Non-Idempotent with Speculative Execution (Dangerous)Non-Idempotent with Speculative Execution (Dangerous)ClientNode 1Node 2ClientClientNode 1Node 1Node 2Node 2UPDATE counter = counter + 1(t=0ms)UPDATE counter = counter + 1(speculative, t=50ms)Execute (+1)Execute (+1)Both requests executeCounter incremented TWICE (corruption)
// Only enable for idempotent queries
Statement statement = SimpleStatement.builder("SELECT * FROM users WHERE id = ?")
.addPositionalValue(userId)
.setIdempotent(true) // Mark as safe
.setSpeculativeExecutionPolicy(speculativePolicy)
.build();
// Disable for non-idempotent queries
Statement counterUpdate = SimpleStatement.builder(
"UPDATE stats SET views = views + 1 WHERE page_id = ?")
.addPositionalValue(pageId)
.setIdempotent(false) // Explicitly mark unsafe
.build();

The delay threshold determines when speculative requests trigger:

ThresholdTrigger RateTrade-off
P50 latency~50% of requestsHigh load, maximum latency reduction
P90 latency~10% of requestsModerate load, good tail reduction
P99 latency~1% of requestsLow load, only extreme outliers
Measurement-Based Tuning ApproachMeasurement-Based Tuning Approach1. Measure current latency distributionP50 = 2ms, P90 = 8ms, P99 = 50ms2. Set delay slightly above target percentileTarget: Reduce P99 without excessive loadDelay: 10ms (slightly above P90)3. Monitor trigger rate and latency improvementBefore: P99 = 50msAfter: P99 = 12ms, trigger rate = 8%4. Adjust based on observed behavior

Speculative requests use the same query plan from load balancing:

ClientNode 1Node 2Node 3ClientClientNode 1Node 1Node 2Node 2Node 3Node 3Query Plan: [Node 1, Node 2, Node 3]Original requestSpeculative #1Speculative #2 (if configured)

Speculative execution and retry serve different purposes:

AspectRetrySpeculative Execution
TriggerAfter failure/timeoutAfter delay (no failure)
GoalHandle errorsReduce latency
SequentialYes (one at a time)No (concurrent)

Both can be enabled simultaneously:

Request Flow with Both PoliciesRequest Flow with Both PoliciesClientClientClientNode 1Node 1Node 1Node 2Node 2Node 2Node 3Node 3Node 3ClientClientNode 1Node 1Node 2Node 2Node 3Node 3Request (t=0ms)50ms passes, no responseSpeculative request (t=50ms)Node 1 times out at 100msRetry policy evaluates:Node 2? Already sent, skipNode 3? YesRetry requestResponseReturn to applicationLate response (ignored)Late response (ignored)Most drivers do not cancelin-flight requests

MetricDescriptionWarning Sign
Speculative trigger rate% of requests triggering speculative>30% indicates latency issues
Speculative wins% of responses from speculative requestLow rate means delay too high
Total request rateIncluding speculative requestsUnexpected increase in cluster load

Example metrics (workload-dependent; use as starting point, not targets):

MetricExpected Range
Trigger rate5-15%
Win rate40-60% of triggered
Latency improvement50%+ reduction in P99

Warning signs (investigate if observed):

ObservationPossible Cause
Trigger rate >50%Delay too low or cluster too slow
Win rate <20%Delay too high, speculative rarely faster
Win rate >80%Delay too low, original always slow

Optimal thresholds vary significantly by workload, cluster topology, and latency distribution.


Use CaseMax ExecutionsDelayNotes
Latency-sensitive reads2P90 latencyConservative, low overhead
Aggressive tail reduction3P75 latencyHigher load, better tail
Read-heavy analyticsDisabled-Throughput more important than latency
Non-idempotent writesDisabled-Never use with non-idempotent ops