14 september
Vi hade väntat i veckor på den här dagen. Vår leverantör av residentiella proxyservrar hade gått i svart med ett betalningsfel redan i juli, och i två månader hade en allt större andel av våra 1 375 källor kravlats i nedsatt skick eller inte alls – fetches som tajmade ut, IP-adresser som blockerades mitt i en session, den typ av långsam blödning som inte visar sig som ett driftstopp utan snarare som ett sakta krympande antal som ingen märker förrän det blir pinsamt. Vi förnyade. Ny pool, 20 000 roterande residentiella sessionslinjer, varje exit testad innan något fick komma nära produktion. 100 % av testet gick igenom. AE, DE, JP – allt live, allt rent.
Så vi körde en övervakad kravling, den typ där någon faktiskt sitter och tittar på dashboarden istället för att lita på cron-jobbet. Jag förväntade mig motsatsen till en katastrof.
Vad vi fick var en databas som hade tappat 84 401 rader i en enda körning, med 102 källor som hade sjunkit mer än 25 % jämfört med föregående ögonblicksbild. Värre än de två månaderna av proxysvält vi precis hade åtgärdat.
Den felaktiga teorin, kort sagt
Min första instinkt – och den tar jag på mig helt öppet – var att den nya poolen av någon anledning var sämre än testet hade antytt. Kanske blev sessions-IP-adresserna hastighetsbegränsade mitt i kravlingen på ett sätt som ett engångstest aldrig skulle fånga upp. Det är en rimlig teori. Den är också fel, och att tro på den även bara ett halvt dygn kostade oss tid vi inte hade, eftersom kravlings-cron-jobbet förblir pausat hela tiden man felsöker en sådan teori – man vill inte att en dålig körning skriver över en bra ögonblicksbild medan man fortfarande gissar.
Det som avslöjade att teorin var fel var dubizzle. En av våra källor med högst volym i Förenade Arabemiraten hade faktiskt hämtat 32 595 annonser under den körningen – ett helt normalt antal, proxyservrarna fungerade uppenbarligen – och sedan kastat bort nästan alla. Inte misslyckats med att hämta. Hämtat, och sedan slängt.
16 september: att hitta den faktiska buggen
Det var då det slutade vara en proxyhistoria och blev en historia om radersättning. Vårt lagringslager tar en ögonblicksbild av varje källa genom att helt skriva över <site>_cars_for_sale.csv vid varje körning – bara aktuella annonser, hela tabellen ersätts. Det är korrekt beteende när en kravling slutförs. Det är katastrofalt när en kravling tajmar ut halvvägs igenom och skraparen skriver vad den lyckades samla in i den partiella omgången som om det vore den fullständiga ögonblicksbilden. En källa som normalt har 9 000 aktiva annonser blir överskriven med de 1 200 den hann skrapa innan tiden rann ut, och de övriga 7 800 försvinner – inte för att bilarna såldes, utan för att vår egen kod bestämde att en ofullständig hämtning var en fullständig.
Proxyservrarna ljög inte för oss. Det var retry-logiken som var problemet, och den hade varit tyst dålig under lång tid, bara maskerad av en friskare pool som förut brukade slutföra hämtningarna innan sweepen hann spela roll.
Så här mycket kostade sweepen i praktiken, när vi till slut räknade på det:
| Gammal retry-sweep | Fixad sweep | |
|---|---|---|
| Antal försök per proxy | 3 | 1 |
| Fördröjning per försök | 1s | — |
| Effektivt tak över en pool på 50 proxyservrar | ~56 minuter per URL | 120 sekunders total budget |
| Beteende vid timeout | skriver partiell omgång som fullständig ögonblicksbild | källan hoppas över, föregående ögonblicksbild bevaras |
56 minuter för att ge upp på en enda URL. Multiplicera det över en kravling som rör mer än tusen källor och man får exakt den typ av tyst, ojämnt fördelat fel vi såg – en del källor helt friska, 102 av dem urholkade, inget i loggarna som skrek "proxyavbrott", eftersom det, tekniskt sett, inte fanns något.
25 september: lösningen, och den del som spelar roll för dig
Patchen som släpptes nio dagar senare gjorde två oglamorösa saker. Den satte ett tak för retry-matematiken så att en fastnad hämtning misslyckas snabbt istället för att äta upp nästan en timme, och – det här är det som faktiskt förhindrar dataförlusten – en partiell hämtning ersätter inte längre den fullständiga raduppsättningen. Om en källa bara hinner med 1 200 av sina vanliga 9 000 annonser behåller vi den tidigare fullständiga ögonblicksbilden istället för att skriva över den med en bråkdel. Samma dag gick en andra ändring live som skriver en synlig flagga, CRAWL_PAUSED, som vår övervakning kontrollerar innan den larmar någon om en nedgång – så att en avsiktlig paus läses som en paus, inte ett larm.
Varför ska en läsare som letar efter en begagnad Hyundai bry sig om något av det här? Eftersom de under-marknadsflaggor vi publicerar – 12 823 av dem live på sajten denna vecka – bara är ärliga om kohorten vi jämför en annons med är den verkliga, fullständiga regionala marknaden och inte ett timeout-trunkerat fragment av den. En fyndmärkning byggd mot en ögonblicksbild som tappat tre fjärdedelar av sitt jämförelseunderlag är inte en fyndmärkning, det är brus i grön etikett. Vi pausar hellre en kravling i nio dagar än publicerar det.
Datasetet ligger idag på 1 108 535 annonser över 73 regioner och 1 375 källor – större än innan allt det här började, proxyservrarna förnyade och radersättningsbuggen åtgärdad. Men talet jag ständigt återkommer till är inte totalsumman. Det är 84 401 – gapet mellan en kravling som såg frisk ut på proxylagret och en som faktiskt var det.



