Top 42 RabbitMQ & Cassandra Interview Questions & Answers (2026)
About RabbitMQ & Cassandra
Top 50 RabbitMQ and Apache Cassandra interview questions covering messaging patterns, exchanges, queues, wide-column storage, consistency, and distributed data modeling. Companies hiring for RabbitMQ & Cassandra roles test this knowledge at every stage — from first-round screens that check the basics to final-round conversations about real-world trade-offs.
What to Expect in a RabbitMQ & Cassandra Interview
Expect a mix of conceptual and practical RabbitMQ & Cassandra questions: clear definitions and core-concept checks for junior roles, hands-on scenario questions for mid-level roles, and architecture or trade-off discussions for senior roles. Interviewers usually move from foundational topics toward the kind of problems you'd actually face on the job.
How to Use This Guide
Work through the RabbitMQ & Cassandra questions in order — Beginner, then Intermediate, then Advanced — so each concept builds on the last. Every question has its own page; bookmark the ones that trip you up and revisit them the day before your interview.
Curated by Tech Baithak Editorial Team · Last updated: June 2026
Core concepts every RabbitMQ & Cassandra developer must know.
01
What is RabbitMQ?
RabbitMQ is an open-source message broker that implements the AMQP (Advanced Message Queuing Protocol) standard. It acts as an intermediary between message producers and consumers, enabling asynchronous, decoupled communication between services. Developed by Rabbit Technologies (acquired by VMware/Broadcom), RabbitMQ routes messages through exchanges to queues where consumers retrieve them. Key features: Multiple protocols: AMQP 0-9-1 (native), AMQP 1.0, MQTT, STOMP, and HTTP. Flexible routing: four exchange types for different routing patterns. Reliability: persistent messages, publisher confirms, consumer acknowledgements. Management UI: built-in web console. Plugins: federation, shovel, delayed messaging. RabbitMQ is used for task queues, microservice communication, event notification, and workflow orchestration.
02
What is the difference between RabbitMQ and Kafka?
RabbitMQ and Kafka are both message brokers but serve different use cases. RabbitMQ: traditional message broker. Messages are deleted after acknowledgement — no replay. Supports complex routing patterns (direct, fanout, topic, headers). Suited for task queues, RPC patterns, and complex routing logic. Each message is typically processed by one consumer. Lower throughput than Kafka but simpler for task-based workloads. Kafka: distributed event streaming platform. Messages are retained on disk for days/weeks — consumers can replay. Simple append-only log per topic partition. Suited for high-throughput event streaming, log aggregation, and analytics. Can deliver the same message to multiple consumer groups independently. Much higher throughput. Rule of thumb: use RabbitMQ when you need complex routing, per-message acknowledgement, or traditional messaging semantics. Use Kafka when you need high throughput, event replay, or multiple independent consumers of the same events.
03
What are RabbitMQ exchanges?
An exchange in RabbitMQ is the component that receives messages from producers and routes them to one or more queues based on routing rules. Producers never send directly to a queue — they send to an exchange with a routing key. Four exchange types: Direct: routes messages to queues whose binding key exactly matches the routing key. Used for one-to-one routing. Fanout: routes to all bound queues, ignoring routing keys. Used for broadcast/publish-subscribe. Topic: routes based on pattern matching with wildcards (* matches one word, # matches zero or more). Flexible for hierarchical routing. Headers: routes based on message header attributes instead of routing keys — allows complex multi-attribute matching. Default (nameless) exchange: built-in direct exchange — routes to a queue with the same name as the routing key. Exchanges are declared by producers or operators before use.
04
What are RabbitMQ queues?
A queue in RabbitMQ is a buffer that stores messages until they are consumed. Messages are stored in FIFO order by default. Key queue properties: Name: unique identifier (or auto-generated). Durable: queue survives a broker restart. Non-durable queues are lost on restart. Exclusive: accessible only to the declaring connection; deleted when the connection closes. Auto-delete: deleted when all consumers disconnect. Arguments: x-message-ttl (expire messages), x-max-length (max messages), x-dead-letter-exchange (where rejected messages go). Quorum queues: replicated across nodes using Raft consensus — the modern replacement for classic mirrored queues. Classic queues: single-node or mirrored (deprecated in favor of quorum). Stream queues: like Kafka topics — retain messages for replay, support multiple consumers. Queue durability + persistent messages ensures messages survive broker restarts.
05
What is a message binding in RabbitMQ?
A binding is a relationship between an exchange and a queue — it defines the routing rule for how messages flow from the exchange to the queue. Create a binding with a binding key: channel.queueBind(queue: "order_processing", exchange: "orders", routingKey: "order.created"). For a direct exchange: the binding key must exactly match the message's routing key. For a topic exchange: the binding key supports wildcards (order.* matches order.created but not order.item.created; order.# matches both). For a fanout exchange: the binding key is ignored — all bound queues receive every message. One exchange can be bound to multiple queues, and one queue can be bound to multiple exchanges. The binding concept separates the concerns of routing logic (exchange) from storage (queue), enabling the same exchange to route to different queues based on binding keys.
06
What is message acknowledgement in RabbitMQ?
Message acknowledgement ensures messages are not lost if a consumer crashes while processing. By default (auto-ack), messages are acknowledged when delivered. With manual ack, the consumer explicitly acknowledges after successful processing: channel.basicAck(deliveryTag, false). If the consumer crashes before acknowledging, RabbitMQ re-queues the message for another consumer — guaranteeing at-least-once delivery. Negative acknowledgement (nack): channel.basicNack(deliveryTag, false, requeue: true) — requeue for retry, or requeue: false to discard/dead-letter. Reject: basicReject(deliveryTag, requeue) — same as nack but for a single message. Prefetch count: channel.basicQos(prefetchCount: 10) — limits unacknowledged messages per consumer, enabling fair dispatch and back pressure. Always use manual acknowledgement in production — auto-ack means messages are lost if the consumer dies mid-processing.
07
What is a dead letter exchange (DLX) in RabbitMQ?
A Dead Letter Exchange (DLX) is an exchange where messages are routed when they cannot be delivered to their intended queue or consumer. Messages become "dead letters" when: they are negatively acknowledged (nack) with requeue: false, they exceed the queue's TTL (x-message-ttl), or the queue exceeds its max length. Configure DLX on a queue: {"x-dead-letter-exchange": "dlx_exchange", "x-dead-letter-routing-key": "dead"}. A second queue binds to the DLX to receive dead letters. Use cases: Error handling: inspect failed messages. Delayed retry: dead-letter to a TTL queue, then re-route back to the original queue after the TTL expires (delayed retry pattern). Monitoring: alert when messages accumulate in the DLX. Dead letter queues are essential for production RabbitMQ systems — without them, failed messages are silently discarded or cause infinite retry loops.
08
What is Apache Cassandra?
Apache Cassandra is an open-source, highly scalable, distributed NoSQL database designed for handling massive amounts of data across many commodity servers with no single point of failure. Originally developed at Facebook for Inbox Search, it was open-sourced in 2008. Cassandra combines key features from Amazon Dynamo (distributed architecture, eventual consistency, tunable consistency) and Google Bigtable (column-family data model). Key characteristics: Linear scalability: add nodes to increase throughput proportionally. High availability: no master node — all nodes are equal. Tolerates node failures without downtime. Tunable consistency: configure per-query between strong and eventual consistency. Wide-column store: data organized in tables with flexible column structure. Used by Netflix, Apple, Discord, Instagram, and thousands of other companies for high-write, high-read workloads requiring 100% uptime.
09
What is Cassandra's data model?
Cassandra uses a wide-column store model. Data is organized in keyspaces (similar to databases) containing tables. A table has rows, but unlike relational databases, rows can have different numbers of columns. Primary key: critical in Cassandra. Consists of: Partition key (required): determines which node stores the data via consistent hashing. All rows with the same partition key are stored together on the same node(s). Clustering columns (optional): sort rows within a partition, enable range queries. A table: CREATE TABLE user_events (user_id UUID, event_time TIMESTAMP, event_type TEXT, data TEXT, PRIMARY KEY (user_id, event_time)) WITH CLUSTERING ORDER BY (event_time DESC);. Queries must include the partition key — Cassandra is not designed for ad-hoc queries. The data model must be designed around query patterns, not normalized relationships. Denormalization and duplication are normal and expected in Cassandra.
10
What is the CAP theorem and how does Cassandra fit?
The CAP theorem states that a distributed system can guarantee at most two of three properties: Consistency (all nodes see the same data at the same time), Availability (every request gets a response), Partition tolerance (system continues despite network partitions). Since network partitions are unavoidable in distributed systems, the real choice is between CP (favor consistency when a partition occurs) and AP (favor availability). Cassandra is AP by default: it prioritizes availability and partition tolerance. When a partition occurs, Cassandra continues accepting reads and writes — but may serve stale data. However, Cassandra offers tunable consistency — you can choose strong consistency at the cost of availability: consistency QUORUM reads/writes require a majority of replica nodes, making Cassandra more CP-like. consistency ALL requires all replicas. consistency ONE is maximum availability (AP). Most production deployments use QUORUM for a balance of consistency and availability.
11
What is Cassandra's replication strategy?
Cassandra replication stores multiple copies of each partition across different nodes for fault tolerance. Configure per keyspace: CREATE KEYSPACE my_app WITH replication = {'class': 'NetworkTopologyStrategy', 'dc1': 3, 'dc2': 2};. SimpleStrategy: places replicas on the next N nodes in the ring (clockwise). Only use for single datacenter setups or testing. NetworkTopologyStrategy: places replicas in specific datacenters with rack awareness. The production choice for multi-DC deployments. Specify replicas per datacenter. Replication factor (RF): how many copies of each partition. RF=3 means 3 copies across 3 nodes (with NetworkTopologyStrategy, spread across racks). With RF=3: you can lose 1 node and still read/write with QUORUM consistency. Consistency level interaction: for strong consistency, reads + writes must overlap: RF=3 with QUORUM (2 nodes) means writes go to 2 nodes and reads come from 2 nodes — guaranteed to see the latest write.
12
What is Cassandra's consistency level?
Cassandra consistency levels define how many replica nodes must respond for a read or write to succeed. Key levels: ONE: one replica responds. Fastest, lowest consistency. A write succeeds when one node confirms. A read returns data from the first node to respond. QUORUM: majority of replicas in the cluster must respond (RF/2 + 1 nodes). Balance of consistency and availability. LOCAL_QUORUM: quorum within the local datacenter only. Best for multi-DC deployments to avoid cross-DC latency on every operation. ALL: every replica must respond. Strongest consistency, least available. LOCAL_ONE: one replica in the local DC. EACH_QUORUM: quorum in each datacenter. Strong consistency condition: write_CL + read_CL > RF. With RF=3: QUORUM write (2 nodes) + QUORUM read (2 nodes) = 4 > 3 — guaranteed to read the latest write. Most production Cassandra uses LOCAL_QUORUM for consistency with low cross-DC latency.
13
What is RabbitMQ's publisher confirms?
Publisher confirms (publisher acknowledgements) ensure that messages from a producer were successfully accepted by the RabbitMQ broker. Without confirms, producers operate in fire-and-forget mode — a network failure or broker issue can silently lose messages. Enable: channel.confirmSelect(). Synchronous confirm: channel.basicPublish(...); channel.waitForConfirmsOrDie(5000) — blocks until the broker confirms or throws if unconfirmed within timeout. Asynchronous confirm: channel.addConfirmListener((sequenceNumber, multiple) -> handleAck, (sequenceNumber, multiple) -> handleNack). The broker sends Ack (message persisted) or Nack (message lost) with a sequence number. Use an in-memory map of pending messages keyed by sequence number — remove on Ack, retry on Nack. Publisher confirms + persistent messages + consumer acknowledgements form RabbitMQ's triple-guarantee for reliable message delivery. Without publisher confirms, message loss can occur between producer send and broker receipt.
14
What is Cassandra's partition key and why is it important?
The partition key is the most critical design decision in Cassandra. It determines how data is distributed across the cluster using a consistent hash: Cassandra hashes the partition key to a token and assigns the data to the node(s) responsible for that token range. Why it matters: Data distribution: a good partition key distributes data evenly across all nodes — avoiding hot partitions (one node handling all traffic). Queries: every query MUST include the partition key (or a full primary key) — Cassandra cannot efficiently query across partitions. Queries without the partition key require a full cluster scan (ALLOW FILTERING — avoid in production). Partition size: recommended max ~100MB or 100K rows per partition. Large partitions cause memory, compaction, and repair issues. Examples of good keys: user_id for user data, (user_id, year_month) for time-series per user. Bad keys: low-cardinality columns like status, country (creates hot partitions). Good partition key design is the foundation of performant Cassandra applications.
15
What is Cassandra's write path?
Cassandra's write path is optimized for high throughput. When a write arrives at a coordinator node: 1. Commit Log: the mutation is appended to the commit log on disk (sequential write — fast). This ensures durability — if Cassandra crashes, the commit log is replayed on startup. 2. MemTable: the mutation is also written to an in-memory data structure called the MemTable, organized by table. The write is acknowledged to the client at this point (when the consistency level is met). 3. SSTable flush: when the MemTable reaches a size threshold, it is flushed to disk as an immutable SSTable (Sorted String Table) file. 4. Compaction: background process merges and removes stale SSTables. Key insight: Cassandra never updates or deletes data in-place — writes are always appends (to commit log and MemTable). Updates create new versions; deletes create tombstones. This makes Cassandra extremely fast for writes — all I/O is sequential appends, which are optimal for disk.
16
What is a tombstone in Cassandra?
A tombstone in Cassandra is a special marker that represents a deleted row or column. Because Cassandra's data files (SSTables) are immutable, deletes cannot remove data in place. Instead, a tombstone is written — a record with the deleted cell's coordinates and a deletion timestamp. During reads, Cassandra merges data from multiple SSTables and the MemTable, and filters out tombstoned data. During compaction, tombstones are removed after the gc_grace_seconds period (default 10 days) — this grace period ensures that all nodes have propagated the delete before actually removing the tombstone. Tombstone problems: accumulating many tombstones causes read performance degradation (Cassandra must skip tombstones during reads). A query scanning thousands of tombstones can cause TombstoneOverwhelmingException. Mitigation: use TTL instead of explicit deletes when possible, design data models to avoid deleting frequently, tune gc_grace_seconds, and monitor tombstone counts.
17
What is RabbitMQ's prefetch and QoS?
Prefetch (Quality of Service / QoS) in RabbitMQ limits the number of unacknowledged messages delivered to a consumer at one time. Set it: channel.basicQos(prefetchCount: 10) — the broker sends at most 10 messages to this consumer that haven't been acknowledged yet. Purpose: Fair dispatch: without prefetch, a busy consumer is flooded with messages while idle consumers wait. With prefetch=1, RabbitMQ gives each consumer one message at a time — when it's acknowledged, the next is sent. Back pressure: prevents a consumer from being overwhelmed with more work than it can handle. Memory management: limits in-flight messages per consumer. Prefetch vs batch size: prefetch is not "process N messages at once" — it's "have at most N unacknowledged messages in flight." A consumer can still acknowledge them one by one. For maximum throughput, use a higher prefetch (100-300). For maximum fairness, use prefetch=1. In production, tune prefetch based on message processing time and consumer count.
18
What is Cassandra's CQL (Cassandra Query Language)?
CQL (Cassandra Query Language) is Cassandra's SQL-like query interface. It looks like SQL but has important differences reflecting Cassandra's distributed nature. Basic operations: CREATE TABLE users (id UUID PRIMARY KEY, name TEXT, email TEXT);. INSERT INTO users (id, name, email) VALUES (uuid(), 'Alice', 'alice@example.com');. SELECT * FROM users WHERE id = ?;. UPDATE users SET name = 'Bob' WHERE id = ?;. DELETE FROM users WHERE id = ?;. Key differences from SQL: WHERE clauses must include the partition key. No arbitrary JOINs (data must be denormalized). No subqueries. ORDER BY only on clustering columns, in the defined clustering order. ALLOW FILTERING enables inefficient full-scan queries — avoid in production. Batch: atomic writes to the same partition: BEGIN BATCH ... APPLY BATCH. TTL: INSERT ... USING TTL 86400 — auto-delete after 1 day. CQL is accessed via drivers (Java, Python, Node.js) or cqlsh CLI.
19
What is Cassandra's eventual consistency and how does it handle conflicts?
Cassandra uses eventual consistency as its default model — all replicas will eventually agree on the same value, but reads might return stale data momentarily. Conflict resolution uses Last Write Wins (LWW): every write is timestamped (in microseconds), and the version with the latest timestamp wins. This means: if two clients write to the same cell simultaneously, the one with the later client timestamp "wins" — the other write is silently discarded. Read repair: when Cassandra reads from multiple replicas and detects inconsistency, it repairs stale replicas in the background (read_repair_chance). Anti-entropy repair: the nodetool repair command compares all replicas and synchronizes them — run regularly in production. Implications: LWW means clock skew between nodes can cause data loss. Using TIMESTAMP in writes allows client-side timestamp control. Cassandra is not suitable for operations requiring strong consistency without configuring QUORUM or ALL consistency levels.
20
What is RabbitMQ's topic exchange?
The topic exchange routes messages based on wildcard pattern matching of the routing key. Routing keys are dot-separated words: order.created.us, order.shipped.eu, user.registered. Binding keys support: * matches exactly one word. # matches zero or more words. Examples: binding key order.* matches order.created and order.shipped but NOT order.item.created. Binding key order.# matches order.created, order.item.created, and order. Binding key # matches all routing keys (like fanout). Binding key *.us.* matches order.us.created but not order.created. Use cases: routing by event type and region (payment.#.eu), routing by severity and component (log.error.#), partial subscription in microservices. Topic exchange is the most flexible exchange type — it can emulate direct (no wildcards) and fanout (# binding).
Practical knowledge for developers with hands-on experience.
01
How does Cassandra's read path work?
Cassandra's read path must merge data from multiple sources. When a read request arrives at a coordinator: 1. Route to replicas: the coordinator determines which nodes hold the partition (based on the partition key hash) and contacts the required number based on consistency level. 2. On each replica: Row cache: if enabled and cache hit, return cached row immediately. Bloom filter: per-SSTable probabilistic filter quickly eliminates SSTables that definitely don't contain the partition. Partition key cache: caches partition key to SSTable offset mappings. SSTable scan: reads from each SSTable that may contain the partition. MemTable: checks in-memory writes. Merge: all read sources are merged, applying timestamps (latest wins) and filtering tombstones. 3. Coordinator merges: combines responses from replicas, returning the most recent data. Read repair: if replicas disagree, repair stale replicas. Reads are typically slower than writes in Cassandra — multiple SSTable reads are merged. Compaction reduces the number of SSTables to improve read performance.
02
What is Cassandra's compaction and its types?
Compaction is Cassandra's background process that merges multiple SSTables into fewer, optimized SSTables — removing tombstones, merging duplicates, and reducing read overhead. Three main compaction strategies: STCS (Size-Tiered Compaction Strategy): default. Groups similarly-sized SSTables and merges them when thresholds are met. Good for write-heavy workloads. Disadvantage: temporarily doubles disk space during compaction; reads can be slow with many SSTables. LCS (Leveled Compaction Strategy): organizes SSTables into levels with fixed sizes. More predictable read performance and less space amplification. Best for read-heavy or mixed workloads. Higher write amplification (more I/O during compaction). TWCS (Time Window Compaction Strategy): designed for time-series data with TTLs. Compacts data within a time window together — enables efficient SSTable expiration when all data in a window is expired. Best for time-series data with consistent TTLs. Choose the strategy based on your read/write ratio and data access patterns.
03
What are RabbitMQ's quorum queues?
Quorum queues are RabbitMQ's modern replicated queue type that uses the Raft consensus algorithm for data safety. They replaced classic mirrored queues (deprecated in RabbitMQ 3.12). How they work: quorum queues are replicated to a configurable number of nodes (default 3). A write is confirmed when a majority (quorum) of nodes acknowledge it. A quorum queue continues to operate as long as a majority of its replicas are available. Key advantages over classic mirrored queues: No message loss on leader failure: Raft guarantees no committed message is lost. Simpler consistency: no split-brain scenarios. Better performance: lower write amplification. Configuration: {"x-queue-type": "quorum"}. Limitations: quorum queues are always durable and cannot be exclusive. They use more disk space (Raft log). Not suitable for very high-frequency consumer cancel/reconnect patterns. Use quorum queues for any production queue requiring high availability and data safety.
04
How do you model time-series data in Cassandra?
Time-series data is one of Cassandra's strongest use cases. Recommended pattern: Partition by time bucket + entity: CREATE TABLE sensor_readings (sensor_id UUID, day DATE, recorded_at TIMESTAMP, value DOUBLE, PRIMARY KEY ((sensor_id, day), recorded_at)) WITH CLUSTERING ORDER BY (recorded_at DESC);. The partition key combines entity ID (sensor_id) and time bucket (day). This gives each day's data for each sensor its own partition — bounded partition size. Clustering by recorded_at DESC enables efficient retrieval of the most recent readings. Query: SELECT * FROM sensor_readings WHERE sensor_id = ? AND day = ? LIMIT 100;. Why time bucketing: a single partition for all a sensor's history would grow unboundedly. Bucketing by day/week/month caps partition size. Bucket granularity: choose based on data volume — high-frequency sensors need smaller buckets (hour), low-frequency need larger (month). Use TTLs to automatically expire old data: INSERT ... USING TTL 2592000 (30 days). Never use ALLOW FILTERING for time-range queries — design the schema to avoid it.
05
What is Cassandra's consistency vs availability trade-off with tunable consistency?
Cassandra's tunable consistency allows per-query configuration of the consistency/availability trade-off. The key formula: writes + reads > replication factor = strong consistency. With RF=3: ONE + QUORUM = 1 + 2 = 3 = RF — NOT strongly consistent (reads might miss recent writes). QUORUM + QUORUM = 2 + 2 = 4 > 3 — strongly consistent. ALL + ONE = 3 + 1 = 4 > 3 — strongly consistent. Practical configurations: Maximum availability, eventual consistency: write ONE, read ONE. Balance (recommended for most apps): write LOCAL_QUORUM, read LOCAL_QUORUM. Strong consistency within a DC without cross-DC latency. Maximum consistency: write ALL, read ONE. Any node has the latest write. Availability with tunable read freshness: write ONE, read QUORUM. Writes are fast; reads are more consistent. The beauty of tunable consistency: you can use different levels for different operations — QUORUM for financial data, ONE for analytics/metrics.
06
What is Cassandra's anti-entropy repair?
Anti-entropy repair is Cassandra's mechanism for synchronizing data across replica nodes to ensure eventual consistency. Run with: nodetool repair keyspace_name table_name. How it works: for each replica, Cassandra builds a Merkle tree (a hash tree where each leaf is the hash of a data row range, and each parent is the hash of its children's hashes). Nodes exchange Merkle trees and compare them — any differences indicate inconsistent data. Cassandra then streams the inconsistent data from the most up-to-date node to stale replicas. Why repairs are needed: hints missed (node was down when a write occurred), network partition, partial failures. Repair frequency: run within every gc_grace_seconds period (default 10 days) — or tombstones may not be cleaned up properly, causing data resurrection. Incremental repair: only repairs data changed since the last repair — much faster than full repair. Repair in production: use nodetool repair -pr (primary range only) to distribute repair load across nodes. Never let repairs lapse in production.
07
What are RabbitMQ streams?
RabbitMQ Streams (introduced in RabbitMQ 3.9) is a new queue type that stores messages as a persistent, append-only log — bringing Kafka-like semantics to RabbitMQ. Unlike classic/quorum queues (messages deleted after consumption), stream messages are retained until a size/time limit. Key features: Replay: consumers can read from any offset, enabling replay of historical messages. Multiple consumers: multiple consumers can independently read the same stream from different offsets without interfering. High throughput: optimized for high-volume logging and event streaming. Long retention: retain messages for hours, days, or until size threshold. Offset tracking: consumers save their offset to resume after disconnection. Create: {"x-queue-type": "stream", "x-max-length-bytes": 5_000_000_000, "x-stream-max-segment-size-bytes": 500_000_000}. Stream protocol: use the native RabbitMQ Stream protocol via stream-specific clients (better performance) or AMQP 0-9-1 for basic usage. Streams make RabbitMQ competitive with Kafka for event streaming use cases while maintaining RabbitMQ's simpler operational model.
08
What is Cassandra's secondary index and materialized view?
Cassandra has limited support for querying non-partition-key columns. Secondary indexes: CREATE INDEX ON users (email);. Allows querying by email without the partition key. Warning: secondary indexes in Cassandra are not like SQL indexes. They are distributed — each node maintains an index for its local data, so a query hits all nodes. Avoid secondary indexes in production for high-cardinality columns (many unique values) or low-cardinality columns (few distinct values, huge results). They cause cluster-wide queries. Materialized views (MVs): pre-computed tables derived from a base table with a different primary key. Example: if the base table has PRIMARY KEY (user_id), a MV can have PRIMARY KEY (email, user_id) — enabling queries by email. Cassandra maintains the MV automatically on writes. Warning: MVs have performance implications — each write to the base table triggers a write to the MV. They have known issues with eventual consistency and are considered experimental by some. Prefer manually maintaining duplicate tables (query tables) over MVs for production use.
09
What is data denormalization in Cassandra?
Denormalization is not an anti-pattern in Cassandra — it is the correct approach. Because Cassandra doesn't support JOINs and queries require the partition key, you must store data in the shape required for each query. The golden rule: one query = one table. Example: in a blog application, you need two queries: (1) get posts by user, (2) get posts by tag. Relational approach: one posts table + JOINs. Cassandra approach: two tables: posts_by_user (user_id, post_id, title, content) and posts_by_tag (tag, post_id, title). Every new post triggers writes to both tables. The data is duplicated — accept this. Query-first design process: (1) identify all queries the app needs, (2) design a table for each query, (3) ensure all queries use the partition key. This is opposite to relational design (start with entities, then optimize queries). Denormalization means more storage and more complex writes, but enables fast, scalable reads without expensive JOINs.
10
What are Cassandra lightweight transactions (LWT)?
Lightweight Transactions (LWT) provide conditional writes in Cassandra using the Paxos consensus algorithm — the only form of compare-and-set (CAS) in Cassandra. Syntax: INSERT INTO users (id, email) VALUES (uuid(), 'alice@example.com') IF NOT EXISTS;. UPDATE users SET status = 'locked' WHERE id = ? IF status = 'active';. If the condition is not met, the operation fails and Cassandra returns the current values so the client can decide what to do. How Paxos works: LWT requires 4 round trips across replicas (prepare, promise, propose, commit) — much slower than regular writes. Performance cost: LWT is 4-10x slower than regular reads/writes. Use sparingly. Use cases: ensuring unique usernames/emails, implementing distributed locks, idempotent operations (create if not exists), optimistic locking patterns. Avoid: using LWT for frequently updated data — it is a significant performance bottleneck. If possible, design the data model to avoid the need for LWT entirely.
11
What is Cassandra's vnodes (virtual nodes)?
Vnodes (virtual nodes) are Cassandra's mechanism for distributing data and making cluster operations seamless. Each physical Cassandra node is responsible for multiple small token ranges (virtual nodes) rather than one large range. Default: 256 vnodes per node. Benefits: Automatic data distribution: when a new node joins or leaves, only small portions of data move — spread across many existing nodes rather than one neighbor taking all the burden. Simpler scaling: no manual token calculation needed when adding nodes. Better load balancing: more uniform distribution of token ranges. Faster recovery: when a node fails, the small vnodes it owned are distributed across many other nodes for faster streaming. Trade-offs: More compaction complexity: each node handles many token ranges. Network overhead: more inter-node communication. For large clusters, reduce vnodes from 256 to 16 or even 1 (one large token range) for better compaction and repair performance. The optimal vnode count depends on cluster size and workload.
12
How do you handle RabbitMQ message retries and exponential backoff?
Implementing retry with exponential backoff in RabbitMQ uses dead letter queues with TTL. Pattern: 1. Processing queue: normal consumer. On failure (nack with requeue: false), message goes to DLX. 2. Retry queues: create multiple queues with increasing TTLs. retry_30s: {"x-message-ttl": 30000, "x-dead-letter-exchange": "main_exchange"}. retry_60s, retry_300s. After TTL expires, the message is dead-lettered back to the main exchange for reprocessing. 3. Track retry count: use a message header x-retry-count. In the consumer: increment the counter on failure; route to the appropriate retry queue based on count; after max retries, route to the dead letter queue. Libraries: rabbitmq-delayed-message-exchange plugin enables configurable per-message delay without multiple queues. Laravel queues have built-in retry/delay with exponential backoff. Pattern advantages: transient failures (DB connection, API timeout) are automatically retried; permanent failures (invalid data) go to DLQ after max retries.
13
What is Cassandra's coordinator node?
A coordinator node in Cassandra is whichever node receives a client request — any node can be a coordinator since all nodes are equal (no master). The coordinator's responsibilities: Route the request: hash the partition key to determine which nodes hold the replicas. Contact replicas: send the read/write to the appropriate replica nodes. Handle consistency: wait for responses from the number of replicas required by the consistency level. Return result to client: aggregate replica responses (for reads: select the most recent data; for writes: confirm success). Handle failures: if a replica is down, route to the next replica in the ring. Write to a hinted handoff if needed. Drivers: modern Cassandra drivers (DataStax Java/Python/Node drivers) are token-aware — they calculate which node is the correct coordinator for each query and send directly to it, eliminating an extra hop. This reduces latency and coordinator load. In production, balance coordinator load across nodes using a token-aware driver and multiple contact points.
Deep expertise questions for senior and lead roles.
01
What are Cassandra's anti-patterns and how do you avoid them?
Common Cassandra anti-patterns: 1. Using ALLOW FILTERING: causes full-cluster scans. Fix: redesign the table with the queried column in the partition or clustering key. 2. Unbounded partitions: writing all data to the same partition key (e.g., status = 'active'). Fix: add a time bucket or UUID to the partition key. 3. Large partitions: partitions exceeding 100MB cause compaction and read performance issues. Fix: add time bucketing to spread data across partitions. 4. Too many tombstones: frequent deletes create tombstone accumulation. Fix: use TTL instead of explicit deletes; reduce gc_grace_seconds if appropriate; avoid delete-heavy patterns. 5. Misusing batches: using LOGGED BATCH across multiple partitions for performance — it actually hurts performance and adds coordinator overhead. BATCH in Cassandra is for atomicity on a single partition, not bulk performance. 6. Secondary indexes on high/low cardinality columns: full-cluster queries. Fix: use materialized views or query tables. 7. Using LWT everywhere: 10x performance hit. Fix: redesign to avoid compare-and-set requirements. 8. Skipping repairs: causes data inconsistency and prevents tombstone cleanup. Fix: run repairs regularly within gc_grace_seconds.
02
How does RabbitMQ handle message ordering and exactly-once delivery?
RabbitMQ's ordering and delivery guarantees: Message ordering: messages in a single queue are FIFO — a single consumer receives them in order. Ordering violation: if a message is nacked and requeued, it is placed back at the head of the queue — ahead of messages published after it. With multiple consumers, messages are consumed concurrently in any order. For strict global ordering, use a single consumer. For per-entity ordering, use consistent hashing (route same entity to same consumer) or a single consumer per entity. Exactly-once delivery: RabbitMQ guarantees at-least-once delivery by default (with publisher confirms + consumer acks). True exactly-once requires idempotent consumers. Implementation: include a unique messageId in each message. Consumers check a processed-IDs store (Redis, DB) before processing. If already processed, skip and acknowledge. This deduplication at the consumer layer achieves exactly-once processing even if delivery is at-least-once. There is no native exactly-once delivery in RabbitMQ — unlike Kafka's transactional producer.
03
What is Cassandra multi-datacenter architecture and geo-distribution?
Cassandra's multi-datacenter architecture is a first-class feature, not an afterthought. Configure with NetworkTopologyStrategy: WITH replication = {'class': 'NetworkTopologyStrategy', 'us-east': 3, 'eu-west': 3}. Consistency across DCs: use LOCAL_QUORUM for operations — quorum within the local DC, async replication to remote DCs. Avoids cross-DC round trips for every operation. LOCAL_ONE: maximum local speed, highest staleness risk. EACH_QUORUM: quorum in every DC — strong global consistency, higher latency. Write path: coordinator writes to local DC synchronously (based on consistency level), and sends the write asynchronously to remote DCs. Remote DC writes are guaranteed to eventually succeed via hinted handoff and repair. Active-active multi-DC: users in each region write to their local DC — both DCs accept writes. Conflicts resolved by LWW. Active-passive: one DC is the primary writer, remote DC is a warm standby. Multi-DC Cassandra is the architecture of choice for global applications requiring local latency, data locality compliance (GDPR), and regional failover.
04
How does RabbitMQ federation and shovel work for multi-datacenter setups?
For multi-datacenter RabbitMQ deployments, two plugins handle cross-cluster messaging. Federation: logically links exchanges or queues across separate RabbitMQ clusters. An upstream exchange/queue feeds a downstream one via a federation link. Messages are pulled from upstream only when a downstream consumer needs them (demand-based). Benefits: works across WANs with high latency; the downstream cluster is independent (different policies, topologies); federation automatically handles network failures and reconnects. Use case: global publish, local consume — publish events to a central cluster, regional clusters subscribe and consume locally. Shovel: reliably moves messages from a source queue (local or remote) to a destination exchange/queue (local or remote). Unlike federation (pull-based), shovel actively moves every message. Better for ETL-like patterns where all messages must be transferred. Use cases: migrating between clusters, cross-DC data synchronization, legacy system integration. Cluster spanning: unlike Erlang clusters (tight coupling, same Erlang cookie, low latency required), federation and shovel work between independent clusters with network partitions and high latency.
05
What is Cassandra's SASI index?
SASI (SSTable-Attached Secondary Index) is an advanced secondary index implementation in Cassandra that avoids many limitations of the standard secondary index. While standard secondary indexes are maintained in a separate table and require full-cluster queries, SASI indexes are stored alongside each SSTable — making them more efficient for certain query patterns. Key features: LIKE queries: WHERE name LIKE '%alice%' — substring and prefix searches on text columns. Range queries: efficiently support <, >, <=, >= on indexed columns. Analyzers: standard (exact match), non-tokenizing (for case-insensitive), or full-text analyzed (tokenize text for keyword search). SASI is still a secondary index — queries without the partition key scan all nodes. Less problematic than standard secondary indexes but still a cluster-wide scan. Limitations: not suitable for high-write workloads (index maintenance cost), not for frequently updated columns, experimental in many Cassandra versions. For full-text search, integrating with Elasticsearch (using Cassandra as the source of truth and ES for search) is often more appropriate.
06
How do you implement the outbox pattern with RabbitMQ?
The outbox pattern solves the dual-write problem: atomically persisting data to a database AND publishing a message to RabbitMQ. Without the outbox: if you save to DB then publish to RabbitMQ, a failure between the two steps causes inconsistency (DB saved, message not sent, or vice versa). With the outbox: 1. Atomic write: in the same database transaction as the business operation, write the event to an outbox table: INSERT INTO outbox (event_type, payload, created_at) VALUES (...). 2. Outbox publisher: a separate process polls the outbox table for unpublished events, publishes to RabbitMQ with publisher confirms, and marks as published on success. Transactional outbox with Debezium: use CDC to capture outbox table changes and stream them to RabbitMQ/Kafka via Debezium connector — no polling needed. Result: the business operation and message publishing are eventually consistent but never inconsistent. The outbox can be retried on RabbitMQ failures without risking data loss. The outbox pattern is considered best practice for event-driven microservices.
07
What are advanced Cassandra data modeling patterns?
Advanced Cassandra data modeling patterns: 1. Bucket pattern: limit partition size by bucketing: PRIMARY KEY ((user_id, week), event_time). Each week is a separate partition, preventing unbounded growth. 2. Queue / inbox pattern: simulate a queue with Cassandra: PRIMARY KEY (queue_name, created_at). Consumers delete messages after processing (using TTL or explicit delete). Cassandra is not ideal for queues due to tombstones — use sparingly. 3. Token-based pagination: WHERE token(partition_key) > token(?) for efficient cluster-wide pagination without ALLOW FILTERING. 4. Reference data with frozen collections: embed related data as FROZEN<LIST<address>> — stored as a blob, entire collection replaces on update. Good for rarely-changed nested data. 5. Table-per-query: create a dedicated table for each access pattern with the query's filter columns as the partition key. 6. Hybrid Cassandra + search: Cassandra for writes and primary storage, Elasticsearch for complex queries (full-text, multi-field filters). Sync via Kafka/Debezium. This pattern is used by many large-scale applications (Twitter, Netflix) to leverage Cassandra's write scalability with search's query flexibility.
08
What is the difference between RabbitMQ Classic, Quorum, and Stream queue types?
RabbitMQ's three queue types serve different use cases. Classic queues: the original queue type. Two sub-types: non-replicated (data on one node) and mirrored (deprecated — async replication to mirrors with known data loss risks on failover). Still supported but Quorum queues are preferred for new deployments. Best for: simple use cases, existing deployments. Limitations: potential message loss on node failure (non-mirrored), complex mirror sync issues. Quorum queues: replicated using Raft consensus. Majority must acknowledge before a write is confirmed. Zero message loss on failover — any committed message is always available in the new leader. Best for: most production use cases requiring durability and high availability. Limitations: higher write latency (Raft overhead), more disk usage (Raft log), all nodes must be RabbitMQ 3.8+. Stream queues: append-only log with consumer offset tracking. Messages retained until size/time limit. Multiple independent consumers, replay from any offset. Best for: high-throughput event streaming, audit logs, event sourcing, Kafka-like use cases. Limitations: different consumer API (stream protocol preferred), higher complexity. Choose Quorum for task queues; Stream for event streaming.
09
How does Cassandra handle schema migrations in production?
Cassandra schema migrations require careful handling due to its distributed nature. Schema propagation: Cassandra schema changes propagate to all nodes via gossip — there is a brief period where some nodes have the new schema and others have the old. During this window, queries may behave inconsistently. Safe migration patterns: Add columns: safe — old clients ignore new columns; new clients can start writing them immediately. Remove columns: two-step: (1) remove all references in application code and deploy, (2) then drop the column from the schema. If you drop first, old code breaks. Table renames: not supported — create new table, migrate data, switch traffic, drop old table. Change primary key: not possible — create new table with desired schema, migrate data. Index changes: create new index, test, drop old index. Tooling: Liquibase has a Cassandra plugin. Pillar (Python) manages Cassandra migrations. Schema versioning: track schema version in a dedicated Cassandra table. Zero-downtime: blue/green deployments — deploy new schema, roll out new code that handles both old and new schema, remove backward compatibility after full rollout.