ബ്ലോഗ്

ഒരൊറ്റ ഭാരമുള്ള ചാറ്റിന് ഞങ്ങളുടെ API-യെ എങ്ങനെ തകർക്കാനാകുമായിരുന്നു

സെപ്റ്റംബർ 28-ന്, ഒരു റിലീസിന് ഏകദേശം 17 മിനിറ്റ് കഴിഞ്ഞ്, ഞങ്ങളുടെ രണ്ട് പ്രൊഡക്ഷൻ API സെർവറുകളും ഒരേ നിമിഷത്തിൽ മെമ്മറി തീർന്ന് റീസ്റ്റാർട്ട് ആയി, ഏകദേശം അഞ്ച് മിനിറ്റ് നേരത്തേക്ക് load balancer-ന് ട്രാഫിക് അയയ്ക്കാൻ ആരോഗ്യമുള്ള ഒരു സെർവറും ഉണ്ടായിരുന്നില്ല. ഞങ്ങളുടെ ആദ്യ പരിഹാരം API-ക്ക് ഇരട്ടി മെമ്മറി നൽകുകയായിരുന്നു. യഥാർത്ഥ കാരണം അന്ന് തന്നെ പിന്നീട് കണ്ടെത്തി: ഒരു പ്രത്യേക ചാറ്റ് തുറക്കുമ്പോൾ API ഒറ്റ അഭ്യർത്ഥനയിൽ 53 MB സന്ദേശങ്ങൾ ലോഡ് ചെയ്യാൻ ആവശ്യപ്പെട്ടു. ചാറ്റ് ചരിത്രം ഇപ്പോൾ എണ്ണം മാത്രമല്ല, വലിപ്പവും അനുസരിച്ചുള്ള പേജുകളിലാണ് ലോഡ് ചെയ്യുന്നത്, ആ ചാറ്റ് ഇപ്പോൾ ക്രാഷ് ചെയ്യുന്നതിന് പകരം 5 MB ആദ്യ പേജോടെ തുറക്കുന്നു.

എന്താണ് തകർന്നത്

ഞങ്ങളുടെ API ഒരു load balancer-ന് പിന്നിൽ രണ്ട് സെർവറുകളിലും ഓരോന്നിലും ഒരു container ആയി ആണ് പ്രവർത്തിക്കുന്നത്. ഓരോ container-നും 384 MiB മെമ്മറി പരിധിയുണ്ടായിരുന്നു. വിശ്രമത്തിലിരിക്കുമ്പോൾ അത് 130–140 MiB ഉപയോഗിക്കുന്നു, അതിനാൽ പരിധി ധാരാളം ഇടമുള്ളതായി തോന്നി.

രണ്ട് container-കളും ഒരുമിച്ച് ആ പരിധിയിൽ എത്തി, "JavaScript heap out of memory" എന്ന സന്ദേശത്തോടെ ക്രാഷ് ചെയ്തു. Node.js പ്രക്രിയ പ്രവർത്തിക്കുന്ന objects-ന് ഉപയോഗിക്കുന്ന മെമ്മറിയാണ് heap. രണ്ട് സെർവറുകളും ഒരേസമയം പരാജയപ്പെട്ടതിനാൽ അഭ്യർത്ഥനകൾ അയയ്ക്കാൻ ഒരിടവും ബാക്കിയുണ്ടായിരുന്നില്ല. രണ്ട് സെർവർ സജ്ജീകരണത്തിന് ഇത് ഏറ്റവും മോശമായ തരം outage ആണ്: ഒരു സെർവർ നശിച്ചാൽ മാത്രമേ അധിക സെർവർ സഹായിക്കൂ, പരാജയങ്ങൾ ഒരേ സമയം വന്നാൽ ഇല്ല.

ആദ്യ പരിഹാരം: കൂടുതൽ ഇടം

സമയം ഒരു റിലീസിലേക്കാണ് വിരൽ ചൂണ്ടിയത്. ഒരു റിലീസിന് ശേഷം, deploy തടസ്സപ്പെടുത്തിയ agent turns വീണ്ടും തുടങ്ങുകയും അവരുടെ transcripts വീണ്ടും സേവ് ചെയ്യുകയും ചെയ്യുന്നു, ആ പണിയുടെ കൂട്ടം മെമ്മറി സ്പൈക്കിന്റെ വ്യക്തമായ കാരണമായി തോന്നി.

അതിനാൽ ആദ്യ മാറ്റം API-യുടെ പരിധി 384 MiB-ൽ നിന്ന് 768 MiB ആക്കി ഉയർത്തുകയായിരുന്നു. അതേ ദിവസം തന്നെ രണ്ട് സെർവറുകളിലും ലൈവ് ആയി പ്രയോഗിച്ചു, അടുത്ത deploy 384 നിശബ്ദമായി തിരികെ കൊണ്ടുവരാതിരിക്കാൻ deploy കോൺഫിഗറേഷനിലും കമ്മിറ്റ് ചെയ്തു. കൈകൊണ്ട് ഒരു സെർവറിൽ ചെയ്ത പരിഹാരം അടുത്ത deploy മാറ്റിമറിക്കുന്നത് ഒരേ outage തിരിച്ചുവരാനുള്ള സാധാരണ വഴിയാണ്.

കൂടുതൽ മെമ്മറി ഒരു നല്ല സുരക്ഷാ മാർജിൻ ആയിരുന്നു. അത് ഒരു വിശദീകരണമായിരുന്നില്ല.

യഥാർത്ഥ കാരണം: ഒരു അഭ്യർത്ഥന, 71 MB

അതേ ദിവസം പിന്നീട്, ഒരു ചാറ്റിന്റെ പകർപ്പിൽ ക്രാഷ് പുനഃസൃഷ്ടിച്ചു, പ്രൊഡക്ഷന്റെ പഴയ മെമ്മറി പരിധി ഉപയോഗിച്ച്. ആ പകർപ്പ് deploy ഒന്നും ഉൾപ്പെടാതെ തന്നെ API-യെ സ്വയം ക്രാഷ് ചെയ്തു.

നിങ്ങൾ ഒരു പ്രോജക്റ്റ് തുറക്കുമ്പോൾ, വെബ് ആപ്പ് ചാറ്റിന്റെ ചരിത്രത്തിനായി API-യോട് ചോദിക്കുന്നു. എൻഡ്പോയിന്റ് ഏറ്റവും പുതിയ 30 സന്ദേശങ്ങൾ മുഴുവനായി തിരികെ നൽകി. മിക്ക ചാറ്റുകൾക്കും 30 സന്ദേശം ചെറുതാണ്. ഈ ചാറ്റിൽ, ഏറ്റവും പുതിയ 30 സന്ദേശങ്ങൾ database-ൽ 53 MB ഉം ഒരു 71 MB പ്രതികരണവും ആയിരുന്നു. Agent-ന്റെ മറുപടികളിൽ പലതും 4–10 MB വീതമായിരുന്നു, മിക്കവയും sub-agents-ന്റെ transcripts ആയിരുന്നു: ഒരു ജോലിയുടെ ഭാഗം സമാന്തരമായി ചെയ്യാൻ പ്രധാന agent തുടങ്ങുന്ന സഹായി agents, അവരുടെ പൂർണ്ണ ജോലി മറുപടിയോടൊപ്പം സേവ് ചെയ്യപ്പെടുന്നു.

ആ ഒരു പ്രതികരണം നിർമ്മിക്കാൻ API-ക്ക് ഉണ്ടായിരുന്നതിനെക്കാൾ കൂടുതൽ heap വേണ്ടിവന്നു. ആ പ്രോജക്റ്റ് തുറക്കുന്ന ഓരോ തവണയും, അല്ലെങ്കിൽ റീഫ്രഷ് ചെയ്യുമ്പോഴും, അഭ്യർത്ഥന വീണ്ടും അയച്ചു. ഒരൊറ്റ ചാറ്റിന് അത് എത്തിച്ചേർന്ന ഏത് സെർവറിനെയും തകർക്കാൻ കഴിയുമായിരുന്നു, പേജ് റീലോഡ് ചെയ്യാമായിരുന്നതിനാൽ അത് രണ്ടിലും എത്താനും കഴിയുമായിരുന്നു.

"30 സന്ദേശങ്ങൾ" ഒരിക്കലും യഥാർത്ഥ വലിപ്പ പരിധി ആയിരുന്നില്ല. സാധാരണ ചാറ്റുകൾക്ക് ചെറുതായതിനാൽ മാത്രം ചെറുതായി തോന്നിയ എണ്ണത്തിന്റെ പരിധിയായിരുന്നു അത്.

പരിഹാരം: വലിപ്പവും എണ്ണവും അനുസരിച്ചുള്ള പേജുകൾ

ചരിത്രത്തിന്റെ ഒരു പേജ് ഇപ്പോൾ 30 സന്ദേശങ്ങൾ അല്ലെങ്കിൽ അവയുടെ ഏകദേശം 4 MB, ഏതാണ് ആദ്യം വരുന്നത് അത്.

ഇത് രണ്ട് ഘട്ടങ്ങളിലാണ് പ്രവർത്തിക്കുന്നത്:

  1. ആദ്യം വലിപ്പങ്ങൾ ചോദിക്കുക. ഏറ്റവും പുതിയ സന്ദേശങ്ങളുടെ ID-കളും സംഭരിച്ച വലിപ്പങ്ങളും ഉള്ളടക്കമില്ലാതെ API database-നോട് ചോദിക്കുന്നു. സന്ദേശങ്ങൾ എത്ര വലുതായാലും ആ query വിലകുറഞ്ഞതാണ്.
  2. യോജിക്കുന്നത് മാത്രം ലോഡ് ചെയ്യുക. പുതിയതിൽ നിന്ന് പഴയതിലേക്ക് നീങ്ങി, അടുത്ത സന്ദേശം പേജിനെ 4 MB കടത്തിവെട്ടുന്നതുവരെ ചേർക്കുന്നു. ആ വരികൾ മാത്രമാണ് പിന്നീട് പൂർണ്ണമായി ലോഡ് ചെയ്യുന്നത്.

ഇത് സുരക്ഷിതമാക്കുന്ന രണ്ട് നിയമങ്ങളുണ്ട്:

  • ഏറ്റവും പുതിയ സന്ദേശം എപ്പോഴും പേജിൽ ഉണ്ടാകും, അത് എത്ര വലുതായാലും. ഒന്നും തിരികെ നൽകാത്ത ഒരു പേജ് ചാറ്റിനെ കുടുക്കും, പിന്നോട്ട് സ്ക്രോൾ ചെയ്യാൻ ഒരു വഴിയുമില്ലാതെ.
  • ഒന്നും മുറിക്കില്ല. ഒരു സന്ദേശവും ചുരുക്കുകയോ ഒഴിവാക്കുകയോ ചെയ്യുന്നില്ല. ചാറ്റിന്റെ ബാക്കി ഭാഗം പഴയ സന്ദേശങ്ങൾ ഇതിനകം ഉപയോഗിച്ചിരുന്ന "Scroll up for earlier messages" നിയന്ത്രണത്തിലൂടെ, ഒരു സമയം ഒരു പേജ് വീതം ലോഡ് ചെയ്യുന്നു.

ഇതേ രൂപത്തിലുള്ള മറ്റൊരിടം കൂടി ഞങ്ങൾ കണ്ടെത്തി. ഒരു turn നിർത്തുമ്പോൾ, ശൂന്യമായ മറുപടികൾ ഉണ്ടോ എന്നും വൃത്തിയാക്കേണ്ടതുണ്ടോ എന്നും API അവസാനത്തെ കുറച്ച് മറുപടികൾ പരിശോധിക്കുന്നു. അതിനായി അത് എട്ട് മുഴുവൻ സന്ദേശങ്ങൾ ലോഡ് ചെയ്തിരുന്നു. ബഹുമെഗാബൈറ്റ് മറുപടികളുള്ള ഒരു ചാറ്റിൽ ഇത് ചെറിയ രൂപത്തിലുള്ള അതേ പ്രശ്നമാണ്. ഇപ്പോൾ അത് database-നോട് ഒരു അതെ-അല്ല ചോദ്യം ചോദിക്കുന്നു — ഈ സന്ദേശത്തിന് എന്തെങ്കിലും ഉള്ളടക്കമുണ്ടോ? — ഉള്ളടക്കം തന്നെ ലോഡ് ചെയ്യാതെ.

ഞങ്ങൾ എങ്ങനെ പരിശോധിച്ചു

പകർപ്പ് ചാറ്റിൽ, പഴയ 384 MiB പരിധിയിൽ പ്രവർത്തിപ്പിച്ചപ്പോൾ:

  • ആദ്യ പേജ് 5 MB ആണ്. മുമ്പ് ഇതേ അഭ്യർത്ഥന API-യെ ക്രാഷ് ചെയ്തിരുന്നു.
  • ഒരേ സമയം ചാറ്റ് തുറക്കുന്ന അഞ്ച് ബ്രൗസർ ടാബുകളുടെ പീക്ക് മെമ്മറി 154 MB ആണ്.
  • ചാറ്റിന്റെ മുഴുവൻ പിന്നോട്ട് സ്ക്രോൾ ചെയ്യുമ്പോൾ എല്ലാ 190 സന്ദേശങ്ങളും ഓരോന്നും ഒരു തവണ മാത്രം, ക്രമത്തിൽ തിരികെ വരുന്നു.

പേജ് തിരഞ്ഞെടുക്കുന്ന ലോജിക്കിനും unit tests ഉണ്ട്, ആ ചാറ്റിലെ ഏറ്റവും പുതിയ സന്ദേശങ്ങളുടെ യഥാർത്ഥ വലിപ്പങ്ങളിൽ നിന്ന് നിർമ്മിച്ച ഒന്ന് ഉൾപ്പെടെ. ആദ്യ പേജിൽ ഒരു സന്ദേശം വരുന്നു, കൂടുതൽ ഉണ്ടെന്ന് പറയുന്നു, അടുത്ത പേജ് അതിന് ശേഷമുള്ളതിൽ നിന്ന് തുടങ്ങുന്നു.

ഞങ്ങൾ ഇതിൽ നിന്ന് പഠിച്ചത്

  • എണ്ണം വലിപ്പ പരിധിയല്ല. വലുതാകാൻ കഴിയുന്ന എന്തിന്റെയെങ്കിലും "ഏറ്റവും പുതിയ N" തിരികെ നൽകുന്ന ഏത് endpoint-നും ഒരു byte budget വേണം. ഡാറ്റ ഒടുവിൽ ആ വിടവ് കണ്ടെത്തും.
  • വ്യക്തമായ സംശയിതം എപ്പോഴും കാരണമാകണമെന്നില്ല. Deploy അധിക ജോലിക്ക് ഒരു യഥാർത്ഥ trigger ആയിരുന്നു, കൂടുതൽ മെമ്മറിയും വിലപ്പെട്ടതായിരുന്നു. എന്നാൽ deploy ഇല്ലാതെയും ക്രാഷ് ആവർത്തിച്ചു, അത് പുനഃസൃഷ്ടിക്കാതിരുന്നെങ്കിൽ മെമ്മറി വർദ്ധന കൊണ്ട് നിർത്തുമായിരുന്നു.
  • ഒരേ അഭ്യർത്ഥന ലഭിക്കുമ്പോൾ രണ്ട് സെർവറുകളും ഒരുമിച്ച് പരാജയപ്പെടുന്നു. ഒരു സെർവർ നശിക്കുന്നതിൽ നിന്നാണ് redundancy സംരക്ഷിക്കുന്നത്. ഏത് സെർവറിൽ എത്തിയാലും അതിനെ കൊല്ലുന്ന ഒരു അഭ്യർത്ഥനയിൽ നിന്ന് അത് സംരക്ഷിക്കില്ല, പ്രത്യേകിച്ച് ഉപയോക്താവ് പേജ് റീഫ്രഷ് ചെയ്ത് സ്വാഭാവികമായി വീണ്ടും ശ്രമിക്കുന്ന ഒന്നിനെ.
  • സെർവറിൽ മാത്രമല്ല, കോൺഫിഗറേഷനിലും ശരിയാക്കുക. മെമ്മറി വർദ്ധന അതേ ദിവസം തന്നെ deploy കോൺഫിഗറേഷനിൽ ചേർത്തു, അതിനാൽ അടുത്ത deploy അത് നിലനിർത്തി.

ഇത് ഞങ്ങളുടെ agent-ന്റെ ഔട്ട്പുട്ട് ഉൾപ്പെടുന്ന ഈയിടെയുള്ള രണ്ടാമത്തെ മെമ്മറി കഥയാണ്. ആദ്യത്തേത് 690 MB സ്ട്രിംഗുകൾ ക്യൂ ചെയ്ത ഒരു status label ആയിരുന്നു. Mythex-ൽ sub-agents ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, അവ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് ഡോക്സിൽ വായിക്കാം.

Mythex · Pricing · AI ഉപയോഗിച്ച് എന്തും നിർമ്മിക്കൂ · വെബ്‌സൈറ്റ്, ആപ്പ് ടെംപ്ലേറ്റുകൾ · Mythex താരതമ്യം · AI ആപ്പ് നിർമ്മാണ ഗ്ലോസറി · സൗജന്യ AI ആപ്പ് നിർമ്മാണ ടൂളുകൾ · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)