Requirements & scope
Problem Statement & Requirements
Functional Requirements
- Given a set of seed URLs, systematically crawl the web by following hyperlinks
- Download and store web page content (HTML, and optionally images/PDFs)
- Discover new URLs from crawled pages and add them to the crawl frontier
- Respect
robots.txtand crawl-delay directives (politeness) - Handle deduplication — don't crawl the same page twice
- Support prioritized crawling (important pages first)
- Re-crawl pages periodically to detect changes
Non-Functional Requirements
- Scalability — crawl billions of pages (the web has ~5 billion indexable pages)
- Throughput — crawl 1,000+ pages/second per worker, 100K+ pages/second cluster-wide
- Politeness — never overload a single web server; respect rate limits
- Robustness — handle malformed HTML, spider traps, infinite loops, timeouts
- Extensibility — pluggable modules for content extraction, URL filtering, storage backends
- Freshness — detect and re-crawl changed pages on a schedule
Out of Scope
- Full-text indexing and search ranking (that's the search engine design)
- Rendering JavaScript-heavy SPAs (requires headless browser — discussed briefly)
- Image/video content analysis
Scale estimations
Scale Estimations
Web Scale
| Metric | Value |
|---|---|
| Total web pages (indexable) | ~5 billion |
| Target crawl coverage | 1 billion pages / month |
| Pages / day | ~33 million |
| Pages / second | ~385 |
| With burst / parallelism headroom | ~1,000 pages/second |
| Re-crawl cycle (popular pages) | Every 1-7 days |
| Re-crawl cycle (long-tail) | Every 30 days |
Storage
| Metric | Value |
|---|---|
| Average page size (HTML only) | 100 KB |
| Average page size (compressed) | 20 KB |
| Storage per month (1B pages) | 1B × 20 KB = ~20 TB |
| Metadata per URL | ~500 bytes (URL, hash, timestamps, priority) |
| URL metadata storage (1B URLs) | 1B × 500 bytes = ~500 GB |
| URL frontier (pending URLs) | ~100M URLs × 200 bytes = ~20 GB |
Network
| Metric | Value |
|---|---|
| Bandwidth (downloads) | 1,000 pages/s × 100 KB = ~100 MB/s |
| DNS lookups / second | ~1,000 (cached heavily) |
| Outbound connections | ~5,000 concurrent (with connection pooling) |
Hardware
| Metric | Value |
|---|---|
| Crawler workers | 50-100 machines |
| Pages per worker per second | 10-20 |
| Storage nodes | 20-30 machines (2 TB SSD each) |
| DNS cache nodes | 2-3 machines |
Layered architecture
Phase 1 of 4 · Client & edge
Start with the entry points
First, define who uses the system and where requests enter. This is the boundary of the design, not yet a complete request path.
- Seed URLs
- Begin with a bounded set of known URLs and a defined crawl scope.
This first layer defines the system boundary. The next chapters add application logic and data dependencies. After examining the request paths and tradeoffs, we will add operational safeguards and bring the complete architecture together.
API & contracts
Phase 2 of 4 · Application & compute
Add the application logic
Keep the entry points and add the services that do the work. Give each service a clear responsibility before defining its contracts. Storage and background dependencies come next.
- URL frontier
- Separate freshness priority from per-host scheduling to preserve crawl politeness.
- Crawler workers
- Respect robots directives and per-domain concurrency limits before fetching.
- HTML parser
- Extract outgoing links and normalize them before adding newly discovered URLs.
The frontier hands a worker a URL with a lease, host policy, and attempt count. The worker returns a fetch outcome, content reference, and discovered links. Treat a lost acknowledgement as a possible duplicate fetch, not proof that the page was never stored. Keep URL identity and content identity separate: different addresses can serve the same page.
Data model
Phase 3 of 4 · Data & async work
Connect data and background work
The services now need their dependencies: durable state, fast lookups, or work that continues outside a request. Separate these responsibilities rather than treating every component as a database.
- Deduplication
- Avoid repeated URLs and duplicate content while accounting for canonicalization tradeoffs.
- Content storage
- Persist page bodies separately from crawl timestamps, status codes, and link metadata.
- DNS cache
- Reuse DNS answers to reduce lookups while respecting expiry and address changes.
Content Storage
Core design decisions
URL Frontier — The Heart of the Crawler
Two-Level Queue Architecture
The frontier must balance two competing goals:
- Priority — crawl important pages first
- Politeness — don't hammer any single domain
Priority Calculation
Request flows
Crawl Workflow — Step by Step
Single Page Crawl Flow
Crawler Worker Internal Pipeline
Performance & caching
URL Deduplication
The Challenge
- Billions of URLs to track
- Must check every extracted URL against "already seen" set
- Different URLs can point to the same content
URL-Level Deduplication (Before Fetching)
Content-Level Deduplication (After Fetching)
DNS Resolution
Advanced design
Politeness — robots.txt & Rate Limiting
robots.txt Handling
Per-Domain Rate Limiting
BFS vs DFS Traversal
Distributed Coordination
Partitioning the Crawl Across Workers
Coordination Service (Zookeeper / etcd)
Re-Crawl Strategy (Freshness)
Handling JavaScript-Rendered Pages
Edge cases
Spider Traps & Robustness
Tradeoffs
Tradeoffs & Design Decisions Summary
| Decision | Option A | Option B | Chosen | Why |
|---|---|---|---|---|
| Traversal | DFS | BFS (priority-based) | Priority BFS | Discovers important pages first; DFS gets trapped easily |
| Partitioning | By URL hash | By domain | By domain | Natural politeness enforcement; DNS/robots.txt cache locality |
| URL dedup | HashSet (exact) | Bloom filter + DB | Bloom + DB | 12.5 GB bloom filter handles 99.2% of checks in memory |
| Content dedup | SHA-256 only | SHA-256 + SimHash | SHA-256 (primary) + SimHash (batch) | Exact dedup is fast; near-dedup runs as offline job |
| Storage | S3 only | HDFS only | HDFS (hot) + S3 (archive) | Fast access for indexing; cheap long-term archival |
| DNS | System resolver | Custom multi-level cache | Multi-level cache | 95%+ cache hit rate; pre-fetch for queued domains |
| Politeness | Fixed delay | Adaptive (response-time based) | Adaptive + robots.txt | Respects slow servers; obeys explicit directives |
| JS rendering | Always render | Selective render | Selective | 10x cost; only ~30% of pages need it |
| Coordination | Centralized queue | Zookeeper + consistent hash | Zookeeper + consistent hash | Decentralized work distribution; resilient to worker failure |
| Re-crawl | Fixed schedule | Adaptive (change-rate based) | Adaptive | Changed pages crawled more often; saves bandwidth |
| Frontier persistence | In-memory only | Redis/disk-backed | Redis (sorted sets) | Survives worker restarts; shared across workers |
Reliability & fault tolerance
Phase 4 of 4 · Operations & resilience
Add operational safeguards
With the request paths and tradeoffs established, add the controls that help detect trouble and keep the system operating. The final diagram retains every layer introduced so far.
- Crawl control
- Monitor queue age and host failures; cap depth and repeated URL patterns to contain spider traps.
Monitoring & Operational Concerns
Production architecture
High-Level Architecture
Detailed Component Architecture
Production Architecture
Further exploration
Try crawling a site with an infinite calendar: every page links to tomorrow. A larger cluster only wastes resources faster. Set a crawl budget, identify repetitive URL patterns, and decide when a new page is worth revisiting. Then introduce a small site that changes hourly and compare the scheduling priorities.
Interview playbook
Interview Tips
Start with the crawl loop — "Fetch → Parse → Extract URLs → Enqueue → Repeat." Draw this first, then expand each box.
Politeness is critical — Interviewers look for this. Show the two-level frontier (priority + per-domain queues), robots.txt caching, and adaptive delays.
Deduplication has two layers — URL-level (before fetch, bloom filter) and content-level (after fetch, SHA-256/SimHash). Mention both.
Discuss spider traps — This shows real-world awareness. Calendar pages, infinite pagination, and redirect loops are common examples.
Partition by domain, not URL — Explain why: politeness enforcement is automatic, DNS cache locality, no distributed rate limiter needed.
BFS, not DFS — Quick explanation: BFS discovers high-value pages near the root first. DFS goes deep into one site and misses breadth.
Don't forget DNS — A crawler does more DNS lookups than almost any other system. Multi-level caching (in-process → shared → resolver) is essential.
Re-crawl strategy — "How do you keep content fresh?" Adaptive scheduling based on change frequency + conditional HTTP requests (If-Modified-Since).
Scale the numbers — Walk through: 1B pages/month → 33M/day → 385/second → 1000/s with headroom → 50-100 workers. This shows you can think quantitatively.
Mention WARC format — If storage comes up, mentioning the Web ARChive standard shows domain knowledge. "We'd batch pages into WARC files to avoid the small-file problem on HDFS."