Pertanyaan Wawancara dan Cakupan
Rancang large-scale web crawler yang menyuplai HTML ke search index. Sistem ini melacak 10 miliar URL yang diketahui dan dapat melakukan paling banyak 1 miliar fetch per hari. Rancang URL frontier, host-level politeness, deduplikasi, recrawling, failure recovery, dan rencana validasi, termasuk estimasi kapasitas.
Ini adalah pertanyaan system design tingkat senior untuk backend, infrastructure, search, dan data-platform engineer. Outputnya berisi raw HTML terkompresi, fetch metadata, dan tautan yang baru ditemukan. Full-text indexing, search ranking, authenticated pages, gambar dan video, serta default JavaScript rendering berada di luar cakupan. Coverage bersifat best effort; sistem tidak menjamin penelusuran seluruh web.
Angka-angka berikut adalah asumsi wawancara, bukan pengukuran produksi: rata-rata response body yang berhasil adalah 200 KB; daily fetch cap mencakup keberhasilan, respons 304, kegagalan, dan percobaan ulang (retries); beban rata-rata menggunakan batas harian penuh, dan peak yang direncanakan adalah 25.000 fetch per detik. URL yang baru ditemukan bersifat tahan lama (durable) dalam 60 detik. Saat kapasitas tersedia, 99% URL prioritas tinggi yang lewat jatuh tempo menerima lease dalam 10 menit. Host politeness adalah hard constraint dan tidak dapat dilonggarkan untuk mengejar throughput.
Sebuah laporan wawancara publik menggambarkan sesi desain 25 menit di mana kode crawler sudah ada dan kandidat harus merancang arsitektur yang scalable. Materi system design publik tahun 2026 juga memperlakukan distributed crawler sebagai latihan mandiri. Satu laporan tidak dapat menetapkan bank soal tetap suatu perusahaan atau frekuensi pertanyaan tersebut, sehingga artikel ini memperlakukannya sebagai masalah system design yang representatif dan tidak mengaitkannya dengan perusahaan mana pun.
Hal yang Dinilai Pewawancara
Sinyal pertama adalah cakupan dan estimasi (scope and estimation). Kandidat yang kuat mendefinisikan target crawl, sasaran kesegaran (freshness), downstream consumer, dan failure semantics sebelum menghitung throughput dan penyimpanan. Langsung menggambar antrean (queue), crawler worker, dan basis data tidak menjelaskan mengapa komponen-komponen tersebut dibutuhkan.
Sinyal kedua adalah scheduling invariant dari URL frontier. Satu FIFO global dapat mendistribusikan beban kerja, tetapi tidak dapat menegakkan konkurensi, delay, dan backoff di semua consumer untuk host yang sama. Desain yang kuat memisahkan “host mana yang siap?” dari “URL mana yang harus diambil host ini berikutnya?” dan memberi setiap host_key satu logical owner untuk status tokennya.
Sinyal ketiga adalah membedakan tiga jenis duplikat: URL ternormalisasi yang sama, URL berbeda dengan konten byte yang identik, dan halaman dengan perbedaan konten kecil. Masing-masing memerlukan status URL yang tepat, hash konten, dan fingerprint near-duplicate. Satu Bloom filter tidak dapat melayani ketiga peran tersebut.
Sinyal terakhir adalah model kegagalan (failure model). Pengambilan eksternal pasti menghadapi timeout, 429, 5xx, kesalahan DNS, loop pengalihan (redirect loops), respons yang sangat besar, dan halaman berbahaya. Jawaban yang baik menerima eksekusi at-least-once, membatasi efek samping duplikat dengan lease, version-conditional writes, dan penyelesaian idempoten, serta mengusulkan pengujian dan metrik yang dapat menguji ketahanan desain.
Pertanyaan yang Perlu Diklarifikasi Sebelum Menjawab
- Siapa yang menggunakan output? Search index membutuhkan HTML, waktu fetch, status, dan URL kanonikal. Sebuah arsip juga membutuhkan versi yang tidak dapat diubah (immutable). Korpus pelatihan akan menekankan filter kualitas dan lisensi. Masalah ini mengirimkan output hanya ke search index.
- Konten apa yang termasuk dalam cakupan? Desain ini mengambil HTML HTTP/HTTPS publik. PDF, media, sesi terotentikasi, atau perenderan JavaScript akan mengubah fetcher, parser, model biaya, dan isolasi keamanan.
- Bagaimana menyeimbangkan cakupan dan keterkinian? Dari 10 miliar URL yang diketahui, masalah ini menyegarkan 100 juta URL bernilai tinggi setiap hari dan menargetkan interval 30 hari untuk 9,9 miliar lainnya. Menyegarkan setiap halaman setiap hari secara matematis tidak kompatibel dengan anggaran harian 1 miliar fetch.
- Pada batas mana politeness diberlakukan? Desain ini membentuk
host_keydarischeme + authoritydan memusatkan kebijakan robots, konkurensi, penundaan minimum, dan backoff yang diarahkan server untuk kunci tersebut. Kelonggaran yang dinegosiasikan hanya mengubah kebijakan host tersebut, bukan invarian global. - Seberapa ketat persyaratan “tanpa duplikat”? Penemuan URL tidak boleh kehilangan URL secara diam-diam karena false positive pada Bloom-filter, sehingga kunci unik yang durable adalah source of truth. Fetch jaringan dapat berulang; penyimpanan dan event downstream harus idempoten.
- Berapa lama halaman yang dihapus dan gagal dipertahankan? Sebuah
404,410, kegagalan berulang, dan5xxsementara memerlukan interval kunjungan ulang yang berbeda. Desain ini mempertahankan tombstone dan status terbaru sehingga penemuan kembali tidak membuat URL baru.
Jawaban 30 Detik
“Satu miliar fetch per hari adalah sekitar 11.600 per detik rata-rata, jadi saya akan merencanakan peak 25.000 per detik dan membagi kesegaran menjadi 100 juta URL yang disegarkan setiap hari dan 9,9 miliar yang disegarkan setiap 30 hari. Discovery melakukan normalisasi konservatif dan deduplikasi unique-key yang tepat. Frontier di-shard berdasarkan host: shard pertama-tama memilih host yang next_allowed_at-nya telah tiba, lalu mengambil URL prioritas tertinggi dari antrean host tersebut. Hal ini memberikan satu pemilik untuk kebijakan robots, konkurensi, dan backoff. Fetcher menggunakan lease dan conditional request, menulis HTML ke object storage, dan mengirimkannya ke parser yang mengalirkan tautan kembali melalui discovery. Eksekusi bersifat at-least-once; versi URL dan penyelesaian idempoten menyerap duplikat. Saya akan memfokuskan validasi pada rate limit per-host, kedaluwarsa lease, 429/503, file robots yang tidak dapat dijangkau, redirect loops, dan crawler traps.”
Pembahasan Mendalam Langkah demi Langkah
Langkah 1: Buktikan bahwa sasaran sesuai dengan anggaran
Satu miliar fetch dibagi 86.400 detik adalah sekitar 11.574 fetch per detik rata-rata. Dengan memperhitungkan variasi lalu lintas dan pekerjaan mengejar ketinggalan (catch-up), bulatkan rencana peak menjadi 25.000 per detik. Jika setiap respons mengembalikan body 200 KB, ingress maksimum sekitar 200 TB per hari, atau rata-rata 2,31 GB per detik. Respons 304 Not Modified tidak memiliki konten respons, sehingga ingress aktual harus lebih rendah dari batas konservatif ini dan harus dikalibrasi dengan uji beban serta distribusi yang diamati.
Rencana kunjungan ulang harian membutuhkan:
100,000,000 + 9,900,000,000 / 30 = 430,000,000 fetches
Itu menyisakan sekitar 570 juta fetch untuk halaman yang baru ditemukan, percobaan ulang, dan halaman yang cepat berubah. Dengan asumsi 200 byte status logis mentah per URL, 10 miliar record URL membutuhkan sekitar 2 TB. Replikasi, indeks, amplifikasi LSM, dan object storage tidak termasuk. Besaran ini menuntut metadata yang dipartisi secara horizontal dan object storage terpisah untuk HTML; body halaman tidak termasuk dalam frontier.
Langkah 2: Bangun aliran data bertahap
Alur lengkapnya adalah: seeds dan Sitemaps → penemuan dan normalisasi URL → exact seen state → metadata URL → frontier scheduler → pemeriksaan robots dan host-politeness → fetcher DNS/HTTP → object storage HTML → parser → tautan yang ditemukan kembali ke discovery. Output yang di-parse dan event penyelesaian fetch kemudian dikirim ke search index dan kalkulator kunjungan ulang.
Sitemap melengkapi seed; sitemap tidak menjamin cakupan. Satu file Sitemap dapat berisi paling banyak 50.000 URL dan ukurannya paling banyak 50 MB tanpa kompresi. Situs besar membaginya di balik indeks Sitemap. Penemuan tautan, Sitemap, dan seed yang disediakan operator semuanya menggunakan titik masuk deduplikasi yang sama sehingga tiga state machine tidak saling bertentangan.
Memisahkan fetch dari parse memiliki dua manfaat langsung. I/O eksternal yang lambat tidak memakan CPU parser, dan crash pada parser dapat memutar ulang (replay) HTML yang tersimpan tanpa menghubungi situs itu lagi. Setiap tahapan membutuhkan antrean berbatas (bounded queue) dan backpressure sehingga laju unduhan sementara yang melebihi kapasitas parsing atau penyimpanan tidak menghabiskan memori.
Langkah 3: Jadikan kesopanan terhadap host sebagai dasar penjadwalan frontier
Frontier menggunakan dua tingkat antrean. Tingkat atas menyimpan next_allowed_at dan prioritas setiap host serta hanya memilih host yang siap dan tidak dalam kondisi backoff. Tingkat bawah adalah antrean prioritas URL untuk host tersebut, yang diurutkan berdasarkan sinyal seperti nilai bisnis, waktu jatuh tempo, kedalaman tautan, dan laju perubahan historis. Memberikan lease pada satu URL akan memperbarui jumlah in_flight host dan waktu kelayakan berikutnya secara atomik.
Hashing host_key menetapkan host ke satu shard scheduler. Bahkan jika sebuah host memiliki satu juta URL yang tertunda, satu logical owner memberikan tokennya sementara pekerjaan fetch dapat berjalan di banyak mesin. Host yang sibuk (hot host) dapat memiliki beberapa koneksi konkuren, tetapi status host yang sama tetap mengontrol kelonggarannya. Menambahkan worker meningkatkan paralelisme di seluruh host; ini tidak dapat melebihi kuota satu host secara tidak sah.
robots.txt diambil dari /robots.txt tingkat atas layanan. Pengambilan yang berhasil mengharuskan crawler untuk mengikuti aturan yang dapat di-parse. Ketika file tidak tersedia dengan 400–499, protokol mengizinkan akses; ketika kesalahan jaringan atau 500–599 membuatnya tidak dapat dijangkau, crawler mengasumsikan disallow penuh. Salinan cache biasanya tidak boleh digunakan lebih dari 24 jam kecuali file tersebut tidak dapat dijangkau. “Satu permintaan konkuren dan penundaan satu detik per host” hanyalah default yang dapat dikonfigurasi dalam wawancara ini; protokol tidak mendefinisikan kecepatan universal. Pada 429 atau 503, hormati Retry-After; jika tidak ada, terapkan jittered exponential backoff dan kurangi jatah host tersebut.
Langkah 4: Pisahkan deduplikasi URL dari deduplikasi konten
Normalisasi hanya melakukan transformasi yang mempertahankan semantik: menyelesaikan referensi relatif, menghapus fragmen, menormalkan case skema dan hostname, menangani port default, dan menyelesaikan dot-segment pada path. Jangan menghapus atau menyusun ulang parameter kueri secara global; beberapa situs menetapkan makna pada urutan dan kunci yang berulang. URL kanonikal yang dideklarasikan halaman dapat memengaruhi penilaian dan pengelompokan, tetapi tidak boleh menimpa URL yang diamati sebagai fakta.
Simpan canonical_url, atau kunci unik yang aman dari tabrakan (collision-safe) untuknya, di penyimpanan metadata yang dipartisi. Bloom filter hanya berfungsi sebagai akselerator negatif: jika “pasti tidak ada”, coba masukkan langsung; jika “mungkin ada”, tetap periksa kunci unik yang durable. Oleh karena itu, false positive hanya menambah satu pembacaan alih-alih membuang halaman. Selesaikan tabrakan hash dengan membandingkan URL lengkap atau fingerprint kedua.
Hitung hash konten hanya setelah pengambilan. Konten yang identik secara byte dapat menggunakan kembali satu objek sambil mempertahankan metadata masing-masing URL. Halaman near-duplicate dapat dikelompokkan dengan fingerprint seperti SimHash. Penelitian telah menunjukkan kelas fingerprint ini pada skala miliaran halaman, tetapi sinyal near-duplicate lebih aman sebagai input untuk penyimpanan, pengindeksan, atau prioritas kunjungan ulang. Membuang halaman secara langsung juga dapat membuang tautan yang unik untuk halaman tersebut.
Langkah 5: Pulihkan dengan status berversi dan lease
Jaga agar record inti tetap ringkas:
UrlState( urlid, canonicalurl, hostkey, stateversion, lastfetchat, nextfetchat, priority, etag, lastmodified, contenthash, failure_count )
HostState( hostkey, robotspolicy, robotsexpiresat, nextallowedat, inflight, backoffuntil, policy_version )
FetchLease(leaseid, urlid, urlversion, expiresat, attempt)
Scheduler menerbitkan lease terbatas yang membawa url_version. Fetcher dapat mengalami crash setelah menulis HTML tetapi sebelum mengonfirmasi (acknowledge) tugas, sehingga kedaluwarsa lease dapat menyebabkan fetch lainnya. Penyelesaian menggunakan conditional write pada (url_id, url_version). Lease lama atau konfirmasi duplikat mengembalikan hasil yang ada dan tidak menerbitkan event indeks lain. Kunjungan ulang baru menaikkan versi terlebih dahulu, sehingga kunci idempotensi putaran sebelumnya tidak dapat menekan pekerjaan baru yang sah.
Jika ETag tersedia, kirim If-None-Match; jika tidak, Last-Modified yang tersimpan dapat memicu If-Modified-Since. Respons 304 memperbarui waktu fetch dan jadwal berikutnya tanpa menulis body kosong. DNS timeout, kegagalan koneksi, dan 5xx masuk ke kebijakan retry terbatas. 404/410 yang durable membuat tombstone dan interval kunjungan ulang yang jauh lebih lama. Pengalihan memiliki batas hop dan deteksi loop.
Langkah 6: Satukan kunjungan ulang, perlindungan terhadap jebakan, dan keamanan dalam satu anggaran
Prioritas kunjungan ulang menggabungkan nilai halaman, interval perubahan terkini, status, dan kelonggaran situs. Perubahan konten memperpendek interval; hasil yang berulang kali tidak berubah memperpanjangnya, dibatasi antara satu dan 30 hari. Ini mengalihkan anggaran dari halaman yang stabil ke halaman yang berubah sambil mempertahankan jaminan kesegaran minimum.
Kedalaman tautan maksimum saja tidak menghentikan kalender, navigasi faset (faceted navigation), atau kombinasi kueri tak terbatas. Tambahkan anggaran harian per-host, batas pertumbuhan template URL, jumlah parameter kueri, deteksi path berulang, batas ukuran body respons dan dekompresi, batas waktu parser, serta batas hop pengalihan. Ketika suatu pola menghabiskan anggarannya, jeda pola tersebut dan simpan sampel tanpa memblokir host yang tidak terkait.
Fetcher memproses input yang tidak tepercaya. Tolak alamat loopback, privat, link-local, dan cloud-metadata dari hasil DNS serta periksa kembali tepat sebelum menghubungkan untuk mengurangi risiko SSRF dan DNS-rebinding. Jalankan parser dengan batas memori dan CPU serta isolasi compression bomb dan HTML yang rusak. Aturan robots mengekspresikan preferensi crawl; itu bukan otorisasi akses.
Langkah 7: Validasi invariant dengan injeksi kegagalan
Mulailah dengan simulasi penjadwalan deterministik. Berikan tiga host kecepatan, aturan robots, dan nilai Retry-After yang berbeda; majukan virtual clock; pastikan tidak ada jendela waktu yang melebihi batas dan path yang dilarang tidak pernah menerima lease. Kemudian injeksikan “proses crash setelah HTTP sukses”, “konfirmasi lease hilang”, “cache robots kedaluwarsa”, “DNS mengarah ke alamat privat”, dan “antrean parser berhenti”. Tugas harus pulih, event indeks harus tetap unik, dan tahap fetch harus menerapkan backpressure.
Uji kapasitas harus mencakup pemberian 25.000 lease per detik, kemiringan partisi (partition skew) di seluruh keyspace 10 miliar URL, dan satu hot host dengan satu juta URL tertunda. Metrik utama mencakup lag kelayakan, laju fetch dan byte, rasio 2xx/304/429/5xx, pelanggaran kebijakan host, percobaan ulang lease, laju duplikat URL dan konten, usia cache robots, backlog parser, dan laju pemicu anggaran. Pelanggaran kebijakan host harus tetap nol; memenuhi throughput rata-rata sambil melanggar politeness adalah pengujian yang gagal.
Alternatif dan batasannya
Pada skala beberapa juta fetch per hari terhadap situs milik sendiri, basis data relasional dapat mengindeks next_fetch_at, menggunakan SKIP LOCKED untuk mengklaim tugas, dan memperbarui token host dalam transaksi yang sama. Pendekatan ini lebih mudah diterapkan dan di-debug. Pada satu miliar fetch per hari, pemindaian indeks global, hot update, dan pembersihan menjadi bottleneck, menjadikan two-level partitioned frontier pilihan yang lebih cocok.
Menggunakan Bloom filter sebagai seen set menghemat pembacaan, tetapi false positive secara permanen mengurangi cakupan. Desain ini menurunkannya menjadi sekadar cache dan mempertahankan kunci unik durable sebagai source of truth. Melewatkan pembacaan konfirmasi hanya masuk akal jika produk secara eksplisit menerima anggaran false positive yang terukur.
Contoh Jawaban yang Kuat
“Saya akan mulai dengan dua invarian: anggaran dan politeness. Satu miliar fetch per hari adalah sekitar 11.600 per detik rata-rata dan peak 25.000 per detik. Menyegarkan 100 juta URL setiap hari ditambah 9,9 miliar setiap 30 hari menjadwalkan sekitar 430 juta fetch per hari, menyisakan ruang untuk discovery, retry, dan refresh yang didorong oleh perubahan. Pada 200 KB per respons, 200 TB per hari adalah batas atas jaringan yang konservatif; respons 304 mengurangi lalu lintas aktual.
Saat masuk, URL hanya menerima normalisasi yang aman dan diperiksa terhadap kunci unik yang durable. Bloom filter hanya menghindari pembacaan untuk URL yang jelas belum pernah dilihat. Frontier dipartisi berdasarkan scheme + authority; setiap shard menjaga kesiapan host ditambah antrean prioritas URL per-host. Mengklaim pekerjaan secara atomik mengonsumsi token host, sehingga banyak fetcher tidak dapat secara kolektif membebani satu situs. File robots yang tidak dapat dijangkau akan menjeda host, dan 429/503 memicu Retry-After atau jittered backoff.
Fetcher menerima lease berbatas, membuat conditional GET, menulis HTML ke object storage, dan menyerahkan parsing ke tahap berikutnya. Tautan yang di-parse kembali melalui titik masuk discovery yang sama. Kedaluwarsa lease dapat mengulang permintaan, tetapi penyelesaian berversi URL mencegah lease lama menimpa status atau memancarkan event indeks kedua. Hash konten menggunakan kembali objek duplikat yang persis sama, sementara SimHash memengaruhi prioritas near-duplicate alih-alih membuang tautan yang berpotensi unik.
Saya akan membuktikan interval per-host dengan virtual clock dan menginjeksikan crash setelah penulisan, konfirmasi yang hilang, status robots yang kedaluwarsa, DNS rebinding, dan parser backpressure. Penerimaan membutuhkan pencapaian peak 25.000 per detik dan nol pelanggaran kebijakan host.”
Kesalahan Umum
- Kesalahan: menggunakan satu antrean pesan global. Mengapa ini gagal: consumer independen tidak dapat bersama-sama menegakkan waktu kelayakan berikutnya dari suatu host, sehingga throughput yang lebih tinggi meningkatkan risiko pelanggaran politeness. Solusi: tetapkan kepemilikan penjadwalan berdasarkan
host_keydan gunakan antrean kesiapan host ditambah antrean URL per-host. - Kesalahan: menggunakan Bloom filter sebagai satu-satunya seen set. Mengapa ini gagal: false positive secara permanen membuang URL yang belum pernah dilihat, dan filter tidak dapat menyimpan status, versi, atau waktu kunjungan ulang. Solusi: gunakan hanya sebagai cache dan simpan status kunci unik yang durable.
- Kesalahan: menganggap URL deduplication sama dengan content deduplication. Mengapa ini gagal: URL yang berbeda dapat mengembalikan konten yang sama, dan satu URL dapat berubah seiring waktu. Solusi: deduplikasi URL yang tepat selama discovery, lalu hitung hash konten dan fingerprint near-duplicate setelah fetching.
- Kesalahan: menjanjikan crawling exactly-once. Mengapa ini gagal: keberhasilan HTTP eksternal dan konfirmasi internal tidak dapat membentuk satu transaksi atomik, meninggalkan celah terjadinya crash. Solusi: terima eksekusi at-least-once dan kendalikan efek samping internal dengan lease, version-conditional writes, dan event idempoten.
- Kesalahan: melanjutkan proses pada setiap kesalahan robots. Mengapa ini gagal: protokol membedakan tidak tersedia (unavailable) dari tidak dapat dijangkau (unreachable); kesalahan jaringan atau
5xxmemerlukan disallow penuh. Solusi: terapkan state machine yang eksplisit dan uji usia cache, pengalihan, serta kelas kegagalan secara terpisah. - Kesalahan: hanya mengandalkan depth maksimum untuk crawler traps. Mengapa ini gagal: satu kedalaman dapat berisi kombinasi faset, kalender, dan parameter kueri yang tak terbatas. Solusi: gabungkan anggaran host, pertumbuhan pola URL, jumlah parameter, ukuran respons, dan batas waktu parser.
Pertanyaan Lanjutan
Bagaimana jika 50% URL tertunda berasal dari satu host?
Pertama, tentukan konkurensi dan kecepatan yang diizinkan oleh situs tersebut. Dengan kuota tetap, menambah worker tidak dapat meningkatkan throughput yang sah dari host tersebut; worker hanya meningkatkan paralelisme di seluruh host lain. Antrean URL host dapat dipartisi untuk mengurangi hotspot penyimpanan, tetapi setiap partisi tetap meminta kapasitas dari satu layanan token logis. Jika bisnis membutuhkan kecepatan lebih, negosiasikan feed khusus atau kuota yang lebih besar dengan situs tersebut dan beri versi pada kebijakan baru.
Mengapa tidak menjamin exactly-once?
Fetcher dapat mengalami crash setelah menerima respons HTTP dan sebelum mengonfirmasi lease-nya, dan situs eksternal tidak berpartisipasi dalam transaksi internal. Transaksi terdistribusi tidak dapat membatalkan permintaan GET yang telah terjadi. Kontrak yang dapat dicapai adalah klaim at-least-once, kemungkinan fetch duplikat, dan penyelesaian internal yang idempoten. Ukur tingkat duplikat dan kurangi biayanya dengan conditional request.
Bagaimana jika halaman memerlukan JavaScript untuk menampilkan kontennya?
Pertahankan fetch HTTP normal sebagai tingkat pertama. Hanya jika hasil parsing kosong, kebijakan situs mengizinkannya, dan nilai halaman melampaui ambang batas, URL boleh masuk ke antrean rendering terpisah. Renderer memiliki konkurensi lebih rendah serta batas CPU, memori, dan waktu yang lebih ketat, serta berbagi token host asli. Jika tidak, rendering yang mahal akan melewati aturan politeness dan menghabiskan anggaran global.
Bagaimana crawler dapat berjalan di beberapa region tanpa mengakses satu host dua kali?
Tetapkan setiap host_key ke home region dan hanya izinkan region tersebut untuk memberikan token host; region lain dapat melakukan parse dan penyimpanan. Pada kegagalan regional, transfer kepemilikan dengan lease yang membawa fencing token. Region lama yang pulih harus memegang epoch baru sebelum memberikan izin kerja. Penjadwalan aktif untuk host yang sama di beberapa region akan melanggar invarian politeness.
Biaya penyimpanan tiba-tiba melebihi anggaran. Apa yang harus dikurangi terlebih dahulu?
Pertama, tingkatkan hit conditional-request, kompresi, dan penggunaan kembali objek duplikat yang identik. Kemudian persingkat retensi raw-HTML berdasarkan nilai konten. Jangan membuang metadata URL dan catatan audit fetch bersamanya; kunjungan ulang, deduplikasi, dan investigasi kepatuhan bergantung pada data tersebut. Deteksi near-duplicate dapat menurunkan prioritas atau memilih storage tier, tetapi tidak boleh memicu penghapusan massal tanpa validasi.