వ్యూ కౌంట్ (View count) అనేది సందర్శకుడు నమ్మే మొదటి సంఖ్య. ఒక వీడియో కోసం ముప్పై సెకన్ల సమయం కేటాయించాలా లేదా ముప్పై నిమిషాల సమయం కేటాయించాలా అనేది ఇది తెలియజేస్తుంది. TopVideoHubలో, ఆ సంఖ్య చాలా వేగంగా మారుతుంది. ఒక ట్రెండింగ్ క్లిప్ పది నిమిషాల్లోనే 40,000 వ్యూస్ను సాధించగలదు. ఒకవేళ పేజీలోని కౌంటర్ ఫ్రీజ్ (freeze) అయితే, ఆ వాతావరణం వెలితిగా అనిపిస్తుంది. వినియోగదారులు వెళ్ళిపోతారు (Users bounce).
ఆ సంఖ్యను బ్రౌజర్కు చేరవేయడం చాలా సులభం అనిపిస్తుంది. కానీ అది అంత సులభం కాదు. చాలా టీమ్లు మొదటగా అనుసరించే పరిష్కారం 'polling'. దీనిని సెటప్ చేయడం సులభం మరియు స్టేజింగ్ (staging) ఎన్విరాన్మెంట్లో ఇది బాగానే పనిచేస్తుంది. కానీ స్టేజింగ్ వాస్తవ పరిస్థితులను ప్రతిబింబించదు.
పోలింగ్ (Polling) ఎప్పుడు మీకు మీరే DDoS దాడిలా మారుతుంది
TopVideoHub టీమ్ ఒక సాధారణ JavaScript pollerను రూపొందించింది. ఇది ప్రతి ఐదు సెకన్లకు లేటెస్ట్ వ్యూ కౌంట్ను తీసుకువస్తుంది. మూడు బ్రౌజర్లు ఓపెన్ చేసిన టెస్ట్ ఎన్విరాన్మెంట్లో ఇది అద్భుతంగా కనిపించింది. కానీ ప్రొడక్షన్లో, ఇది ప్లాట్ఫామ్ను కుప్పకూల్చింది.
ప్రతి ఐదు సెకన్లకు రిఫ్రెష్ అవుతున్న ఎనిమిది వేల కన్కరెంట్ వ్యూయర్స్ (concurrent viewers), సెకనుకు 1,600 రిక్వెస్ట్లను సృష్టించాయి. ప్రతి రిక్వెస్ట్ డేటాబేస్ను ప్రభావితం చేసింది. Replication lag పెరిగింది. Read replicas భరించలేకపోయాయి. Cache layers బైపాస్ అయ్యాయి. టీమ్ వీడియోలను అందించడం లేదు, తమకు తామే సృష్టించుకున్న లోడ్ను (self-inflicted load) భరిస్తోంది.
తక్కువ ట్రాఫిక్ ఉన్న డ్యాష్బోర్డ్లు లేదా అడ్మిన్ ప్యానెల్ల కోసం పోలింగ్ సరిపోతుంది. కానీ ఒక వైరల్ వీడియో పేజీకి మాత్రం, ఇది ఒక పేలుడు బాంబు వంటిది. టీమ్కు సర్వర్ నుండి బ్రౌజర్కు ఒక పర్సిస్టెంట్ పైప్ (persistent pipe) అవసరమైంది, కానీ వారికి ఫుల్-డ్యూప్లెక్స్ ప్రోటోకాల్ (full-duplex protocol) యొక్క సంక్లిష్టత అవసరం లేదు.
వన్-వే పైప్లకు SSE ఎందుకు సరిపోతుంది
Server-Sent Events (SSE) సరిగ్గా ఇటువంటి సమస్యల కోసమే రూపొందించబడింది: సర్వర్ వద్ద డేటా ఉంటుంది మరియు బ్రౌజర్ దానిని వినాల్సి ఉంటుంది (listen).
WebSockets లా కాకుండా, SSE సాధారణ HTTP పైనే పనిచేస్తుంది. ఇది వినబడే దానికంటే చాలా ముఖ్యం. మీకు కొత్త ప్రాక్సీ రూల్స్, అప్గ్రేడ్ హెడర్స్ లేదా లోడ్-బ్యాలెన్సర్ జిమ్నాస్టిక్స్ అవసరం లేదు. మీ సర్వర్ HTTP/1.1 లేదా HTTP/2ని ఉపయోగిస్తుంటే, SSE పనిచేస్తుంది. స్ట్రీమ్ కేవలం టెక్స్ట్ రూపంలో ఉండటం వల్ల డీబగ్గింగ్ (debugging) చాలా సులభం. మీరు curlను ఎండ్పాయింట్కు పాయింట్ చేసి, నంబర్లు రియల్ టైమ్లో ఎలా మారుతున్నాయో చూడవచ్చు. ఇది బైనరీ సాకెట్ ఫ్రేమ్ ఎందుకు తప్పుగా వెళ్ళిందో ఊహించడం కంటే చాలా మెరుగైనది.
బ్రౌజర్ కష్టమైన పనులన్నింటినీ ఉచితంగానే చూసుకుంటుంది. కనెక్షన్ కట్ అయితే, SSE Last-Event-ID హెడర్తో ఆటోమేటిక్గా రీకనెక్ట్ అవుతుంది, తద్వారా సర్వర్ ఎక్కడ నుండి కొనసాగించాలో తెలుస్తుంది. JavaScriptలో దీని API చాలా చిన్నది: ఒక EventSourceని సృష్టించి, onmessage హ్యాండ్లర్ను అటాచ్ చేస్తే సరిపోతుంది.
క్యాషింగ్ (Caching) అనేది అసలైన ఆర్కిటెక్చర్
లైవ్ కౌంటర్లలో జరిగే అతిపెద్ద ఆర్కిటెక్చరల్ తప్పు ఏమిటంటే, ప్రతి బ్రౌజర్ కనెక్షన్ను డేటాబేస్ను క్వరీ చేయడానికి ఒక కారణంగా భావించడం. 8,000 మంది ఒకే వీడియోను చూస్తున్నప్పుడు, ప్రతి రెండు సెకన్లకు 8,000 క్వరీలను రన్ చేయడం పిచ్చి పని. వైరల్ ట్రాఫిక్ను మీ డేటాబేస్ తట్టుకోలేదు.
TopVideoHub దీనిని APCu (PHP యొక్క in-memory opcode మరియు user cache)తో పరిష్కరించింది. దీని విధానం చాలా సరళం. ఒక బ్యాక్గ్రౌండ్ ప్రాసెస్—లేదా టైమర్పై పనిచేసే ఒక లైట్వెయిట్ ఎండ్పాయింట్—ప్రతి రెండు సెకన్లకు ఒకసారి ప్రస్తుత వ్యూ కౌంట్ను APCuలోకి రాస్తుంది. వేలాది బ్రౌజర్లు ఓపెన్ చేసి ఉంచే SSE ఎండ్పాయింట్, కేవలం APCu నుండి మాత్రమే డేటాను చదువుతుంది.
ఫలితం: ఎంతమంది వ్యూయర్స్ చూస్తున్నా, డేటాబేస్కు ప్రతి రెండు సెకన్లకు ఒకే ఒక్క రిక్వెస్ట్ వెళ్తుంది. క్యాష్ (Cache) ఇక్కడ షాక్ అబ్జార్బర్గా పనిచేస్తుంది. APCu అనేది కొత్తది కాదు. ఇది PHPతో పాటే వస్తుంది, షేర్డ్ మెమరీలో ఉంటుంది మరియు ఏ నెట్వర్క్ రౌండ్-ట్రిప్ కంటే వేగంగా డేటాను చదువుతుంది. తరచుగా మారే కానీ తక్షణమే మారాల్సిన అవసరం లేని ఒకే ఒక సంఖ్య కోసం, ఇది సరైన సాధనం.
మీరు APCuని ఉపయోగించకపోతే, Redis లేదా Memcached కూడా పనిచేస్తాయి. సూత్రం మాత్రం ఒక్కటే: డేటాబేస్ నుండి 'హాట్ రీడ్ పాత్' (hot read path)ను వేరు చేయండి.
PHP, LiteSpeed మరియు Cloudflareలను స్ట్రీమింగ్ కోసం ఒప్పించడం
PHP తన పనిని పూర్తి చేసి ముగించాలని అనుకుంటుంది. వెబ్ సర్వర్లు అవుట్పుట్ను బఫర్ (buffer) చేసి ఒకేసారి పంపాలని చూస్తాయి. కానీ SSE కి దీనికి విరుద్ధంగా కావాలి: కనెక్షన్ ఓపెన్ అయి ఉండాలి మరియు బైట్లు వచ్చిన వెంటనే ఫ్లష్ (flush) అవ్వాలి. జాగ్రత్త తీసుకోకపోతే, మీ "స్ట్రీమ్" ముప్పై సెకన్ల తర్వాత ఒకే పెద్ద బ్లాక్గా వస్తుంది, దీనివల్ల అసలు ఉద్దేశమే దెబ్బతింటుంది.
TopVideoHub ఈ పైప్ను ఎలా క్లియర్ గా ఉంచారో ఇక్కడ చూడండి.
అవుట్పుట్ బఫరింగ్ను నిలిపివేయండి (Kill output buffering). SSE స్క్రిప్ట్ ప్రారంభంలో, PHP ఎనేబుల్ చేసిన ప్రతి బఫరింగ్ లేయర్ను డిసేబుల్ చేయండి. ఒకవేళ బఫర్ యాక్టివ్గా ఉంటే ob_end_flush()ని కాల్ చేయండి మరియు హెడర్స్ పంపిన తర్వాత ob_implicit_flush(true)తో ఇంప్లిసిట్ ఫ్లషింగ్ను ఆపివేయండి.
ప్రాక్సీలకు వెనక్కి తగ్గమని చెప్పండి (Tell proxies to back off). X-Accel-Buffering: no హెడర్ను పంపండి. Nginx దీనిని వింటుంది. LiteSpeed కూడా దీనిని వింటుంది. ఇది రెస్పాన్స్ను బఫర్ చేయకూడదని లేదా క్యాచబుల్ బ్లాక్గా కంప్రెస్ చేయకూడదని సూచిస్తుంది.
తక్కువ లైఫ్టైమ్ను సెట్ చేయండి (Set a short lifetime). ప్రతి SSE కనెక్షన్ ఒక PHP వర్కర్ను ఆక్రమిస్తుంది. TopVideoHub స్ట్రీమ్లను 55 సెకన్లకు పరిమితం చేస్తుంది. టైమర్ ముగిసినప్పుడు, సర్వర్ ఒక ఫైనల్ కామెంట్ను పంపి, స్ట్రీమ్ను మూసివేస్తుంది మరియు బ్రౌజర్ ఆటోమేటిక్గా రీకనెక్ట్ అవుతుంది. ఆ రీకనెక్షన్ ఒక కొత్త వర్కర్కు వెళ్తుంది, దీనివల్ల ఏ ఒక్క ప్రాసెస్ కూడా శాశ్వతంగా ఆక్రమించబడదు.
కనెక్షన్ సజీవంగా ఉండటానికి పింగ్ చేయండి. ప్రతి ఇరవై సెకన్లకు ఒక కామెంట్ లైన్—: ping వంటిది—పంపండి. SSEలో కామెంట్లు బ్రౌజర్ మెసేజ్ హ్యాండ్లర్ ద్వారా విస్మరించబడతాయి, కానీ అవి TCP కనెక్షన్ను యాక్టివ్గా ఉంచుతాయి. లోడ్ బ్యాలెన్సర్లు మరియు CDNs తరచుగా ముప్పై లేదా అరవై సెకన్ల తర్వాత నిశ్శబ్దంగా ఉన్న కనెక్షన్లను నిలిపివేస్తాయి. ఒక చిన్న న్యూలైన్ (newline) మిమ్మల్ని ఆ సమస్య నుండి కాపాడుతుంది.
యూజర్ ట్యాబ్ను గౌరవించండి. సందర్శకుడు ట్యాబ్ను మినిమైజ్ చేసినా లేదా దాచినా, కనెక్షన్ను నిలిపివేయండి. బ్రౌజర్లో visibilitychange కోసం వేచి చూడండి మరియు eventSource.close()ని కాల్ చేయండి. సర్వర్ కూడా క్లయింట్ డిస్కనెక్ట్ అయినట్లు గుర్తించి, లూప్ను ముగించాలి. PHP లూప్లో connection_aborted() ద్వారా దీనిని తనిఖీ చేయవచ్చు. పది నిమిషాల క్రితమే వెళ్ళిపోయిన వారి కోసం 'ఘోస్ట్ కనెక్షన్స్' (ghost connections) వర్కర్లను వృధా చేయనివ్వకండి.
కఠినమైన పరిమితి: PHP Workers
PHPలో SSE తన పరిమితుల గురించి స్పష్టంగా ఉంటుంది. ప్రతి ఓపెన్ SSE కనెక్షన్ ఒక PHP వర్కర్ను వినియోగిస్తుంది. మీ పూల్లో వంద వర్కర్లు ఉంటే, మీకు వంద స్ట్రీమ్లు మాత్రమే ఉంటాయి. అంతే. మీరు Apache లేదా PHP-FPM ప్రాసెస్ మోడల్లో ఉన్నంత కాలం ఎటువంటి async పరిష్కారం ఉండదు. మీరు pm.max_childrenను సర్దుబాటు చేయవచ్చు, కానీ మెమరీ మరియు CPU అసలైన పరిమితులను నిర్ణయిస్తాయి.
మీరు రెగ్యులర్ పేజీ లోడ్లు, API కాల్స్ మరియు అసెట్ జనరేషన్ కోసం కూడా వర్కర్లను ఉపయోగిస్తుంటే, ఆ పరిమితి త్వరగానే ఎదురవుతుంది. మీ వర్కర్ సాచురేషన్ను జాగ్రత్తగా పర్యవేక్షించండి. అన్ని వర్కర్లు ఇరవై నిమిషాల స్ట్రీమ్లలో నిలిచిపోయి, మీ SSE ఎండ్పాయింట్ క్యూయింగ్ (queuing) చేయడం ప్రారంభిస్తే, మీ వెబ్సైట్ మొత్తం నెమ్మదిస్తుంది.
సంఖ్యలు సరిపోనప్పుడు, వేరే దానికి మారండి. Rust, Node.js లేదా Erlang కూడా అదే పాత్రను పోషించగలవు, కానీ సాధారణంగా తదుపరి దశగా Go ని ఎంచుకుంటారు. Go యొక్క goroutines ఇక్కడ కీలకం. ఒక goroutine కేవలం కొన్ని కిలోబైట్ల మెమరీని మాత్రమే తీసుకుంటుంది. సాధారణ హార్డ్వేర్తో కూడా మీరు ఎటువంటి ఇబ్బంది లేకుండా వేల సంఖ్యలో స్ట్రీమ్లను నిర్వహించవచ్చు. కోర్ లాజిక్ ఒకేలా ఉంటుంది—క్యాష్ నుండి చదవడం, సాకెట్కు రాయడం—కానీ రన్టైమ్ భారీ ప్రాసెస్ల నుండి తేలికపాటి త్రెడ్లకు (lightweight threads) మారుతుంది.
అయితే, అక్కడి నుండే ప్రారంభించకండి. PHP మిమ్మల్ని ఊహించని విధంగా ముందుకు తీసుకెళ్తుంది. మొదట ఉత్పత్తిని (product) పరీక్షించండి. మెట్రిక్స్ పేజీలో డేటాబేస్ ఓవర్లోడ్ బదులు వర్కర్ల కొరత (worker exhaustion) కనిపిస్తే, మీరు ఆ స్టాక్ను దాటి ముందుకు వెళ్లారని అర్థం. అది ఒక మంచి సమస్య.
సారాంశం
లైవ్ కౌంటర్లు కేవలం సాంకేతికత గురించి మాత్రమే కాదు. అవి మీ డేటాబేస్ను మీ స్వంత వినియోగదారుల నుండి రక్షించడం గురించి. SSEతో ప్రారంభించండి ఎందుకంటే ఇది చూసేదాని కంటే సులభం. స్ట్రీమ్ మరియు డేటాబేస్ మధ్య దూకుడుగా (aggressively) క్యాషింగ్ను ఉపయోగించండి, తద్వారా కనెక్షన్ల సంఖ్య క్వెరీల సంఖ్యగా మారకుండా చూడవచ్చు. మీ వర్కర్ పరిమితులను నిశితంగా గమనించండి. మరియు సరళంగా ప్రారంభించండి. PHP సరిపోదు అన్నంత వరకు అది సరిపోతుంది, అప్పటికి మీరు ఎందుకు మళ్లీ రాస్తున్నారో మీకు ఖచ్చితంగా తెలుస్తుంది.
మీ తదుపరి ప్రాజెక్ట్ కోసం:
- డేటా ఒకే దిశలో, అంటే సర్వర్ నుండి బ్రౌజర్కు ప్రవహిస్తున్నప్పుడు SSEని ఉపయోగించండి.
- డేటాబేస్ ముందు ఒక క్యాష్ లేయర్ను ఉంచండి. ప్రతి కొన్ని సెకన్లకు ఒక క్వెరీ చేయడం వేల క్వెరీల కంటే మెరుగైనది.
- SSE కనెక్షన్లను ఒక నిమిషం కంటే తక్కువగా ఉంచి, బ్రౌజర్ మళ్లీ కనెక్ట్ అయ్యేలా చూడండి.
- ట్యాబ్ దాచబడినప్పుడు స్ట్రీమ్లను మూసివేయండి. ఖాళీగా ఉన్న కనెక్షన్ల కోసం లైవ్ వర్కర్లను వృధా చేయకండి.
- PHP వర్కర్ వినియోగాన్ని పర్యవేక్షించండి. మీరు గరిష్ట స్థాయికి చేరుకున్నప్పుడు, స్ట్రీమింగ్ లేయర్ను Go కి మార్చండి.
