സ്റ്റേജിംഗിൽ (staging) സുഗമമായി പ്രവർത്തിക്കുന്ന ഒരു API, യഥാർത്ഥ ട്രാഫിക് എത്തുന്ന നിമിഷം തകർന്നടിയാം. ഈ പരാജയം പലപ്പോഴും പെട്ടെന്നുള്ള ഒന്നായിരിക്കില്ല. അത് ചെറിയ ചെറിയ പ്രശ്നങ്ങൾ അടിഞ്ഞുകൂടി ഉണ്ടാകുന്ന വലിയൊരു തകർച്ചയാണ്. ഇവിടെ ഒരു ബ്ലോക്ക്ഡ് ത്രെഡും (blocked thread), അവിടെ ഒരു അനാവശ്യ ക്വറിയും (redundant query). കുറഞ്ഞ ലോഡ് ഉള്ളപ്പോൾ ഈ ചെറിയ കാര്യക്ഷമതയില്ലായ്മകൾ ശ്രദ്ധിക്കപ്പെടില്ല. എന്നാൽ പ്രൊഡക്ഷൻ സമ്മർദ്ദത്തിൽ, അവ ത്രെഡ് പൂൾ സ്റ്റാർവേഷൻ (thread pool starvation), ഡാറ്റാബേസ് ചോക്കിംഗ് (database choking), ഉപഭോക്താക്കളുടെ വിശ്വാസം തകർക്കുന്ന റെസ്‌പോൺസ് ടൈം (response times) എന്നിവയായി മാറുന്നു. പെർഫോമൻസ് ട്യൂണിംഗ് എന്നാൽ ഒരു മാന്ത്രിക പരിഹാരം കണ്ടെത്തലല്ല. മറിച്ച്, ത്രെഡുകൾ, മെമ്മറി, ഡാറ്റാബേസ് കണക്ഷനുകൾ എന്നിവയുടെ പരിമിതികളെ ഓരോ ലെയറും ബഹുമാനിക്കുന്ന ഒരു സിസ്റ്റം നിർമ്മിക്കലാണ്. ഈ വിഭവങ്ങൾ പരിമിതമാണെന്ന് നിങ്ങൾ തിരിച്ചറിയുമ്പോൾ, തകരാറുകൾ സംഭവിക്കുമ്പോൾ പ്രതികരിക്കുന്നതിന് പകരം അവ തടയാൻ നിങ്ങൾക്ക് സാധിക്കും.

Sync-over-Async നിങ്ങളെ തകർത്തതിന് മുൻപ് അതിനെ ഇല്ലാതാക്കൂ

ഉയർന്ന ട്രാഫിക്കുള്ള ASP.NET Core ആപ്ലിക്കേഷനുകളിലെ ഏറ്റവും വിനാശകരമായ രീതിയാണ് sync-over-async. ആന്തരികമായി ഒരു അസിൻക്രണസ് (asynchronous) മെത്തേഡിന്റെ വാല്യൂ ഇപ്പോൾ തന്നെ വേണമെന്നും കോൾ സ്റ്റാക്ക് (call stack) റീഫാക്ടർ ചെയ്യാൻ താല്പര്യമില്ലെന്നും കരുതി ഒരാൾ .Result അല്ലെങ്കിൽ .Wait() ഉപയോഗിക്കുമ്പോഴാണ് ഇത് സംഭവിക്കുന്നത്. ആ തീരുമാനം കോൾ ചെയ്യുന്ന ത്രെഡിനെ ബ്ലോക്ക് ചെയ്യുന്നു. ആ ത്രെഡ് വെറുതെ ഇരിക്കുകയാണ്, മറ്റൊരിടത്ത് നടന്നുകൊണ്ടിരിക്കുന്ന ഒരു ജോലിക്കായി കാത്തിരിക്കുന്നു, എന്നാൽ റൺടൈമിന് (runtime) അത് മറ്റൊരു റിക്വസ്റ്റിനായി വീണ്ടും ഉപയോഗിക്കാൻ കഴിയില്ല.

ആവശ്യത്തിന് റിക്വസ്റ്റുകൾ ഇങ്ങനെ ചെയ്യുമ്പോൾ, ത്രെഡ് പൂൾ ശൂന്യമാകുന്നു (thread pool starves). പ്രോസസറുകൾ തിരക്കിലല്ലാത്തതിനാൽ നിങ്ങളുടെ CPU ഗ്രാഫ് ആരോഗ്യകരമായി കാണപ്പെട്ടേക്കാം, എന്നാൽ ലേറ്റൻസി (latency) കുതിച്ചുയരും. ഒരിക്കലും ഒഴിവുണ്ടാകാത്ത ത്രെഡുകൾക്കായി റിക്വസ്റ്റുകൾ ക്യൂവിൽ നിൽക്കും. ഇതിനുള്ള പരിഹാരം ലളിതമാണ് എന്നാൽ അച്ചടക്കം ആവശ്യമാണ്: കോൾ സ്റ്റാക്കിന്റെ മുകളിൽ വരെ await ഉപയോഗിക്കുക. ഒരു മെത്തേഡ് ഒരു async API വിളിക്കുന്നുണ്ടെങ്കിൽ, അത് സ്വയം async ആയിരിക്കണം. ഇവിടെ കുറുക്കുവഴികളില്ല. നിങ്ങൾ നീക്കം ചെയ്യുന്ന ഓരോ സിൻക്രണസ് തടസ്സവും യഥാർത്ഥ ട്രാഫിക്കിനായി കൂടുതൽ സൗകര്യങ്ങൾ നൽകുന്നു.

ഡിസ്കണക്ട് ആയ ക്ലയന്റുകൾക്കായി സമയം പാഴാക്കുന്നത് നിർത്തുക

ക്ലയന്റുകൾ ഡിസ്കണക്ട് ആകുന്നു. ബ്രൗസറുകൾ ടാബുകൾ അടയ്ക്കുന്നു. മൊബൈൽ ആപ്പുകൾ സിഗ്നൽ നഷ്ടപ്പെടുന്നു. ക്ലയന്റ് പോയി എന്ന് നിങ്ങളുടെ സെർവറിന് അറിയില്ലെങ്കിൽ, ആരും സ്വീകരിക്കാത്ത ഒരു റെസ്‌പോൺസിനായി അത് ഡാറ്റാബേസ് ക്വറികൾ പ്രവർത്തിച്ചുകൊണ്ടും, JSON പാഴ്സ് ചെയ്തുകൊണ്ടും, ത്രെഡുകൾ ഉപയോഗിച്ചുകൊണ്ടും സമയം പാഴാക്കും. സപ്പോർട്ട് ചെയ്യുന്ന എല്ലാ async ഓപ്പറേഷനുകളിലേക്കും ഒരു CancellationToken പാസ്സ് ചെയ്യുക. അതായത് Entity Framework ക്വറികൾ, HttpClient ഉപയോഗിച്ചുള്ള HTTP കോളുകൾ, കൂടാതെ ദീർഘനേരം നീണ്ടുനിൽക്കുന്ന ബാക്ക്ഗ്രൗണ്ട് ജോലികൾ എന്നിവയെല്ലാം ഇതിൽ ഉൾപ്പെടുന്നു.

കണക്ഷൻ നഷ്ടപ്പെടുമ്പോൾ, ടോക്കൺ ക്യാൻസലേഷൻ (cancellation) ട്രിഗർ ചെയ്യുകയും ജോലി ഉടൻ തന്നെ നിൽക്കുകയും ചെയ്യുന്നു. ഇത് ഡാറ്റാബേസ് CPU സൈക്കിളുകൾ സംരക്ഷിക്കുകയും ത്രെഡുകളെ വേഗത്തിൽ പൂളിലേക്ക് തിരികെ എത്തിക്കുകയും ചെയ്യുന്നു. മെത്തേഡ് സിഗ്നേച്ചറുകളിൽ വരുത്തുന്ന ചെറിയൊരു മാറ്റം ലോഡ് സമയത്ത് വലിയ ഗുണം നൽകുന്നു.

മാറ്റമില്ലാത്ത കാര്യങ്ങൾ കാഷെ (Cache) ചെയ്യുക

നിങ്ങളുടെ പ്രൊഡക്റ്റ് കാറ്റലോഗ് (product catalog) ഓരോ റിക്വസ്റ്റിനിടയിലും മാറണമെന്നില്ല. കോൺഫിഗറേഷൻ ഫ്ലാഗുകൾ (configuration flags) തീർച്ചയായും മാറില്ല. എന്നിട്ടും പല API-കളും ഒരേ സ്റ്റാറ്റിക് ഡാറ്റയ്ക്കായി വീണ്ടും വീണ്ടും ഡാറ്റാബേസിനെ സമീപിക്കുന്നു. ASP.NET Core-ലെ ഔട്ട്പുട്ട് കാഷിംഗ് (Output caching), റെൻഡർ ചെയ്ത റെസ്‌പോൺസുകൾ സ്റ്റോർ ചെയ്യാനും നിങ്ങളുടെ കൺട്രോളറുകളെയോ ഡാറ്റാബേസിനെയോ വീണ്ടും സ്പർശിക്കാതെ തന്നെ അവ നേരിട്ട് മെമ്മറിയിൽ നിന്ന് നൽകാനും നിങ്ങളെ അനുവദിക്കുന്നു.

ടാഗ് അടിസ്ഥാനമാക്കിയുള്ള ഇൻവാലിഡേഷൻ (tag-based invalidation) ശ്രദ്ധയോടെ ഉപയോഗിക്കുക. ഒരു പ്രൊഡക്റ്റ് അപ്‌ഡേറ്റ് ചെയ്യുമ്പോൾ, ആ കാറ്റഗറിയുമായോ ഐറ്റവുമായോ ബന്ധപ്പെട്ട ടാഗ് മാത്രം ഇൻവാലിഡ് ആക്കുക. മുഴുവൻ കാഷെയും ക്ലിയർ ചെയ്യേണ്ടതില്ല. ഇത് നിങ്ങളുടെ കാഷെ ഹിറ്റ് റേഷ്യോ (cache hit ratio) ഉയർത്താനും ഡാറ്റാബേസ് ക്വറി എണ്ണം കുറയ്ക്കാനും സഹായിക്കുന്നു.

ആദ്യം നിങ്ങളുടെ ഡാറ്റാ ആക്സസ് (Data Access) ശരിയാക്കുക

മിക്ക API-കളിലും ഡാറ്റാബേസ് കോളുകളാണ് റിക്വസ്റ്റ് സമയത്തിന്റെ ഭൂരിഭാഗവും എടുക്കുന്നത്. മറ്റെന്തും ഒപ്റ്റിമൈസ് ചെയ്യുന്നതിന് മുമ്പ്, ഇവിടെ ശ്രദ്ധിക്കുക.

ഡാറ്റ പ്രദർശിപ്പിക്കാൻ വേണ്ടി മാത്രമാണ് നിങ്ങൾ ക്വറി ചെയ്യുന്നതെങ്കിൽ, അത് ഒരിക്കലും അപ്‌ഡേറ്റ് ചെയ്യാൻ ഉദ്ദേശിക്കുന്നില്ലെങ്കിൽ, നിങ്ങളുടെ Entity Framework ക്വറികളിൽ AsNoTracking() ചേർക്കുക. EF Core ചേഞ്ച് ട്രാക്കിംഗും (change tracking) സ്നാപ്പ്ഷോട്ട് നിർമ്മാണവും ഒഴിവാക്കുന്നു.