Memtable

MEMTABLE - The In-Memory Speed Demon

ðŸ’ū Master Cassandra's write buffer: data structures, flush triggers, memory management, and sub-millisecond performance!

📖 Instagram: 1 Billion Writes/Day, Sub-5ms Latency

Instagram's challenge: 1 billion+ users generating massive write traffic. Every like, comment, story, message = write to Cassandra. Peak: 500,000 writes/second! The requirement: Sub-5ms latency (users notice delays > 10ms). Traditional disk-based writes = 10-50ms (too slow!). The solution: Memtable - in-memory write buffer. How it works: Every write goes to memtable FIRST → In-memory sorted tree structure (RAM = instant!). Write latency: 0.1ms → 100 microseconds! 100x faster than disk. Sorted on insert → Maintains partition key + clustering key order. Flush to SSTable later → When memtable reaches 128MB (async). Result: P50 latency: 2.8ms ✓ (0.1ms memtable + 1ms commit log + 1.7ms network). P99 latency: 8ms ✓ (still under 10ms requirement!). 1 billion writes/day → memtable absorbs bursts effortlessly. Users never wait → instant feedback on every action. Instagram Engineering: "The memtable is why Cassandra can handle our write volume. RAM is 100,000x faster than disk - by buffering writes in memory, we achieve sub-millisecond latency at massive scale. The 128MB flush threshold perfectly balances memory usage vs flush frequency. Without memtable, Instagram wouldn't scale!"

ðŸ’ū What is a Memtable?

Memtable is Cassandra's in-memory write buffer - where speed magic happens!

📋

Definition

What: In-memory sorted data structure
Type: Write buffer (part of LSM tree)
Purpose: Fast writes + recent read cache
Location: JVM heap memory
Per-table: Each table has its own memtable
Volatile: Data lost on crash (commit log protects!)

⚡

Why It Exists

Problem: Disk writes are slow (10-50ms)
Solution: Buffer writes in RAM first
Speed: RAM = 0.1ms vs Disk = 10ms
Batch: Flush many writes at once → SSTable
Efficiency: Amortize disk I/O cost
Result: Sub-millisecond write latency!

🔄

Lifecycle

1. Create: Empty memtable on startup
2. Fill: Accept writes until threshold (64-128MB)
3. Freeze: Make read-only when full
4. Flush: Write to SSTable on disk
5. Delete: Free memory after flush
6. Repeat: New memtable for next batch

ðŸŒģ

Data Structure

Type: Skip list (concurrent sorted map)
Sorted by: Partition key → Clustering key
Why sorted: Fast lookups + efficient SSTable write
Concurrency: Lock-free for high throughput
Complexity: O(log n) insert and lookup
Typical size: 64-128MB of data

ðŸ’ū

Memory Characteristics

Heap-based: Lives in JVM heap
GC impact: Can cause pauses if too large
Off-heap option: Available to reduce GC
Compression: None (raw data for speed)
Typical usage: 10-20% of heap
Monitoring: Track memtable size carefully

ðŸŽŊ

Role in LSM Tree

LSM: Log-Structured Merge Tree
Level 0: Memtable (in memory)
Level 1+: SSTables (on disk)
Write path: Always to memtable first
Read path: Check memtable before SSTables
Merge: Flush creates new SSTable level

Memtable in the Write Path Client Write INSERT UPDATE 0.1ms ðŸ’ū Memtable (RAM) ✓ Sorted tree structure ✓ 64-128MB size ~100 microseconds! SUCCESS ⚠ïļ When Memtable Reaches 128MB... 1. Freeze (make read-only) 2. Create new memtable 3. Flush old to SSTable async ðŸ’ŋ SSTable (Disk) ✓ Immutable file (takes 2-5 seconds) 🔑 Key Insight: Why Memtable Makes Writes Fast RAM access = 100 nanoseconds (0.0001ms) vs Disk = 10 milliseconds → Writing to memtable is 100,000x faster than writing directly to disk! → Batch flush amortizes disk I/O cost across many writes ✓

ðŸ’Ą The Speed Secret

Why is memtable so fast?

RAM vs Disk Physics:
â€Ē RAM latency: 100 nanoseconds = 0.0001ms
â€Ē SSD latency: 100 microseconds = 0.1ms (1,000x slower)
â€Ē HDD latency: 10 milliseconds = 10ms (100,000x slower!)

By keeping recent writes in memtable (RAM), Cassandra avoids disk I/O completely for hot data. This is the foundation of sub-5ms write latency at massive scale. The memtable is Cassandra's secret weapon!

ðŸŒģ Data Structure: Skip List Deep Dive

Memtable uses a concurrent skip list for lock-free sorted storage!

📊

Skip List Basics

Type: Probabilistic balanced tree
Layers: Multiple levels of linked lists
Bottom layer: All elements sorted
Higher layers: Express lanes (skip ahead!)
Search: Start top, drop down when needed
Complexity: O(log n) average for all ops

🔒

Why Skip List?

Concurrent: Lock-free updates!
No rebalancing: Unlike red-black trees
Simple: Easier to implement than B-trees
Sorted: Maintains order automatically
Fast: O(log n) with low constants
Memory: Efficient space usage

🔑

Sort Order

Primary key: Partition key (hash)
Secondary: Clustering key (defines row order)
Example: users (user_id, timestamp)
Sorted by: user_id → timestamp
Why important: Fast range queries
SSTable: Written in same order

⚡

Insert Performance

Time complexity: O(log n)
Typical: 10-20 comparisons for 1M rows
Latency: ~100 microseconds
Concurrency: Lock-free (CAS operations)
Throughput: Millions of inserts/sec
Bottleneck: Rarely (memory bandwidth!)

🔍

Lookup Performance

Single key: O(log n)
Range scan: O(log n + k) where k = results
Hit rate: 80-95% for recent data
Latency: Sub-millisecond
Cache friendly: Sequential memory access
Miss: Continue to SSTables

ðŸ’ū

Memory Layout

Nodes: Key + Value + Pointers
Overhead: ~20-30 bytes per entry
Fragmentation: Minimal (linked structure)
GC pressure: Can be high if large
Off-heap option: Reduce GC pauses
Typical: 64-128MB total size

⚙ïļ Lock-Free Concurrency

Why lock-free matters:

With locks: Multiple threads compete for lock, one wins, others wait. Throughput limited by lock contention. At high concurrency, performance degrades linearly.

Lock-free (skip list): Use Compare-And-Swap (CAS) atomic operations. Multiple threads can insert simultaneously. No waiting, no contention. Throughput scales with CPU cores!

This is why Cassandra can handle 500,000 writes/sec on a single node - the memtable never blocks!

✍ïļ Write Operations: Inserts and Updates

Every write goes through the memtable instantly - here's how!

1ïļâƒĢ

INSERT Operation

Step 1: Find insertion point (binary search)
Step 2: Create new node with data
Step 3: CAS insert into skip list
Step 4: Update memtable size counter
Latency: ~100 microseconds
Thread-safe: Lock-free CAS ensures atomicity

2ïļâƒĢ

UPDATE Operation

No in-place update! Insert new version instead
Same key: Insert with newer timestamp
Old version: Kept until compaction
Read: Returns newest timestamp
Why: Immutability = lock-free!
Cleanup: Compaction removes old versions

3ïļâƒĢ

DELETE Operation

Tombstone: Insert deletion marker
Not deleted: Data still in memtable!
Timestamp: Deletion time recorded
Reads: Skip tombstoned entries
Cleanup: Removed during compaction
Why: Fast deletes without searching

📊

Size Tracking

Counter: Track total memtable size
Per-write: Add data size to counter
Overhead: Include node pointers
Threshold: 64-128MB triggers flush
Atomic: Thread-safe increment
Monitoring: Check via JMX metrics

⚡

Batch Mutations

BATCH: Multiple writes together
Atomic: All or nothing semantics
Same memtable: All go to same structure
Performance: Amortize overhead
Size check: After batch, check threshold
Benefit: Reduce network roundtrips

🔄

Timestamp Management

Mutation timestamp: Microsecond precision
Client-provided: Or server generates
Conflict resolution: Last-Write-Wins (LWW)
Stored: With each column value
Read: Return newest timestamp
Critical: Determines data freshness

⚡ Twitter: 400,000 Tweets/Second in Memtable

Twitter's peak write load during major events:

The Challenge:
â€Ē Super Bowl, World Cup = 400,000 tweets/second
â€Ē Each tweet = INSERT into timelines table
â€Ē Must handle bursts without latency spikes
â€Ē Users expect instant tweet posting

Memtable Performance:
â€Ē Skip list handles 400k inserts/sec per node
â€Ē Average insert latency: 95 microseconds
â€Ē Lock-free = no contention even at peak
â€Ē Memtable absorbs burst (128MB buffer)
â€Ē Flush happens async (doesn't block writes!)

Key metric: P99 write latency stayed under 5ms even during Super Bowl peak! The memtable's lock-free skip list scaled linearly with CPU cores. This is why Twitter trusts Cassandra for real-time social feeds!

📖 Read Operations: Memtable as Cache

Memtable isn't just for writes - it's also a blazing-fast read cache!

📌

Read Path Priority

Step 1: Check memtable FIRST
Hit: Return data immediately (sub-ms!)
Miss: Continue to SSTables
Why first: Most recent data here
Hit rate: 80-95% for hot data
Benefit: Avoid disk I/O for recent writes

🔍

Single Key Lookup

Partition key: Hash to find node
Skip list search: O(log n) traversal
Found: Return value + timestamp
Not found: Check SSTables
Latency: 50-200 microseconds
Efficiency: No disk access needed!

📋

Range Query

Clustering range: Use skip list order
Sequential scan: After finding start
Performance: O(log n + k) where k = rows
Efficient: Sorted structure = fast scan
Merge: Combine with SSTable results
Typical: Faster than SSTables!

⏱ïļ

Cache Hit Benefits

No disk I/O: Skip SSTable read
No bloom filter: Skip probabilistic check
No index lookup: Direct memory access
Latency: <1ms vs 10-50ms disk
Throughput: Millions of reads/sec
Cost: No I/O cost!

🔄

Read-Write Consistency

Write then read: Always see latest
Same node: Memtable guarantees freshness
Timestamp: Newest version returned
No stale reads: Within same node
Distributed: CL determines freshness
Local consistency: Perfect!

📊

Multi-Memtable Reads

Active memtable: Check current first
Flushing memtables: Check frozen too
Multiple: During flush, 2+ exist
Merge: Combine results by timestamp
Rare: Usually only 1 memtable
Performance: Still sub-millisecond

🚀 Read Performance Impact

Memtable cache hit rates matter A LOT:

95% hit rate: P99 latency = 2ms (mostly memtable)
50% hit rate: P99 latency = 15ms (half go to disk)
10% hit rate: P99 latency = 50ms (mostly disk I/O)

For read-heavy workloads, keeping your working set in memtable is CRITICAL for performance. This is why larger memtables (128MB vs 64MB) can dramatically improve read latency!

⚡ Flush Triggers: When Memtable Becomes SSTable

Understanding flush triggers is critical for tuning Cassandra performance!

📏

1. Size Threshold (Primary)

Default: 64MB per table memtable
Configurable: 32-256MB typical range
When: Memtable reaches threshold size
Trigger: Automatic background flush
Frequency: Depends on write rate
Config: memtable_heap_space_in_mb

⏰

2. Time-Based Flush

Default: 1 hour (3600 seconds)
Purpose: Prevent stale data in memory
When: Even if size not reached
Why: Free commit log space
Low traffic: Tables flush eventually
Config: memtable_flush_period_in_ms

ðŸ’ū

3. Memory Pressure

Trigger: Total memtable memory > threshold
Threshold: Typically 2-4GB total
Action: Flush largest memtable first
Emergency: Prevent OOM (out of memory)
Cascading: Flush multiple if needed
Monitoring: Watch total memtable size

📜

4. Commit Log Pressure

Trigger: Commit log size exceeds limit
Default: Usually 8GB total
Problem: Can't truncate commit log
Solution: Force memtable flush
Why: Allow commit log cleanup
Impact: May flush smaller memtables

🔧

5. Manual Flush

Command: nodetool flush [keyspace] [table]
When: Operator initiated
Use cases: Before backup, repair, upgrade
Effect: All memtables flushed immediately
Blocks: Waits for flush completion
Safe: No data loss risk

🛑

6. Shutdown Flush

When: Node gracefully stopped
Action: Flush ALL memtables
Purpose: Minimize commit log replay
Duration: Can take 1-5 minutes
Skip: Kill -9 doesn't flush (unsafe!)
Result: Clean shutdown, fast restart

Memtable Flush Decision Tree Memtable Active (accepting writes) Size: 0MB → 64MB → 128MB Size >= 128MB? (or time > 1 hour?) YES TRIGGER FLUSH 1. Freeze current memtable 2. Create new memtable NO Continue accepting writes Keep accumulating data repeat Flush Process Timeline T=0 Trigger T=1ms Freeze + new memtable T=2-5s Write SSTable (128MB → disk) T=5s Complete ✓ Free memory ðŸ’Ą Key: Freeze + new memtable takes ~1ms. Writes never blocked! Actual SSTable write (2-5s) happens asynchronously in background

⚙ïļ Tuning Flush Threshold

Larger memtable (128-256MB):
✅ Fewer flushes = less I/O overhead
✅ Better compression (more data = better ratios)
✅ Higher cache hit rate (more data in RAM)
❌ Longer flush time (more data to write)
❌ More memory usage
❌ Longer commit log replay on crash

Smaller memtable (32-64MB):
✅ Faster flush (less data to write)
✅ Less memory usage
✅ Faster crash recovery
❌ More frequent flushes = more I/O
❌ More SSTables = slower reads

Sweet spot: 64-128MB for most workloads!

🧠 Memory Management: Heap vs Off-Heap

Proper memory management is critical for stability and performance!

ðŸ“Ķ

Heap-based Memtable

Default: Lives in JVM heap
Allocation: Standard Java objects
GC impact: Part of GC scanning
Pros: Simple, fast allocation
Cons: GC pauses with large heaps
Typical: 10-20% of heap size

🔓

Off-heap Memtable

Available: Cassandra 2.1+
Location: Direct ByteBuffer (native memory)
GC impact: Minimal (not scanned!)
Pros: No GC pauses from memtable
Cons: Slower allocation, more complex
Config: memtable_allocation_type: offheap_objects

⚠ïļ

GC Pause Impact

Small heap (8GB): GC pauses <100ms ✓
Medium heap (16GB): Pauses 200-500ms ⚠ïļ
Large heap (32GB+): Pauses 1-5s ❌
Memtable contribution: 20-40% of pause time
Solution: Use off-heap or G1GC
Monitoring: Track GC pause frequency

📊

Total Memory Budget

Heap allocation: 8-16GB typical
Memtable: 1-3GB (10-20% of heap)
Row cache: 0-2GB (optional)
Other: 5-11GB (bloom filters, index, buffers)
Off-heap: OS file cache uses remaining RAM
Recommendation: Leave 50% RAM for OS cache

🔧

Memory Configuration

memtable_heap_space_in_mb: Max total size
Default: 1/4 of heap
memtable_offheap_space_in_mb: Off-heap limit
memtable_cleanup_threshold: Flush trigger
JVM heap: -Xms8G -Xmx8G (example)
Monitoring: nodetool info | grep Memtable

⚖ïļ

Heap vs Off-heap Trade-offs

Use heap when: Heap <16GB, simple setup
Use off-heap when: GC pauses >200ms
Heap benefit: Faster allocation, simpler
Off-heap benefit: No GC pauses
Performance: Similar (not a magic bullet!)
Most common: Heap-based with G1GC

🧠 Netflix: Solving GC Pauses with Off-heap

Netflix's GC problem:

Before (heap memtable):
â€Ē 32GB heap with 4GB memtable space
â€Ē GC pauses: 2-5 seconds (terrible!)
â€Ē P99 latency spikes to 6 seconds during GC
â€Ē Users see buffering/errors during pauses
â€Ē Problem: Large heap + large memtables = long GC

After (off-heap memtable):
â€Ē Reduced heap to 16GB
â€Ē 4GB memtable moved off-heap
â€Ē GC pauses: 100-200ms (95% reduction!)
â€Ē P99 latency: 15ms (consistent)
â€Ē Zero user-visible pauses ✓

Configuration:
â€Ē memtable_allocation_type: offheap_objects
â€Ē memtable_offheap_space_in_mb: 4096
â€Ē JVM: -Xms16G -Xmx16G + G1GC

Netflix Engineering: "Moving memtables off-heap was transformative. GC pauses dropped from 5 seconds to 200ms. The trade-off is minimal - allocation is slightly slower, but that's nothing compared to eliminating multi-second pauses. For large heaps (>16GB), off-heap memtables are essential!"

🚀 Performance Characteristics

Understanding memtable performance limits helps with capacity planning!

✍ïļ

Write Throughput

Single node: 100,000-500,000 writes/sec
Limited by: CPU cores (lock-free scales!)
8 cores: ~200,000 writes/sec
16 cores: ~400,000 writes/sec
Not limited by: Memory (until GC pressure)
Bottleneck: Usually network or commit log

📖

Read Throughput

Cache hit: 1,000,000+ reads/sec
Latency: 50-200 microseconds
Limited by: Memory bandwidth
Sequential scan: Very fast (sorted!)
Random access: O(log n) still fast
Miss: Continue to SSTables (slower)

⏱ïļ

Latency Breakdown

Write operation:
â€Ē Serialize: 20Ξs
â€Ē Memtable insert: 100Ξs
â€Ē Commit log: 1000Ξs (1ms)
â€Ē Total: ~1.2ms
Read operation:
â€Ē Memtable lookup: 100Ξs
â€Ē If miss, SSTable: +10ms

ðŸ’ū

Memory Efficiency

Data overhead: 20-30 bytes per entry
Compression: None (speed over space)
Typical ratio: 1.2-1.5x raw data size
128MB memtable: ~100MB actual data
Efficient: Skip list = low overhead
Compare SSTable: 3-5x compression possible

📊

Scaling Characteristics

CPU cores: Linear scaling (lock-free!)
Memory: More = higher hit rate
Flush frequency: Larger = fewer flushes
Tables: Each has own memtable
50 tables: 50x memory requirement
Limitation: Total memory budget

ðŸŽŊ

Real Benchmarks

Test: 16-core server, 32GB RAM
Write: 380,000 ops/sec sustained
Read (hit): 1.2M ops/sec
P50 latency: 0.8ms write, 0.15ms read
P99 latency: 2.5ms write, 0.5ms read
CPU: 70% utilized, GC <5%

ðŸĒ Real Company Memtable Strategies

ðŸ“ą WhatsApp: 1 Billion Users, 256MB Memtables

Scale: 1B+ users, 100B+ messages/day
Challenge: Minimize latency for message delivery

Configuration:
â€Ē memtable_heap_space_in_mb: 256 (2x default!)
â€Ē Why larger: Fewer flushes = more stable latency
â€Ē Trade-off: More memory, but worth it
â€Ē JVM heap: 24GB (16GB for memtables)
â€Ē GC: G1GC with off-heap option

Results:
â€Ē Flush frequency: Every 10 minutes (vs 2-3 min default)
â€Ē P99 latency: 4ms (consistent!)
â€Ē No latency spikes during flush
â€Ē Cache hit rate: 97% (larger memtable = more hits!)
â€Ē GC pauses: <100ms average

Key insight: Larger memtables reduce flush frequency and improve cache hit rates. The extra memory cost is worth it for latency-sensitive workloads!

ðŸŽĩ Spotify: Off-heap for User Listening Data

Use case: Track user listening history (billions of plays)
Problem: Large heap causing 3-5s GC pauses

Solution:
â€Ē Switched to off-heap memtables
â€Ē memtable_allocation_type: offheap_objects
â€Ē memtable_offheap_space_in_mb: 8192 (8GB!)
â€Ē Reduced JVM heap: 32GB → 16GB
â€Ē More RAM for OS file cache

Before (heap):
â€Ē GC pauses: 3-5 seconds
â€Ē P99 latency: 6 seconds (during GC)
â€Ē User-facing errors during pauses

After (off-heap):
â€Ē GC pauses: 150ms average ✓
â€Ē P99 latency: 12ms ✓
â€Ē Zero user-facing errors ✓
â€Ē 96% reduction in GC pause time!

Spotify Engineering: "Off-heap memtables transformed our stability. The 5-second GC pauses were killing us. Now with off-heap, we get all the benefits of large memtables without the GC penalty!"

ðŸŽŪ Blizzard: 32MB Memtables for Predictable Performance

Use case: World of Warcraft game state (millions of players)
Requirement: Predictable low latency (game feel!)

Strategy:
â€Ē Smaller memtables: 32MB (vs 64-128MB typical)
â€Ē Why: More frequent flushes = more predictable
â€Ē Flush every 30-60 seconds (fast!)
â€Ē SSTable count higher, but acceptable
â€Ē Trade-off: More I/O for consistency

Benefits:
â€Ē Latency variance: Very low (5ms Âą 1ms)
â€Ē No large flush delays
â€Ē Predictable commit log size
â€Ē Fast crash recovery (<30 seconds)
â€Ē Memory pressure: Lower

Key insight: Smaller memtables = more predictable behavior. For latency-sensitive gaming workloads, consistency matters more than peak throughput!

✅ Best Practices: Memtable Optimization

1ïļâƒĢ

1. Size Memtables Appropriately

Default 64MB: Good starting point
High write load: 128-256MB
Low latency need: 32-64MB
Rule of thumb: Flush every 2-10 minutes
Monitor: nodetool tablestats
Adjust: Based on flush frequency

2ïļâƒĢ

2. Monitor Memory Usage

Total memtable size: Should be <25% heap
Alert threshold: >30% heap = problem
Check: nodetool info | grep Memtable
GC impact: Watch pause times
Action: If >30%, reduce memtable size
Tools: JMX metrics, Prometheus

3ïļâƒĢ

3. Use Off-heap for Large Heaps

If heap >16GB: Consider off-heap
If GC >200ms: Definitely use off-heap!
Config: memtable_allocation_type: offheap_objects
Benefit: Eliminate memtable GC pauses
Cost: Slightly slower allocation
Worth it: For large deployments

4ïļâƒĢ

4. Limit Number of Tables

Each table: Has its own memtable
100 tables: = 100x memory requirement
Problem: Memory fragmentation
Recommendation: <50 tables per node
Alternative: Use larger nodes
Anti-pattern: One table per user (bad!)

5ïļâƒĢ

5. Tune Flush Writers

memtable_flush_writers: Parallel flush threads
Default: 2 threads
High write load: Increase to 4-8
Benefit: Faster flush = less memory pressure
Trade-off: More disk I/O concurrency
Monitor: Flush queue depth

6ïļâƒĢ

6. Test Memtable Size Changes

Don't assume: Bigger is always better
Benchmark: Test different sizes
Measure: Latency, flush freq, GC pauses
Sweet spot: Different per workload
Load test: Simulate production traffic
Monitor: P99 latency under load

ðŸšĻ Common Mistakes

  • ❌ Memtables too large: GC pauses kill performance (use off-heap!)
  • ❌ Too many tables: Each has memtable = memory explosion
  • ❌ Ignoring GC pauses: >500ms = major problem
  • ❌ Not monitoring flush frequency: Too frequent = I/O storm
  • ❌ Heap-based with >16GB heap: Use off-heap instead!
  • ❌ Assuming defaults are optimal: Tune for your workload!

💞 Interview Questions & Answers

1
Explain what a memtable is and why it's critical for Cassandra's write performance

Complete Answer:

A memtable is Cassandra's in-memory write buffer - a sorted data structure that temporarily holds recent writes before they're flushed to disk as SSTables.

What is Memtable:

  • Structure: Concurrent skip list (lock-free sorted tree)
  • Location: JVM heap memory (or off-heap)
  • Per-table: Each Cassandra table has its own memtable
  • Size: Typically 64-128MB before flush
  • Sorted: Maintains order by partition key → clustering key
  • Volatile: Data lost on crash (protected by commit log)

Why Critical for Write Performance:

1. RAM is 100,000x faster than disk:

  • RAM access: 100 nanoseconds = 0.0001ms
  • SSD access: 100 microseconds = 0.1ms (1,000x slower)
  • HDD access: 10 milliseconds (100,000x slower!)
  • Writing to memtable = writing to RAM = instant!

2. Batches writes to amortize disk I/O:

  • Instead of writing each mutation to disk individually
  • Accumulate many writes in memtable (64-128MB)
  • Flush all at once to SSTable
  • One big sequential write >> many small random writes
  • Reduces disk I/O overhead by 100-1000x!

3. Provides sorted structure:

  • Skip list maintains sort order automatically
  • When flushed, SSTable is already sorted
  • No need to sort on flush (would be slow!)
  • Makes range queries fast

Write Path Flow:

  1. Write arrives at coordinator
  2. Write to commit log (durability) - 1ms
  3. Write to memtable (performance) - 0.1ms
  4. Return SUCCESS to client - total ~3ms
  5. Later: Flush memtable to SSTable (async)

Performance Impact:

Without memtable: Every write = disk I/O = 10-50ms latency

With memtable: Every write = RAM access = 0.1ms latency

Result: 100-500x faster writes!

Flush Process:

  • When memtable reaches 64-128MB threshold
  • Freeze current memtable (make read-only)
  • Create new empty memtable (1ms operation)
  • Flush frozen memtable to SSTable in background (2-5 seconds)
  • Writes never blocked - go to new memtable immediately!

Key Insight: The memtable is the foundation of Cassandra's write performance. By buffering writes in RAM and batching disk I/O, Cassandra achieves sub-5ms write latency even at 500,000 writes/second. This is what makes Cassandra suitable for write-heavy workloads like time-series data, logging, and real-time analytics!

2
Why does Cassandra use a skip list for memtable? Compare to other data structures.

Complete Answer:

Cassandra uses a concurrent skip list for memtable because it provides O(log n) operations with lock-free concurrency - critical for high-throughput writes.

Skip List Basics:

  • Structure: Multiple levels of sorted linked lists
  • Bottom level: All elements in sorted order
  • Higher levels: "Express lanes" that skip ahead
  • Search: Start at top level, drop down when needed
  • Probabilistic: Random promotion to higher levels
  • Complexity: O(log n) average for insert, search, delete

Why Skip List vs Alternatives:

Skip List vs Red-Black Tree:

  • Skip list advantage: Lock-free concurrent updates!
  • Red-black tree requires locking for rebalancing
  • Lock contention kills throughput at high concurrency
  • Skip list: Use Compare-And-Swap (CAS) operations
  • Multiple threads can insert simultaneously without waiting
  • Throughput scales linearly with CPU cores
  • Skip list advantage: Simpler implementation
  • No complex rotation/rebalancing logic
  • Easier to reason about correctness

Skip List vs Hash Table:

  • Skip list: Maintains sorted order
  • Hash table: No inherent order
  • Critical: Cassandra needs sort order for clustering keys
  • Range queries require sorted structure
  • SSTable flush requires sorted data
  • Skip list: Range scan is O(log n + k)
  • Hash table: Range scan would be O(n)

Skip List vs B-tree:

  • Skip list advantage: Better for in-memory
  • B-tree optimized for disk (minimize seeks)
  • In memory, simpler structure wins
  • Skip list advantage: Lock-free possible
  • B-tree difficult to make lock-free (complex balancing)
  • Skip list: Lower constant factors
  • Fewer pointer chases than B-tree

Lock-Free Concurrency Deep Dive:

This is THE critical reason Cassandra uses skip list!

Problem with locks:

  • Thread A acquires lock, inserts data
  • Threads B, C, D wait for lock
  • At high concurrency (100+ threads), massive contention
  • Throughput degrades as threads increase

Skip list lock-free approach:

  • Use atomic CAS (Compare-And-Swap) operations
  • Insert attempts: CAS(node.next, NULL, new_node)
  • If CAS fails (another thread inserted), retry
  • No waiting, no blocking
  • All threads make progress simultaneously
  • Throughput scales linearly with cores!

Real Performance Impact:

Benchmark: 16-core server, concurrent inserts:

Red-black tree (locked): 50,000 inserts/sec (lock contention)

Skip list (lock-free): 400,000 inserts/sec (8x faster!)

Scaling: Skip list throughput increases with cores, locked structure plateaus

Trade-offs:

  • Skip list downside: Probabilistic (not guaranteed O(log n))
  • In practice: Very rare to degrade
  • Skip list downside: Pointer overhead
  • Each node needs multiple next pointers (for levels)
  • ~20-30 bytes overhead per entry
  • Acceptable for in-memory structure

Key Insight: The skip list's lock-free property is what enables Cassandra to handle 500,000 writes/second on a single node. Any locked data structure would become a bottleneck at that scale. The combination of O(log n) operations, sorted order, and lock-free concurrency makes skip list the perfect choice for memtable!

Advertisement

Responsive Ad