“2 PB in S3 and no file servers”
Kabir reads TiffinGo’s engineering blog to prepare for his internship. One line stops him: “Our lake holds 2 PB in S3 and we have no file servers at all.” He has always thought of storage as a hard disk with folders. Where do two petabytes go if not on a disk?
Sir, what is S3? If there are no file servers, where are the folders?
S3 is Amazon’s object storage. There are no real folders. You give it a key, like a long name, and some bytes, and it gives the same bytes back when you ask with that key. It looks like folders only because keys contain slashes.
Like a cloakroom at a wedding hall? You hand over your bag and get a token?
A very good picture, Riya. And the cloakroom is so big that it never fills up, keeps copies of your bag in three buildings, and charges you a few paise per day for it.
Then why do we still have normal disks and folders at all?
Because each kind of storage is good at different things. Databases need block storage for fast small updates. Teams share documents through file storage. Big data lakes use object storage (or Hadoop’s HDFS) because it is cheap and nearly limitless. Today you’ll see all three, write a file into HDFS, meet the small-files problem and learn why “rename” can be dangerously slow in the cloud.
Block, file and object storage
Block storage divides storage into fixed-size blocks addressed by number and presents them to a server as a raw volume on which a file system or database is built; it offers low latency and in-place updates. File storage organises data as files in a hierarchy of directories accessed by path, often shared over a network (NAS, NFS, SMB). Object storage stores data as immutable objects, each with a unique key and metadata, in a flat namespace of buckets accessed through an HTTP API; it scales to exabytes at low cost and is the usual foundation of cloud data lakes. A distributed file system such as HDFS spreads large files as replicated blocks across a cluster.
Block storage is a raw disk that one computer uses, perfect for databases. File storage is folders and files that a team shares. Object storage is a huge, cheap store where each item has a name (key) and you put or get whole items over the internet. Big data lakes live mostly on object storage, or on Hadoop’s HDFS.
Words you’ll meet in this lesson
tiffingo-lake.orders/date=2026-10-19/part-0.parquet.orders/date=2026-10-19/.Typical numbers to reason with (approximate)
| HDFS block size | 128 MB by default (often 256 MB), stored as 3 replicas |
|---|---|
| Object size limits (S3) | single object up to 5 TB; uploads above 5 GB must be split into parts |
| S3 durability | designed for 99.999999999% (eleven nines) by storing data across several facilities |
| Good file size for analytics | about 128 MB to 1 GB per file; thousands of KB-sized files are a warning sign |
| Storage tiers | hot (frequent access) → cool/infrequent → cold → archive (cheapest, retrieval takes minutes to hours) |
Storage at three levels
Beginner A plot of land, a filing cabinet and a cloakroom
- Block storage is an empty plot of land: raw space divided into equal blocks. You (or a database) build whatever structure you want on it. It is fast but sits attached to one machine. Example: your laptop’s SSD, a cloud disk such as Amazon EBS.
- File storage is an office filing cabinet: folders inside folders, files with names. Many people can open the same cabinet. Example: a shared office drive (NAS), Google Drive’s folders.
- Object storage is a giant cloakroom: hand over an item, get a token (the key). No shelves to manage, almost unlimited space, very cheap. Example: Amazon S3, Azure Blob/ADLS, Google Cloud Storage.
Rule of thumb: databases → block; shared team folders → file; data lakes, backups, photos and videos → object.
Intermediate How each one is accessed, and where HDFS fits
- Block: the operating system sees a raw disk, puts a file system on it, and reads or writes any 4 KB block in place. Lowest latency (sub-millisecond on SSD). Usually one machine at a time.
- File: paths like
/finance/2026/oct.csv, shared over the network (NFS, SMB). Supports in-place edits, locks and renames. Scaling to billions of files is hard. - Object: a flat namespace of buckets and keys, used over HTTP (
PUT,GET,LIST,DELETE). Each object has metadata. Objects are written whole: to change one byte, you upload a new version. - HDFS is a distributed file system: files are split into large blocks (128 MB by default) stored on many DataNodes, usually with 3 copies; a NameNode keeps the directory tree and block locations. It brought storage and compute onto the same machines (data locality).
- Today’s default: cloud object storage has largely replaced HDFS for new lakes, because storage and compute can scale and be paid for separately.
Advanced Durability, consistency, small files and renames
- Durability vs availability: durability is the chance your data is never lost (S3 is designed for 99.999999999%, “eleven nines”); availability is the chance you can read it right now. They are different promises.
- Replication vs erasure coding: 3 full copies cost 200% extra space; erasure coding splits data into, say, 6 data pieces plus 3 parity pieces and survives the loss of any 3, for only 50% extra. HDFS 3 and cloud stores use erasure coding for colder data.
- Consistency: S3 has offered strong read-after-write consistency since December 2020: a successful write is visible to every reader immediately. Older advice about “eventual consistency” is outdated.
- Small files: every object or HDFS file has a fixed cost: a metadata entry (roughly 150 bytes of NameNode memory per file or block), an open request, a listing entry and per-request charges. Millions of tiny files make jobs slow and bills high. Compact to files of roughly 128 MB to 1 GB.
- Rename is not cheap on object stores: there are no real directories, so “renaming a folder” means copying and deleting every object under the prefix, which is slow and not atomic. Table formats (Delta Lake, Iceberg) avoid renames by committing through a transaction log.
- Lifecycle and tiers: rules move objects automatically from hot to cool, cold and archive tiers as they age, and delete them when retention ends.
Exam tip: Compare block, file and object storage in a table on structure, access method, scalability, latency, cost, update style and examples. Then add HDFS: block size, replication factor 3, NameNode and DataNode roles. These two tables answer most storage questions.
Four kinds of storage compared
Block storage
Raw volumes attached to one server. Fast random reads and writes. Databases, VM disks, Kafka broker disks.
Fast · one serverFile storage
Shared folders and files over the network. Familiar paths, locking and edits. Team shares, home directories.
Folders · sharedObject storage
Buckets of objects with keys and metadata over HTTP. Nearly unlimited, cheap, very durable. Lakes, backups, media.
Huge · cheapDistributed file system (HDFS)
Large files split into replicated blocks across a cluster, processed where they sit. Classic Hadoop platforms.
Cluster · localSide by side
| Block | File | Object | HDFS | |
|---|---|---|---|---|
| Structure | Numbered blocks | Folder tree | Flat: bucket + key | Folder tree over 128 MB blocks |
| Access | OS disk calls | Paths (NFS, SMB) | HTTP API (PUT/GET) | HDFS client API |
| Update in place | Yes | Yes | No: rewrite the object | Append only |
| Scale | One volume, TBs | Large, but hard at billions of files | Practically unlimited | Thousands of nodes |
| Latency | Lowest | Low | Higher (tens of ms per request) | Low within the cluster |
| Cost per GB | Highest | Medium | Lowest | Hardware you run |
| Typical use | Databases | Shared documents | Data lakes, backups, media | On-prem Hadoop lakes |
| Examples | Laptop SSD, Amazon EBS, Azure Disk | NAS, Amazon EFS, Azure Files | Amazon S3, Azure Blob/ADLS Gen2, Google Cloud Storage | Apache HDFS |
“Folders” in S3 are an illusion: the console shows orders/ because many keys start with that prefix. This is why a key naming scheme, such as orders/date=2026-10-19/part-00001.parquet, is one of the first design decisions in a data lake.
From one database disk to a petabyte lake
Block storage: a disk for one server
A PostgreSQL database for TiffinGo’s live orders runs on a cloud disk (block storage). When an order’s status changes, the database rewrites one small block in place, in well under a millisecond.
Fast, in-place, small updates are exactly what databases need. But the disk is attached to one server and is the most expensive storage per GB.File storage: shared folders
The finance team keeps monthly reports in
Familiar and convenient for people. At the scale of billions of files and petabytes, managing one giant folder tree becomes slow and costly./finance/2026/on a shared drive. Anyone with access can open, edit and rename files by path.HDFS: one 300 MB file becomes blocks
HDFS cuts the file into 128 MB blocks (the last one is smaller), and stores 3 copies of each on different DataNodes. The NameNode remembers which blocks make up the file and where they are.import math file_mb, block_mb, replicas = 300, 128, 3 blocks = math.ceil(file_mb / block_mb) last = file_mb - (blocks - 1) * block_mb print("Blocks:", blocks, "| last block:", last, "MB") print("Raw space used:", file_mb * replicas, "MB")Blocks: 3 | last block: 44 MB Raw space used: 900 MBObject storage: keys, not folders
Listing a “folder” is really asking for every key that starts with a prefix. The key naming scheme decides how easily you can find, partition and delete data later.bucket = {} bucket["orders/date=2026-10-19/part-0.parquet"] = b"..." bucket["orders/date=2026-10-20/part-0.parquet"] = b"..." bucket["reviews/2026/10/19/O1043.jpg"] = b"..." prefix = "orders/" print([k for k in bucket if k.startswith(prefix)])['orders/date=2026-10-19/part-0.parquet', 'orders/date=2026-10-20/part-0.parquet']Copies vs erasure coding
Three full copies need 300 TB of disk for 100 TB of data. Erasure coding (6 data + 3 parity pieces) survives losing any 3 pieces and needs only 150 TB. Cloud object stores use techniques like this behind the scenes.data_tb = 100 print("3 replicas :", data_tb * 3, "TB raw") print("Erasure 6 + 3 :", data_tb * (6 + 3) / 6, "TB raw")3 replicas : 300 TB raw Erasure 6 + 3 : 150.0 TB rawThe cost of many tiny files
Only 76 GB of data, yet over five hours of pure overhead just opening and listing two million files one by one (at an illustrative 10 ms each). Compacting them into a few hundred large files makes the overhead disappear.files, avg_kb = 2_000_000, 40 per_file_ms = 10 print("Total data :", round(files * avg_kb / 1024 / 1024, 1), "GB") print("Open + list overhead:", round(files * per_file_ms / 1000 / 60), "minutes")Total data : 76.3 GB Open + list overhead: 333 minutes
One photo: what Riya sees, and what the storage does
Step through the six frames. Left: Riya uploading and viewing a review photo. Right: how object storage stores, serves and ages it.
- Riya adds a photo of her thali to a review and taps Upload.
- The 3.1 MB photo uploads in a couple of seconds.
- Her review is posted with the photo.
- Other customers browse the kitchen page with its review photos.
- Riya’s photo opens almost instantly for a viewer in Mumbai.
- A year later, the photo in her order history is archived and takes a while to restore.
- The app sends the bytes to an upload service with an HTTPS
PUT. Nobody chooses a disk or a folder. - The photo becomes an object: a key (bucket plus full name), the bytes, and metadata such as order id and size.
- Object storage spreads the data across three availability zones (separate buildings), so even losing a whole zone loses nothing.
- The app’s database (on block storage) keeps a small row with the photo’s key. Big binary data stays in object storage.
- Viewers fetch the photo through a CDN: the first request goes to the bucket, later ones are served from a cache near the viewer.
- A lifecycle rule moves the object from hot to cool to archive tiers as it ages, and deletes it when the retention period ends. (Tier timings are an example policy.)
Real-time scenarios: storage under load
Three live scenarios: a file written into HDFS that heals itself after a node failure, the small-files problem and its fix, and an advanced look at why renaming is unsafe on object storage.
Real-time scenario 1Writing a 300 MB file into HDFS, and surviving a dead node
Kabir uploads a 300 MB orders file to a small HDFS cluster with four DataNodes. Watch it split into blocks, get copied three times, and heal itself when a machine fails.
- The HDFS client splits the 300 MB file into blocks of 128 MB, 128 MB and 44 MB. A small last block doesn’t waste a full 128 MB.
- For each block, the NameNode chooses three DataNodes (on different racks where possible). The client streams the block to the first, which passes it to the second, which passes it to the third: a write pipeline.
- All three blocks are stored three times. The NameNode keeps only metadata: which blocks form the file and where each copy is.
- DataNode 2 fails. The NameNode notices missing heartbeats and sees that B1 and B3 have only two copies left.
- It schedules new copies from the surviving replicas, so every block is back to three copies. Readers never notice. (Placement shown is simplified.)
The small-files problem: 86,400 files a day
A streaming job at TiffinGo saves rider pings every second, one small file each time. The data is tiny; the trouble is the number of files.
- Writing one 50 KB file per second gives 86,400 files a day and about 3 crore files a year, although the total data is only around 1.5 TB.
- A daily report must list and open every file. Most of the time goes into listing and opening, not reading. In object storage every request is also billed.
- On HDFS, the NameNode keeps every file and block in memory, roughly 150 bytes each. Crores of tiny files can exhaust its RAM.
- Compaction: a scheduled job rewrites each day’s small files into a few large files of 128 MB to 1 GB.
- Reports become fast and cheap again. Even better is to avoid the problem: write in micro-batches every few minutes and use table formats that compact automatically. (Numbers are illustrative.)
Why “rename” is dangerous on object storage
Many big data tools were designed for HDFS, where renaming a folder is instant. Moved to cloud object storage unchanged, the same habit becomes slow and unsafe. Here’s why, and what modern platforms do instead.
- Classic Spark and Hadoop jobs write output into a temporary folder and, when finished, rename it to its final name. On HDFS this makes results appear all at once.
- On HDFS, renaming a directory is one metadata update in the NameNode: instant and atomic.
- Object storage has no real directories. Renaming a “folder” means copying every object to a new key and deleting the old one: 1,000 files means thousands of requests and minutes of waiting.
- If the job crashes half-way, some files are under the new name and some under the old. Readers can see partial output, which is a correctness problem, not just a speed problem.
- Modern platforms avoid renames: table formats write data files once and then commit by adding a single entry to a transaction log, and special committers do the same for plain files. Readers see the old or the new version, never a mix.
Where each kind of storage is used
1. Live app databases on block storage
Order, payment and user databases run on fast SSD block volumes (for example Amazon EBS or Azure managed disks), often with copies in another zone for safety.
2. Data lakes on object storage
Most modern lakes keep raw and curated data in S3, ADLS Gen2 or Google Cloud Storage, organised by key prefixes such as bronze/orders/date=…/, with Spark, SQL engines and ML reading directly from there.
3. On-premises Hadoop clusters with HDFS
Banks, telecoms and government departments that must keep data in their own data centres still run HDFS clusters, sometimes alongside an on-prem object store.
4. Backups and compliance archives
Old transaction data, call recordings and CCTV footage that must be kept for years go to archive tiers that cost a fraction of hot storage, with lifecycle rules handling the moves.
A tiny object store in a dictionary
Object storage is a giant key → bytes map with metadata. This program builds one with a Python dictionary: put, get and list by prefix. Then try the challenges: split a file into HDFS blocks, survive a node failure, compare replication with erasure coding, cost the small-files problem and plan storage tiers.
bucket = {}
def put(key, data, **meta):
bucket[key] = {"data": data, "size": len(data), **meta}
def get(key):
return bucket[key]["data"]
def list_prefix(prefix):
return sorted(k for k in bucket if k.startswith(prefix))
put("orders/date=2026-10-19/part-0.csv", b"O1,Pune,420\nO2,Thane,250\n", type="csv")
put("orders/date=2026-10-20/part-0.csv", b"O3,Pune,180\n", type="csv")
put("reviews/2026/10/19/O1.jpg", b"...jpeg bytes...", type="image", order="O1")
print("All orders keys:", list_prefix("orders/"))
print("One day only :", list_prefix("orders/date=2026-10-19/"))
print("Read back :", get("orders/date=2026-10-20/part-0.csv"))
print("Metadata :", {k: v for k, v in bucket["reviews/2026/10/19/O1.jpg"].items() if k != "data"})def put(key, data, **meta):Storing is just “this key → these bytes, plus some metadata”. There is no folder to create first.return sorted(k for k in bucket if k.startswith(prefix))A “folder listing” is really a filter on key prefixes. This is why key naming matters so much.put("reviews/2026/10/19/O1.jpg", b"...jpeg bytes...", type="image", order="O1")Metadata travels with the object: type, order id, size.
Run it on your PC: a mini object store and the small-files test
This program builds a tiny object store in a folder: objects are saved under hashed names with a metadata file, and “folders” exist only as key prefixes. Then it writes the same data as 5,000 small files and as one big file and times reading both. Only the standard library is used. Save it as storage_lab.py in an empty folder and run it.
Object store + small-files test
"""A tiny object store on your disk, and the small-files problem measured for real.
Only the Python standard library is used."""
import hashlib, json, os, time
STORE = "my_bucket"
def put(key, data: bytes, **metadata):
"""Store bytes under a key. 'Folders' are just part of the key."""
path = os.path.join(STORE, "objects", hashlib.sha1(key.encode()).hexdigest())
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "wb") as f:
f.write(data)
meta = {"key": key, "size": len(data), "etag": hashlib.md5(data).hexdigest(), **metadata}
with open(path + ".meta.json", "w") as f:
json.dump(meta, f)
def get(key):
path = os.path.join(STORE, "objects", hashlib.sha1(key.encode()).hexdigest())
with open(path, "rb") as f:
return f.read()
def list_prefix(prefix):
keys = []
for name in os.listdir(os.path.join(STORE, "objects")):
if name.endswith(".meta.json"):
with open(os.path.join(STORE, "objects", name)) as f:
k = json.load(f)["key"]
if k.startswith(prefix):
keys.append(k)
return sorted(keys)
put("reviews/2026/10/19/O1043.jpg", b"\xff\xd8 fake image bytes", content_type="image/jpeg", order="O1043")
put("reviews/2026/10/19/O1044.jpg", b"\xff\xd8 another image", content_type="image/jpeg", order="O1044")
put("orders/date=2026-10-19/part-0.csv", b"O1043,Pune,420\nO1044,Thane,250\n", content_type="text/csv")
print("Keys under reviews/2026/10/19/:", list_prefix("reviews/2026/10/19/"))
print("Read back:", get("orders/date=2026-10-19/part-0.csv").decode().strip().splitlines())
print("Note: there are no real folders on disk, only hashed object names + metadata files.\n")
# ---- the small-files problem: same bytes, 5,000 files vs 1 file
os.makedirs("small_files", exist_ok=True)
row = b"O1043,Pune,thali,220,2026-10-19\n"
for i in range(5000):
with open(f"small_files/part-{i:05d}.csv", "wb") as f:
f.write(row * 20)
with open("one_big_file.csv", "wb") as f:
f.write(row * 20 * 5000)
t = time.perf_counter()
total = 0
for name in os.listdir("small_files"):
with open(os.path.join("small_files", name), "rb") as f:
total += f.read().count(b"\n")
small_s = time.perf_counter() - t
t = time.perf_counter()
with open("one_big_file.csv", "rb") as f:
big_rows = f.read().count(b"\n")
big_s = time.perf_counter() - t
print(f"5,000 small files: {total // 100000} lakh rows read in {small_s * 1000:.0f} ms")
print(f"1 big file : {big_rows // 100000} lakh rows read in {big_s * 1000:.0f} ms")
print(f"Same data, about {small_s / big_s:.0f}x slower as small files on this machine")
# In a terminal: python storage_lab.pyRecorded from a real run with Python 3.13 on an SSD. Your times will differ (Windows antivirus scanning can make small files even slower), but the big file always wins. Open the my_bucket/objects folder: there are no reviews or orders folders, only hashed object files and their metadata. Real object stores add HTTP requests on top, so the small-files penalty is larger still.
Re-replicating blocks after a failure, one line at a time
Two blocks have three copies each. Node DN2 dies. Watch the program find each block that lost a copy and pick a new node for it.
Worked examples: real problems, solved and traced in memory
Four storage calculations a data engineer actually makes, from HDFS blocks to a tiered storage bill. Each runs live and is traced.
Block, file or object?
Problem statement
Choose a storage type for each workload using simple rules: databases → block; files people share and edit → file; large analytics data, media and backups → object.
orders database, finance team reports, data lake, CCTV footage, VM boot disk
orders database -> block storage finance team reports -> file storage data lake -> object storage CCTV footage -> object storage VM boot disk -> block storage
Approach
- Describe each workload with a kind.
- Map each kind to a storage type with a dictionary.
- Print the choice.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
How much raw HDFS space does a table need?
Problem statement
A table grows by 400 GB a day and is kept for 180 days. HDFS uses 3 replicas, and admins keep 25% of disk free. How much raw disk is needed, and how many 48 TB nodes?
400 GB/day × 180 days, 3 replicas, 25% free, 48 TB per node
Data kept : 70 TB With 3 copies: 211 TB With 25% free: 281 TB -> 6 nodes of 48 TB
Approach
- Data kept = daily size × days.
- Raw = data × replicas; then divide by 0.75 to keep 25% free.
- Nodes = raw ÷ capacity per node, rounded up.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
Design object keys for a lake
Problem statement
Build keys for daily order files in the format zone/table/date=YYYY-MM-DD/part-NNNNN.parquet, and then list all keys for one week using a prefix filter.
5 days of files, 2 parts per day
Total keys: 10 Week keys : 6 silver/orders/date=2026-10-19/part-00000.parquet
Approach
- Generate dates with
datetime.timedelta. - Format each key with zero-padded part numbers.
- Select a week by comparing the date part of the key.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
Monthly bill with and without storage tiers
Problem statement
A lake adds 1 TB a day and keeps data for 2 years. Hot storage costs Rs 1,800, cool Rs 1,000 and archive Rs 100 per TB per month (illustrative). Data is hot for 30 days, cool until 1 year, then archive. Compare the steady-state monthly bill with keeping everything hot.
1 TB/day, 730 days, tiers 30 d / 365 d
TB per tier : {'hot': 30, 'cool': 335, 'archive': 365}
Tiered bill : Rs 425500
All hot : Rs 1314000
Saving : 68%Approach
- Count how many days of data sit in each tier once the lake is full.
- Multiply TB in each tier by its price.
- Compare with all 730 TB in hot storage.
Solution: run it live
What happens in memory, step by step
Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.
Check yourself
Quick revision
Lesson 2.3 in one screen
- Block: raw volumes, fastest, in-place updates, one server → databases.
- File: folders and paths, shared (NAS, NFS, SMB) → team documents.
- Object: bucket + key + metadata over HTTP, flat namespace, cheapest, nearly unlimited → lakes, backups, media.
- HDFS: 128 MB blocks × 3 replicas on DataNodes; NameNode keeps the namespace and block map.
- Durability ≠ availability. S3 is designed for eleven nines of durability and is strongly consistent since 2020.
- Replication (3× space) vs erasure coding (e.g. 6+3 = 1.5× space).
- Avoid small files (compact to 128 MB–1 GB); avoid renames on object stores (use table formats); use lifecycle tiers.
Interview and viva questions
Differentiate block, file and object storage.
Block storage presents raw fixed-size blocks to a single server, which builds a file system or database on top; it offers the lowest latency and in-place updates. File storage organises data as files in a directory hierarchy accessed by path, usually shared over a network with NFS or SMB. Object storage keeps data as immutable objects with unique keys and metadata in a flat namespace of buckets, accessed over HTTP; it is the cheapest and most scalable, and is the usual foundation for data lakes, backups and media.
Explain HDFS architecture.
HDFS splits files into large blocks (128 MB by default) and stores each block on several DataNodes (replication factor 3 by default, spread across racks). The NameNode maintains the file system namespace and the mapping of blocks to DataNodes in memory; DataNodes store blocks and send heartbeats and block reports. When a DataNode fails, the NameNode re-replicates its blocks from surviving copies. Clients ask the NameNode for block locations and then read or write data directly with DataNodes. A standby NameNode provides high availability.
Why has object storage replaced HDFS in many companies?
Object storage is fully managed, nearly unlimited, very durable and cheap per GB, and it separates storage from compute, so clusters can be resized or shut down without losing data and many engines can share the same data. HDFS ties storage to the compute cluster and requires running and scaling the hardware yourself. HDFS remains common on-premises, especially where data must stay in a company's own data centre.
What is the small-files problem and how do you fix it?
When data is stored as a huge number of tiny files, the fixed per-file costs (NameNode memory in HDFS, listing and request costs in object storage, task overhead in Spark) dominate, making jobs slow and expensive. Fix it by writing larger files (micro-batches, fewer output partitions), compacting existing files into 128 MB to 1 GB files, and using table formats with automatic compaction.
What are storage tiers?
Classes of storage with different prices and access speeds, for example hot (frequent access, highest cost per GB), cool or infrequent access, cold, and archive (cheapest, with retrieval taking minutes to hours and extra retrieval charges). Lifecycle policies move data between tiers as it ages and delete it when retention ends.
Practice problems
Storage calculations from HDFS blocks to cloud bills. The last two are business tasks.
Blocks in a file
How many 128 MB HDFS blocks does a 1,000 MB file need?
1000 MB
8
Show solution and explanation
import math
print(math.ceil(1000 / 128))How it works: Round up: 7 full blocks plus one partial block.
Raw space with replicas
Print the raw disk space for 20 TB of data with 3 replicas.
20 TB, 3 replicas
60 TB
Show solution and explanation
print(20 * 3, "TB")How it works: Every block is stored three times.
Keys under a prefix
Print the keys that start with orders/.
4 keys
['orders/a.csv', 'orders/b.csv']
Show solution and explanation
keys = ["orders/a.csv", "reviews/x.jpg", "orders/b.csv", "logs/app.log"]
print([k for k in keys if k.startswith("orders/")])How it works: This is what a “folder listing” does in object storage.
Average file size
Given file sizes in KB, print the average size in MB and say “compact” if it is below 64 MB.
[40, 52, 38, 61, 45]
0.046 MB -> compact
Show solution and explanation
sizes_kb = [40, 52, 38, 61, 45]
avg_mb = sum(sizes_kb) / len(sizes_kb) / 1024
print(round(avg_mb, 3), "MB ->", "compact" if avg_mb < 64 else "ok")How it works: A tiny average file size is the classic sign of the small-files problem.
Under-replicated blocks
Print the blocks that have fewer than 3 copies.
B1: 3, B2: 2, B3: 3, B4: 1
['B2', 'B4']
Show solution and explanation
copies = {"B1": 3, "B2": 2, "B3": 3, "B4": 1}
print([b for b, c in copies.items() if c < 3])How it works: HDFS tracks exactly this and re-replicates such blocks automatically.
Erasure coding overhead
Print the raw space and overhead percentage for 100 TB with schemes 3 replicas, 6+3 and 10+4.
100 TB
3 replicas 300 TB (+200%) 6+3 150 TB (+50%) 10+4 140 TB (+40%)
Show solution and explanation
for name, d, p in [("3 replicas", 1, 2), ("6+3", 6, 3), ("10+4", 10, 4)]:
raw = 100 * (d + p) / d
print(f"{name:10} {raw:.0f} TB (+{raw - 100:.0f}%)")How it works: Erasure coding gives similar fault tolerance with far less extra space.
NameNode memory
Each file and each block takes about 150 bytes of NameNode RAM. Compare 10 lakh files of 1 MB with the same data in 128 MB files.
10 lakh × 1 MB
1 MB files: 1000000 files, NameNode RAM ≈ 286.1 MB 128 MB files: 7812 files, NameNode RAM ≈ 2.2 MB
Show solution and explanation
import math
total_mb = 10_00_000
for size in [1, 128]:
files = total_mb // size
blocks = files * math.ceil(size / 128)
ram_mb = (files + blocks) * 150 / 1024 / 1024
print(f"{size:4} MB files: {files:8} files, NameNode RAM ≈ {ram_mb:.1f} MB")How it works: The same data in large files needs about 128 times less NameNode memory.
Tiered storage saving
600 TB of data: 50 TB hot (Rs 1,800/TB-month), 250 TB cool (Rs 1,000), 300 TB archive (Rs 100). Print the monthly bill and the saving compared with all hot.
600 TB
Tiered: Rs 370000 All hot: Rs 1080000 Saving: Rs 710000
Show solution and explanation
tiered = 50 * 1800 + 250 * 1000 + 300 * 100
all_hot = 600 * 1800
print("Tiered: Rs", tiered)
print("All hot: Rs", all_hot)
print("Saving: Rs", all_hot - tiered)How it works: Moving rarely used data down the tiers cuts the bill sharply. (Prices are illustrative.)
Nodes for a Hadoop cluster
A company must keep 900 TB of data on HDFS with 3 replicas and 30% free space. Each node has 60 TB. How many nodes?
900 TB, 3×, 30% free, 60 TB/node
Raw needed: 3857 TB Nodes: 65
Show solution and explanation
import math
raw = 900 * 3 / 0.7
print("Raw needed:", round(raw), "TB")
print("Nodes:", math.ceil(raw / 60))How it works: Replication and free-space headroom multiply the hardware needed.
Real-world scenario questions (asked in company interviews)
Storage decisions and problems from real data teams. Decide your answer first, then open the model answer.
Where should each kind of data live?
A new fintech app has customer accounts, a stream of transactions, KYC document scans and seven years of history for audits. Where would you store each?
The interviewer is checking: can you match workloads to block, file and object storage?
Show a strong answer
- Accounts and live transactions: a relational database on SSD block storage, replicated across zones.
- Transaction history for analytics: Parquet tables in object storage (the lake), partitioned by date.
- KYC scans: object storage with encryption, restricted access and the object key stored in the database.
- Seven-year audit data: lifecycle rules moving old partitions to cool and archive tiers, with deletion after the legal period.
Avoid: putting scanned documents in database tables, or everything on expensive SSD volumes.
The report got slower every week
A daily Spark report on a Kafka-fed table took 5 minutes in January and 50 minutes in June. Data volume grew only 20%.
The interviewer is checking: do you suspect the small-files problem and know how to confirm and fix it?
Show a strong answer
- Count files and their average size per partition; you will likely find thousands of KB-sized files per day.
- Check where time goes in the Spark UI: listing and task scheduling for tiny tasks dominate.
- Fix the writer: larger micro-batches, fewer output partitions (
coalesce), or a table format with optimised writes. - Run compaction (for example Delta
OPTIMIZE) on old partitions. - Add a monitor on average file size so it doesn’t creep back.
Avoid: adding more executors, which only creates even more tiny tasks.
Our jobs broke after moving to S3
A team copied its Hadoop jobs from HDFS to S3 unchanged. Jobs now run much longer at the commit step, and once a crash left a half-written output folder that a dashboard read.
The interviewer is checking: do you know the semantic differences between HDFS and object storage?
Show a strong answer
HDFS renames are atomic metadata operations; on S3 a directory rename is copy-plus-delete of every object, slow and not atomic. Use object-store-aware committers (such as the S3A committers) or, better, write through a table format (Delta Lake, Iceberg, Hudi) that commits via a transaction log. Also revisit file sizes, listing-heavy code and data-locality assumptions, since compute and storage are now separate.
Avoid: blaming S3 performance and adding bigger clusters.
“Explain HDFS architecture”
A standard interview question: describe how HDFS stores a file and handles failures.
The interviewer is checking: can you explain blocks, replication, NameNode and DataNodes clearly?
Show a strong answer
A file is split into large blocks (128 MB by default). Each block is stored on several DataNodes (replication factor 3 by default, placed on different racks for safety). The NameNode holds the namespace (directories, files) and the mapping of blocks to DataNodes in memory; DataNodes store the blocks and send heartbeats and block reports. On a DataNode failure, the NameNode re-replicates the affected blocks from surviving copies. Clients get block locations from the NameNode and read data directly from DataNodes. For high availability, a standby NameNode takes over if the active one fails.
Avoid: confusing the NameNode with storage of the actual data.