Case Study: Design Web Crawler — Full System Design Interview Walkthrough

“Web crawler giống như con nhện giăng tơ trên Internet — nó bò từ trang này sang trang khác, dệt nên một tấm bản đồ khổng lồ của toàn bộ World Wide Web. Google bot crawl hàng tỷ trang mỗi tháng để xây dựng search index mà chúng ta dùng hàng ngày.”

Tags: system-design case-study web-crawler alex-xu interview chapter-9 Student: Hieu Prerequisite: Tuan-01-Scale-From-Zero-To-Millions · Tuan-02-Back-of-the-envelope Liên quan: Tuan-08-Message-Queue · Tuan-09-Rate-Limiter · Tuan-10-Consistent-Hashing · Tuan-03-Networking-DNS-CDN · Tuan-06-Cache-Strategy · Tuan-07-Database-Sharding-Replication


Context & Why — Tại sao Web Crawler quan trọng?

Con nhện giăng tơ trên Internet

Hieu, hãy tưởng tượng Internet là một khu rừng khổng lồ với hàng tỷ trang web. Mỗi trang web là một chiếc lá, và các hyperlink là những sợi tơ nối chúng lại với nhau. Web crawler (hay còn gọi là spider, bot) chính là con nhện — nó bắt đầu từ một điểm, bò theo sợi tơ (link) từ lá này sang lá khác, và ghi nhớ mọi thứ nó đã thấy.

Google bot — con nhện nổi tiếng nhất — crawl khoảng 130 nghìn tỷ trang (tính đến 2024) để xây dựng Google Search Index. Mỗi khi em Google một thứ gì đó, em đang tìm kiếm trong cái “bản đồ” mà con nhện này đã vẽ ra.

Ai dùng Web Crawler?

Use CaseVí dụ thực tếMô tả
Search Engine IndexingGooglebot, BingbotThu thập nội dung web để xây search index
Web ArchivingWayback Machine (Internet Archive)Lưu trữ lịch sử Internet
Web MiningFintech, Market ResearchThu thập dữ liệu giá cả, tin tức, reviews
Web MonitoringBrand monitoring, SEO toolsTheo dõi thay đổi trên các website
Copyright DetectionYouTube Content ID (web phiên bản)Phát hiện nội dung vi phạm bản quyền

Tại sao câu hỏi này khó?

Web crawler nghe đơn giản — “cứ download HTML rồi follow link” — nhưng thực tế đụng vào gần như mọi vấn đề kinh điển của distributed systems:

Thách thứcLiên quan đến
Phải crawl hàng tỷ trangScalability, distributed computing
Không được DDoS websiteRate limiting, politeness
Nội dung trùng lặpDeduplication, hashing
URL vô tận (spider trap)Graph traversal, trap detection
DNS lookup chậmCaching, DNS resolver optimization
Lưu trữ petabytes dữ liệuDistributed storage, compression
Fault toleranceCheckpointing, graceful recovery

Aha Moment: Web crawler là bài toán “đơn giản mà không đơn giản”. Nó test khả năng em nhìn thấy edge cases và trade-offs trong một hệ thống tưởng chừng straightforward.


Overview — Bốn bước của Alex Xu

Alex Xu chia mọi System Design Interview thành 4 bước:

BướcTên gọiThời gian (45 phút)
1Understand the Problem & Establish Design Scope~5 phút
2Propose High-Level Design~15 phút
3Design Deep Dive~20 phút
4Wrap Up~5 phút

Aha Moment: Đừng nhảy thẳng vào vẽ diagram. Interviewer muốn thấy em biết hỏi đúng câu hỏi trước khi thiết kế. Với web crawler, scope rất rộng — phải narrow down ngay từ đầu.


Step 1 — Understand the Problem & Establish Design Scope

1.1 Functional Requirements (Yêu cầu chức năng)

Hieu, câu đầu tiên em hỏi interviewer phải là: “Mục đích chính của crawler này là gì?” Bởi vì web crawler cho search engine khác hoàn toàn web crawler cho price monitoring.

Câu hỏi clarify với interviewer:

Câu hỏiTrả lời / Giả định
Mục đích chính của crawler?Search engine indexing — thu thập HTML content
Cần crawl bao nhiêu trang/tháng?1 Billion (1B) pages/month
Chỉ crawl HTML hay cả media (images, videos, PDF)?Chỉ HTML
Có cần xử lý nội dung JavaScript-rendered không?Không, chỉ static HTML (simplify scope)
Nội dung mới crawl hay cần re-crawl?Cả hai — crawl trang mới + re-crawl trang đã thay đổi
Lưu trữ bao lâu?5 năm
Xử lý trang trùng nội dung?Có, phải dedup
Crawl chỉ một domain hay toàn bộ Internet?Toàn bộ Internet (open web)

Tóm tắt Functional Requirements:

  1. Crawl — Bắt đầu từ seed URLs, follow links, download HTML content
  2. Dedup — Không lưu trữ nội dung trùng lặp (cả URL và content)
  3. Store — Lưu HTML content vào distributed storage
  4. Re-crawl — Định kỳ quay lại crawl trang đã thay đổi
  5. Politeness — Tuân thủ robots.txt, không gửi quá nhiều request đến cùng một host

1.2 Non-Functional Requirements (Yêu cầu phi chức năng)

RequirementTargetGiải thích
Scalability (Khả năng mở rộng)1B pages/month, scale horizontallyPhải handle toàn bộ open web
Robustness (Tính bền vững)Handle failures gracefullyServer crash, network timeout, malformed HTML, spider traps
Politeness (Lịch sự)Respect robots.txt, rate limit per hostKhông được DDoS bất kỳ website nào
Extensibility (Khả năng mở rộng chức năng)Dễ thêm module mớiThêm image crawler, PDF crawler sau này
Freshness (Tính cập nhật)Ưu tiên re-crawl trang hay thay đổiNews sites crawl thường xuyên hơn static pages
Efficiency (Hiệu quả)Tối ưu bandwidth, storage, computeMỗi byte tải về đều tốn tiền

1.3 Capacity Estimation (Ước lượng năng lực)

Tham chiếu chi tiết: Tuan-02-Back-of-the-envelope

Assumptions (Giả thiết)

Thông sốGiá trịGiải thích
Pages to crawl/month1 Billion (1B)Yêu cầu từ interviewer
Average HTML page size500 KBBao gồm HTML + metadata
Average URL length100 bytesTrung bình
Metadata per page500 bytesTimestamp, headers, status
Storage retention5 nămLưu trữ lâu dài
Total unique URLs to track10 Billion (10B)Nhiều URL hơn pages vì có URL chưa crawl

QPS — Pages per Second

Nhận xét: 400 pages/second trung bình — nghe ít nhưng mỗi page cần DNS lookup + TCP connection + download + parse + extract links. Pipeline phải rất hiệu quả.

Bandwidth

Nhận xét: 1.6 Gbps trung bình — cần nhiều máy với đường truyền tốt. Một máy đơn lẻ không đủ bandwidth.

Storage

Nhận xét: 30 PB trong 5 năm — đây là lý do phải dùng distributed file system (HDFS, S3) và nén dữ liệu. Với compression ratio ~5x, thực tế cần khoảng 6 PB raw storage.

URL Frontier Size

Giả sử tại bất kỳ thời điểm nào, URL Frontier chứa khoảng 100M URLs đang chờ crawl:

Nhận xét: 10 GB — vừa đủ để giữ trong memory, nhưng thực tế URL Frontier sẽ dùng kết hợp memory + disk.

Bloom Filter Size cho 10B URLs

Bloom filter dùng để kiểm tra “URL này đã thấy chưa?” với false positive rate :

Với URLs và (false positive rate):

Số hash functions tối ưu:

Nhận xét: 12 GB cho Bloom filter — hoàn toàn fit trong RAM. Đây là lý do Bloom filter được ưa chuộng cho URL dedup: kiểm tra O(1) với memory rất nhỏ so với lưu toàn bộ 10B URLs.

Tổng kết Estimation

MetricGiá trị
Avg pages/second~400
Peak pages/second~1,200
Avg bandwidth1.6 Gbps
Peak bandwidth4.8 Gbps
Monthly storage (raw)500 TB
5-year storage (compressed)~6 PB
URL Frontier memory~10 GB
Bloom filter for 10B URLs~12 GB

Step 2 — Propose High-Level Design

2.1 Luồng chính của Web Crawler

Hieu, web crawler hoạt động theo một vòng lặp (loop) liên tục. Alex Xu mô tả flow chính như sau:

Seed URLs → URL Frontier → HTML Downloader → Content Parser
→ Content Seen? → Link Extractor → URL Filter → URL Seen?
→ URL Frontier (quay lại vòng lặp)

Mỗi component có một vai trò rõ ràng:

ComponentVai tròInputOutput
Seed URLsĐiểm bắt đầu crawlDanh sách URLs ban đầuURLs đưa vào Frontier
URL FrontierHàng đợi URLs cần crawlURLs mới + URLs re-crawlURL tiếp theo để download
HTML DownloaderTải HTML từ InternetURLRaw HTML content
Content ParserValidate + parse HTMLRaw HTMLParsed HTML hoặc discard
Content Seen?Kiểm tra nội dung trùngParsed HTMLPass (mới) hoặc skip (trùng)
Content StorageLưu trữ HTMLParsed HTML đã qua dedupPersisted content
Link ExtractorTrích xuất URLs từ HTMLParsed HTMLDanh sách URLs mới
URL FilterLọc URLs không hợp lệRaw URLsFiltered URLs
URL Seen?Kiểm tra URL đã crawl chưaFiltered URLPass (chưa thấy) hoặc skip

2.2 Web Crawler Architecture — Mermaid Diagram

flowchart TD
    SEED["Seed URLs<br/>(Starting points)"]
    FRONTIER["URL Frontier<br/>(Priority + Politeness Queues)"]
    DNS["DNS Resolver<br/>(with Cache)"]
    DOWNLOADER["HTML Downloader<br/>(Distributed Workers)"]
    ROBOTS["robots.txt<br/>Cache"]
    PARSER["Content Parser<br/>(Validate HTML)"]
    DEDUP_CONTENT["Content Seen?<br/>(SimHash / MinHash)"]
    STORAGE["Content Storage<br/>(Distributed FS)"]
    EXTRACTOR["Link Extractor<br/>(Extract URLs from HTML)"]
    FILTER["URL Filter<br/>(Blacklist, Extension filter)"]
    DEDUP_URL["URL Seen?<br/>(Bloom Filter)"]

    SEED --> FRONTIER
    FRONTIER --> DNS
    DNS --> DOWNLOADER
    ROBOTS -.->|"Check rules"| DOWNLOADER
    DOWNLOADER --> PARSER
    PARSER -->|"Invalid HTML"| DISCARD1["Discard"]
    PARSER -->|"Valid HTML"| DEDUP_CONTENT
    DEDUP_CONTENT -->|"Already seen<br/>(duplicate)"| DISCARD2["Discard"]
    DEDUP_CONTENT -->|"New content"| STORAGE
    DEDUP_CONTENT -->|"New content"| EXTRACTOR
    EXTRACTOR --> FILTER
    FILTER --> DEDUP_URL
    DEDUP_URL -->|"New URL"| FRONTIER
    DEDUP_URL -->|"Already seen"| DISCARD3["Discard"]

    style FRONTIER fill:#0d6efd,stroke:#333,color:#fff
    style DOWNLOADER fill:#198754,stroke:#333,color:#fff
    style DEDUP_CONTENT fill:#dc3545,stroke:#333,color:#fff
    style DEDUP_URL fill:#dc3545,stroke:#333,color:#fff
    style STORAGE fill:#6f42c1,stroke:#333,color:#fff
    style DNS fill:#fd7e14,stroke:#333,color:#fff

2.3 Seed URLs — Điểm bắt đầu

Seed URLs là tập URLs ban đầu mà crawler bắt đầu bò. Chiến lược chọn seed URLs ảnh hưởng lớn đến hiệu quả:

Chiến lượcMô tảKhi nào dùng
By popularityTop sites theo Alexa/Similarweb rankingGeneral-purpose crawler
By topic/categoryURLs theo danh mục (news, shopping, education)Topic-focused crawler
By geographyURLs theo quốc gia (VN: vnexpress.net, dantri.com.vn)Regional crawler
By domain diversityPhân bố đều across domainsĐảm bảo coverage rộng

Tip cho interview: Em có thể nói “For a general-purpose crawler, I’d start with top 10,000 most popular domains from Alexa ranking, distributed across different categories and geographies.”

2.4 BFS vs DFS Traversal

Web crawler về bản chất là bài toán graph traversal — Internet là một đồ thị khổng lồ, mỗi trang là một node, mỗi link là một edge.

Tiêu chíBFS (Breadth-First Search)DFS (Depth-First Search)
Cách hoạt độngCrawl tất cả links ở level hiện tại trước khi đi sâuĐi sâu theo một path cho đến khi không còn link
Queue typeFIFO QueueStack (LIFO)
Ưu điểmKhám phá rộng, tìm nhanh trang quan trọngĐơn giản implement
Nhược điểmQueue lớn, có thể chậm tìm trang sâuDễ rơi vào spider trap, không đảm bảo politeness
Dùng cho web crawler?Thường dùng BFS (có biến thể)Hầu như không dùng DFS thuần

Vấn đề của BFS thuần:

  1. Không có priority — Trang quan trọng (CNN.com) được đối xử ngang trang vô danh
  2. Impolite — BFS có thể gửi nhiều request đồng thời đến cùng một host
  3. Không tính recrawl — BFS chỉ crawl một lần, không xử lý trang thay đổi

Aha Moment: Vì vậy crawler thực tế dùng modified BFS — BFS kết hợp priority queue và politeness constraints. Đây chính là URL Frontier mà ta sẽ deep dive ở Step 3.


Step 3 — Design Deep Dive

3.1 URL Frontier — Bộ não của Crawler

URL Frontier không phải chỉ là một queue đơn giản. Nó là component phức tạp nhất trong crawler, kết hợp two concerns:

  1. Priority — URL nào nên crawl trước?
  2. Politeness — Không được gửi quá nhiều request đến cùng host

3.1.1 Priority Queue — Crawl cái gì trước?

Không phải tất cả URLs đều quan trọng như nhau. CNN.com homepage quan trọng hơn một blog post random. Cách tính priority:

FactorWeightGiải thích
PageRankCaoTrang được nhiều trang khác link đến → quan trọng
Update frequencyCaoNews sites thay đổi liên tục → cần crawl thường xuyên
Domain authorityTrung bình.edu, .gov thường có authority cao hơn
FreshnessTrung bìnhTrang lâu chưa crawl lại → ưu tiên re-crawl
Depth from seedThấpTrang gần seed URL thường quan trọng hơn trang sâu

Kiến trúc Priority Queue:

  • Prioritizer nhận URL → tính priority score → đưa vào queue tương ứng
  • Có nhiều queues (Q1, Q2, …, Qn) với priority khác nhau
  • Queue Selector chọn URL từ queue nào tiếp theo (queues priority cao được chọn thường xuyên hơn)

3.1.2 Politeness Queue — Đừng DDoS ai cả

Đây là constraint quan trọng nhất mà nhiều ứng viên quên. Nếu crawler gửi 100 requests/second đến cùng một host → đó là DDoS attack, không phải crawling.

Nguyên tắc: Mỗi host chỉ được crawl bởi một worker tại một thời điểm, với delay giữa các request (thường 1-10 giây).

Kiến trúc Politeness Queue:

  • Mỗi host có riêng một queue (per-host queue)
  • Queue Router nhận URL → hash hostname → đưa vào đúng queue
  • Mỗi queue gắn với một worker thread duy nhất
  • Worker tuân thủ crawl delay (thường lấy từ robots.txt hoặc default 1s)

3.1.3 URL Frontier Detail — Mermaid Diagram

flowchart TD
    subgraph "Prioritization Layer"
        IN["Incoming URLs"]
        PRIOR["Prioritizer<br/>(PageRank, Freshness,<br/>Domain Authority)"]
        PQ1["Priority Q1<br/>(Highest)"]
        PQ2["Priority Q2<br/>(High)"]
        PQ3["Priority Q3<br/>(Medium)"]
        PQN["Priority QN<br/>(Low)"]
        SEL["Queue Selector<br/>(Weighted Random)"]

        IN --> PRIOR
        PRIOR --> PQ1
        PRIOR --> PQ2
        PRIOR --> PQ3
        PRIOR --> PQN
        PQ1 --> SEL
        PQ2 --> SEL
        PQ3 --> SEL
        PQN --> SEL
    end

    subgraph "Politeness Layer"
        ROUTER["Queue Router<br/>(hash hostname → queue)"]
        HQ1["Host Queue 1<br/>(cnn.com)"]
        HQ2["Host Queue 2<br/>(bbc.co.uk)"]
        HQ3["Host Queue 3<br/>(vnexpress.net)"]
        HQN["Host Queue N<br/>(...)"]
        W1["Worker 1<br/>(delay: 1s)"]
        W2["Worker 2<br/>(delay: 2s)"]
        W3["Worker 3<br/>(delay: 1s)"]
        WN["Worker N<br/>(delay: 3s)"]

        SEL --> ROUTER
        ROUTER --> HQ1
        ROUTER --> HQ2
        ROUTER --> HQ3
        ROUTER --> HQN
        HQ1 --> W1
        HQ2 --> W2
        HQ3 --> W3
        HQN --> WN
    end

    W1 --> OUT["To HTML Downloader"]
    W2 --> OUT
    W3 --> OUT
    WN --> OUT

    style PRIOR fill:#0d6efd,stroke:#333,color:#fff
    style SEL fill:#0d6efd,stroke:#333,color:#fff
    style ROUTER fill:#198754,stroke:#333,color:#fff
    style OUT fill:#fd7e14,stroke:#333,color:#fff

3.1.4 Freshness — Re-crawl Strategy

Web thay đổi liên tục. Một crawler tốt phải biết khi nào cần re-crawl một trang:

Chiến lượcCách hoạt độngƯu/Nhược
Recrawl all periodicallyCrawl lại mọi trang sau X ngàyĐơn giản nhưng lãng phí bandwidth
Prioritize by change frequencyTrang thay đổi thường → crawl thườngHiệu quả nhưng cần tracking history
Use HTTP headersDùng Last-Modified, ETag, If-Modified-SinceTiết kiệm bandwidth, server phải support
Adaptive recrawlMachine learning predict change frequencyPhức tạp nhưng tối ưu nhất

Adaptive Recrawl trong thực tế:

  • Lần crawl trước: content hash = abc123
  • Lần crawl này: content hash = abc123 (không đổi) → tăng recrawl interval (ví dụ: 7 ngày → 14 ngày)
  • Lần crawl tiếp: content hash = xyz789 (đã đổi) → giảm recrawl interval (ví dụ: 14 ngày → 3 ngày)

3.2 HTML Downloader — Tải nội dung

HTML Downloader là component chịu trách nhiệm tải HTML từ Internet. Nó đụng vào nhiều vấn đề thực tế.

3.2.1 robots.txt Compliance

robots.txt là file đặt ở root domain (ví dụ: https://example.com/robots.txt) mà website owner dùng để “nói” với crawler: “Đừng crawl những URL này.”

Ví dụ robots.txt:

User-agent: *
Disallow: /admin/
Disallow: /private/
Crawl-delay: 10

User-agent: Googlebot
Allow: /
Crawl-delay: 1
DirectiveÝ nghĩa
User-agent: *Áp dụng cho tất cả crawlers
Disallow: /admin/Không được crawl /admin/
Crawl-delay: 10Đợi 10 giây giữa mỗi request
Allow: /Googlebot được crawl toàn bộ

Cách xử lý trong crawler:

  1. Trước khi crawl bất kỳ URL nào → kiểm tra robots.txt của domain đó
  2. Cache robots.txt (TTL ~24h) để không phải tải lại liên tục
  3. Tuân thủ Crawl-delay nếu có
  4. Nếu robots.txt trả 5xx → coi như disallow all (conservative approach)

3.2.2 Distributed Downloading

Một máy đơn lẻ không thể tải 400 pages/second liên tục. Crawler cần phân tán across multiple machines và regions:

Chiến lượcGiải thích
Geographic distributionĐặt crawler workers ở nhiều regions (US, EU, Asia) → giảm latency khi crawl websites ở cùng region
Worker poolMỗi region có pool of workers, mỗi worker chạy trên separate machine
URL assignmentDùng consistent hashing để assign URLs cho workers → đảm bảo cùng host luôn được crawl bởi cùng worker (politeness)
Connection poolingReuse TCP connections đến cùng host → giảm overhead
Async I/ONon-blocking I/O để một worker có thể handle nhiều downloads đồng thời

3.2.3 DNS Resolver — Bottleneck ẩn

DNS resolution là bottleneck lớn nhất mà ít người nhận ra. Mỗi URL cần DNS lookup để chuyển hostname thành IP address, và DNS lookup mất 10-200ms.

Với 400 pages/second, nếu mỗi DNS lookup mất 100ms:

→ Cần 40 threads chỉ riêng cho DNS! Và đây là trường hợp trung bình.

Giải pháp DNS Bottleneck:

Giải phápMô tảHiệu quả
Local DNS cacheCache DNS results trong crawler (TTL-aware)Giảm 80-90% DNS lookups
Pre-fetchingDNS lookup trước khi thực sự cần downloadGiấu latency
Custom DNS resolverChạy local DNS resolver (unbound, CoreDNS) thay vì dùng ISP DNSKiểm soát cache, higher throughput
Batch DNSGom nhiều DNS queries và gửi cùng lúcTăng throughput

Aha Moment: DNS là bottleneck mà nhiều ứng viên quên hoàn toàn. Nếu em mention DNS caching trong interview, interviewer sẽ ấn tượng vì nó cho thấy em hiểu production challenges.

3.2.4 Handling Timeouts & Retries

Không phải mọi download đều thành công. Crawler phải handle gracefully:

ScenarioResponseAction
Connection timeout (10s)Không kết nối đượcRetry với exponential backoff (1s → 2s → 4s), max 3 retries
Read timeout (30s)Kết nối thành công nhưng tải quá lâuCancel, đưa URL lại queue với priority thấp
HTTP 4xxClient error (404, 403)Không retry — URL invalid hoặc bị chặn
HTTP 5xxServer errorRetry sau delay, mark host as potentially down
HTTP 301/302RedirectFollow redirect (max 5 hops), lưu final URL
HTTP 200SuccessTiếp tục pipeline
Quá lớn (>10MB)HTML page bất thườngTruncate hoặc skip

3.3 Content Parser & Validation

Sau khi download HTML, cần validate và parse:

CheckMục đích
Malformed HTMLLoại bỏ HTML không hợp lệ hoặc corrupt
Encoding detectionXác định charset (UTF-8, ISO-8859-1, etc.)
Language detectionNếu chỉ muốn crawl tiếng Việt/Anh
Content extractionTách nội dung chính khỏi boilerplate (nav, footer, ads)
Size checkSkip pages quá nhỏ (<1KB, có thể empty) hoặc quá lớn

3.4 Content Deduplication — Content Seen?

Trên Internet, ~30% trang web có nội dung trùng lặp hoặc gần trùng (mirror sites, syndicated content, copy-paste). Lưu trữ duplicate content lãng phí storage và bandwidth.

3.4.1 Tại sao không dùng hash thông thường?

  • MD5/SHA-256 hash: Chỉ phát hiện exact duplicate. Nếu hai trang khác nhau 1 ký tự → hash hoàn toàn khác.
  • Nhưng web content thường near-duplicate — cùng bài viết nhưng khác ads, timestamps, sidebar.

3.4.2 SimHash — Fingerprinting cho near-duplicate detection

SimHash tạo ra một “fingerprint” sao cho hai documents tương tự nhau sẽ có fingerprint tương tự.

Cách SimHash hoạt động (high-level):

  1. Tokenize document thành features (words, n-grams)
  2. Hash mỗi feature thành bit vector
  3. Weighted sum tất cả bit vectors
  4. Binarize: positive → 1, negative → 0 → SimHash fingerprint

So sánh hai documents:

  • Tính Hamming distance (số bit khác nhau) giữa hai SimHash fingerprints
  • Nếu Hamming distance (thường cho 64-bit SimHash) → near-duplicate
Phương phápPhát hiện exact dupPhát hiện near-dupMemory per docSo sánh
MD5YesNo16 bytesO(1)
SHA-256YesNo32 bytesO(1)
SimHashYesYes8 bytes (64-bit)O(1)
MinHash (Jaccard)YesYes~100 bytes (100 hashes)O(k)

3.4.3 MinHash — Jaccard Similarity Estimation

MinHash là phương pháp khác để ước lượng Jaccard similarity giữa hai documents:

Với là tập hợp shingles (n-grams) của hai documents.

Cách MinHash hoạt động:

  1. Tạo hash functions ngẫu nhiên
  2. Với mỗi hash function, tính min hash value across all shingles → MinHash signature
  3. So sánh signatures: tỉ lệ positions giống nhau Jaccard similarity
ThresholdÝ nghĩaAction
Near-duplicate (rất giống)Skip, không lưu
Partially similarCó thể lưu nhưng đánh dấu
Khác nhau đủLưu cả hai

3.4.4 Content Dedup Flow — Mermaid Diagram

flowchart TD
    HTML["Parsed HTML Content"]
    FP["Compute Fingerprint<br/>(SimHash 64-bit)"]
    LOOKUP["Lookup Fingerprint<br/>in Fingerprint Store"]
    CHECK{"Hamming Distance<br/> ≤ 3?"}
    NEW["New Content<br/>→ Store fingerprint<br/>→ Save to Content Storage<br/>→ Pass to Link Extractor"]
    DUP["Near-Duplicate<br/>→ Discard content<br/>→ Still extract links<br/>(optional)"]

    HTML --> FP
    FP --> LOOKUP
    LOOKUP --> CHECK
    CHECK -->|"No match found<br/>or distance > 3"| NEW
    CHECK -->|"Match found<br/>distance ≤ 3"| DUP

    style FP fill:#0d6efd,stroke:#333,color:#fff
    style CHECK fill:#ffc107,stroke:#333
    style NEW fill:#198754,stroke:#333,color:#fff
    style DUP fill:#dc3545,stroke:#333,color:#fff

3.5 URL Deduplication — URL Seen?

Trước khi thêm URL mới vào Frontier, phải kiểm tra xem URL này đã crawl rồi chưa hoặc đã nằm trong queue rồi chưa.

3.5.1 Tại sao Bloom Filter?

Với 10B URLs, lưu toàn bộ vào HashSet cần:

→ Không fit trong RAM! Bloom filter chỉ cần 12 GB (tính ở phần Estimation) với 1% false positive.

Trade-off của Bloom Filter:

AspectBloom FilterHashSet
MemoryO(m) — rất nhỏO(n * size_per_entry) — rất lớn
False PositiveCó (tunable, ví dụ 1%)Không
False NegativeKhông bao giờKhông
Delete supportKhông (trừ Counting Bloom)

Quan trọng: Bloom filter không bao giờ cho false negative. Nghĩa là nếu Bloom filter nói “chưa thấy URL này” → chắc chắn chưa thấy. Nếu nó nói “đã thấy” → 99% đúng, 1% false positive. Với web crawler, false positive chỉ có nghĩa là skip một URL — chấp nhận được.

3.5.2 URL Normalization

Trước khi check Bloom filter, URL phải được normalize để tránh crawl cùng một trang nhiều lần:

Vấn đềVí dụNormalized
Trailing slashexample.com/page vs example.com/page/example.com/page
Protocolhttp:// vs https://Chọn https:// nếu có
www prefixwww.example.com vs example.comChọn non-www (hoặc canonical)
Fragmentexample.com/page#section1Remove fragment → example.com/page
Query params order?a=1&b=2 vs ?b=2&a=1Sort alphabetically → ?a=1&b=2
Percent encoding%7E vs ~Decode unreserved chars → ~
Default portexample.com:80Remove default port → example.com
CaseExample.COM/PageLowercase hostname → example.com/Page (path case-sensitive!)
Tracking params?utm_source=google&page=1Remove tracking params (utm_*)

Aha Moment: URL normalization là chi tiết nhỏ nhưng cực kỳ quan trọng. Không normalize → crawler sẽ crawl cùng trang hàng chục lần với các URL “trông khác nhưng cùng nội dung”. Lãng phí bandwidth và storage.

3.6 Content Storage — Lưu ở đâu?

3.6.1 Storage Architecture

Với 500 TB/month, cần distributed file system:

Storage LayerLưu gìTechnology
Metadata StoreURL, timestamp, HTTP headers, crawl statusDistributed DB (Cassandra, HBase)
Content StoreRaw HTML content (compressed)Distributed FS (HDFS, S3, GCS)
URL StoreBloom filter, URL → fingerprint mappingIn-memory (Redis) + persistent backup
Fingerprint StoreSimHash fingerprintsDistributed DB hoặc in-memory store

3.6.2 Storage Optimization

Kỹ thuậtMô tảTiết kiệm
Compressiongzip/zstd compress HTML~5x reduction
Dedup at storageChỉ lưu content mới (SimHash filter)~30% reduction
Tiered storageHot data → SSD, Cold data → HDD/S3Giảm chi phí
TTL-based cleanupXóa content quá cũ (>5 năm)Free up space

3.7 Scalability — Mở rộng Crawler

3.7.1 Multiple Crawl Workers

Mỗi crawl worker là một process/container chạy trên separate machine:

Giả sử mỗi worker handle 10 pages/s (including DNS, download, parse):

3.7.2 Consistent Hashing cho URL Assignment

Dùng consistent hashing (Tuan-10-Consistent-Hashing) để assign URLs cho workers dựa trên hostname:

Lợi íchGiải thích
Politeness tự nhiênCùng hostname → cùng worker → dễ enforce rate limit
DNS cache hiệu quảCùng worker crawl cùng domain → DNS cache hit rate cao
robots.txt cacheMỗi worker chỉ cần cache robots.txt cho domains nó phụ trách
Rebalance khi scaleThêm/bớt worker chỉ ảnh hưởng tối thiểu URL assignment

3.7.3 Multi-region Deployment

flowchart TB
    subgraph "Region: US-East"
        F_US["URL Frontier<br/>(US URLs)"]
        W_US1["Worker 1"]
        W_US2["Worker 2"]
        W_USN["Worker N"]
        F_US --> W_US1
        F_US --> W_US2
        F_US --> W_USN
    end

    subgraph "Region: EU-West"
        F_EU["URL Frontier<br/>(EU URLs)"]
        W_EU1["Worker 1"]
        W_EU2["Worker 2"]
        W_EUN["Worker N"]
        F_EU --> W_EU1
        F_EU --> W_EU2
        F_EU --> W_EUN
    end

    subgraph "Region: Asia-Pacific"
        F_AP["URL Frontier<br/>(Asia URLs)"]
        W_AP1["Worker 1"]
        W_AP2["Worker 2"]
        W_APN["Worker N"]
        F_AP --> W_AP1
        F_AP --> W_AP2
        F_AP --> W_APN
    end

    subgraph "Central"
        CS["Content Storage<br/>(S3 / HDFS)"]
        DEDUP["Global Dedup Service"]
    end

    W_US1 --> CS
    W_EU1 --> CS
    W_AP1 --> CS
    W_US1 --> DEDUP
    W_EU1 --> DEDUP
    W_AP1 --> DEDUP

    style CS fill:#6f42c1,stroke:#333,color:#fff
    style DEDUP fill:#dc3545,stroke:#333,color:#fff

Lợi ích multi-region:

  • Crawl websites ở Asia từ Asia region → giảm latency 200-300ms per request
  • Tránh cross-continent bandwidth → giảm chi phí network
  • Nếu một region down → các regions khác vẫn tiếp tục crawl

3.8 Spider Traps & Problematic Content

3.8.1 Spider Trap là gì?

Spider trap là website (cố ý hoặc vô ý) tạo ra vô hạn URLs, khiến crawler bò mãi không thoát ra được.

Loại trapVí dụGiải thích
Infinite loop/a/b/a/b/a/b/...Trang A link đến B, B link đến A
Dynamic URL generation/page?id=1, /page?id=2, … /page?id=99999999Server tạo vô hạn pages
Calendar trap/calendar/2025/01/01, /calendar/2025/01/02, …Calendar component tạo URL cho mỗi ngày đến vô tận
Session ID in URL/page?session=abc123, /page?session=def456Mỗi visit tạo URL mới
Soft 404Mọi URL đều trả HTTP 200 với nội dung “Page not found”Server không trả 404 đúng cách

3.8.2 Anti-Trap Strategies

Chiến lượcMô tảHiệu quả
Max URL depthGiới hạn crawl depth (ví dụ: tối đa 15 levels từ seed)Tránh bò quá sâu
Max pages per domainGiới hạn số trang crawl per domain (ví dụ: 100K pages)Ngăn một domain chiếm hết resources
URL length limitSkip URLs dài hơn 2048 ký tựURLs dài thường là trap
URL pattern detectionPhát hiện repeating patterns (/a/b/a/b/)Heuristic-based
Manual blacklistĐội ops maintain danh sách domains/patterns cần blockCatch-all cuối cùng
Content similarityNếu N trang liên tiếp từ cùng domain có content gần giống → nghi trapDùng SimHash
Crawl budget per domainMỗi domain được “ngân sách” crawl cố định per cycleFair resource allocation

Aha Moment: Spider traps là lý do chính DFS không được dùng cho web crawling. DFS sẽ bò sâu vào trap và không bao giờ quay lại. BFS với depth limit an toàn hơn nhiều.

3.8.3 Problematic Content khác

Vấn đềMô tảGiải pháp
JavaScript-rendered pagesSPA (React, Angular) — HTML trống, content render bằng JSHeadless browser (Puppeteer, Playwright) — tốn resources hơn nhiều
Login wallsContent sau login formSkip hoặc dùng authenticated crawling (phức tạp)
CAPTCHAsAnti-bot protectionSkip — đây là tín hiệu website không muốn bị crawl
Rate limiting responsesHTTP 429 Too Many RequestsBack off, giảm crawl rate cho domain đó
Huge filesPDF 500MB, video embeddedSet max download size, filter by Content-Type header
Encoding issuesTrang tiếng Trung, Nhật với encoding lạDetect charset từ HTTP header + meta tag + content sniffing

Step 4 — Wrap Up

4.1 Security Considerations (Bảo mật)

4.1.1 robots.txt Compliance — Tôn trọng chủ nhà

Đây không chỉ là kỹ thuật mà còn là vấn đề pháp lý và đạo đức:

AspectChi tiết
Bắt buộc tuân thủrobots.txt là “gentleman’s agreement” — không bắt buộc kỹ thuật nhưng vi phạm có thể bị kiện
Cache robots.txtTải một lần, cache 24h. Đừng tải robots.txt trước MỖI request
Crawl-delayTuân thủ Crawl-delay directive. Nếu không có, default 1-5 giây
User-agent identificationCrawler phải tự xưng danh qua User-Agent header (ví dụ: HieuBot/1.0)

4.1.2 Crawl Rate Limiting — Đừng DDoS

Không có crawl rate limiting = DDoS attack không chủ đích. Xem chi tiết Tuan-09-Rate-Limiter.

Loại limitGiá trị khuyến nghịMục đích
Per-host request rate1 request/1-10 giâyKhông overwhelm bất kỳ server nào
Per-host concurrent connections1 connectionPoliteness
Global request rateTuỳ bandwidth budgetKiểm soát tổng tải
Per-host daily limit10K-100K pagesNgăn crawl quá nhiều từ một domain
Vấn đề pháp lýChi tiếtGiải pháp
GDPR (EU)Crawl có thể thu thập personal data (email, tên, địa chỉ trên web pages)Không index/store personal data. Nếu lưu → phải cho phép “right to be forgotten”
CopyrightHTML content có bản quyềnCrawler thu thập để index, KHÔNG republish. Fair use doctrine
Computer Fraud and Abuse Act (CFAA)Truy cập “unauthorized” vào hệ thốngTuân thủ robots.txt = implicit authorization. Bypass = rủi ro pháp lý
Terms of ServiceNhiều website cấm crawling trong ToSRủi ro bị kiện nếu vi phạm ToS (case: LinkedIn vs hiQ Labs)
DMCANội dung được bảo vệ bản quyềnCơ chế DMCA takedown request

Aha Moment: Nhiều ứng viên focus vào kỹ thuật mà quên hoàn toàn khía cạnh pháp lý. Mention GDPR và robots.txt compliance trong interview cho thấy em hiểu bài toán end-to-end, không chỉ engineering.

4.1.4 Malicious Content Handling

Mối đe dọaMô tảGiải pháp
Malware in HTMLTrang web chứa mã độcSandbox environment cho parser, không execute JavaScript trong crawler
Phishing pagesTrang giả mạo ngân hàng, Google, etc.Integrate phishing detection (Google Safe Browsing API) trước khi index
SEO spamTrang chứa toàn keyword spam, hidden textContent quality scoring — nếu score thấp → giảm priority hoặc skip
Link farmsNetwork of sites link đến nhau để tăng PageRankPhát hiện bằng graph analysis — cluster of sites với unnatural linking patterns
CloakingServer trả content khác cho crawler vs userRandom User-Agent rotation, so sánh crawl result vs actual page

4.1.5 Phishing Page Detection

Phishing pages giả mạo websites hợp pháp để lừa người dùng. Crawler có thể giúp phát hiện:

TechniqueMô tả
URL analysisDomain tương tự domain hợp pháp (googIe.com vs google.com, paypa1.com vs paypal.com)
Content similaritySo sánh content với trang gốc bằng SimHash — nếu rất giống nhưng domain khác → nghi phishing
SSL certificate checkPhishing sites thường dùng free SSL hoặc self-signed cert
Domain ageDomain mới tạo (<30 ngày) + nội dung giống trang nổi tiếng → red flag
Blacklist checkCheck domain against known phishing databases (PhishTank, OpenPhish)

4.2 DevOps — Deployment, Monitoring, Operations

4.2.1 Monitoring — Theo dõi sức khỏe Crawler

Tham chiếu: Tuan-13-Monitoring-Observability

MetricMô tảAlert Threshold
Crawl rate (pages/second)Tốc độ crawl hiện tại< 200 pages/s (dưới 50% target)
Success rate% requests trả về HTTP 200< 80%
Error rate by type% HTTP 4xx, 5xx, timeout4xx > 20%, 5xx > 10%, timeout > 5%
Queue depthSố URLs trong Frontier> 500M (queue đang phình) hoặc < 1M (sắp hết việc)
Download latency (P50, P99)Thời gian tải mỗi trangP99 > 10 giây
DNS resolution timeThời gian DNS lookupP99 > 500ms
Duplicate rate% content bị detect là duplicate> 50% (có thể crawler đang bị trap)
Bloom filter false positive rateEstimated FP rate> 5% (cần resize)
Storage growth rateTB/day mới thêmDeviation > 50% so với expected
Worker healthCPU, memory, network I/O per workerCPU > 90%, Memory > 85%

Dashboard layout gợi ý:

PanelMetricVisualization
Top-leftCrawl rate (pages/s) real-timeTime-series line chart
Top-rightSuccess/Error rateStacked area chart
Middle-leftQueue depth over timeLine chart with threshold lines
Middle-rightTop 10 domains by crawl volumeBar chart
Bottom-leftDownload latency P50/P95/P99Histogram
Bottom-rightWorker status gridHeatmap (green/yellow/red)

4.2.2 Distributed Deployment

ComponentDeploymentScaling Strategy
URL FrontierStateful service, sharded by hostname hashScale shards khi queue depth tăng
Crawl WorkersStateless containers (K8s pods)Horizontal auto-scaling based on queue depth
DNS ResolverPer-region caching resolverScale with worker count
Content ParserStateless, CPU-intensiveScale with crawl rate
Dedup ServiceStateful (Bloom filter, fingerprint store)Scale memory, partition Bloom filter
Content StorageS3/HDFS clusterAdd nodes khi storage đầy
Metadata DBCassandra/HBase clusterAdd nodes, consistent hashing tự rebalance

4.2.3 Graceful Shutdown

Khi cần restart/update crawler, không được kill process ngay lập tức:

BướcActionLý do
1Stop accepting new URLs từ FrontierKhông nhận thêm việc mới
2Finish in-flight downloads (timeout 30s)Không lãng phí downloads đã bắt đầu
3Save Frontier state to diskURLs trong queue không bị mất
4Save Bloom filter snapshotKhông phải rebuild từ đầu
5Flush parsed content đến storageKhông mất data đã parse
6Shutdown workersClean exit

4.2.4 Checkpoint & Resume

Crawler chạy liên tục 24/7. Khi crash (và SẼ crash), phải resume được:

State cần checkpointFrequencyStorage
URL FrontierMỗi 5 phútDisk (RocksDB / local SSD)
Bloom filterMỗi 15 phútDisk snapshot
Crawl progress per domainReal-time (mỗi page)Metadata DB
Worker assignmentMỗi khi thay đổiCoordination service (ZooKeeper/etcd)

Recovery flow:

  1. Worker crash → Coordination service detect (heartbeat timeout)
  2. Reassign URLs of dead worker → healthy workers (consistent hashing makes this efficient)
  3. New worker starts → load latest Bloom filter snapshot + Frontier state
  4. Resume crawling from last checkpoint

Aha Moment: Checkpoint/resume là thứ phân biệt production crawler với toy crawler. Không ai muốn restart crawl 10B URLs từ đầu vì một process crash.

4.2.5 Alerting Strategy

SeverityConditionAction
P0 — CriticalCrawl rate = 0 (toàn bộ crawler dừng)Page on-call engineer ngay lập tức
P1 — HighCrawl rate < 50% target liên tục > 15 phútNotify team, investigate trong 30 phút
P2 — MediumError rate > 20% cho specific domain clusterAuto-reduce crawl rate, notify team
P3 — LowBloom filter FP rate > 3%Schedule resize trong sprint tiếp

Aha Moments & Pitfalls — Những điều cần nhớ

Aha Moment 1: Politeness vs Speed — Trade-off cốt lõi

Hieu, đây là trade-off trung tâm của web crawler. Em muốn crawl nhanh (1B pages/month) nhưng đồng thời phải lịch sự (không DDoS bất kỳ ai).

Nếu quá nhanhNếu quá chậm
Website block IP crawlerKhông đạt target 1B pages/month
Bị kiện (CFAA violation)Content index không fresh
Reputation damageSearch results quality giảm
Website sập → crawler cũng không crawl đượcTốn tiền server chạy lâu

Giải pháp: Nhanh tổng thể nhưng chậm với từng host. Crawl song song hàng nghìn hosts, mỗi host 1 request/vài giây.

Aha Moment 2: Spider Traps — Hố đen của Crawler

Spider traps có thể “nuốt” toàn bộ resources của crawler nếu không phòng bị. Ví dụ thực tế: một calendar widget có thể tạo URLs cho mọi ngày từ năm 1970 đến 9999 — hàng triệu URLs, tất cả đều hợp lệ nhưng vô nghĩa.

Cách phòng: Defense in depth — kết hợp max depth + max pages per domain + URL pattern detection + manual blacklist. Không có silver bullet.

Aha Moment 3: URL Normalization — Chi tiết nhỏ, impact lớn

Không normalize URLs → crawler có thể crawl cùng trang hàng chục lần:

  • http://Example.COM/page
  • https://www.example.com/page/
  • https://example.com/page?utm_source=google
  • https://example.com/page#section1

Tất cả là cùng một trang! Normalize trước khi đưa vào Bloom filter.

Aha Moment 4: DNS Bottleneck — Kẻ thù giấu mặt

DNS lookup tưởng “có gì đâu, mỗi cái 100ms” — nhưng nhân với 400 pages/second = 40,000ms DNS time mỗi giây. Không cache DNS = crawler chạy chậm hơn 10x.

Giải pháp đơn giản: local DNS cache + custom DNS resolver + pre-fetching. Đa số DNS entries có TTL dài (hours-days), nên cache hit rate rất cao.

Aha Moment 5: Content Near-Duplicate — 30% Internet là copy-paste

Trên Internet, cùng một bài báo xuất hiện trên hàng chục websites (syndicated content). Lưu tất cả = lãng phí 30% storage. SimHash cho phép detect near-duplicate với chỉ 8 bytes per document — cực kỳ hiệu quả.

Pitfall 1: Dùng DFS thay BFS

DFS sẽ bò sâu vào một domain/path và không quay lại. Kết hợp với spider trap → crawler bị stuck mãi mãi. Luôn dùng BFS (hoặc modified BFS với priority).

Pitfall 2: Không handle HTTP redirects đúng cách

Redirect chains có thể tạo loop: A → B → C → A. Phải set max redirect hops (thường 5-10) và track visited URLs trong chain.

Pitfall 3: Không set timeout cho downloads

Một server chậm (hoặc cố tình) có thể giữ connection mở mãi mãi → worker bị block. Luôn set connection timeout (10s) và read timeout (30s).

Pitfall 4: Quên xử lý character encoding

Trang web có thể dùng UTF-8, ISO-8859-1, EUC-KR, Shift_JIS, etc. Parse sai encoding → content bị garbled → dedup không hoạt động đúng → lưu duplicates.

Pitfall 5: Single point of failure ở URL Frontier

Nếu URL Frontier chạy trên một máy duy nhất → máy đó chết = toàn bộ crawler dừng. Frontier phải được sharded và replicated.


Tổng kết — Checklist cho Interview

Khi trả lời “Design a Web Crawler” trong interview, Hieu cần cover:

#TopicMust mention
1Clarify requirementsScale (1B pages), purpose, HTML only vs media
2High-level flowSeed → Frontier → Download → Parse → Dedup → Extract → Loop
3URL FrontierPriority queue + Politeness (per-host queue)
4Politenessrobots.txt, crawl delay, per-host rate limit
5DedupContent dedup (SimHash) + URL dedup (Bloom filter)
6DNS optimizationLocal cache, custom resolver
7RobustnessSpider traps, timeouts, retries, checkpoint/resume
8ScalabilityDistributed workers, consistent hashing, multi-region
9StorageDistributed FS, compression, tiered storage
10EstimationPages/s, bandwidth, storage, Bloom filter size

Liên kết kiến thức

Concept trong bàiTuần đã họcÁp dụng cụ thể
Message QueueTuan-08-Message-QueueURL Frontier chính là một message queue phức tạp
Rate LimiterTuan-09-Rate-LimiterPoliteness = rate limiting per host
Consistent HashingTuan-10-Consistent-HashingURL assignment cho workers, sharding Frontier
DNS & CDNTuan-03-Networking-DNS-CDNDNS resolution optimization
Cache StrategyTuan-06-Cache-StrategyDNS cache, robots.txt cache, content cache
Database ShardingTuan-07-Database-Sharding-ReplicationMetadata DB sharding, content storage

Appendix — So sánh Web Crawler vs các Case Study khác

AspectURL ShortenerChat SystemNews FeedWeb Crawler
Read/Write patternRead-heavyWrite-heavy (messages)Read-heavy (feed)Write-heavy (crawl + store)
Core challengeHashing, uniquenessReal-time deliveryFan-out, rankingPoliteness, dedup, scale
StorageSmall (URLs)Medium (messages)Medium (posts)Massive (petabytes of HTML)
Latency requirementVery low (<50ms)Very low (<100ms)Low (<500ms)Not critical (batch)
Distributed?Optional at small scaleYes (WebSocket servers)Yes (fan-out workers)Always (mandatory)
Unique patternsBase62 encodingWebSocket, presencePush vs Pull modelBFS traversal, Bloom filter

“Web crawler là bài toán mà simplicity deceives — nhìn đơn giản nhưng mỗi component đều ẩn chứa complexity. Em sẽ không bao giờ nhìn Google Search giống cách cũ nữa sau khi hiểu được bao nhiêu engineering đằng sau việc ‘crawl mấy trang web’.”