Memahami Dampak Scraper Nakal pada Database

Scraper nakal yang terus-menerus menarik data tanpa batas sering mendorong query berat, blocking, dan pagination yang menumpuk. Dengan mengidentifikasi tempat-tempat di mana indeks tidak terpakai atau pagination memaksa database membaca ribuan baris yang tidak diperlukan, kita bisa menahan lonjakan latency sebelum sistem mencapai titik jenuh. Langsung dari perspektif operasi, penyelesaian awalnya adalah memetakan pain points—bukan hanya berdasarkan jumlah request, tapi berdasarkan waktu eksekusi query dan contention pada buffer.

Pertanyaan pertama: di mana scraper membuat query lamban? Gunakan EXPLAIN plus statistik sistem (pg_stat_statements, performance_schema, atau APM) untuk melihat apakah query berjalan full scan, menunggu lock, atau menghasilkan pagination offset yang besar. Jawaban ini akan memandu langkah optimasi selanjutnya.

Identifikasi Bottleneck dengan EXPLAIN dan Statistik

Mulailah dari query yang sering dipanggil scraper. Jalankan EXPLAIN (ANALYZE) selama jendela rendah traffic untuk memahami apakah planner menggunakan indeks yang kita harapkan. Perhatikan hal-hal berikut:

  • Seq Scan pada tabel besar harus menjadi alarm pertama. Jika query seharusnya dapat menggunakan indeks tapi tidak, evaluasi kondisi WHERE dan tipe data kolom.
  • Sort kosongan atau Hash Aggregate dengan jumlah baris besar menandakan data yang harus diurutkan dari buffer.
  • Buffers hit vs read menunjukkan apakah data berada di memori atau harus dibaca ulang dari disk. Scraper yang meminta halaman tetap membuat buffer churn.

Selain EXPLAIN, pantau statistik server seperti:

  • Lock waits (postgreSQL pg_stat_activity atau MySQL performance_schema). Scraper dapat menyebabkan lock pada indeks yang padat, menyebabkan query lain menunggu.
  • Query latency 95/99 percentile untuk memastikan kita tidak hanya fokus pada median.
  • Page scans atau read IO yang meningkat bersamaan dengan scraper untuk menilai dampak langsung.

Catat query yang naik drastis selama scraper aktif, dan simpan query plan untuk analisis perubahan.

Evaluasi dan Optimasi Indeks

Setelah mengetahui query mana yang bermasalah, evaluasi indeks yang ada. Indeks yang tidak selektif, terlalu banyak kolom, atau bahkan tidak digunakan dapat sia-sia terhadap beban scraper.

Review Indeks Eksisting

Gunakan pg_stat_user_indexes atau information_schema.statistics untuk melihat seberapa sering indeks digunakan. Indeks yang jarang dipakai tetapi memakan ruang dan waktu pemeliharaan bisa dihapus, mengurangi contention pada write.

Menambahkan Partial Index

Scraper biasanya menarget subset data (misalnya status public atau published). Partial index hanya pada baris tersebut mengurangi ukuran indeks dan mempercepat query. Contoh di PostgreSQL:

CREATE INDEX idx_articles_published ON articles (updated_at DESC) WHERE status = 'published';

Kenapa ini efektif? Karena indeks hanya mencakup baris yang relevan, sehingga planner bisa menelusuri lebih sedikit blok ketika status cocok. Pastikan kolom yang digunakan pada WHERE menyertakan kondisi dalam query scraper agar optimizer memakai indeks ini.

Indeks Tersusun untuk Pagination

Pada query pagination dengan ORDER BY, gunakan indeks yang mencakup kolom urutan dan kunci filter. Misalnya:

CREATE INDEX idx_events_public_time ON events (is_public, created_at DESC);

Dengan indeks ini, query yang memfilter is_public = TRUE dan memerintahkan ORDER BY created_at DESC bisa langsung memanfaatkan indeks tanpa sort kosongan.

Pengendalian Pagination dan Caching

Scraper umumnya menggunakan pagination berbasis offset, yang membuat database harus melewati N baris untuk sampai ke halaman tinggi. Penanganan pagination yang tepat sangat penting.

Gunakan Keyset Pagination

Alih-alih OFFSET, gunakan kunci terakhir yang sudah dilihat (keyset). Contoh:

SELECT id, title FROM articles WHERE status = 'published' AND updated_at < $1 ORDER BY updated_at DESC LIMIT 25;

Kita memakai kolom updated_at sebagai cursor. Ini menghindari OFFSET besar yang memicu scan ulang. Pastikan indeks mendukung kondisi ini (lihat partial index sebelumnya).

Batasi Pagination Maksimal

Jika scraper tetap mencoba offset tinggi, batasi akses dengan logika API seperti “hanya dapatkan 100 halaman pertama” atau “offset maksimum 10.000”. Ini mencegah database dipaksa melakukan scan masif tanpa manfaat bisnis yang jelas.

Caching Query Strategis

Implementasikan caching pada level aplikasi atau cache terdistribusi (Redis, memcached) untuk query yang sering diminta dan jarang berubah. Atur TTL pendek jika data bergerak cepat, tapi cukup panjang untuk mencegah serangan scraper berdampak langsung pada database.

Gunakan cache invalidation yang deterministic: misalnya, invalidate cache ketika updated_at berubah. Jika scraper mengakses halaman publik yang jarang berubah, cache dapat membalikkan beban dengan signifikan.

Throttle dan Monitoring Agar Sistem Responsif

Selain optimasi query, throttle request agar scraper tidak mendominasi resource.

Implementasi Rate Limiting

Gunakan middleware atau gateway API untuk membatasi requests per IP atau token. Penyusunan token bucket atau leaky bucket akan memperlambat permintaan beruntun dan menjaga headroom database. Pastikan throttle menghasilkan kode status yang jelas (misalnya 429) agar klien dapat merespons.

Cache-Hit vs Cache-Miss Visibility

Tambahkan metric cache hit ratio agar kita bisa melihat apakah cache membantu. Jika hit ratio tiba-tiba turun, scraper mungkin meminta data yang tidak ter-cache, memicu load tambahan.

Checklist Monitoring dan Alert

  • Alert saat latensi query 95/99 percentile meningkat > 2x baseline.
  • Alert ketika jumlah lock wait atau deadlock spike dalam waktu pendek.
  • Monitor cache hit ratio untuk query utama—alert saat turun di bawah ambang tertentu.
  • Tracking request rate per endpoint agar scraper tak lepas kontrol.
  • Visualisasi penggunaan indeks (pg_stat_user_indexes atau equivalent) untuk mendeteksi indeks tidak terpakai.
  • Alert jika disk IO naik karena scan full table.

Checklist ini membantu mendeteksi perubahan perilaku scraper lebih cepat dan merespons sebelum load menjadi kritis.

Kesimpulan

Mitigasi scraper nakal membutuhkan pendekatan ganda: perbaiki indeks dan pagination agar query efisien, serta kontrol aliran request agar tidak menghabiskan resource. Gunakan data plan, statistik, dan monitoring untuk melihat di mana optimasi dibutuhkan. Dengan partial index yang tepat, keyset pagination, caching, dan throttle yang terukur, database dapat tetap responsif walaupun menghadapi traffic scraper berat.