Jump to Category
| 🌐 Core Architecture & Distributed Concepts | 🏗️ Data Modeling & Schema Design |
| ⚙️ Read/Write Path & Internals | 🔏 Consistency & Transactions |
| 🛠️ Maintenance & Operations | ✨ Advanced Features |
Core Architecture & Distributed Concepts
1. How does the Gossip protocol work in Cassandra and what is its purpose?
Gossip is a peer-to-peer communication protocol that Cassandra nodes use to exchange location and state information about each other. Periodically (every second), each node gossips with a few other random nodes in the cluster, sharing its own state and the state of other nodes it knows about. This information propagates exponentially through the cluster, allowing every node to quickly build a complete map of the cluster’s topology and health.
Its primary purpose is for failure detection and maintaining cluster membership information without needing a central master node.
Read a blog post explaining the Gossip Protocol.2. What are virtual nodes (vnodes) and why were they introduced?
Virtual nodes (vnodes) allow a single physical node to own multiple, smaller, non-contiguous ranges of the token ring. Instead of a node being responsible for one large token range, it is responsible for many smaller ones.
They were introduced to solve several problems with the old single-token architecture:
- Faster Rebalancing: When a new node joins, it can “steal” small token ranges from many different nodes in the cluster, making rebalancing faster and more efficient.
- Quicker Recovery: When a node fails, its ranges are distributed among many other nodes, spreading the load.
- Heterogeneous Hardware: Allows for assigning a different number of vnodes to machines with different capacities.
3. Explain the role of a Snitch in Cassandra.
A **Snitch** is a configurable component that determines the network topology of the cluster. It provides information about which datacenter and rack a node belongs to. This information is crucial for the replica placement strategy, which tries to place replicas on different racks (and datacenters) to improve fault tolerance. It ensures that requests are routed efficiently to the closest replica and that replicas are distributed to avoid single points of failure (like a power outage to a single rack).
4. What is a Coordinator node?
A **Coordinator** is the node that receives a client request in a Cassandra cluster. It is responsible for routing the request to the appropriate replica nodes that own the data, based on the partition key and the cluster’s replication strategy. The Coordinator then waits for responses from the replicas, and once the requested consistency level is met, it sends the result back to the client. Any node in the cluster can act as a coordinator for any request.
5. What is the significance of the Replication Factor (RF) and how does it relate to availability?
The **Replication Factor (RF)** is the total number of copies of your data stored across the cluster. An RF of 3 means that for every piece of data, there is a primary copy and two replicas stored on different nodes.
A higher RF directly increases availability and read scalability. If a node goes down, its data is still available on other replicas. An RF of 1 means you have no fault tolerance—if that one node fails, the data is unavailable. A typical production setting is an RF of 3.
Data Modeling & Schema Design
6. Explain the difference between a partition key and a clustering column.
- The **Partition Key** determines which node(s) in the cluster will store the data. Cassandra hashes the partition key to calculate a token, which maps to a position on the token ring. All rows with the same partition key reside on the same set of replica nodes.
- Clustering Columns** (or clustering keys) determine the on-disk sorting order of rows *within* a single partition. This allows for efficient range queries (slice queries) within a partition.
A table’s primary key is composed of the partition key and, optionally, one or more clustering columns.
Read about the basic rules of Cassandra Data Modeling.7. Why is a “query-first” approach essential for Cassandra data modeling?
Unlike SQL databases where you can join tables freely, Cassandra’s data model is heavily optimized for fast reads but is very restrictive in how you can query. You cannot perform server-side joins or query on non-key columns efficiently. Therefore, you must design your tables specifically to answer your application’s queries. The “query-first” approach means you start by identifying all the queries your application will need, and then design tables where the `PRIMARY KEY` and clustering order directly support those queries, even if it means denormalizing and duplicating data across multiple tables.
8. What is a static column and what is its use case?
A **static column** is a special column that is shared by all rows within a single partition. While regular columns have a different value for every row (defined by the clustering keys), a static column has only one value per partition key.
This is useful for storing metadata about a partition. For example, in a `users` table where `user_id` is the partition key and `event_timestamp` is a clustering column, you could have static columns for `user_name` and `user_email`. This way, the user’s name and email are not duplicated for every single event row within that user’s partition.
9. What is a “wide partition” or “hotspot” and how can you avoid it?
A **wide partition** is a partition that grows very large, containing a huge number of rows. A **hotspot** is a partition that receives a disproportionate amount of read/write traffic. Both are caused by poor data modeling where a single partition key is used too frequently.
To avoid them, you need to ensure an even distribution of data. A common technique is to add a “bucketing” field to the partition key. For example, instead of partitioning time-series data by `sensor_id` alone, you could partition by `(sensor_id, month)` or `(sensor_id, day)` to create smaller, more manageable partitions.
10. When should you use a User-Defined Type (UDT)?
A User-Defined Type allows you to group multiple related fields into a single column, similar to a `struct` in other languages. You should use a UDT when you have a set of fields that logically belong together and will always be queried and updated as a single unit. For example, you could create an `address` UDT with fields for `street`, `city`, and `zip_code`. This can be more convenient than having many separate columns, but you cannot index individual fields within a UDT.
Read/Write Path & Internals
11. Describe the write path of a Cassandra request.
The write path is optimized for high throughput and low latency. When a write request arrives at the coordinator node:
- The data is immediately written to an on-disk **Commit Log** for durability. This is an append-only log, so it’s very fast.
- The data is then written to an in-memory structure called a **Memtable**.
- An acknowledgment is sent back to the client as soon as these two steps are complete.
Periodically, when the Memtable becomes full or after a configurable time, its contents are flushed to a new, immutable file on disk called an **SSTable** (Sorted String Table).
Read about how writes are handled in Cassandra.12. Describe the read path. How does Cassandra find data in SSTables?
The read path is more complex as it needs to consolidate data from multiple sources.
- The query first checks the **Memtable** for the requested data.
- If not found, it checks the **Bloom Filter** for each SSTable. The Bloom Filter is a probabilistic data structure in memory that can definitively say if a key *is not* in an SSTable, avoiding unnecessary disk reads.
- If the Bloom Filter reports a possible hit, it checks the in-memory **Partition Key Cache**.
- If still not found, it goes to disk, reading the **Partition Summary** and **Index File** to find the exact offset of the data in the main **Data File** (the SSTable).
Data from the Memtable and all relevant SSTables are merged at query time to construct the final result, always taking the row with the most recent timestamp.
Read about how data is read in Cassandra.13. What are tombstones and what is their performance impact?
Because SSTables are immutable, Cassandra cannot perform in-place deletes. When you delete data, Cassandra writes a special marker called a **tombstone**. This tombstone indicates that the data is deleted. During a read, if a tombstone is found, the corresponding data is omitted from the result set.
Tombstones have a significant performance impact because they are not “free.” They occupy space on disk and must be read and processed during queries. A query that scans over many tombstones can become very slow. Tombstones are permanently removed during the **compaction** process, but only after they are older than `gc_grace_seconds`.
Learn about Deletes and Tombstones.14. What is compaction and why is it necessary? Compare two compaction strategies.
Compaction is the process of merging multiple SSTables on disk into a new, single SSTable. Its primary purposes are to consolidate data fragments, remove deleted data (tombstones), and evict stale data, which keeps read performance high.
- Size-Tiered Compaction Strategy (STCS): Merges SSTables of a similar size. It’s good for write-heavy workloads but can lead to a lot of wasted space while old SSTables are waiting to be compacted.
- Leveled Compaction Strategy (LCS): Organizes SSTables into multiple “levels” of a fixed size. This results in more predictable read performance and less wasted space, but at the cost of higher I/O overhead for writes. It’s better for read-heavy workloads.
Consistency & Transactions
15. Explain tunable consistency. What does the formula `R + W > N` guarantee?
Tunable consistency** means that you can specify, on a per-query basis, how many replica nodes must acknowledge a read (`R`) or a write (`W`) for it to be considered successful. `N` is the replication factor.
The formula `R + W > N` guarantees **strong consistency**. It ensures that the set of nodes you read from (`R`) and the set of nodes you write to (`W`) will always have at least one node in common (an overlap). This guarantees that you will always read the most recently written version of the data.
A common configuration is `N=3`, `W=QUORUM (2)`, and `R=QUORUM (2)`. Here, `2 + 2 > 3`, so strong consistency is achieved.
Explore how to configure Data Consistency.16. What is the difference between `QUORUM` and `LOCAL_QUORUM`?
- `QUORUM`: Requires a majority of replicas across *all* datacenters in the cluster to respond. For an RF of 3 in two datacenters (total replicas = 6), a `QUORUM` would be 4.
- `LOCAL_QUORUM`: Requires a majority of replicas only in the *local* datacenter (the one the coordinator belongs to) to respond. This is much faster and avoids cross-datacenter latency for acknowledgements, making it the preferred choice for multi-datacenter deployments.
17. What are Lightweight Transactions (LWTs)? How do they work?
Lightweight Transactions provide conditional, check-and-set operations using the `IF` clause (e.g., `INSERT … IF NOT EXISTS`). They allow you to perform an update only if a certain condition is met, ensuring atomicity for a single operation.
Under the hood, they use a consensus protocol based on **Paxos**. This involves multiple round trips between the coordinator and replica nodes to propose, agree upon, and commit the change. Because of this overhead, LWTs are significantly slower than regular writes and should be used sparingly.
Learn about Lightweight Transactions.18. Explain the different types of batch statements (`LOGGED`, `UNLOGGED`, `COUNTER`). When should you use a batch?
- `LOGGED`: Guarantees atomicity. The batch is sent to a batchlog to ensure that either all mutations in the batch succeed or none do. This incurs a performance penalty.
- `UNLOGGED`: Does not guarantee atomicity. It’s primarily a tool for the driver to group mutations together to reduce network round trips. This is the most common type.
- `COUNTER`: Used exclusively for updating counter columns.
You should use batches primarily to achieve atomicity (`LOGGED`) for a small number of updates to a *single partition*. They are an anti-pattern for bulk-loading data, as this can overload the coordinator node. Asynchronous queries are better for bulk loading.
Maintenance & Operations
19. What is the purpose of the `nodetool repair` command?
`nodetool repair` is a critical maintenance process that synchronizes data between replica nodes to fix any inconsistencies. Due to the distributed nature of Cassandra, inconsistencies can arise if a node is down during a write or due to other failures. The repair process streams data between nodes to ensure every replica has the most recent version of all data it’s supposed to own. It should be run periodically (e.g., weekly) on all nodes in the cluster.
20. What is `gc_grace_seconds` and what are the implications of setting it incorrectly?
`gc_grace_seconds` is a per-table setting that defines the amount of time Cassandra will wait before a tombstone can be permanently removed by the compaction process. Its purpose is to give a downed node enough time to recover and learn about the deletion via repair.
If you set it too low, a downed node could be brought back online after a tombstone has been garbage collected, causing the “deleted” data to be re-introduced into the cluster (this is called a “zombie” row). If you set it too high, tombstones will linger for a long time, negatively impacting read performance. The default is 10 days, and it should be set lower than your regular repair schedule.
21. What happens when you add a new node to a running cluster?
When a new node joins, it gets assigned several token ranges (vnodes). It then streams the data for which it is now responsible from the existing replica nodes in the cluster. During this “bootstrapping” process, the cluster remains online and available. Once the streaming is complete, the new node will begin taking a share of the read and write traffic for its assigned ranges.
22. What are hinted handoffs?
If a write is sent to a replica node that is temporarily down, the coordinator node will store a “hint” locally. A hint contains the data and information about which node it belongs to. The coordinator will periodically try to deliver the hint to the downed node. Once the node comes back online, the hint is delivered, and the write is applied. This is a mechanism that provides write availability even during short-term node failures.
Advanced Features
23. What are Materialized Views and what are their limitations?
A Materialized View is a server-side denormalized view of a base table, but organized by a different primary key. It allows you to have an alternative, efficient query path for your data without needing to manage the denormalization in your application code.
Limitations: They are considered an experimental feature with many restrictions. For example, you cannot delete from a materialized view, and updates to the base table can be significantly slower because the view must also be updated. They can also be a source of instability, and many experts recommend handling denormalization manually in the application instead.
24. What are counter columns and their limitations?
Counters are a special column type used for counting. They support only increment and decrement operations. Updates to counters are not idempotent; retrying a counter update will result in it being incremented multiple times. They must be updated using `COUNTER` batches and cannot be mixed with regular updates in the same statement.
25. Can you perform a `DELETE` operation with a `WHERE` clause on a non-primary key column?
No. In Cassandra, `DELETE` operations, like `SELECT` operations, must be able to uniquely identify the row(s) to be affected using the primary key. You must provide the full partition key and can optionally filter by clustering columns. You cannot perform a delete based on the value of a non-key column unless that column has a secondary index (which is often an anti-pattern for deletes).
26. How do you handle schema changes in a live cluster?
Schema changes in Cassandra are not applied instantly across the cluster. The change is propagated via the Gossip protocol. It’s important to wait for the schema to agree across all nodes before using the new schema in your application. This can be checked with `nodetool describecluster`. Adding a new column is a safe, non-breaking operation. Dropping a column is also safe, but you should ensure no code is still using it. Modifying a column’s type is a more complex operation that often requires creating a new table and migrating the data.
27. What are User-Defined Functions (UDFs) and User-Defined Aggregates (UDAs)?
UDFs allow you to define custom functions in languages like Java or JavaScript that can be executed on the server side as part of a query. This can be used to perform complex data transformations directly in Cassandra.
UDAs allow you to define custom aggregation functions, beyond the built-in `count`, `sum`, `avg`, etc. You define the state function and the final function to create your own aggregation logic.
Both should be used with caution as they execute on the server and can be a source of performance problems if not written carefully.
28. What are some common anti-patterns in Cassandra?
- Using secondary indexes on high-cardinality columns: This can create significant cluster overhead.
- Allowing unbounded partition growth: Not using a bucketing strategy for wide partitions.
- Using `IN` queries with a large number of keys: This can put significant pressure on the coordinator node.
- Using batches for bulk loading: Asynchronous queries are the correct tool for this.
- Reading before writing: This pattern is inefficient and often indicates a data modeling problem that could be solved with denormalization.
29. What is speculative retry?
Speculative retry is a client-side optimization. If a read request to one node is taking too long to respond, the driver can proactively send a second request to another replica node for the same data. It then uses whichever response comes back first and discards the other. This can improve tail latency in a cluster where some nodes might be temporarily slow, but it comes at the cost of sending redundant requests.
30. What is the purpose of `TRUNCATE` and how does it work?
The `TRUNCATE` command removes all data from a table instantly. Unlike a `DELETE` query, it does not generate individual tombstones for each row, making it a very fast operation. It works by creating a new set of empty SSTables for the table and marking the old ones for deletion, which is much more efficient than creating millions of tombstones.