Jika tagihan untuk proxy meningkat lebih cepat daripada volume data yang dikumpulkan, masalahnya hampir selalu terletak pada logika retry. Parser diam-diam mengulangi permintaan yang gagal beberapa kali, menghabiskan trafik untuk timeout dan captcha, sementara pengembang bahkan tidak melihat pengeluaran ini di log. Mari kita bahas bagaimana menghitung kerugian nyata dan menguranginya tanpa mengorbankan kualitas data.
Mengapa logika retry menghabiskan trafik
Sebagian besar parser ditulis dengan logika retry yang naif: jika permintaan tidak berhasil — ulangi, dan begitu seterusnya hingga 3-5 kali. Masalahnya adalah setiap permintaan ulang — bukan hanya permintaan HTTP baru, tetapi juga siklus penuh: TCP handshake, TLS negotiation, memuat halaman secara keseluruhan (meskipun hanya satu blok data yang diperlukan), dan kadang-kadang juga memuat ulang gambar atau file JS, jika parser menggunakan browser headless alih-alih klien HTTP sederhana.
Pengulangan sangat mahal saat bekerja melalui proxy residensial, di mana trafik dikenakan biaya berdasarkan volume, bukan jumlah permintaan. Satu permintaan yang gagal pada halaman produk Wildberries dengan gambar dan skrip dapat menghabiskan 300-500 KB. Jika parser melakukan 3 pengulangan saat timeout, Anda membayar untuk satu permintaan gagal yang sama empat kali berturut-turut — dan ini tanpa jaminan bahwa percobaan keempat akan berhasil.
Alasan kedua adalah retry pada kesalahan yang tidak dapat diperbaiki dengan pengulangan. Jika situs mengembalikan 403 karena deteksi bot, permintaan ulang dengan sidik jari yang sama dan sesi cookie yang sama hampir pasti akan mendapatkan jawaban yang sama. Parser menghabiskan trafik untuk upaya yang secara matematis tidak dapat berhasil, sampai alamat IP atau sidik jari browser berubah.
Berapa banyak trafik yang benar-benar digunakan untuk pengulangan
Untuk memahami skala masalah, mari kita ambil contoh sederhana. Parser mengumpulkan kartu produk dari marketplace, ukuran rata-rata respons — 250 KB (HTML + JSON API + sebagian statis). Dalam operasi yang stabil tanpa pemblokiran, proporsi permintaan yang gagal tetap di tingkat 5-8%. Namun, saat melakukan pengambilan data secara agresif melalui proxy data center yang murah, angka ini dapat meningkat hingga 25-35%, karena penyedia target dengan cepat mengenali pola dan mulai mengembalikan captcha atau larangan sementara berdasarkan IP.
Mari kita hitung dengan angka. Misalkan, kita perlu mengumpulkan 100.000 kartu produk:
| Proporsi permintaan yang gagal | Pengulangan per permintaan (rata-rata) | Trafik total | Pemborosan |
|---|---|---|---|
| 5% | 0.15 | 28.75 GB | +15% |
| 15% | 0.45 | 36.25 GB | +45% |
| 30% | 0.90 | 47.5 GB | +90% |
Seperti yang terlihat, dengan proporsi kegagalan 30% dan strategi retry "ulang hingga 3 kali", trafik nyata hampir dua kali lipat dibandingkan dengan minimum teoritis sebesar 25 GB. Justru 20+ GB tambahan ini adalah kerugian langsung dari anggaran untuk proxy, yang dapat dikurangi jika logika pengulangan ditinjau kembali.
Kesalahan umum dalam logika retry parser
Sebelum memperbaiki logika retry, penting untuk mengenali pola antipattern umum yang muncul di 90% parser buatan sendiri:
- Retry tanpa memeriksa kode kesalahan. Pengulangan dimulai pada setiap situasi tidak normal — 403, 429, 500, timeout, putusnya koneksi — padahal strategi penanganan untuk mereka harus berbeda.
- Penundaan tetap antara pengulangan. Misalnya, 2 detik antara percobaan tanpa mempedulikan apakah ini percobaan pertama atau kelima — ini bisa terlalu agresif untuk situs, atau terlalu lambat untuk volume besar.
- Pengulangan dengan IP dan sesi yang sama. Jika situs memblokir permintaan berdasarkan sidik jari, pengulangan dengan parameter identik tidak mengubah hasil, tetapi menghabiskan trafik.
- Tidak ada batas atas untuk percobaan. Beberapa parser terjebak pada URL "mati" dan melakukan puluhan pengulangan sebelum menyerah.
- Tidak ada perbedaan antara kesalahan sementara dan permanen. 404 (halaman tidak ada) dan 503 (server sementara tidak tersedia) memerlukan logika yang berbeda — tetapi sering kali diproses sama.
Backoff eksponensial dengan kode dalam Python
Solusi sederhana tetapi efektif adalah penundaan eksponensial dengan jitter (penyebaran acak), yang mengurangi jumlah pengulangan yang tidak berguna dan mendistribusikan beban seiring waktu. Alih-alih jeda tetap antara percobaan, penundaan meningkat secara eksponensial, memberi situs waktu untuk "mendinginkan" setelah pemblokiran, dan parser itu sendiri — tidak menghabiskan trafik untuk permintaan yang hampir pasti akan gagal.
import time
import random
import requests
def fetch_with_backoff(url, proxies, max_retries=4, base_delay=1.0):
retryable_codes = {429, 500, 502, 503, 504}
non_retryable_codes = {404, 410}
for attempt in range(max_retries + 1):
try:
response = requests.get(url, proxies=proxies, timeout=10)
if response.status_code == 200:
return response
if response.status_code in non_retryable_codes:
# tidak ada gunanya mengulang — halaman secara fisik tidak ada
return None
if response.status_code not in retryable_codes:
return None
except (requests.exceptions.Timeout,
requests.exceptions.ConnectionError):
pass # kesalahan jaringan sementara — bisa diulang
if attempt == max_retries:
return None
# penundaan eksponensial dengan jitter
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
return None
Ide kunci dari kode ini adalah membagi kesalahan menjadi tiga kategori: yang tidak dapat diperbaiki dengan pengulangan (404, 410), yang dapat diulang dengan penundaan (429, 500-504, timeout), dan semua yang lain yang segera dianggap gagal tanpa menghabiskan untuk percobaan tambahan. Pembagian semacam itu sendiri mengurangi trafik yang tidak perlu sebesar 20-30% dibandingkan dengan "ulang semua".
Tip: tambahkan Retry-After header dalam penanganan —
banyak situs memberi tahu berapa detik untuk menunggu sebelum mengulang. Mengabaikan header ini —
adalah penyebab umum larangan dan trafik yang tidak perlu.
Circuit breaker: kapan harus berhenti
Backoff eksponensial membantu pada tingkat satu permintaan, tetapi tidak melindungi dari situasi di mana seluruh domain atau node proxy tertentu sementara tidak tersedia untuk ratusan URL berturut-turut. Di sini diperlukan pola circuit breaker — "pemutus otomatis", yang melacak proporsi kesalahan selama periode terakhir dan sementara menghentikan upaya jika melebihi ambang batas, alih-alih terus-menerus mengetuk pintu tertutup.
class CircuitBreaker:
def __init__(self, failure_threshold=0.5, window_size=50, cooldown=60):
self.failure_threshold = failure_threshold
self.window_size = window_size
self.cooldown = cooldown
self.results = []
self.open_until = 0
def is_open(self):
return time.time() < self.open_until
def record(self, success: bool):
self.results.append(success)
if len(self.results) > self.window_size:
self.results.pop(0)
if len(self.results) == self.window_size:
failure_rate = 1 - sum(self.results) / self.window_size
if failure_rate > self.failure_threshold:
self.open_until = time.time() + self.cooldown
self.results.clear()
Logika sederhana: jika dari 50 permintaan terakhir lebih dari setengahnya gagal, parser menghentikan upaya untuk domain atau proxy ini selama 60 detik. Selama waktu ini, Anda dapat mengganti IP, mengurangi kecepatan permintaan atau beralih ke kumpulan proxy lain. Ini sangat penting saat bekerja dengan situs target yang sementara memblokir rentang IP setelah melebihi frekuensi permintaan — terus-menerus mengetuk pintu tertutup hanya berarti membakar trafik dengan sia-sia.
Rotasi proxy cerdas saat pengulangan
Salah satu langkah paling efektif untuk menghindari pengulangan yang tidak perlu adalah tidak mengulangi permintaan dari IP yang sama yang sudah ditolak. Logikanya sederhana: jika kesalahan terkait dengan pemblokiran berdasarkan IP (403, 429, pengalihan ke captcha), mengganti proxy sebelum pengulangan secara drastis meningkatkan peluang keberhasilan dan mengurangi jumlah percobaan.
Untuk pengambilan data dari marketplace seperti Wildberries, Ozon, atau Avito, kombinasi yang baik adalah: permintaan biasa dilakukan melalui proxy data center — mereka lebih cepat dan lebih murah, dan begitu detektor pemblokiran terpicu beberapa kali berturut-turut, parser beralih ke proxy residensial, yang lebih jarang terjebak dalam filter sistem anti-bot. Pendekatan hibrida ini mengurangi total penggunaan trafik, karena IP residensial yang mahal hanya digunakan di tempat yang benar-benar diperlukan, bukan untuk semua permintaan berturut-turut.
| Jenis kesalahan | Strategi pengulangan | Perlu mengganti IP? |
|---|---|---|
| Timeout koneksi | Backoff, 1-2 pengulangan | Tidak |
| 403 / captcha | Rotasi segera | Ya, wajib |
| 429 (batas laju) | Backoff berdasarkan Retry-After | Diinginkan |
| 500-503 | Backoff, 2-3 pengulangan | Tidak |
| 404 / 410 | Tanpa pengulangan | — |
Untuk parser yang meniru trafik seluler (misalnya, pengumpulan data dari versi seluler aplikasi marketplace atau media sosial), ada baiknya menggunakan proxy seluler — mereka lebih jarang menimbulkan kecurigaan dari sistem perlindungan karena operator seluler memberikan IP yang sama kepada ribuan pengguna nyata secara bersamaan, dan pemblokiran titik menjadi tidak praktis untuk situs target.
Pemantauan metrik retry
Tanpa metrik, optimisasi logika retry menjadi tebak-tebakan. Setidaknya, indikator yang harus dicatat pada setiap permintaan:
- Rasio retry — proporsi permintaan yang memerlukan setidaknya satu pengulangan.
- Keberhasilan setelah retry — persentase pengulangan yang akhirnya berhasil (jika angka ini rendah, pengulangan hanya membakar trafik).
- Trafik untuk hasil yang berhasil — total volume data yang ditransfer, dibagi dengan jumlah catatan yang berhasil dikumpulkan. Ini adalah metrik kunci efektivitas.
- Pembagian kesalahan berdasarkan kode — membantu memahami di mana kebocoran trafik utama terjadi: timeout, 403, 429, atau lainnya.
- Rasio retry untuk node proxy tertentu — jika satu IP memberikan rasio retry 80%, sementara yang lain 10%, masalahnya lokal dan dapat diselesaikan dengan mengganti node tertentu, bukan seluruh logika.
Bahkan tabel sederhana di Google Sheets atau log dalam CSV dengan lima metrik ini, yang diperbarui setiap jam, memberikan cukup data untuk melihat anomali dan segera menyesuaikan strategi — misalnya, mengurangi frekuensi permintaan ke bagian tertentu dari situs atau meningkatkan proporsi IP residensial dalam kumpulan.
Checklist optimisasi trafik pada retry
- Pisahkan kode kesalahan menjadi retryable dan non-retryable — jangan ulang 404/410.
- Implementasikan backoff eksponensial dengan jitter alih-alih penundaan tetap.
- Hormati header
Retry-After, jika situs mengirimkannya. - Ganti IP sebelum pengulangan pada 403 dan kecurigaan deteksi bot.
- Tetapkan batas ketat pada jumlah percobaan (biasanya 3-4 sudah cukup).
- Implementasikan circuit breaker untuk domain dan node proxy dengan tingkat kegagalan tinggi.
- Catat rasio retry dan trafik untuk hasil yang berhasil — tanpa metrik, optimisasi tidak mungkin dilakukan.
- Pisahkan kumpulan proxy: data center murah untuk area yang stabil, IP residensial atau seluler — untuk yang bermasalah.
Kesimpulan
Logika retry bukanlah detail kecil dari parser, tetapi salah satu faktor utama yang mempengaruhi biaya pengumpulan data. Strategi naif "ulang semua" dapat meningkatkan trafik nyata hingga 40-90% dibandingkan dengan minimum teoritis, sementara sebagian besar pengulangan berakhir dengan kegagalan yang sama seperti percobaan pertama. Pembagian kesalahan berdasarkan jenis, backoff eksponensial, circuit breaker, dan rotasi IP yang cerdas memungkinkan pengurangan kerugian ini secara signifikan tanpa mengurangi kelengkapan data yang dikumpulkan.
Jika parser Anda bekerja dengan situs yang secara agresif mendeteksi bot — marketplace, media sosial, platform iklan — ada baiknya mengombinasikan beberapa jenis proxy tergantung pada tugas. Untuk operasi dasar, proxy data center cocok digunakan, dan di tempat yang memerlukan ketahanan maksimum terhadap pemblokiran, proxy residensial dengan alamat IP nyata dari pengguna biasa. Pendekatan hibrida semacam ini, dikombinasikan dengan logika retry yang cerdas, memberikan pengurangan signifikan dalam penggunaan trafik dengan volume data yang sama yang dikumpulkan.