ஒரு பார்வையாளர் முதலில் நம்பும் எண் 'view count' (பார்வை எண்ணிக்கை) ஆகும். ஒரு வீடியோவிற்கு முப்பது வினாடிகள் செலவிடலாமா அல்லது முப்பது நிமிடங்கள் செலவிடலாமா என்பதை இதுவே தீர்மானிக்கிறது. TopVideoHub-இல், அந்த எண் மிக வேகமாக நகர்கிறது. டிரெண்டிங்கில் இருக்கும் ஒரு வீடியோ பத்து நிமிடங்களில் 40,000 பார்வைகளைப் பெறக்கூடும். பக்கத்தில் உள்ள அந்த எண்ணாட்டியில் (counter) மாற்றம் இல்லாமல் அப்படியே நின்றால், அந்த இடம் வெறிச்சோடிப் போனது போன்ற உணர்வைத் தரும். பயனர்கள் வெளியேறிவிடுவார்கள் (Users bounce).
அந்த எண்ணை உலாவியில் (browser) கொண்டு வருவது எளிது என்று தோன்றலாம். ஆனால் அது அவ்வாறு இல்லை. பெரும்பாலான குழுக்கள் முதலில் முயற்சிக்கும் தீர்வு 'polling' ஆகும். இதை அமைப்பது எளிது மற்றும் staging சூழலில் இது நன்றாகச் செயல்படும். ஆனால் staging சூழல் உண்மையைச் சொல்லாது.
Polling எப்போது உங்களுக்கு எதிராகவே ஒரு DDoS தாக்குதலாக மாறுகிறது
TopVideoHub குழு ஒரு எளிய JavaScript poller-ஐ உருவாக்கியது. அது ஒவ்வொரு ஐந்து வினாடிக்கும் சமீபத்திய பார்வை எண்ணிக்கையைப் பெற்று வந்தது. மூன்று உலாவிகள் திறந்திருந்த ஒரு சோதனைச் சூழலில் (test environment), அது சிறப்பாகச் செயல்பட்டது. ஆனால் production சூழலில், அது தளத்தையே முடக்கியது.
ஒவ்வொரு ஐந்து வினாடிக்கும் புதுப்பித்துக் கொள்ளும் (refresh) எட்டு ஆயிரம் ஒரே நேரத்தில் இருக்கும் பார்வையாளர்கள், ஒரு வினாடிக்கு 1,600 கோரிக்கைகளை (requests) உருவாக்கினர். ஒவ்வொரு கோரிக்கையும் தரவுத்தளத்திற்குள் (database) ஊடுருவியது. Replication lag அதிகரித்தது. Read replicas திணறியன. Cache அடுக்குகள்கள் தவிர்க்கப்பட்டன (bypassed). அந்தத் team வீடியோவை வழங்கவில்லை; மாறாக தாங்களே உருவாக்கிய சுமையை (load) சுமந்து கொண்டிருந்தனர்.
Polling என்பது அது சிக்கலாக மாறும் வரை ஒரு நல்ல முறையாகவே இருக்கும். குறைந்த போக்குவரத்து (low-traffic) கொண்ட dashboards அல்லது admin panels-களுக்கு இது பரவாயில்லை. ஆனால் ஒரு வைரல் வீடியோ பக்கத்திற்கு, இது ஒரு வெடிக்கக் காத்திருக்கும் குண்டு போன்றது. அந்தத் team-க்கு சர்வரிலிருந்து உலாவிற்கு ஒரு நிலையான இணைப்பு (persistent pipe) தேவைப்பட்டது, ஆனால் அவர்களுக்கு ஒரு full-duplex protocol-இன் சிக்கலான தன்மை தேவையில்லை.
ஒருவழித் தொடர்புகளுக்கு (One-Way Pipes) SSE ஏன் பொருத்தமானது
Server-Sent Events (SSE) சரியாக இத்தகைய சிக்கல்களுக்காகவே உருவாக்கப்பட்டது: சர்வரில் தரவு உள்ளது, உலாவியோ அதைக் கேட்டால் (listen) போதுமானது.
WebSockets போலல்லாமல், SSE சாதாரண HTTP-இல் இயங்குகிறது. இது நீங்கள் நினைப்பதை விட மிக முக்கியமானது. உங்களுக்குப் புதிய proxy விதிகள், upgrade headers அல்லது load-balancer மாற்றங்கள் தேவையில்லை. உங்கள் சர்வர் HTTP/1.1 அல்லது HTTP/2-ஐப் பயன்படுத்தினால், SSE வேலை செய்யும். இதில் debugging செய்வது மிகவும் எளிது, ஏனெனில் அந்த stream வெறும் உரையாக (text) மட்டுமே இருக்கும். நீங்கள் curl-ஐ endpoint-க்கு அனுப்பி, எண்கள் நிகழ்நேரத்தில் (real time) நகர்வதைப் பார்க்கலாம்; இது ஒரு binary socket frame ஏன் தவறாகச் சென்றது என்று ஊகிப்பதை விடச் சிறந்தது.
உலாவியே கடினமான வேலைகளை இலவசமாகச் செய்துவிடுகிறது. இணைப்பு துண்டிக்கப்பட்டால், SSE தானாகவே Last-Event-ID header மூலம் மீண்டும் இணையும், இதனால் சர்வர் எங்குத் தொடர வேண்டும் என்பதைத் தெரிந்துகொள்ளும். JavaScript-இல் இதற்கான API மிகவும் எளிமையானது: ஒரு EventSource-ஐ உருவாக்கி, ஒரு onmessage handler-ஐ இணைத்தால் போதும், வேலை முடிந்தது.
Caching தான் உண்மையான கட்டமைப்பு (Architecture)
நேரலை எண்ணாட்டிகளில் (live counters) செய்யப்படும் மிகப்பெரிய கட்டமைப்புத் தவறு என்னவென்றால், ஒவ்வொரு உலாவியின் இணைப்பையும் தரவுத்தளத்தைக் (database) கேட்பதற்கான ஒரு காரணமாகக் கருதுவதுதான். 8,000 பேர் ஒரே வீடியோவைப் பார்க்கும்போது, ஒவ்வொரு இரண்டு வினாடிக்கும் 8,000 வினவல்களை (queries) இயக்குவது பைத்தியக்காரத்தனம். வைரல் போக்குவரத்தைத் (viral traffic) தாங்கும் சக்தி உங்கள் தரவுத்தளத்திற்கு இருக்காது.
TopVideoHub இதை PHP-இன் in-memory opcode மற்றும் user cache ஆன APCu மூலம் தீர்த்தது. இதன் செயல்முறை எளிமையானது. ஒரு background process—அல்லது ஒரு timer மூலம் இயங்கும் ஒரு இலகுவான endpoint—ஒவ்வொரு இரண்டு வினாடிக்கும் தற்போதைய பார்வை எண்ணிக்கையை APCu-இல் எழுதும். ஆயிரக்கணக்கான உலாவிகள் திறந்து வைத்திருக்கும் SSE endpoint, APCu-விலிருந்து மட்டுமே தரவைப் படிக்கும்.
இதன் முடிவு: எத்தனை பார்வையாளர்கள் பார்த்துக் கொண்டிருந்தாலும், தரவுத்தளம் ஒவ்வொரு இரண்டு வினாடிக்கும் ஒருமுறை மட்டுமே அணுகப்படும். Cache இங்கே ஒரு அதிர்வுத் தாங்கியாக (shock absorber) செயல்படுகிறது. APCu என்பது ஏதோ விசித்திரமான ஒன்றல்ல. இது PHP-உடன் வருகிறது, shared memory-இல் இயங்குகிறது, மேலும் எந்தவொரு network round-trip-ஐ விடவும் வேகமாகப் படிக்கிறது. அடிக்கடி மாறக்கூடிய, ஆனால் உடனடியாக மாறாத ஒரு தனி எண்ணிற்கு, இதுவே சரியான கருவி.
நீங்கள் APCu பயன்படுத்தவில்லை என்றால், Redis அல்லது Memcached-ஐயும் பயன்படுத்தலாம். இதன் தத்துவம் ஒன்றுதான்: தரவுத்தளத்திலிருந்து 'hot read path'-ஐத் தனிமைப்படுத்துங்கள்.
PHP, LiteSpeed மற்றும் Cloudflare-ஐ Stream செய்யத் தூண்டுவது எப்படி
PHP தனது வேலையை முடித்துவிட்டுப் போக விரும்புகிறது. Web servers வெளியீட்டைத் தற்காலிகமாகச் சேமித்து வைத்து (buffer) ஒரு முழுமையான பதிலை வழங்க விரும்புகின்றன. ஆனால் SSE இதற்கு நேர்மாறானது: இணைப்பு திறந்தே இருக்க வேண்டும், மற்றும் bytes வந்தவுடன் அவற்றை உடனடியாக அனுப்ப வேண்டும் (flush). கவனமாக இல்லையென்றால், உங்கள் "stream" முப்பது வினாடிகளுக்குப் பிறகு ஒரே தொகுப்பாக (single blob) வந்துவிடும், இது நோக்கத்தையே சிதைத்துவிடும்.
TopVideoHub இந்த இணைப்பைத் தடையின்றி வைத்திருந்தது எப்படி என்பதை இங்கே காணலாம்.
Output buffering-ஐத் தவிர்க்கவும். SSE script-இன் தொடக்கத்தில், PHP செயல்படுத்தியிருக்கக்கூடிய அனைத்து buffering அடுக்குகளையும் முடக்குங்கள். ஒரு buffer செயல்பாட்டில் இருந்தால் ob_end_flush()-ஐ அழைக்கவும், மேலும் உங்கள் headers அனுப்பப்பட்ட பிறகு ob_implicit_flush(true) மூலம் implicit flushing-ஐ அணைக்கவும்.
Proxies-களுக்குத் தெரிவிக்கவும். X-Accel-Buffering: no என்ற header-ஐ அனுப்பவும். Nginx மற்றும் LiteSpeed ஆகிய இரண்டும் இதைக் கவனிக்கும். பதில் (response) buffer செய்யப்படக்கூடாது அல்லது ஒரு cacheable தொகுப்பாகச் சுருக்கப்படக்கூடாது என்பதை இது உணர்த்துகிறது.
குறுகிய கால அளவை நிர்ணயிக்கவும். ஒவ்வொரு SSE இணைப்பும் ஒரு PHP worker-ஐப் பிடித்துக் கொள்கிறது. TopVideoHub streams-களை 55 வினாடிகளில் நிறுத்துகிறது. Timer முடிந்ததும், சர்வர் ஒரு இறுதித் टिप्पणी (comment) அனுப்பி, stream-ஐ மூடிவிடும், உலாவியும் தானாகவே மீண்டும் இணையும். அந்த மறு இணைப்பு ஒரு புதிய worker-இல் அமையும், இதனால் எந்தவொரு தனிச் செயல்பாடும் (process) நீண்ட நேரம் பிடித்துக் கொண்டிருப்பதைத் தவிர்க்கலாம்.
இணைப்பைத் தக்கவைக்க 'ping' செய்யுங்கள். ஒவ்வொரு இருபது வினாடிக்கும் ஒரு கமெண்ட் வரியை—: ping போன்ற ஒன்றை—அனுப்புங்கள். SSE-இல் உள்ள கமெண்ட்களை பிரவுசரின் மெசேஜ் ஹேண்ட்லர் புறக்கணித்துவிடும், ஆனால் அவை TCP இணைப்பைத் துண்டிக்கப்படாமல் வைத்திருக்கும். லோட் பேலன்சர்கள் (Load balancers) மற்றும் CDNs பெரும்பாலும் முடங்கியிருக்கும் இணைப்புகளை முப்பது அல்லது அறுபது வினாடிகளுக்குப் பிறகு துண்டித்துவிடும். ஒரு சிறிய புதிய வரி (newline) உங்களை அந்தத் துண்டிப்பிலிருந்து காப்பாற்றும்.
பயனரின் டேப்-ஐ (tab) மதியுங்கள். ஒரு பார்வையாளர் டேப்பைச் சுருக்குவதோ அல்லது மறைப்பதோ செய்தால், இணைப்பைத் துண்டித்துவிடுங்கள். பிரவுசரில் visibilitychange நிகழ்வைக் கவனித்து eventSource.close() என்பதை அழைக்கவும். சர்வர் கூட கிளையண்ட் துண்டிக்கப்படுவதைக் கண்டறிந்து லூப்பை (loop) நிறுத்த வேண்டும். PHP-இல் ஒரு லூப்பிற்குள் connection_aborted() மூலம் இதைச் சரிபார்க்கலாம். பத்து நிமிடங்களுக்கு முன்பே வெளியேறியவர்களுக்காக, பயனற்ற (ghost) இணைப்புகள் மூலம் வொர்க்கர்களை (workers) வீணாக்காதீர்கள்.
கடினமான வரம்பு: PHP வொர்க்கர்கள்
PHP-இல் SSE அதன் வரம்புகளைத் தெளிவாகக் காட்டுகிறது. ஒவ்வொரு திறந்திருக்கும் SSE இணைப்பும் ஒரு PHP வொர்க்கரை எடுத்துக்கொள்ளும். உங்கள் பூலில் (pool) நூறு வொர்க்கர்கள் இருந்தால், உங்களிடம் நூறு ஸ்ட்ரீம்கள் (streams) மட்டுமே இருக்கும். அவ்வளவுதான். நீங்கள் Apache அல்லது PHP-FPM செயல்முறை மாதிரியில் (process model) இருக்கும்போது, இதற்கு மாற்று வழி (async workaround) ஏதுமில்லை. நீங்கள் pm.max_children-ஐ மாற்றியமைக்கலாம், ஆனால் மெமரி (memory) மற்றும் CPU தான் உண்மையான எல்லையைத் தீர்மானிக்கின்றன.
வழக்கமான பக்கப் பதிவேற்றம் (page loads), API அழைப்புகள் மற்றும் அசெட் உருவாக்கம் (asset generation) ஆகியவற்றிற்கும் வொர்க்கர்களைப் பயன்படுத்தினால், இந்த வரம்பு மிக விரைவாகத் தீர்ந்துவிடும். உங்கள் வொர்க்கர்களின் பயன்பாட்டு அளவை (saturation) கவனமாகக் கண்காணிக்கவும். அனைத்து வொர்க்கர்களும் இருபது நிமிட ஸ்ட்ரீம்களில் பிஸியாக இருப்பதால், உங்கள் SSE எண்ட்பாயிண்ட் (endpoint) வரிசையில் (queuing) காத்திருக்கத் தொடங்கினால், உங்கள் முழுத் தளமும் மெதுவாகச் செயல்படும்.
எண்கள் உங்கள் வரம்பைத் தாண்டும்போது, அடுத்த கட்டத்திற்குச் செல்லுங்கள். வழக்கமாக அடுத்த கட்டமாக Go பயன்படுத்தப்படுகிறது, இருப்பினும் Rust, Node.js அல்லது Erlang ஆகியவையும் அதே பணியைச் செய்யலாம். Go-வின் goroutines தான் இதன் முக்கிய அம்சம். ஒரு goroutine சில கிலோபைட்களை மட்டுமே எடுத்துக்கொள்ளும். சாதாரண வன்பொருளிலேயே (hardware) நீங்கள் சிரமமின்றி பல்லாயிரக்கணக்கான ஸ்ட்ரீம்களைத் தக்கவைக்க முடியும். அதன் அடிப்படை தர்க்கம் (core logic) மாறாது—கேச்சிலிருந்து (cache) வாசிப்பது, சாக்கெட்டில் (socket) எழுதுவது—ஆனால் ரன்டைம் (runtime) கனமான செயல்முறைகளிலிருந்து (heavy processes) இலகுவான திரெட்களாக (lightweight threads) மாறுகிறது.
ஆனால் அங்கிருந்து தொடங்க வேண்டாம். PHP உங்களை வியக்கத்தக்க வகையில் முன்னேற்றும். முதலில் உங்கள் தயாரிப்பைச் சரிபார்க்கவும். மெட்ரிக்ஸ் பக்கத்தில் டேட்டாபேஸ் அதிகப்படியான சுமைக்கு (overload) பதிலாக வொர்க்கர்கள் தீர்ந்துவிட்டதைக் காட்டும்போது, நீங்கள் அந்தத் தொழில்நுட்பத் தளத்தைத் தாண்டி வளர்ந்துவிட்டீர்கள் என்று அர்த்தம். அது ஒரு நல்ல சிக்கல்.
முக்கியக் கருத்துக்கள்
நேரலை கவுண்டர்கள் (Live counters) என்பது வெறும் தொழில்நுட்பம் சார்ந்தது மட்டுமல்ல. அவை உங்கள் பயனர்களிடமிருந்து உங்கள் டேட்டாபேஸைப் பாதுகாப்பதைப் பற்றியது. SSE பார்ப்பதை விட எளிமையானது என்பதால் அதிலிருந்து தொடங்குங்கள். இணைப்புகளின் எண்ணிக்கை (connection count) வினவல்களின் எண்ணிக்கையாக (query count) மாறாமல் இருக்க, ஸ்ட்ரீமிற்கும் டேட்டாபேஸிற்கும் இடையில் தீவிரமாக கேச்சிங் (caching) செய்யுங்கள். உங்கள் வொர்க்கர் வரம்புகளைக் கூர்மையாகக் கவனியுங்கள். எளிமையாகத் தொடங்குங்கள். PHP போதுமானதாக இருக்கும் வரை அதையே பயன்படுத்துங்கள், அது போதுமானதாக இல்லாதபோது, நீங்கள் ஏன் மாற்ற வேண்டியிருக்கிறது என்பதையும் துல்லியமாகத் தெரிந்து வைத்திருப்பீர்கள்.
உங்கள் அடுத்த திட்டத்திற்கு:
- தரவு சர்வரிலிருந்து பிரவுசருக்கு ஒரு திசையில் மட்டும் பாயும்போது SSE-ஐப் பயன்படுத்தவும்.
- டேட்டாபேஸிற்கு முன்னால் ஒரு கேச் லேயரை (cache layer) வைக்கவும். சில வினாடிகளுக்கு ஒருமுறை செய்யப்படும் வினவல் (query), ஆயிரக்கணக்கான வினவல்களை விடச் சிறந்தது.
- SSE இணைப்புகளை ஒரு நிமிடத்திற்குள் முடித்துவிட்டு, பிரவுசர் மீண்டும் இணைய (reconnect) அனுமதிக்கவும்.
- டேப்பை மறைக்கும்போது ஸ்ட்ரீம்களை மூடிவிடவும். பயனற்ற இணைப்புகளுக்காக நேரடி வொர்க்கர்களை வீணாக்காதீர்கள்.
- PHP வொர்க்கர் பயன்பாட்டைக் கண்காணிக்கவும். நீங்கள் உச்ச வரம்பைத் தொடும்போது, ஸ்ட்ரீமிங் லேயரை Go-விற்கு மாற்றவும்.
