Apache Cassandra Developer Associate study materials
Apache Cassandra Developer Associate study resources

Apache Cassandra Developer Associate cheat sheet

Apache Cassandra Developer Associate · Keep the key ideas within reach.

Quick reference

Cassandra Architecture and Data Distribution

  • A cluster is a ring of nodes; each node owns token ranges determined by the partitioner (Murmur3Partitione by default). Data is distributed by hashing the partition key to a token.

  • Replication factor (RF) defines how many copies of each partition exist. SimpleStrategy is for single-DC only; NetworkTopologyStrategy is required for multi-DC and rack awareness.

  • Consistency level (CL) is per-operation. Write CL + read CL > RF ensures strong consistency for a single DC (e.g., RF=3, W=QUORUM, R=QUORUM).

  • Hinted handoff: if a replica is down, the coordinator stores a hint and replays it when the node returns (default 3 hours).

  • Read repair: during a read, the coordinator compares replicas and repairs stale ones. Blocking read repair triggers when replicas differ; background repair may also run.

  • Anti-entropy repair (nodetool repair) uses Merkle trees to reconcile data across replicas. Must run within gc_grace_seconds to avoid resurrecting deleted data.

  • Gossip protocol disseminates node state (up/down, load, schema) every second. Phi accrual failure detector marks nodes down.

  • Snitch determines network topology (racks, DCs) for replica placement. Common snitches: SimpleSnitch (single DC), GossipingPropertyFileSnitch (multi-DC), Ec2Snitch.

  • Commit log is a crash-safe log on disk; memtable is in-memory. Writes go to commit log and memtable; SSTables are immutable on-disk files flushed from memtables.

Quick reference

Data Modeling and Schema Design

  • Model around queries, not entities. Start with the query patterns; each query should map to one table (denormalization is expected).

  • Partition key determines data distribution and must be chosen for even spread and to avoid hot partitions. Composite partition keys can help.

  • Clustering columns define sort order within a partition and support range queries. Order matters: it defines the on-disk order.

  • Primary key = partition key + clustering columns. Only columns in the primary key can be used in WHERE without ALLOW FILTERING.

  • Avoid wide partitions: keep partitions under ~100MB and under 100k rows for performance. Use bucketing (e.g., time-based) to split large partitions.

  • Collection types (list, set, map) have overhead; use frozen collections for immutability and better performance when the whole collection is read/written.

  • Use counter columns only for distributed counters; they cannot be mixed with non-counter columns in the same table.

  • Secondary indexes are for low-cardinality columns; they can cause scatter-gather across nodes. Prefer denormalized tables or materialized views (with caution).

  • TTL (time-to-live) can be set per column or per table to expire data automatically; compaction removes expired tombstones after gc_grace_seconds.

Quick reference

CQL (Cassandra Query Language)

  • CQL is a query language similar to SQL but with no joins, no subqueries, and limited support for OR. It is case-insensitive for keywords; identifiers are case-insensitive unless quoted.

  • SELECT statements must include the partition key (with = or IN) for efficient queries; otherwise ALLOW FILTERING may be required, which is expensive.

  • INSERT is an upsert: it inserts or updates based on primary key. There is no separate UPDATE for new rows; UPDATE only updates existing rows (or creates them if they don't exist? Actually UPDATE can create a row if it doesn't exist? In Cassandra, UPDATE can create a row if it doesn't exist? No, UPDATE will create a new row if it doesn't exist? Actually, in Cassandra, UPDATE is an upsert? Let's check: In Cassandra, INSERT and UPDATE are both upserts. UPDATE will create a row if it doesn't exist? Yes, in Cassandra, UPDATE can create a row if it doesn't exist? I think it's: INSERT is an upsert. UPDATE is also an upsert? Actually, in Cassandra, UPDATE is an upsert? I recall that UPDATE can create a row if it doesn't exist? Let's verify: In CQL, UPDATE can create a new row if it doesn't exist? I think it's: INSERT will create or update. UPDATE will only update if the row exists? Actually, in Cassandra, UPDATE is an upsert as well. For example, UPDATE users SET name='John' WHERE id=1; if id=1 doesn't exist, it will create a new row with id=1 and name='John'. So both INSERT and UPDATE are upserts. But there is a subtlety: INSERT with IF NOT EXISTS is conditional. So I'll state: INSERT and UPDATE are both upserts; they create or overwrite rows. DELETE removes columns or rows; it creates tombstones.

  • BATCH statements group mutations for atomicity and performance. Use UNLOGGED BATCH for multiple partitions? Actually, LOGGED BATCH ensures atomicity across partitions but has overhead; use for small batches. UNLOGGED BATCH is for single partition and improves performance.

  • Lightweight transactions (LWT) use IF conditions (e.g., IF NOT EXISTS) with SERIAL consistency. They are expensive (Paxos) and should be used sparingly.

  • CQL supports collections, user-defined types (UDTs), and tuples. UDTs must be frozen to be used in primary key or as collection element.

  • Functions: now(), uuid(), toTimestamp(), toDate(), etc. Aggregations: COUNT, SUM, AVG, MIN, MAX. COUNT(*) is expensive on large tables.

  • CQL limits: no JOIN, no GROUP BY (except with aggregates), no OR (use IN), no subqueries. Use denormalization to avoid joins.

Quick reference

Client Drivers and Application Development

  • Drivers: Java, Python, Node.js, C#, etc. Use the DataStax driver (now Apache Cassandra driver) for your language. Drivers handle connection pooling, load balancing, and failover.

  • Consistency level is set per statement or at session level. Use LOCAL_QUORUM for multi-DC to avoid cross-DC latency.

  • Prepared statements improve performance by caching the query plan on the server; use them for repeated queries.

  • Token-aware routing: drivers route requests directly to a replica holding the data when possible, reducing latency.

  • Retry policies: default retry policy handles host down, read timeout, write timeout. Customize based on application needs.

  • Speculative execution: drivers can send requests to multiple replicas if the first is slow, reducing tail latency. Configure carefully.

  • Connection pooling: maintain enough connections to each node (default 1 per node per pool). Tune based on throughput.

  • Idempotence: mark statements as idempotent to allow safe retries. Non-idempotent statements (e.g., counters) should not be retried blindly.

  • Use paging for large result sets (fetch size). Drivers automatically page; set fetch size appropriately.

Quick reference

Performance Tuning and Query Optimization

  • Monitor with nodetool tpstats, tablestats, and metrics (e.g., Prometheus). Look for dropped mutations, pending compactions, and high GC.

  • Tune JVM: heap size (usually 8-16GB), GC (G1GC recommended), and avoid swapping. Set -Xms and -Xmx equal.

  • Compaction strategy: SizeTieredCompactionStrategy (STCS) for write-heavy, LeveledCompactionStrategy (LCS) for read-heavy with low space overhead, TimeWindowCompactionStrategy (TWCS) for time-series.

  • Key cache and row cache: key cache is on by default and helps; row cache is usually off and only for small, frequently read partitions.

  • Bloom filters reduce disk reads; tune bloom_filter_fp_chance (default 0.01). Lower value = more memory but fewer false positives.

  • Use compression (LZ4 or Zstd) to reduce disk I/O and storage; LZ4 is faster, Zstd compresses better.

  • Avoid ALLOW FILTERING; design tables to support queries. Use secondary indexes only when necessary.

  • Batch writes to the same partition to reduce overhead; avoid large batches across partitions.

  • Use denormalization and materialized views to optimize reads, but be aware of write overhead and consistency issues.

Quick reference

Operations, Maintenance, and Troubleshooting

  • nodetool status: shows cluster state (UN = Up Normal). nodetool ring: shows token ownership. nodetool info: node details.

  • nodetool repair: run regularly (weekly) to reconcile data. Use -pr for partition range repair to reduce impact. Must run within gc_grace_seconds.

  • nodetool cleanup: removes data no longer owned by the node after topology changes (e.g., adding a node). Run on all nodes after adding/removing nodes.

  • nodetool refresh: loads new SSTables from the data directory (used after restoring from backup).

  • nodetool snapshot: creates a hard-link snapshot of SSTables. Use nodetool clearsnapshot to remove.

  • Backup strategies: snapshots + commit log archiving. Restore: stop node, clear data, copy snapshot files, restart.

  • Troubleshooting: check system.log, debug.log. Common issues: out of memory, disk full, high GC, tombstones, large partitions.

  • nodetool cfstats / tablestats: shows table statistics (read/write latency, SSTable count, bloom filter false positives).

  • nodetool tpstats: thread pool stats; look for dropped messages (e.g., MutationStage, ReadStage).