Cassandra Partition Keys

The partition key is the first part of every Cassandra primary key. It determines which node in the cluster stores a row and groups related rows together into a single unit called a partition. Understanding partition keys is essential because they control data distribution, query performance, and cluster balance.

What Is a Partition?

A partition is a group of rows that share the same partition key value. Cassandra stores all rows in a partition on the same node (and its replica nodes). Rows within a partition are sorted by clustering columns. Reading a partition is a single disk seek — it is the fastest read operation Cassandra can do.

Table: messages_by_chat

Partition Key: chat_id

Partition A (chat_id = 'chat-101'):
  msg_time             | sender | text
  ────────────────────────────────────────
  2024-06-01 09:00:00  | alice  | Hello!
  2024-06-01 09:01:00  | bob    | Hi there!
  2024-06-01 09:02:00  | alice  | How are you?

Partition B (chat_id = 'chat-202'):
  msg_time             | sender | text
  ────────────────────────────────────────
  2024-06-02 14:00:00  | carol  | Meeting?
  2024-06-02 14:01:00  | dave   | Yes!

How Cassandra Chooses a Node for a Partition

Cassandra runs the partition key through a hash function called Murmur3. The result is a number — called a token — between roughly -2^63 and 2^63. Every node owns a range of tokens. The node whose range includes the token stores the partition.

Partition key: 'chat-101'
          │
          ▼
    Murmur3 hash
          │
          ▼
    Token: 3,456,789,012
          │
          ▼
    Token range owner: Node C
          │
          ▼
    Row stored on Node C (+ replicas)

Simple vs Compound Partition Keys

Simple Partition Key — One Column

CREATE TABLE products (
  product_id UUID PRIMARY KEY,
  name TEXT,
  price DECIMAL
);

Each product lives in its own partition. You retrieve a product by its product_id instantly.

Compound Partition Key — Multiple Columns

Wrap multiple columns in parentheses to form a compound partition key.

CREATE TABLE weather_readings (
  city    TEXT,
  year    INT,
  month   INT,
  day     INT,
  temp    FLOAT,
  PRIMARY KEY ((city, year), month, day)
);

The partition key is (city, year). All temperature readings for New York in 2024 go into one partition. This makes it fast to fetch all readings for a city within a given year.

Partition: city='New York' + year=2024
  month | day | temp
  ──────────────────
  1     |  1  | -2.0
  1     |  2  | -1.5
  ...
  12    | 31  |  4.0

Partition: city='London' + year=2024
  month | day | temp
  ──────────────────
  1     |  1  |  8.0
  ...

Cardinality: The Key to Good Distribution

Cardinality refers to how many distinct values a column has. A column with high cardinality (like a UUID) produces many different partitions spread evenly across the cluster. A column with low cardinality (like a boolean or a country name with only a few values) creates very few partitions, which overloads a small number of nodes.

Cardinality Comparison:

High (good for partition key):
  user_id: uuid-001, uuid-002, uuid-003, ... uuid-10000000
  → 10 million partitions spread across all nodes evenly

Low (bad for partition key):
  status: 'active', 'inactive'
  → Only 2 partitions; 50% of all data on one node

Partition Size Guidelines

Each partition has a maximum practical size. Cassandra recommends keeping partitions under 100 MB and under 100,000 rows. Very large partitions cause memory pressure during reads, slow down compaction, and make repairs take longer.

Partition Size Check:

Good:  10,000 rows × 500 bytes each = ~5 MB ✓
Risky: 500,000 rows × 200 bytes each = ~100 MB ⚠
Bad:   2,000,000 rows × 500 bytes each = 1 GB ✗

Fixing an Oversized Partition

Add a bucket or time component to the partition key to break a large partition into smaller ones.

Before (one huge partition per user):
  PRIMARY KEY (user_id)

After (one partition per user per month):
  PRIMARY KEY ((user_id, event_month), event_time)

Partition 'alice / 2024-01':  manageable size ✓
Partition 'alice / 2024-02':  manageable size ✓

Querying by Partition Key

Cassandra requires the full partition key in a WHERE clause for efficient queries. Providing the partition key lets Cassandra route the request to exactly the right node without scanning the whole cluster.

-- Efficient: full partition key provided
SELECT * FROM weather_readings
WHERE city = 'New York' AND year = 2024;

-- Inefficient: missing part of compound partition key
SELECT * FROM weather_readings
WHERE city = 'New York';  -- requires ALLOW FILTERING

Avoiding Hot Partitions

A hot partition receives a disproportionate share of traffic. This happens when many application users all access the same partition key simultaneously — for example, a trending product or a viral social post. Strategies to avoid hot partitions include adding a random suffix to the partition key or pre-distributing popular data across multiple partition buckets.

Hot partition problem:
  product_id = 'IPHONE-15-MAX'
  → 1 million requests per second hit one node

Solution (random bucket suffix):
  partition key = 'IPHONE-15-MAX#1'  → Node A gets 1/4 traffic
  partition key = 'IPHONE-15-MAX#2'  → Node B gets 1/4 traffic
  partition key = 'IPHONE-15-MAX#3'  → Node C gets 1/4 traffic
  partition key = 'IPHONE-15-MAX#4'  → Node D gets 1/4 traffic

Summary

The partition key determines which node stores your data and how efficiently Cassandra can retrieve it. Use high-cardinality columns for partition keys to spread data evenly. Keep partitions under 100 MB by incorporating time or bucket components when needed. Always provide the full partition key in queries to avoid cluster-wide scans. Good partition key design is the single biggest factor in Cassandra performance.

Leave a Comment

Your email address will not be published. Required fields are marked *