Redisలో Sliding Window Rate Limiterని నిర్మించడం

గత త్రైమాసికంలో రెండుసార్లు ఉదయం 9:00 గంటల కంటే ముందే మా YouTube API కోటా సున్నాకి చేరుకుంది. దీనివల్ల మాలోని సగం ప్రాంతాలలో ట్రెండింగ్ ఫీడ్‌లు పాతవిగా (stale) మారిపోయాయి.

సమస్య ట్రాఫిక్ పెరగడం కాదు. సమస్య మా రేట్ లిమిటర్ (rate limiter).

మేము fixed-window counterని ఉపయోగించాము. విండో బౌండరీ (window boundary) వద్ద API కాల్స్ భారీగా వచ్చినప్పుడు, రెండు పెద్ద బర్స్ట్‌లు (bursts) లోపలికి వెళ్లే అవకాశం ఉండేది. 8 ప్రాంతాలతో కూడిన గ్లోబల్ పైప్‌లైన్ కోసం, ఈ బౌండరీ ఓవర్‌ల్యాప్ తరచుగా జరిగేది. ఇది మా రోజువారీ కోటాను బడ్జెట్ లీక్‌గా మార్చేసింది.

నేను fixed window స్థానంలో Redis sorted sets ఉపయోగించి sliding window logని ప్రవేశపెట్టాను.

ఇది ఎలా పనిచేస్తుందంటే:

  • టైమ్‌స్టాంప్‌తో రిక్వెస్ట్‌ను రికార్డ్ చేయడానికి ZADDని ఉపయోగించండి.
  • విండో వెలుపల ఉన్న పాత ఎంట్రీలను తొలగించడానికి ZREMRANGEBYSCOREని ఉపయోగించండి.
  • విండోలో ఖచ్చితంగా ఎన్ని రిక్వెస్ట్‌లు మిగిలి ఉన్నాయో లెక్కించడానికి ZCARDని ఉపయోగించండి.
  • ఖాళీగా ఉన్న కీలను (idle keys) ఆటోమేటిక్‌గా క్లీన్ చేయడానికి PEXPIREని ఉపయోగించండి.

ఈ పద్ధతి ఖచ్చితమైనది. ఇందులో బౌండరీ సమస్య ఉండదు.

నేను దీనిని Redisలో Lua script ఉపయోగించి అమలు చేశాను. దీనివల్ల చెక్ మరియు రికార్డ్ ప్రక్రియ మొత్తం 'atomic'గా జరుగుతుంది. మీరు ఈ దశలను అప్లికేషన్ కోడ్‌లో రన్ చేస్తే, race conditions కారణంగా అదనపు రిక్వెస్ట్‌లు లోపలికి వెళ్లే అవకాశం ఉంది.

ప్రొడక్షన్ కోసం ముఖ్యమైన సాంకేతిక నిర్ణయాలు:

  • Redis TIMEని ఉపయోగించండి: మీ అప్లికేషన్ సర్వర్ల టైమ్‌స్టాంప్‌లను ఉపయోగించవద్దు. సర్వర్‌ల మధ్య ఉండే క్లాక్ స్క్యూ (clock skew) విండో ఖచ్చితత్వాన్ని దెబ్బతీస్తుంది.
  • వెయిటెడ్ కాస్ట్‌లు (Weighted costs): అన్ని API కాల్స్ ఒకేలా ఉండవు. ఒక సెర్చ్ కాల్ 100 యూనిట్లు ఖర్చు చేయవచ్చు, అదే వీడియో లిస్ట్ 1 యూనిట్ మాత్రమే కావచ్చు. ప్రతి కాల్‌కు బహుళ మెంబర్స్‌ను ఇన్సర్ట్ చేయడం ద్వారా నా స్క్రిప్ట్ దీనిని నిర్వహిస్తుంది.
  • ఖచ్చితమైన Retry-After: sorted setలోని పాత ఎంట్రీని చూడటం ద్వారా, కెపాసిటీ ఎప్పుడు ఖాళీ అవుతుందో సిస్టమ్ ఖచ్చితంగా లెక్కిస్తుంది.
  • ఫెయిల్-సేఫ్ లాజిక్: నేను EVALSHAతో పాటు EVAL ఫాల్‌బ్యాక్‌ను ఉపయోగిస్తాను. రీస్టార్ట్ సమయంలో Redis స్క్రిప్ట్ క్యాష్ క్లియర్ అయితే, అప్లికేషన్ దానిని సులభంగా హ్యాండిల్ చేస్తుంది.

దీని వల్ల కలిగే నష్టం మెమరీ (memory). ప్రతి రిక్వెస్ట్ సుమారు 100 బైట్లు తీసుకుంటుంది. 10,000 యూనిట్ల రోజువారీ కోటా కోసం, అది కేవలం 1 MB మెమరీ మాత్రమే. చాలా సందర్భాలలో, ఈ ఖచ్చితత్వం కోసం మెమరీని ఖర్చు చేయడం సరైనదే.

ఈ మార్పు చేసినప్పటి నుండి, మా కోటా ఒక్కసారి కూడా అయిపోలేదు. మా జాబ్స్ 403 ఎర్రర్‌లను ఎదుర్కోవడానికి బదులుగా, క్రమబద్ధంగా ఆగిపోతున్నాయి.

మీ రేట్ లిమిటర్ గడియారంలోని ఒక నిర్దిష్ట సమయం (round number) వద్ద రీసెట్ అవుతుంటే, మీకు లిమిట్ లేనట్టే. మీకు ఒక లూప్‌హోల్ (loophole) ఉంది.

Source: https://dev.to/ahmet_gedik778845/building-a-sliding-window-rate-limiter-in-redis-for-a-multi-region-video-api-50ni