14 בספטמבר
חיכינו שבועות ליום הזה. ספק הפרוקסי השוכני (residential) שלנו השתתק באי-תקלה בחיוב עוד ביולי, ובמשך חודשיים נתח הולך וגדל מ-1,375 המקורות שלנו זחל במצב פגום או לא זחל כלל - בקשות שנתקעות בטיימאאוט, כתובות IP שנחסמות באמצע הסשן, הסוג הזה של דימום איטי שלא נראה כמו תקלה אלא כמו מספר שמתכווץ, שאף אחד לא שם לב אליו עד שזה נהיה מביך. חידשנו את המאגר. מאגר חדש, 20,000 שורות סשן שוכניות ומתחלפות, שנבדקו (probed) אחת-אחת לפני שהותר לאיזושהי מהן להתקרב לסביבת הפרודקשן. 100% מהבדיקה עברה בהצלחה. איחוד האמירויות, גרמניה, יפן - כולן פעילות, כולן נקיות.
אז הרצנו זחילה בפיקוח, מהסוג שבו מישהו באמת צופה בדשבורד במקום לסמוך על ה-cron. ציפיתי להפך המוחלט מאסון.
מה שקיבלנו היה מסד נתונים שאיבד 84,401 שורות במעבר אחד, עם 102 מקורות שנפלו ביותר מ-25% מהתמונה (snapshot) הקודמת שלהם. גרוע יותר משני חודשי הרעבת הפרוקסי שבדיוק תיקנו.
התיאוריה השגויה, בקצרה
האינסטינקט הראשון שלי - ואני אודה בזה בפתיחות - היה שהמאגר החדש היה בצורה כלשהי גרוע יותר ממה שהבדיקה הצביעה עליו. אולי כתובות ה-IP של הסשן נכנסו להגבלת קצב (rate limiting) באמצע הזחילה, בצורה שבדיקה חד-פעמית לא הייתה תופסת. זו תיאוריה סבירה. היא גם שגויה, והאמונה בה למשך חצי יום כבר עלתה לנו בזמן שלא היה לנו, כי ה-cron של הזחילה נשאר בהשהיה כל עוד אתה מנסה לנפות (debug) תיאוריה כזו - אתה לא רוצה שמעבר גרוע ידרוס תמונת מצב תקינה בזמן שאתה עדיין מנחש.
הסימן שהפריך את התיאוריה היה dubizzle. אחד המקורות הגדולים ביותר שלנו באיחוד האמירויות, הוא בפועל שלף 32,595 מודעות באותה הרצה - מספר בריא לחלוטין, שמוכיח שהפרוקסי עבדו - ואז השליך כמעט את כולן. לא נכשל בשליפה. נשלף, ואז נזרק.
16 בספטמבר: מציאת הבאג האמיתי
זה הרגע שבו הסיפור הפסיק להיות סיפור פרוקסי והפך לסיפור של החלפת שורות (row-replacement). שכבת ההתמדה (persistence) שלנו שומרת תמונת מצב של כל מקור כדריסה מלאה של <site>_cars_for_sale.csv בכל מעבר - רק המודעות הנוכחיות, החלפת הטבלה כולה. זו התנהגות תקינה כשזחילה מסתיימת. זו קטסטרופה כשזחילה נתקעת בטיימאאוט באמצע, והסקרייפר כותב כל מה שהצליח לאסוף בחבילה חלקית כאילו הייתה זו התמונה המלאה. מקור שבדרך כלל מכיל 9,000 מודעות פעילות נדרס עם ה-1,200 שהוא הצליח לשרוד לפני שנגמר הזמן, וה-7,800 הנותרות נעלמות - לא בגלל שהרכבים נמכרו, אלא בגלל שהקוד שלנו עצמו החליט ששליפה חלקית היא שליפה מלאה.
הפרוקסי לא שיקרו לנו. לוגיקת ה-retry הייתה הבעיה, והיא הייתה שקטה וגרועה הרבה זמן, רק שהוסוותה על ידי מאגר בריא יותר שהספיק לסיים שליפות לפני שהטיימינג (sweep) נהיה קריטי.
הנה מה שהסוויפ הזה בפועל עלה לנו, לאחר שעשינו את החשבון:
| סוויפ ה-retry הישן | סוויפ מתוקן | |
|---|---|---|
| ניסיונות חזרה לכל פרוקסי | 3 | 1 |
| השהיה בכל ניסיון | שנייה אחת | - |
| תקרת זמן אפקטיבית במאגר של 50 פרוקסי | כ-56 דקות ל-URL | תקציב כולל של 120 שניות |
| התנהגות בטיימאאוט | כותב חבילה חלקית כתמונה מלאה | המקור מדולג, התמונה הקודמת נשמרת |
חמישים ושש דקות כדי להתייאש מ-URL בודד. הכפל את זה על פני זחילה שנוגעת ביותר מאלף מקורות, ותקבל בדיוק את הסוג הזה של כשל שקט ולא-אחיד שראינו - חלק מהמקורות בסדר, 102 מהם רוקנו, שום דבר ביומנים (logs) שצועק "תקלת פרוקסי", כי טכנית, לא הייתה כזו.
25 בספטמבר: התיקון, והחלק שחשוב לך
התיקון ששוחרר תשעה ימים לאחר מכן עשה שני דברים לא-מרשימים. הוא הגביל את חשבון ה-retry כך ששליפה שנתקעת נכשלת מהר במקום לבלוע כמעט שעה, וזה - החלק שבאמת מונע את אובדן המידע - שליפה חלקית לא מחליפה יותר את מערך השורות המלא. אם מקור מספיק לעבור רק 1,200 מתוך 9,000 המודעות הרגילות שלו, אנחנו שומרים את התמונה המלאה הקודמת במקום לדרוס אותה בשבר. באותו יום, שינוי שני נחת, שכותב דגל (flag) גלוי בשם CRAWL_PAUSED שהניטור שלנו בודק לפני שהוא מתריע למישהו על ירידה - כך שהשהיה מכוונת נקראת כהשהיה, לא כהתראה.
למה שקורא שמחפש יונדאי יד שנייה יתעניין בכל זה? כי דגלי המחיר-מתחת-לשוק שאנחנו מפרסמים - 12,823 מהם חיים באתר נכון לשבוע הזה - הם הוגנים רק אם הקוהורט שאנחנו משווים מודעה אליו הוא השוק האזורי האמיתי והמלא, ולא שבר מקוצץ-טיימאאוט שלו. תג דיל שנבנה על תמונת מצב שאיבדה שלושה-רבעים מקבוצת ההשוואה שלה אינו תג דיל, הוא רעש שחובש תווית ירוקה. אנחנו מעדיפים להשהות זחילה לתשעה ימים מאשר לפרסם את זה.
מערך הנתונים כיום עומד על 1,108,535 מודעות ב-73 אזורים ו-1,375 מקורות - גדול יותר ממה שהיה לפני שכל זה התחיל, עם הפרוקסי מחודשים ובאג החלפת השורות סגור. אבל המספר שאני חוזר אליו שוב ושוב אינו הסך הכולל. זה 84,401 - הפער בין זחילה שנראתה בריאה בשכבת הפרוקסי לבין אחת שבאמת הייתה.



