NoSQL for Big Data

Cassandra, MongoDB, and HBase at scale

Scaling Beyond Relational Databases

When your data grows to billions of records, traditional relational databases hit their limits. NoSQL databases like Cassandra, MongoDB, and HBase are designed from the ground up for massive scale, handling petabytes of data across hundreds of servers. They sacrifice some traditional database features (like complex joins and strict consistency) for horizontal scalability, high availability, and performance. Understanding when and how to use each is critical for building systems that can handle internet-scale workloads.

What Qualifies as "Big Data"?

Big Data isn't just about size, it's about the 3 V's (or 5 V's):

πŸ“Š Volume

Terabytes to petabytes of data, too large for single server

⚑ Velocity

High-speed data streams, millions of writes per second

πŸ”„ Variety

Structured, semi-structured, unstructured, many data types

βœ“ Veracity

Quality and trustworthiness of data varies

πŸ’° Value

Extracting business value from massive datasets

⚠️ Important: Don't use NoSQL just because it's trendy. If your data fits on one server and you need ACID transactions and complex joins, stick with PostgreSQL or MySQL. NoSQL is for when you've truly outgrown relational databases.

CAP Theorem: Choose Two

In distributed systems, you can only guarantee two of three properties:

C
Consistency

All nodes see the same data at the same time

A
Availability

Every request gets a response (success/failure)

P
Partition Tolerance

System works despite network failures

DatabaseCAP ChoiceTrade-off
CassandraAP (Availability + Partition)Eventually consistent (tunable)
MongoDBCP (Consistency + Partition)May sacrifice availability during partition
HBaseCP (Consistency + Partition)Strong consistency, regions may be unavailable

Apache Cassandra

Write-optimized, masterless architecture

Cassandra is a wide-column store designed for massive write throughput and linear scalability. With no single point of failure and masterless architecture, it's perfect for time-series data, IoT, and applications that need to write millions of events per second.

Key Characteristics

πŸ”„ Masterless Architecture

All nodes are equal, no master/slave. Any node can handle any request.

πŸ“ˆ Linear Scalability

Double your nodes = double your throughput. Scales horizontally to 1000+ nodes.

βš™οΈ Tunable Consistency

Choose consistency level per query: ONE, QUORUM, ALL

✍️ Write-Optimized

Optimized for writes, uses log-structured storage, extremely fast inserts

Data Model: Query-First Design

Unlike relational databases, you design Cassandra tables around your queries, not entities.

-- Create keyspace (like database)
CREATE KEYSPACE ecommerce 
WITH replication = {
  'class': 'NetworkTopologyStrategy',
  'datacenter1': 3,  -- 3 replicas in DC1
  'datacenter2': 2   -- 2 replicas in DC2
};

-- Create table (design for specific query!)
CREATE TABLE user_activity_by_date (
  user_id UUID,
  activity_date DATE,
  activity_time TIMESTAMP,
  action TEXT,
  details MAP<TEXT, TEXT>,
  PRIMARY KEY ((user_id, activity_date), activity_time)
) WITH CLUSTERING ORDER BY (activity_time DESC);
Design:
Partition key: (user_id, activity_date), groups data by user and date
Clustering key: activity_time, sorts within partition (descending)

Example: Writing Data

-- Insert (extremely fast, just append to log)
INSERT INTO user_activity_by_date (
  user_id, activity_date, activity_time, action, details
) VALUES (
  uuid(),
  '2024-01-15',
  toTimestamp(now()),
  'page_view',
  {'page': '/products', 'duration_sec': '45'}
);
Result:
Written in ~1ms (log-structured, no locks)
Replicated to 3 nodes asynchronously

Example: Efficient Query

-- Query by partition key (FAST, single partition)
SELECT * FROM user_activity_by_date
WHERE user_id = 550e8400-e29b-41d4-a716-446655440000
  AND activity_date = '2024-01-15'
LIMIT 100;
Result:
Returns 100 most recent activities for user on Jan 15
Query hits 1 partition on 1-3 nodes (milliseconds)

Example: Inefficient Query (Anti-Pattern)

-- BAD: Query without partition key
SELECT * FROM user_activity_by_date
WHERE action = 'purchase';  -- Scans ALL partitions!
Result:
❌ Full cluster scan, touches every node
❌ Extremely slow on large datasets
Solution: Create a separate table indexed by action

Consistency Levels

ONE

Wait for 1 replica to respond

Fastest, least consistent
QUORUM

Wait for majority (RF/2 + 1)

Balanced (most common)
ALL

Wait for all replicas

Slowest, strongest consistency

When to Use Cassandra

  • Time-series data (IoT sensors, logs, metrics)
  • High write throughput requirements (millions/sec)
  • Need linear scalability to 1000+ nodes
  • Multi-datacenter deployments
  • Messaging/social media feeds
  • Event logging and click streams

Pros & Cons

βœ… Pros
  • Linear scalability (proven to 1000+ nodes)
  • No single point of failure
  • Extremely fast writes
  • Multi-datacenter replication built-in
  • Tunable consistency
  • Handles petabytes of data
❌ Cons
  • No joins or aggregations
  • Must design tables per query (data duplication)
  • Eventually consistent by default
  • Complex operational overhead
  • Steep learning curve
  • Poor for ad-hoc queries

MongoDB

Document database with rich queries

MongoDB stores data as flexible JSON-like documents with dynamic schemas. It's developer-friendly with a rich query language, supports sharding for horizontal scaling, and provides ACID transactions. Popular for web applications, content management, and rapid development.

Key Characteristics

πŸ“„ Document Model

Flexible JSON documents, each can have different fields

πŸ” Rich Queries

Powerful query language with aggregation pipeline, text search

πŸ”€ Sharding

Automatic horizontal partitioning across servers

πŸ” ACID Transactions

Multi-document ACID transactions (since v4.0)

Architecture: Replica Sets + Sharding

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              SHARDED CLUSTER                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Shard 1     β”‚  β”‚  Shard 2     β”‚  β”‚  Shard 3  β”‚ β”‚
β”‚  β”‚ (Replica Set)β”‚  β”‚ (Replica Set)β”‚  β”‚(Replica...β”‚ β”‚
β”‚  β”‚              β”‚  β”‚              β”‚  β”‚           β”‚ β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚
β”‚  β”‚ β”‚ Primary  β”‚ β”‚  β”‚ β”‚ Primary  β”‚ β”‚  β”‚β”‚Primary  β”‚β”‚ β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚  β”‚β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚
β”‚  β”‚ β”‚Secondary β”‚ β”‚  β”‚ β”‚Secondary β”‚ β”‚  β”‚β”‚Secondaryβ”‚β”‚ β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚  β”‚β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚         β–²                β–²                β–²        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                    β”‚   mongos    β”‚
                    β”‚  (Router)   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Data partitioned across shards, each shard is a replica set

Example: Flexible Schema

// Insert documents with different structures
db.products.insertMany([
  {
    name: "Laptop",
    price: 999,
    specs: {cpu: "Intel i7", ram: "16GB"},
    tags: ["electronics", "computers"]
  },
  {
    name: "T-Shirt",
    price: 25,
    size: "L",
    color: "blue",
    tags: ["clothing"]
    // Different fields, no problem!
  }
]);
Result:
2 documents inserted with different schemas
No migrations needed, schema-less flexibility

Example: Rich Queries

// Complex query with operators
db.products.find({
  price: { $gte: 100, $lte: 2000 },
  tags: { $in: ["electronics", "computers"] },
  "specs.ram": { $exists: true }
}).sort({ price: -1 }).limit(10);
Result:
Returns top 10 electronics with RAM between $100-$2000
Sorted by price descending, all in one query

Example: Aggregation Pipeline

// Analytics: Average price by category
db.products.aggregate([
  { $match: { price: { $gt: 0 } } },
  { $group: {
      _id: "$category",
      avgPrice: { $avg: "$price" },
      count: { $sum: 1 }
    }
  },
  { $sort: { avgPrice: -1 } }
]);
Result:
[ { _id: "Electronics", avgPrice: 750, count: 45 }, { _id: "Clothing", avgPrice: 35, count: 120 } ]

Sharding Strategy

// Enable sharding on database
sh.enableSharding("ecommerce");

// Shard collection by user_id (hashed for even distribution)
sh.shardCollection(
  "ecommerce.orders",
  { user_id: "hashed" }
);

// Result: Orders distributed evenly across shards
// Queries for specific user_id route to single shard
Result:
Data automatically partitioned across shards
Horizontal scaling achieved, add shards as data grows

When to Use MongoDB

  • Rapid application development (flexible schema)
  • Content management systems
  • Catalogs with varied product types
  • Real-time analytics with aggregation pipeline
  • Mobile apps with offline sync
  • When you need both scale AND rich queries

Pros & Cons

βœ… Pros
  • Developer-friendly (JSON, no schema)
  • Rich query language
  • Powerful aggregation framework
  • ACID transactions
  • Horizontal scaling via sharding
  • Strong community and tooling
❌ Cons
  • Memory intensive (indexes in RAM)
  • Data duplication with embedded docs
  • Sharding complexity for large clusters
  • Not ideal for complex joins
  • Can be overkill for simple use cases
  • Write amplification with indexes

Apache HBase

Hadoop's column-family database for sparse data

HBase is Google Bigtable's open-source implementation, built on top of Hadoop HDFS. It excels at storing billions of rows with millions of columns per row, perfect for wide, sparse datasets. Strong consistency and tight Hadoop integration make it ideal for big data analytics pipelines.

Key Characteristics

πŸ“Š Column-Family Store

Billions of rows, millions of columns, extremely sparse

🐘 Hadoop Integration

Built on HDFS, tight integration with MapReduce, Spark

🎯 Strong Consistency

CP in CAP, always consistent reads/writes

⏱️ Versioned Data

Automatic timestamping, keeps multiple versions of cells

Architecture: Regions and RegionServers

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 HBase CLUSTER                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚RegionServer1β”‚  β”‚RegionServer2β”‚  β”‚RegionServerβ”‚ β”‚
β”‚  β”‚             β”‚  β”‚             β”‚  β”‚            β”‚ β”‚
β”‚  β”‚ Region A    β”‚  β”‚ Region B    β”‚  β”‚ Region C   β”‚ β”‚
β”‚  β”‚ (rows 0-100)β”‚  β”‚(rows 101-200β”‚  β”‚(rows 201+) β”‚ β”‚
β”‚  β”‚             β”‚  β”‚             β”‚  β”‚            β”‚ β”‚
β”‚  β”‚  MemStore   β”‚  β”‚  MemStore   β”‚  β”‚ MemStore   β”‚ β”‚
β”‚  β”‚  HFile      β”‚  β”‚  HFile      β”‚  β”‚ HFile      β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚         β–²                β–²                β–²       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚                β”‚                β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”
                    β”‚   Master    β”‚
                    β”‚ (metadata)  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                   β”‚    ZooKeeper   β”‚
                   β”‚ (coordination) β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Data split into regions by row key range
Regions automatically split and rebalanced

Data Model: Row Key Design is Critical

# Create table with Column Families (CF)
create 'web_analytics',
  {NAME => 'user_info', VERSIONS => 3},
  {NAME => 'page_views', VERSIONS => 1}

# Key Strategy: Reverse Timestamp RowKey
# RowKey = [user_id] + [Long.MAX_VALUE - timestamp]
Design:
Row key determines data locality and scan efficiency
Column families group related columns (stored together)

Example: Writing Data

// Put data (Java API)
Put put = new Put(Bytes.toBytes("user123_99999984321")); // RowKey

// Column Family : Qualifier : Value
put.addColumn(CF_INFO, Bytes.toBytes("name"), Bytes.toBytes("Alice"));
put.addColumn(CF_VIEWS, Bytes.toBytes("/products"), Bytes.toBytes("5"));

table.put(put);
Result:
Data written to MemStore (in-memory)
Flushed to HFile on HDFS periodically
Strong consistency guaranteed
Storage Representation
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ RowKey               β”‚ CF:Family β”‚ CF:Qualifier β”‚ Value   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ user123_99999984321  β”‚ user_info β”‚ name         β”‚ Alice   β”‚
β”‚ user123_99999984321  β”‚ page_viewsβ”‚ /products    β”‚ 5       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example: Scanning Data

// Scan range of rows (user's recent activity)
Scan scan = new Scan();
scan.withStartRow(Bytes.toBytes("user123_999999999999000"));
scan.withStopRow(Bytes.toBytes("user123_999999999999999"));
scan.addFamily(Bytes.toBytes("page_views"));

ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
  // Process results
}
Result:
Efficient range scan, data is co-located by row key
Returns all page_view data for user in time range

Example: Versioning

// Get multiple versions of a cell
Get get = new Get(Bytes.toBytes("user123"));
get.addColumn(Bytes.toBytes("user_info"), Bytes.toBytes("email"));
get.setMaxVersions(3);  // Get last 3 versions

Result result = table.get(get);
List<Cell> cells = result.getColumnCells(...);
// Returns 3 timestamped versions of email
Result:
[ { timestamp: 1704067200000, value: "alice@new.com" }, { timestamp: 1704063600000, value: "alice@old.com" }, { timestamp: 1704060000000, value: "alice@original.com" } ]

When to Use HBase

  • Massive datasets (100TB+) with sparse columns
  • Need Hadoop ecosystem integration
  • Time-series data with historical versioning
  • Sequential reads/writes by row key
  • Strong consistency required
  • Search engine indexing, web crawling

Pros & Cons

βœ… Pros
  • Handles billions of rows effortlessly
  • Strong consistency (CP)
  • Perfect for sparse, wide tables
  • Tight Hadoop integration
  • Automatic versioning
  • Battle-tested at scale
❌ Cons
  • Complex setup (HDFS, ZooKeeper)
  • Requires Java knowledge
  • Row key design critical (can't change)
  • No secondary indexes (limited queries)
  • Heavy operational overhead
  • Overkill for small datasets

Side-by-Side Comparison

FeatureCassandraMongoDBHBase
Data ModelWide-column storeDocument (JSON)Column-family
CAP TheoremAP (tunable)CPCP
ConsistencyEventually consistentStrong (primary reads)Strong
Query LanguageCQL (SQL-like)Rich query APIKey-based + scans
TransactionsLightweight (no multi-row)Multi-document ACIDRow-level only
ScalabilityLinear (1000+ nodes)Sharding (100s nodes)100s of nodes
Best ForTime-series, IoT, writesWeb apps, CMS, flexibleHadoop, sparse, versioned
Learning CurveSteepEasyVery steep

Best Practices for NoSQL at Scale

Unlike relational databases where you normalize first and query later, NoSQL requires understanding your queries BEFORE designing tables.

βœ… Do:
  • List all queries your app will make
  • Create separate tables for different access patterns (denormalize)
  • Design partition/shard keys that align with queries
  • Accept data duplication as a trade-off for performance
❌ Don't:
  • Try to normalize data like in SQL
  • Design tables around entities instead of queries
  • Expect to support ad-hoc queries efficiently

Your partition key determines data distribution and query performance. A bad key = hot spots and slow queries.

βœ… Good Keys
  • user_id (evenly distributed)
  • device_id (IoT data)
  • hashed(email) (uniform)
  • Composite: (user_id, date)
❌ Bad Keys
  • timestamp (all writes hit same partition)
  • status ("active" gets all traffic)
  • country (uneven distribution)
  • Sequential IDs (hot spots)

NoSQL databases require active monitoring, problems often appear only at scale.

Key Metrics to Watch:
  • Read/Write latency, Spikes indicate problems
  • CPU and memory per node, Hot spots?
  • Compaction lag (Cassandra/HBase), Affects reads
  • Replication lag, Consistency issues
  • Disk usage per node, Unbalanced?
πŸ’‘ Pro Tip: Use tools like DataStax OpsCenter (Cassandra), MongoDB Atlas, or Cloudera Manager (HBase) for comprehensive monitoring.

Data that never expires will eventually fill your cluster. Implement time-to-live (TTL) policies to automatically expire old data.

// Cassandra: Auto-delete after 30 days
INSERT INTO sensor_data (...) VALUES (...) 
USING TTL 2592000;

// MongoDB: TTL index (expires after 24 hours)
db.logs.createIndex(
  { "createdAt": 1 },
  { expireAfterSeconds: 86400 }
);
Result: Old data automatically removed, no manual cleanup needed

Different operations need different consistency guarantees. Don't use strong consistency everywhere, it kills performance.

Use CaseConsistency LevelReasoning
Financial transactionsQUORUM/ALLMoney must be accurate
Page view countsONEApproximate is fine
User profile updatesQUORUMBalance speed/accuracy
Sensor readings (IoT)ONEHigh volume, eventual OK

NoSQL databases behave differently at scale. What works with 1GB might fail with 1TB.

Load Testing Checklist:
  • Test with production-like data volume (10x current size)
  • Simulate realistic query patterns and concurrency
  • Test node failures, does it recover gracefully?
  • Measure performance during compaction/maintenance
  • Test with network partitions (chaos engineering)
  • Verify backup/restore procedures at scale

Decision Framework: Which Database?

Start with These Questions:

1️⃣ Can your data fit on one server (now and in 3 years)?

If YES: Use PostgreSQL or MySQL. Don't overcomplicate.
If NO: Continue to question 2

2️⃣ Do you need complex joins and transactions?

If YES: Consider PostgreSQL with sharding (Citus) or CockroachDB
If NO: Continue to question 3

3️⃣ What's your primary workload?

Massive writes, time-series: β†’ Cassandra
Flexible documents, rich queries: β†’ MongoDB
Hadoop integration, sparse data: β†’ HBase

4️⃣ What's more important: Availability or Consistency?

Availability (AP): β†’ Cassandra
Consistency (CP): β†’ MongoDB or HBase

Quick Reference Guide

Choose Cassandra If:
  • Writing millions of events/sec
  • Time-series or IoT data
  • Need 99.999% availability
  • Multi-datacenter required
  • Simple query patterns
Choose MongoDB If:
  • Building web applications
  • Need flexible schemas
  • Want rich query language
  • Need aggregations
  • Fast iteration/prototyping
Choose HBase If:
  • Already using Hadoop
  • Billions of rows, sparse
  • Need strong consistency
  • Sequential access patterns
  • Historical versioning

Common Pitfalls to Avoid

❌ Using NoSQL Like SQL

Mistake: Normalizing data, expecting joins to work

Solution: Denormalize, duplicate data across tables designed for specific queries

❌ Ignoring Partition Key Design

Mistake: Using timestamp as partition key (all writes hit one node)

Solution: Use high-cardinality keys (user_id, device_id) or composite keys

❌ Over-Using Strong Consistency

Mistake: ALL consistency for every operation (kills throughput)

Solution: Use QUORUM for most, ONE for analytics, ALL only when critical

❌ Not Planning for Growth

Mistake: No TTL policies, data grows forever

Solution: Implement TTL early, archive old data to object storage

❌ Poor Monitoring Setup

Mistake: No visibility into cluster health until it's too late

Solution: Set up comprehensive monitoring from day 1 (Prometheus, Grafana)

❌ Underestimating Operational Complexity

Mistake: Treating NoSQL like a managed service when self-hosting

Solution: Use managed services (AWS, Atlas, Astra) or hire experienced DBAs

Real-World Use Cases

Netflix, Cassandra

Streaming Analytics Platform

Challenge: Track viewing history for 200M+ users globally
Solution: Multi-datacenter Cassandra cluster (2500+ nodes)
Scale: 1 trillion writes/day, 420TB data

Why Cassandra? Masterless architecture = no single point of failure, linear scalability, and fast writes for real-time viewing data.

Adobe, MongoDB

Creative Cloud Platform

Challenge: Store diverse assets (images, videos, metadata)
Solution: MongoDB sharded cluster
Scale: 80TB data, millions of users

Why MongoDB? Flexible schema for varied asset types, rich queries for searching, and fast iteration on features.

Facebook, HBase

Messages Platform

Challenge: Store billions of messages with quick retrieval
Solution: HBase on top of HDFS
Scale: 135+ billion messages/month

Why HBase? Handles sparse data (not all columns set), strong consistency for message ordering, and integrates with Hadoop for analytics.

Uber, Cassandra

Trip Data Storage

Challenge: Store location data from millions of trips daily
Solution: Cassandra across multiple datacenters
Scale: Petabytes of trip/location data

Why Cassandra? Time-series data (GPS points), massive write throughput, and global availability for multi-region operations.

Key Takeaways

  • NoSQL is not a silver bullet, use it when you've truly outgrown relational databases
  • CAP theorem matters, understand your consistency vs availability trade-offs
  • Design for queries first, unlike SQL, you model data around access patterns
  • Partition keys are critical, they determine performance and scalability
  • Each has sweet spots, Cassandra for writes, MongoDB for flexibility, HBase for Hadoop
  • Operational complexity is real, consider managed services unless you have expertise