לדלג לתוכן

Rate Limiting מוסבר

תארו לעצמכם API ציבורי בלי שום הגבלה. משתמש אחד, בכוונה או בטעות, כותב סקריפט ששולח אלף בקשות בשנייה. השרת שלכם, שנבנה לשרת עומס סביר, קורס תחת המשקל, וכל שאר המשתמשים הלגיטימיים נופלים איתו. Rate limiting הוא המנגנון שמונע בדיוק את התרחיש הזה, וכל API רציני צריך אותו מהיום הראשון.

אז מה זה בעצם Rate Limiting

הגבלת קצב היא מגבלה שקובעת כמה בקשות מותר לגורם מסוים - משתמש, כתובת IP, מפתח API - לשלוח בפרק זמן נתון. חורגים מהמגבלה? השרת מסרב לבקשה, בדרך כלל עם קוד סטטוס 429 (Too Many Requests), ולעתים קרובות גם עם header בשם Retry-After שאומר למשתמש כמה זמן לחכות לפני שהוא ינסה שוב.

זה נראה כמו מגבלה טכנית קטנה, אבל היא קריטית לשלוש מטרות שונות - הגנה מפני התקפות מכוונות שמנסות להציף את השרת, מניעת שימוש יתר לא מכוון (למשל באג בקוד של קליינט שמייצר לולאת בקשות אינסופית), ושמירה על שימוש הוגן כשמשאבי השרת מוגבלים ומשותפים בין כל המשתמשים.

אלגוריתם ראשון - Fixed Window

הגישה הפשוטה ביותר היא לחלק את הזמן לחלונות קבועים - למשל כל דקה - ולספור בקשות בתוך כל חלון. חרגתם מהמגבלה בתוך הדקה הנוכחית? הבקשות הבאות נדחות עד שהחלון מתחלף. זה קל ליישום, אבל יש לו חולשה - משתמש יכול לנצל את הגבול המקסימלי ממש בסוף חלון אחד, ומיד את הגבול המקסימלי שוב בתחילת החלון הבא, ולמעשה לשלוח כפול מהקצב המותר בפרק זמן קצר סביב הגבול בין החלונות.

אלגוריתם שני - Sliding Window

כדי לפתור את הבעיה הזאת, sliding window לא מסתכל על חלונות קבועים, אלא בודק כמה בקשות התקבלו בפרק הזמן הנע האחרון - למשל, בדיוק בששים השניות האחרונות, לא משנה איפה הן נופלות ביחס לשעון. זה נותן הגבלה חלקה ומדויקת יותר, במחיר של חישוב מעט מורכב יותר.

אלגוריתם שלישי - Token Bucket

זו הגישה הנפוצה ביותר במערכות אמיתיות, כי היא מאזנת בין דיוק לגמישות. מדמיינים דלי שמתמלא באסימונים בקצב קבוע. כל בקשה "צורכת" אסימון אחד מהדלי. אם יש אסימונים - הבקשה עוברת. אם הדלי ריק - הבקשה נדחית. היתרון המרכזי הוא שהדלי מאפשר "פרץ" קצר של בקשות אם נצברו אסימונים בזמן שקט, בלי לוותר על ההגבלה הכללית לאורך זמן. זה מדמה יותר טוב התנהגות משתמש אמיתי, שלרוב לא שולח בקשות בקצב אחיד לגמרי.

איפה בפועל שומרים את הספירה

מימוש הגבלת קצב דורש מקום מהיר לשמור ולעדכן מונים - וזו בדיוק הסיבה ש-Redis כל כך שכיח בהקשר הזה. הוא מספיק מהיר כדי לבדוק ולעדכן מונה בכל בקשה בלי לעכב את המשתמש בצורה מורגשת, וברגע שיש כמה שרתים שמשרתים את אותו API, כולם צריכים לראות את אותם מונים - בדיוק תפקיד שמאגר מהיר ומשותף כמו Redis יודע למלא.

הגבלה חכמה - לא כולם שווים

הגבלה טובה לא מגבילה את כולם באותו קצב. משתמש אנונימי מקבל בדרך כלל הגבלה מחמירה יותר ממשתמש מזוהה עם מפתח API בתשלום. endpoint שמבצע פעולה יקרה, כמו יצירת דוח מורכב, מקבל הגבלה נמוכה יותר מ-endpoint שרק קורא מידע פשוט. ההגבלה נועדה להגן על המערכת, לא להעניש משתמשים לגיטימיים, ולכן חשוב לכוון אותה בהתאם לעלות האמיתית של כל פעולה.

איך לומדים ליישם את זה נכון

הבנת האלגוריתמים היא שלב ראשון, אבל ליישם הגבלת קצב אמיתית שעובדת נכון עם כמה שרתים, לא פוגעת בביצועים, ונותנת הודעת שגיאה ברורה למשתמש - זה נלמד רק כשבונים API אמיתי מקצה לקצה. בקורס צד-שרת מיישמים הגבלת קצב עם Redis בתוך פרויקט אמיתי.

ה-API שלכם נחשף לניצול לרעה ולא בטוחים איך להתחיל להגן עליו? זה בדיוק סוג השאלה שכדאי לשאול בקהילה שלנו.

הצטרפו לקהילה בדיסקורד

לסיכום

הגבלת קצב היא לא תכונה שולית, היא קו הגנה בסיסי שכל API חייב. בין אם בוחרים fixed window הפשוט, sliding window המדויק יותר, או token bucket הגמיש, המטרה זהה - להגן על השרת מעומס ומניצול, בלי לפגוע בחוויה של משתמשים לגיטימיים שמשתמשים במערכת כמו שצריך.