Big Data Ingestion Patterns — Complete Guide
In this tutorial, you'll learn about Big Data Ingestion Patterns. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Big Data ingestion is the Process of moving data from source systems into storage or processing platforms — and choosing the right ingestion pattern determines the reliability, latency, and cost of your entire data pipeline.
What You'll Learn
In this tutorial, you'll learn the main data ingestion patterns — batch ingestion, streaming ingestion, change data capture (CDC), log ingestion, and API polling — with Python examples for each pattern.
Why It Matters
Data ingestion is where pipelines break most often. A poorly designed ingestion pattern causes data loss, duplicate records, excessive latency, and snowballing operational costs.
Real-World Use
Netflix ingests 1.5 trillion events daily from 230 million subscribers across multiple patterns: Kafka streams for real-time viewing events, S3 batch uploads for content metadata, and CDC from relational databases for user profile changes.
flowchart TD
subgraph Sources
A[Databases]
B[Logs]
C[APIs]
D[Message Queues]
E[IoT Devices]
end
subgraph Ingestion Patterns
F[Batch Ingestion]
G[Streaming Ingestion]
H[CDC]
I[Log Ingestion]
J[API Polling]
end
subgraph Storage
K[Data Lake S3]
L[Kafka Topics]
M[Warehouse]
end
A --> H
B --> I
C --> J
D --> G
E --> F
H --> L
I --> K
J --> F
G --> L
F --> K
Batch Ingestion
Batch ingestion loads data in scheduled intervals (hourly, daily). It's simple, cost-effective, and suitable for non-latency-sensitive use cases.
import time
from datetime import datetime
def simulate_batch_ingestion():
source_data = [
{"id": 1, "name": "Alice", "signup_date": "2026-06-20"},
{"id": 2, "name": "Bob", "signup_date": "2026-06-21"},
{"id": 3, "name": "Charlie", "signup_date": "2026-06-22"},
]
last_ingested_id = 0
batch_count = 0
def ingest_batch(source, last_id, batch_size=2):
new_records = [r for r in source if r["id"] > last_id][:batch_size]
if new_records:
print(f"[{datetime.now().strftime('%H:%M:%S')}] Batch {batch_count}:")
for record in new_records:
print(f" Ingested: {record}")
return max(r["id"] for r in new_records)
return last_id
while last_ingested_id < len(source_data):
batch_count += 1
last_ingested_id = ingest_batch(source_data, last_ingested_id)
time.sleep(0.5)
print(f"\nBatch ingestion complete. {len(source_data)} records ingested.")
simulate_batch_ingestion()
Expected output:
[HH:MM:SS] Batch 1:
Ingested: {'id': 1, 'name': 'Alice', 'signup_date': '2026-06-20'}
Ingested: {'id': 2, 'name': 'Bob', 'signup_date': '2026-06-21'}
[HH:MM:SS] Batch 2:
Ingested: {'id': 3, 'name': 'Charlie', 'signup_date': '2026-06-22'}
Batch ingestion complete. 3 records ingested.
Batch ingestion uses a watermark (last_ingested_id) to track progress. Each batch loads only new records since the last watermark.
Streaming Ingestion
Streaming ingestion processes data continuously as it arrives. It's more complex but provides sub-second latency.
import time
import random
def simulate_streaming_ingestion():
print("Starting stream ingestion (Ctrl+C to stop)...")
events_ingested = 0
start = time.time()
source_events = ["click", "view", "purchase", "search"] * 10000
for event_type in source_events[:20]:
event = {
"type": event_type,
"user_id": random.randint(1000, 9999),
"timestamp": time.time(),
"value": random.random() * 100,
}
events_ingested += 1
elapsed = time.time() - start
print(f"[{elapsed:.3f}s] Ingested: {event['type']} user={event['user_id']}")
time.sleep(random.uniform(0.05, 0.2))
rate = events_ingested / (time.time() - start)
print(f"\nStream rate: {rate:.1f} events/second")
simulate_streaming_ingestion()
Expected output (approximate):
Starting stream ingestion (Ctrl+C to stop)...
[0.000s] Ingested: click user=5432
[0.123s] Ingested: view user=7890
[0.198s] Ingested: purchase user=1234
...
[2.500s] Ingested: search user=9876
Stream rate: ~7.5 events/second
Streaming ingestion decouples producers and consumers through a message queue (Kafka, Kinesis). The ingestion rate adapts to source throughput.
Change Data Capture (CDC)
CDC captures database changes (inserts, updates, deletes) in real time by reading the database Transaction log.
import json
import time
def simulate_cdc_ingestion():
transaction_log = [
{"lsn": 100, "operation": "INSERT", "table": "users", "data": {"id": 1, "name": "Alice"}},
{"lsn": 101, "operation": "UPDATE", "table": "users", "data": {"id": 1, "name": "Alice Smith"}},
{"lsn": 102, "operation": "DELETE", "table": "users", "data": {"id": 2}},
{"lsn": 103, "operation": "INSERT", "table": "orders", "data": {"id": 100, "user_id": 1, "amount": 49.99}},
]
state = {}
last_lsn = 0
def apply_change(change):
table = change["table"]
op = change["operation"]
data = change["data"]
if table not in state:
state[table] = {}
if op == "INSERT":
state[table][data["id"]] = data
print(f"CDC INSERT: {table}[{data['id']}]")
elif op == "UPDATE":
state[table][data["id"]] = data
print(f"CDC UPDATE: {table}[{data['id']}]")
elif op == "DELETE":
del state[table][data["id"]]
print(f"CDC DELETE: {table}[{data['id']}]")
for change in transaction_log:
if change["lsn"] > last_lsn:
apply_change(change)
last_lsn = change["lsn"]
time.sleep(0.3)
print("\nReplicated state:")
print(json.dumps(state, indent=2))
simulate_cdc_ingestion()
Expected output:
CDC INSERT: users[1]
CDC UPDATE: users[1]
CDC DELETE: users[2]
CDC INSERT: orders[100]
Replicated state:
{
"users": {
"1": {"id": 1, "name": "Alice Smith"}
},
"orders": {
"100": {"id": 100, "user_id": 1, "amount": 49.99}
}
}
Tools like Debezium and AWS DMS implement CDC by reading database binlogs (MySQL) or WAL (PostgreSQL) and streaming changes to Kafka.
Log Ingestion
Log ingestion collects application and system logs for analysis.
import json
import time
def simulate_log_ingestion():
log_entries = [
{"level": "ERROR", "service": "auth", "message": "Connection timeout to DB", "ip": "10.0.0.1"},
{"level": "INFO", "service": "api", "message": "Request processed in 45ms", "ip": "10.0.0.2"},
{"level": "WARN", "service": "auth", "message": "Rate limit approaching", "ip": "10.0.0.1"},
{"level": "ERROR", "service": "payment", "message": "Payment gateway declined", "ip": "10.0.0.3"},
]
log_aggregator = []
for entry in log_entries:
log_aggregator.append(entry)
print(f"LOG {entry['level']}: {entry['service']} - {entry['message']}")
print(f"\nTotal logs ingested: {len(log_aggregator)}")
error_count = sum(1 for e in log_aggregator if e["level"] == "ERROR")
print(f"Errors detected: {error_count}")
simulate_log_ingestion()
Expected output:
LOG ERROR: auth - Connection timeout to DB
LOG INFO: api - Request processed in 45ms
LOG WARN: auth - Rate limit approaching
LOG ERROR: payment - Payment gateway declined
Total logs ingested: 4
Errors detected: 2
Flume, Filebeat, and Fluentd are common log ingestion agents. They tail log files and forward entries to HDFS, Kafka, or Elasticsearch.
Common Mistakes Beginners Make
1. Not handling duplicates
Network retries cause duplicate messages. Design idempotent ingestion — processing the same message twice should produce the same result.
2. Ignoring schema evolution
Source schemas change. Use schema registries (Avro, Protobuf) and design your ingestion to handle backward-compatible schema changes.
3. Overwhelming downstream systems
A sudden data burst can saturate your warehouse. Use Rate Limiting, buffering (Kafka), and backpressure handling in ingestion.
4. No monitoring for ingestion lag
Ingestion lag (time between event creation and ingestion) is a key health metric. Alert when lag exceeds thresholds.
5. Forgetting about data retention
Source systems may delete old data after ingestion. Ensure you have the retention policy and backup Strategy before cleaning sources.
Practice Questions
What is the difference between batch and streaming ingestion? Batch ingestion loads data at scheduled intervals (hourly/daily) with higher latency but lower cost. Streaming ingestion processes data continuously with sub-second latency but higher complexity.
How does Change Data Capture (CDC) work? CDC reads database Transaction logs (binlog, WAL) and streams changes to a target system. It captures inserts, updates, and deletes without impacting the source database.
Why is idempotent ingestion important? Network retries and exactly-once delivery guarantees can produce duplicate messages. Idempotent ingestion ensures duplicates don't create incorrect results.
Challenge
Design a CDC pipeline for a PostgreSQL database that streams changes to Kafka, transforms them with Kafka Streams, and lands them in both S3 (Parquet) and a real-time dashboard. Handle schema changes gracefully.
Real-World Task
Set up a filebeat agent on your local machine to tail a log file and forward entries to a local Elasticsearch instance via Logstash. Verify the ingested logs in Kibana.
FAQ
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
What's Next
Congratulations on completing this Big Data Ingestion tutorial! Here's where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro