స్టేజింగ్ (staging) లో అద్భుతంగా పనిచేసే API, రియల్ ట్రాఫిక్ రాగానే కుప్పకూలిపోవచ్చు. ఈ వైఫల్యం అరుదుగా ఒక్కసారిగా పెద్దగా కనిపించదు. ఇది వేల చిన్న చిన్న సమస్యల వల్ల కలిగే నష్టం (death by a thousand cuts) వంటిది. ఇక్కడ ఒక బ్లాక్ అయిన త్రెడ్ (thread), అక్కడ ఒక అనవసరమైన క్వెరీ (query). తక్కువ లోడ్ ఉన్నప్పుడు, ఈ చిన్న చిన్న అసమర్థతలు కనిపించవు. కానీ ప్రొడక్షన్ ఒత్తిడి పెరిగినప్పుడు, అవి thread pool starvation, డేటాబేస్ చోకింగ్ (choking), మరియు యూజర్ నమ్మకాన్ని దెబ్బతీసే రెస్పాన్స్ టైమ్స్గా మారుతాయి. పెర్ఫార్మెన్స్ ట్యూనింగ్ అంటే ఏదో ఒక మ్యాజిక్ పరిష్కారాన్ని కనుగొనడం కాదు. ప్రతి లేయర్ త్రెడ్స్, మెమరీ మరియు డేటాబేస్ కనెక్షన్ల కొరతను గౌరవించేలా ఒక వ్యవస్థను నిర్మించడం. మీరు ఆ వనరులను పరిమితమైనవిగా (finite) పరిగణించినప్పుడు, సమస్యలు వచ్చినప్పుడు స్పందించడం మానేసి, వాటిని నివారించడం ప్రారంభిస్తారు.
Sync-over-Async మిమ్మల్ని నాశనం చేసేలోపే దానిని అరికట్టండి
హై-ట్రాఫిక్ ASP.NET Core అప్లికేషన్లలో అత్యంత వినాశకరమైన పద్ధతి sync-over-async. ఎవరైనా ఒక అసమ 同 (asynchronous) మెథడ్పై .Result లేదా .Wait()ని కాల్ చేసినప్పుడు మీరు దీనిని చూడవచ్చు; ఎందుకంటే వారికి ఆ విలువ వెంటనే కావాలి మరియు వారు కాల్ స్టాక్ను (call stack) రీఫ్యాక్టర్ చేయకూడదని అనుకుంటారు. ఆ నిర్ణయం కాల్ చేసే త్రెడ్ను బ్లాక్ చేస్తుంది. ఆ త్రెడ్ వేరే చోట జరుగుతున్న పని కోసం వేచి చూస్తూ ఖాళీగా కూర్చుంటుంది, కానీ రన్టైమ్ దానిని మరొక రిక్వెస్ట్ కోసం తిరిగి ఉపయోగించలేదు.
చాలా రిక్వెస్ట్లు ఇలా చేసినప్పుడు, thread pool starvation జరుగుతుంది. మీ CPU గ్రాఫ్ ఆరోగ్యంగా కనిపిస్తుంది ఎందుకంటే ప్రాసెసర్లు బిజీగా లేవు, కానీ మీ లేటెన్సీ (latency) విపరీతంగా పెరుగుతుంది. రిక్వెస్ట్లు క్యూలో నిలిచిపోతాయి, ఎప్పటికీ ఖాళీ కాని త్రెడ్స్ కోసం వేచి చూస్తుంటాయి. దీనికి పరిష్కారం మెకానికల్, కానీ క్రమశిక్షణ అవసరం: కాల్ స్టాక్ అంతటా awaitని ఉపయోగించండి. ఒక మెథడ్ async APIని కాల్ చేస్తే, అది కూడా async గానే ఉండాలి. ఇక్కడ షార్ట్కట్లు లేవు. మీరు తొలగించే ప్రతి సింక్రోనస్ బ్లాకేజ్, రియల్ ట్రాఫిక్ కోసం అదనపు సామర్థ్యాన్ని (headroom) అందిస్తుంది.
డిస్కనెక్ట్ అయిన క్లయింట్ల కోసం పనిని వృథా చేయడం ఆపండి
క్లయింట్లు డిస్కనెక్ట్ అవుతుంటారు. బ్రౌజర్లు ట్యాబ్లను మూసివేస్తుంటాయి. మొబైల్ యాప్లు సిగ్నల్ కోల్పోతుంటాయి. క్లయింట్ వెళ్ళిపోయారని మీ సర్వర్కు తెలియకపోతే, అది డేటాబేస్ క్వెరీలను రన్ చేస్తూ, JSONని పార్స్ చేస్తూ, ఎవరూ చూడని రెస్పాన్స్ కోసం త్రెడ్స్ను వృథా చేస్తూనే ఉంటుంది. ఇది సపోర్ట్ చేసే ప్రతి async ఆపరేషన్లో CancellationTokenని పంపండి. అంటే Entity Framework క్వెరీల నుండి, HttpClientతో చేసే HTTP కాల్స్ వరకు మరియు ఏదైనా లాంగ్-రన్నింగ్ బ్యాక్గ్రౌండ్ వర్క్ వరకు.
కనెక్షన్ కట్ అయినప్పుడు, టోకెన్ క్యాన్సిలేషన్ను ట్రిగ్గర్ చేస్తుంది మరియు పని వెంటనే ఆగిపోతుంది. ఇది డేటాబేస్ CPU సైకిల్స్ను ఆదా చేస్తుంది మరియు త్రెడ్స్ను త్వరగా పూల్కు తిరిగి పంపిస్తుంది. ఇది మెథడ్ సిగ్నేచర్లలో చేసే చిన్న మార్పు, కానీ లోడ్ ఉన్నప్పుడు గొప్ప ఫలితాలను ఇస్తుంది.
మార్పు లేని వాటిని క్యాష్ (Cache) చేయండి
మీ ప్రొడక్ట్ క్యాటలాగ్ ప్రతి రిక్వెస్ట్ మధ్య మారకపోవచ్చు. మీ కాన్ఫిగరేషన్ ఫ్లాగ్స్ (configuration flags) ఖచ్చితంగా మారవు. అయినప్పటికీ, చాలా APIలు ఒకే స్టాటిక్ డేటా కోసం పదేపదే డేటాబేస్ను హిట్ చేస్తాయి. ASP.NET Coreలోని అవుట్పుట్ క్యాషింగ్ (Output caching), మీరు రెండర్ చేసిన రెస్పాన్స్లను స్టోర్ చేసుకోవడానికి మరియు మీ కంట్రోలర్లను లేదా డేటాబేస్ను మళ్ళీ తాకకుండా నేరుగా మెమరీ నుండి అందించడానికి అనుమతిస్తుంది.
ట్యాగ్-బేస్డ్ ఇన్వాలిడేషన్ (tag-based invalidation)ను జాగ్రత్తగా ఉపయోగించండి. మీరు ఒక ప్రొడక్ట్ను అప్డేట్ చేసినప్పుడు, ఆ కేటగిరీ లేదా ఐటెమ్కు సంబంధించిన ట్యాగ్ను మాత్రమే ఇన్వాలిడేట్ చేయండి. మీరు మొత్తం క్యాచీని క్లియర్ చేయాల్సిన అవసరం లేదు. ఇది మీ క్యాష్ హిట్ రేషియోను (cache hit ratio) ఎక్కువగా మరియు డేటాబేస్ క్వెరీ కౌంట్ను తక్కువగా ఉంచుతుంది.
ముందుగా మీ డేటా యాక్సెస్ను సరిచేయండి
చాలా APIలలో డేటాబేస్ కాల్స్ రిక్వెస్ట్ సమయంలో ఎక్కువ భాగాన్ని తీసుకుంటాయి. మీరు వేరే దేనినైనా ఆప్టిమైజ్ చేసే ముందు, ఇక్కడ చూడండి.
మీరు డేటాను కేవలం ప్రదర్శించడానికి మాత్రమే క్వెరీ చేస్తున్నట్లయితే మరియు దానిని ఎప్పుడూ అప్డేట్ చేయాలని ప్లాన్ చేయకపోతే, మీ Entity Framework క్వెరీలకు AsNoTracking()ని జోడించండి. EF Core, చేంజ్ ట్రాకింగ్ (change tracking) మరియు స్నాప్షాట్ క్రియేషన్ను స్కిప్ చేస్తుంది.
