Case studies
Case study: web crawler
Crawl billions of pages politely, with a Mercator-style frontier, DNS and robots caches, Bloom and SimHash deduplication, and defenses against spider traps.
A crawler looks like a loop over URLs until you reach scale. At a billion pages a month, the hard problems are politeness (not overloading a small site), deduplication (the same content under a thousand URLs) and spider traps (endless links that waste the crawl). Important pages also need revisits often enough to stay useful.
The classic design is Mercator, described by Heydon and Najork, plus the frontier design in Manning, Raghavan and Schütze's Introduction to Information Retrieval. Crawls for LLM training add opt-out signals and quality filters on the same skeleton.
Requirements
- Fetch on the order of 10⁹ pages per month, about 400 per second on average.
- Be polite: cap requests per host, space them by seconds, and honor
robots.txt. - Recrawl important or changing pages more often than the long tail.
- Survive timeouts, traps, soft error pages and broken encodings.
Ranking is out of scope here. See search systems for the index side.
Concepts in this topic
| Step | Concept | What it answers |
|---|---|---|
| 1 | URL frontier | Which URL should be fetched next? |
| 2 | Politeness and back queues | How do you keep threads busy without hammering one host? |
| 3 | Deduplication | How do you skip URLs and pages you already have? |
| 4 | Spider traps and recrawl | How do you avoid endless URLs and keep pages fresh? |
Architecture
The pipeline runs in order: seed the frontier, schedule each URL when politeness allows, fetch with timeouts and size caps, parse out text and links, deduplicate, then store the page for later indexing or training.
DNS and robots.txt
Slow DNS lookups once blocked whole crawlers. Keep a large DNS cache and resolve names asynchronously. Fetch robots.txt once per host and cache it for hours. Check every URL against the cached rules before fetching. Decide in advance whether a failed robots.txt fetch fails open or closed, and apply that choice everywhere.
Distributed crawling
Assign hosts to workers with hash(hostname) % N. Each worker owns the frontier for its hosts, so politeness stays local. Links that point to another worker's host are forwarded to that worker. Checkpoint frontiers to durable storage, so a deploy does not lose months of discovered URLs.
Storage handoff
Store fetched bytes in object storage, keyed by content hash. Keep URL metadata alongside: last fetch time, last status, ETag, content fingerprint, priority and the next fetch due time. The recrawl scheduler reads that table. Publish a "document ready" event to a queue, so indexers can fall behind without slowing fetches.
Example
One billion pages a month is about 386 pages per second. At 50 KB of HTML per page, that is about 19 MB per second, or roughly 50 TB a month before compression and duplicates. If near-duplicate suppression removes 30% of bodies, that saves about 15 TB and the index work that goes with it.
Failure modes
| Problem | Mitigation |
|---|---|
| Frontier runs out of memory | Disk-backed queues |
| Soft 404s, pages that return 200 with "not found" | Content heuristics and site-level anomaly checks |
| Budget wasted on traps | Per-host caps and pattern detection |
| Host returns 429 or 403 | Back off exponentially and reduce that host's budget |
robots.txt newly disallows a path | Honor it at once and stop enqueuing those URLs |
Politeness is product policy
Legal and product teams set the policy, and engineering enforces it. Examples include one request per second per host by default, faster rates for partners, a contact address in the User-Agent, and no crawling of login or cart pages.
Common mistakes
- Sharing one queue across hosts. One slow site then blocks threads that could fetch elsewhere.
- Counting raw fetches as success. Measure useful pages per second, after deduplication and quality filters.
- Seeding from noisy directories. Spam becomes the first thing you crawl, and it uses up budget.
- Normalizing URLs too aggressively or too little. Both waste budget in different ways.
Key takeaways
- A scalable crawler is a frontier, polite fetchers, a parser, deduplication and storage, sharded by host.
- Front queues set priority, and per-host back queues enforce politeness.
- Cache DNS and
robots.txt, and rate-limit each host and the whole crawl. - Defend against spider traps, and schedule recrawls by importance and change rate.
- LLM crawls add quality filters, PII checks and opt-out handling to the same backbone.
Further learning
A complete "design a web crawler" interview with an ex-Meta staff engineer. It is good for the dataflow-first presentation.
Related
Probabilistic data structures
Compact structures that answer membership, distinct-count, frequency, sampling and similarity questions with a small, bounded error. Start here for the family and how to choose one.
Message queues
A durable buffer between the code that creates work and the code that does it. Start here for the map of queue concepts.
Pretraining a language model
Data, objective and compute: how a base model is trained on trillions of tokens.
The URL frontier
The URL frontier is the crawler's queue of pages still to fetch. Front queues decide what matters most, and the politeness rules decide when each host can be fetched.
Politeness and back queues
One queue per host, plus a heap of next-allowed fetch times, lets many fetcher threads stay busy while no site is contacted faster than its politeness delay.
Deduplicating URLs and content
Crawlers deduplicate twice. A Bloom filter checks URLs already seen, and fingerprints (exact hashes or SimHash) check whether the page content is already stored.
Spider traps and recrawl scheduling
Spider traps are endless URL patterns that waste crawl budget. Per-host caps, pattern detection and change-based recrawl schedules keep the budget on pages that matter.