அதிகாலை மூன்று மணிக்கு உங்கள் தரவுத்தளத்தின் (database) CPU 100% ஆக உயர்ந்துவிடுகிறது. போக்குவரத்து (traffic) இயல்பாகவே உள்ளது. கோரிக்கைகளின் (requests) எண்ணிக்கை வழக்கத்திற்கு மாறாக அதிகமாகவும் இல்லை. இருப்பினும், உங்கள் முதன்மைத் தரவுச் சேமிப்பு (primary store) முடங்குகிறது, ஏனெனில் அந்த ஒவ்வொரு கோரிக்கையும் ஒரே நேரத்தில் சரியாக ஒரே விஷயத்தைக் கேட்கின்றன.
இதுதான் thundering herd பிரச்சனை.
ஒரு இசை நிகழ்ச்சியின் முடிவில் ஒரு மைதானத்தை நினைத்துப் பாருங்கள். ஒரு மணி நேரத்திற்குள், அதே வெளியேறும் கதவு மூலம் அனைவரும் நிம்மதியாக வெளியேற முடியும். ஆனால், கூட்டமே ஒரே பத்து வினாடிகளுக்குள் அந்த ஒற்றைக் கதவு வழியாக வெளியேற முடிவு செய்தால், கதவு உடைந்துவிடாது. ஆனால், அந்த ஒரே நேரத்தில் நிகழும் கூட்ட நெரிசலை (concurrency) அதனால் கையாள முடியாது. அந்த நெரிசலே பிழை (bug), கதவு அல்ல.
இந்த நெரிசல் எங்கு உருவாகிறது
பல செயல்முறைகள் (processes) ஒரே நிகழ்வின் அடிப்படையில் ஒருங்கிணைக்கப்படும்போது இந்த முறை வெளிப்படுகிறது. இதற்குத் தீய நோக்கம் கொண்ட போக்குவரத்து (malicious traffic) தேவையில்லை. சாதாரண அமைப்புகளே தங்களுக்குத் தாங்களே இதைச் செய்து கொள்கின்றன.
Cache expiration. ஒரு முக்கியமான cache key காலாவதியாகிறது. அது ஒரு தயாரிப்பு பட்டியல் (product catalog), ஒரு feature flag அல்லது பயனரின் அனுமதிப் பட்டியல் (permissions list) ஆக இருக்கலாம். ஆயிரக்கணக்கான பயன்பாட்டுச் சேவையகங்கள் (application servers) ஒரே நேரத்தில் அந்த காலியான இடத்தைக் கவனிக்கின்றன. ஒவ்வொரு சேவையகமும், நல்லெண்ணத்துடன், தனது சொந்த தரவுத்தள இணைப்பைத் தொடங்கி, அந்த மதிப்பை மீண்டும் உருவாக்க அதே கடினமான வினவலை (heavy query) இயக்குகிறது. ஒரே விலையுயர்ந்த கேள்விக்கு இரண்டாயிரம் முறை இணையாக (in parallel) பதிலளிக்கும் வகையில் தரவுத்தளம் கட்டமைக்கப்படவில்லை. ஒரு காலாவதியான key முழு கிளஸ்டரையும் (cluster) முடக்கிவிடும்.
Connection pool wakeups. சில கட்டமைப்புகளில் (architectures), பல பணியாளர் செயல்முறைகள் (worker processes) வேலை வரும் வரை ஒரு குறிப்பிட்ட நிபந்தனைக்காகக் காத்திருக்கின்றன. அந்த நிபந்தனை நிறைவேறும்போது, இயங்குதளம் (operating system) தூங்கிக் கொண்டிருக்கும் அனைத்துப் பணியாளர்களையும் எழுப்புகிறது. ஆனால் ஒரு பணியாளர் மட்டுமே உண்மையில் அந்த இணைப்பையோ அல்லது பணியையோ பெறுகிறார். மற்றவர்கள் விழித்துக்கொண்டு, தாங்கள் போட்ட போட்டியில் தோற்றுவிட்டதை உணர்ந்து மீண்டும் தூங்கச் செல்கிறார்கள். இந்தச் சுழற்சி context switches மூலம் CPU-வைச் செலவழிப்பதோடு, உண்மையான உற்பத்தித் திறனுள்ள வேலைகளைப் பாதிக்கலாம்.
Retry storms. ஒரு கீழ்நிலைச் சேவை (downstream service) தற்காலிகத் தடுமாற்றத்தைச் சந்திக்கிறது. ஒவ்வொரு கிளையன்ட்டும் (client) timeout-ஐக் கண்டறிந்து, மீண்டும் முயற்சிப்பதற்கு முன் ஒரு குறிப்பிட்ட இடைவெளியை (உதாரணமாக சரியாக ஒரு வினாடி) காத்திருக்கிறது. அந்தச் சேவை மீண்டும் இயங்கி போக்குவரத்தை ஏற்கத் தொடங்கும் போது, அனைத்து கிளையன்ட்களும் ஒரே கணத்தில் அதைத் தாக்குகின்றன. அப்போது அந்தச் சேவை இன்னும் முழுமையாகச் சீரடையாத நிலையில் இருப்பதால், மீண்டும் முடங்குகிறது. இந்தச் சுழற்சி மீண்டும் மீண்டும் நிகழ்கிறது.
Cron collisions. நீங்கள் பராமரிப்புப் பணிகள், அறிக்கை உருவாக்கம் அல்லது cache warming போன்றவற்றை ஒரு கூட்டத் தொடர் சேவையகங்களில் (fleet of instances) சரியாக 00:00 UTC நேரத்தில் இயங்குமாறு திட்டமிட்டால், நீங்கள் ஒரு போக்குவரத்து அதிகரிப்பை (traffic spike) மிகத் துல்லியமாக உருவாக்குகிறீர்கள். இந்தச் சுமை கணிக்கக்கூடியதுதான், ஆனால் அதன் செறிவு (concentration) ஆபத்தானது.
Request Coalescing
Cache stampedes-க்கான மிகவும் பயனுள்ள தீர்வு, ஒரே கேள்விக்கு ஒன்றுக்கும் மேற்பட்ட முறை பதிலளிப்பதைத் தடுப்பதாகும். ஒரு cache miss ஏற்படும் போது, 2,500 திரெட்களும் (threads) தனித்தனியாக தரவுத்தள வினவலை இயக்கக்கூடாது. ஒரு திரெட் வினவலை இயக்க வேண்டும், மற்ற 2,499 திரெட்களும் அந்த முடிவிற்காகக் காத்திருக்க வேண்டும்.
இந்த முறை பெரும்பாலும் request coalescing என்று அழைக்கப்படுகிறது. Go மொழியில், golang.org/x/sync-ல் உள்ள singleflight தொகுப்பு இதற்கான ஒரு சிறந்த நடைமுறைச் செயலாக்கத்தை (canonical implementation) வழங்குகிறது. ஒரு குறிப்பிட்ட key-க்காக Do-வை அழைக்கும் முதல் goroutine வேலையைத் தொடங்குகிறது. அதே key-யைக் கொண்டு அழைக்கும் அடுத்தடுத்த பயனர்கள் அதே Do அழைப்பிற்காகக் காத்திருப்பார்கள் (block). வேலை முடிந்ததும், காத்திருப்பவர்கள் அனைவரும் ஒரே நேரத்தில் முடிவைப் பெறுகிறார்கள். நீங்கள் ஒரே ஒரு வினவலை மட்டும் இயக்கி 2,500 கோரிக்கைகளுக்குப் பதிலளித்துள்ளீர்கள்.
promises, futures அல்லது channels கொண்ட ஒரு in-memory concurrent map மூலம் இதே போன்ற செயல்பாட்டை நீங்கள் உருவாக்கலாம். ஒரு செயல்பாட்டில் இருக்கும் கோரிக்கையை (in-flight request) அணுநிலைத் தன்மையுடன் (atomically) சரிபார்த்துப் பதிவு செய்வதே இதன் ரகசியம். கோரிக்கை தோல்வியடைந்தால், அனைவரும் பிழையைப் பெறுவார்கள், இதுவே சரியான அணுகுமுறை. அது வெற்றியடைந்தால், அனைவரும் சேமிக்கப்பட்ட (cached) மதிப்பைத் தெரிந்துகொள்வார்கள், மேலும் அடுத்தடுத்த கோரிக்கைகள் நேரடியாக கேச் மூலம் செயல்படும். இதனால் தரவுத்தளச் சுமை ஒரு செங்குத்தான அதிகரிப்பிலிருந்து (vertical spike) ஒரு சீரான கோடாக (flat line) குறைகிறது.
Probabilistic Early Expiration
சில நேரங்களில், நெரிசலை நிர்வகிப்பதை விட அதைத் தவிர்க்கவே நீங்கள் விரும்புவீர்கள். XFetch போன்ற அல்காரிதம்கள் மூலம் செயல்படுத்தப்படும் probabilistic early expiration இதற்குப் பயன்படுகிறது.
ஒரு நிலையான காலாவதி நேரத்திற்குப் பதிலாக, ஒவ்வொரு சேமிக்கப்பட்ட மதிப்பும் ஒரு மென்மையான காலாவதி கால இடைவெளியைக் (soft expiration window) கொண்டிருக்கும். ஒரு கோரிக்கை வரும்போது, பயன்பாடு ஒரு சீரற்ற எண்ணை (random number) உருவாக்கி ஒரு எளிய நிகழ்தகவுச் சோதனையைச் செய்கிறது. அந்தச் சோதனை வெற்றி பெற்றால், அந்த ஒற்றைக் கோரிக்கை கேச்சை முன்கூட்டியே புதுப்பிக்கும். இல்லையெனில், அந்த கோரிக்கை சற்று பழைய மதிப்பை வழங்கும்.
ஒவ்வொரு கோரிக்கையும் அதன் சொந்தத் தற்காலத்தைச் சோதிப்பதால், புதுப்பிக்கும் பணிகள் அந்த மென்மையான கால இடைவெளியில் பரவிச் செல்கின்றன. ஒரு கிளையன்ட் நிலையான காலாவதிக்கு நாற்பது வினாடிகளுக்கு முன்பே புதுப்பிக்கலாம், மற்றொன்று பன்னிரண்டு வினாடிகளுக்கு முன்பே செய்யலாம், மேலும் பெரும்பாலானவை செய்யாமலேயே இருக்கலாம். வேலை என்பது ஒரு ஒத்திசைக்கப்பட்ட திடீர் அதிகரிப்பிலிருந்து மென்மையான
