systemd-ல் Process Memory, CPU வரம்பை அமைப்பது எப்படி
VPS முழுவதும் முடங்காமல் இருக்க systemd unit-ல் MemoryHigh, MemoryMax, CPUQuota, TasksMax அமைக்கவும். OOM kill ஏற்பட்டதா என்பதை log-ல் சரிபார்க்கவும்.
systemd drop-in மூலம் process memory மற்றும் CPU-ஐ வரம்பிடுதல்
Process-ஐ இயக்கும் unit-ல் சில வரிகளைச் சேர்ப்பதன் மூலம் Linux VPS-ல் அதன் memory மற்றும் CPU பயன்பாட்டை வரம்பிடலாம். MemoryMax= என்பது memory-க்கான கடினமான உச்சவரம்பாகும். CPUQuota= என்பது processor time-க்கான உச்சவரம்பாகும். இவை இரண்டும் cgroup v2 (control groups, version 2) மூலம் அமல்படுத்தப்படுகின்றன. ஒவ்வொரு service-ஐயும் அந்த system-ல் கணக்கிட systemd ஏற்கனவே பயன்படுத்தும் kernel அம்சமே இது.
sudo systemctl edit myapp.serviceComments-ல் உள்ள instructions-உடன் ஒரு drop-in file திறக்கும். அவற்றுக்கு மேலே இதைச் சேர்க்கவும்:
[Service]
MemoryHigh=512M
MemoryMax=768M
MemorySwapMax=0
CPUQuota=80%
TasksMax=128sudo systemctl daemon-reload
sudo systemctl restart myapp.service
systemctl show myapp.service -p MemoryHigh -p MemoryMax -p CPUQuotaPerSecUSec -p TasksMaxsystemctl show, நீங்கள் உள்ளிட்ட numbers-ஐ kernel பயன்படுத்தும் சொந்த units-ல் மீண்டும் காட்ட வேண்டும்: MemoryMax=805306368 மற்றும் CPUQuotaPerSecUSec=800ms. அது MemoryMax=infinity என்று காட்டினால், drop-in load ஆகவில்லை. File /etc/systemd/system/myapp.service.d/override.conf என்ற இடத்தில் உருவாகியுள்ளதா என்பதைச் சரிபார்க்கவும். அது [Service] header-ல் தொடங்குகிறதா என்பதையும் உறுதிப்படுத்தவும். ஏனெனில் அதற்கு முன் section இல்லாமல் settings line இருந்தால், systemd Assignment outside of section. Ignoring. என்று log செய்து, எந்த limits-உம் இல்லாமல் service-ஐத் தொடங்கும்.
இந்த numbers-ஐ எவ்வாறு தேர்வு செய்வது, அவற்றை அமைத்த பிறகும் எந்தப் பிரச்சினைகள் ஏற்படலாம் என்பதே இந்த guide-ன் மீதமுள்ள பகுதி.
runaway process VPS-ஐ ஏன் முழுமையாக நிரப்பாமலேயே முடக்குகிறது
கடுமையான memory cap-ஐ அடையும் process சுமார் ஒரு second-ல் நிறுத்தப்பட்டு, அந்த service மீண்டும் தொடங்கும். இது நல்ல நிலை. மோசமான நிலை என்பது எதுவும் நிறுத்தப்படாத நிலை: box ping-க்கு பதிலளிக்கும், SSH connection-ஐ ஏற்றுக்கொள்ளும், ஆனால் shell prompt ஒருபோதும் வராது. Machine இயங்கிக்கொண்டே இருக்கும்; ஆனால் அந்தப் பணிகளில் எதுவும் பயனுள்ளதாக இருக்காது.
இது எவ்வாறு நடக்கிறது என்பதைப் பார்ப்போம். காரணம் உடனடியாகத் தெளிவாக இருக்காது. Free memory குறையும்போது, kernel புதிய memory-ஐ வழங்குவதற்குப் பதிலாக pages-ஐ reclaim செய்கிறது. Reclaim செய்ய மிகவும் குறைந்த செலவுடைய pages file-backed pages ஆகும்; இயங்கிக்கொண்டிருக்கும் அனைத்தின் executable code-ஐ page cache வைத்திருக்கும். எனவே kernel sshd-ன் text pages-ஐ வெளியேற்றுகிறது. அடுத்ததாக sshd இயக்கும் instruction, storage-இலிருந்து அந்த bytes-ஐ மீண்டும் படிக்க வேண்டிய page fault ஆகிறது. ஒவ்வொரு process-மும் இயங்குவதற்குப் பதிலாக disk-க்காக காத்திருக்கிறது. அதே pages மீண்டும் மீண்டும் வெளியேறி திரும்புகின்றன. இந்த நிலையே thrashing எனப்படுகிறது.
Laptop-ஐ விட VPS-ல் இந்தப் பிரச்சினை தீவிரமாக இருப்பதற்கு இரண்டு காரணங்கள் உள்ளன. Storage பெரும்பாலும் network-attached அல்லது shared ஆக இருக்கும். ஆகவே ஒவ்வொரு fault-க்கும் local NVMe device-ஐ விட அதிக milliseconds தேவைப்படும். மேலும் kernel நேரத்தை அளப்பதில்லை; failure-ஐ அளக்கிறது. Reclaim மெதுவாக இருந்தாலும் தொடர்ந்து ஒரு page-ஐ திருப்பிக் கொடுத்துக்கொண்டிருக்கும் வரை, kernel முன்னேற்றம் நடக்கிறது என்று கருதும். எனவே out of memory (OOM) killer-ஐ இயக்காது. எதுவும் kill செய்யப்படுவதற்கு முன், box பல minutes அந்த நிலையிலேயே இருக்கலாம்.
இது நடப்பதை நீங்கள் monitor செய்யலாம். Linux 4.20 மற்றும் அதற்குப் பிந்தைய versions-ல் kernel pressure stall information (PSI)-ஐ வெளியிடுகிறது:
cat /proc/pressure/memory
cat /proc/pressure/iosome avg10=63.72 avg60=41.02 avg300=12.33 total=13729481
full avg10=48.15 avg60=30.44 avg300=8.90 total=9114233full line தான் முக்கியமானது. full avg10=48.15 என்பது கடந்த ten seconds-ல் 48% நேரம் box-ல் runnable ஆக இருந்த அனைத்து tasks-உம் memory work-க்காக stalled ஆக இருந்தன என்பதைக் குறிக்கிறது. அதனால் எதுவும் இயங்கவில்லை. ஆரோக்கியமான server-ல் full மதிப்பு zero-க்கு அருகில் இருக்கும். 10-க்கு மேல் இருந்தால் மனிதருக்கு அது மெதுவாகத் தெரியும். 40 அல்லது அதற்கு மேல் இருந்தால், மக்கள் frozen என்று விவரிக்கும் நிலை இது.
இதனால்தான் ஒரு limit மட்டும் போதுமான உத்தரவாதம் அல்ல. MemoryHigh=-ன் கீழ் வைக்கப்பட்ட unit kill செய்யப்படுவதற்குப் பதிலாக throttle செய்யப்படுகிறது. எனவே அது இயங்கிக்கொண்டே இருக்கும், மெதுவாகவும் இருக்கும். systemd-ன் பார்வையில் அது ஒருபோதும் fail ஆகவில்லை என்பதால், யாரும் அதை restart செய்யமாட்டார்கள். Swap பயன்படுத்த இன்னும் அனுமதிக்கப்பட்ட capped unit உருவாக்கும் reads மற்றும் writes அந்த unit-க்கு charge செய்யப்படும். ஆனால் அவை ஒரே shared device மூலம் serve செய்யப்படும். இதனால் box-ல் உள்ள மற்ற ஒவ்வொரு service-க்கும் /proc/pressure/io அதிகரிக்கக்கூடும். Limits மூலம் memory shortage-க்கான செலவை யார் ஏற்க வேண்டும் என்பதைத் தீர்மானிக்கலாம்; அவை capacity-ஐ உருவாக்க முடியாது.
உங்கள் VPS cgroup v2-ஐ இயக்குகிறதா என்பதைச் சரிபார்க்கவும்
stat -fc %T /sys/fs/cgroupcgroup2fs என்பது unified hierarchy ஆகும். கீழே உள்ள ஒவ்வொரு setting-க்கும் இதுவே தேவை. tmpfs என்றால், server பழைய v1 layout-ஐக் கொண்டு boot ஆகியுள்ளது என்று பொருள். அந்த layout-ல் MemoryHigh= மற்றும் MemorySwapMax= இருக்காது; ஒவ்வொரு unit-ன் OOM நடத்தைவும் வேறுபடும். Ubuntu 22.04 மற்றும் அதற்குப் பிறகான பதிப்புகளும், Debian 11 மற்றும் அதற்குப் பிறகான பதிப்புகளும், இயல்பாக v2-ஐப் பயன்படுத்துகின்றன. பழைய image அல்லது systemd.unified_cgroup_hierarchy=0 உடன் boot செய்யப்பட்ட kernel இதைப் பயன்படுத்தாது.
cgroup v2 systemd-ல், ஒவ்வொரு unit-க்கும் memory accounting இயல்பாக இயக்கப்படும். எனவே அந்த memory எண்ணிக்கைகள் ஏற்கனவே கிடைக்கும்:
systemd-cgtop -mஇது cgroups-ஐ memory பயன்பாட்டின் அடிப்படையில் வரிசைப்படுத்திக் காட்டும். Server இன்னும் பதிலளிக்கும் நிலையில் இருக்கும்போது, “இந்த server-ன் memory-ஐ எது அதிகமாகப் பயன்படுத்துகிறது?” என்ற கேள்விக்கு விரைவாகப் பதில் பெற இதுவே சிறந்த வழி. Server புதியதாக இருந்தால், புதிய VPS-ல் முதல் பத்து நிமிடங்களில் செய்ய வேண்டிய பணிகள் இதற்கு முன் செய்யப்பட வேண்டும்.
MemoryHigh throttles. MemoryMax kills.
இரண்டு memory settings-களின் வேறுபாடே failure எப்படி தோன்றும் என்பதைத் தீர்மானிக்கிறது.
MemoryHigh=என்பது soft cap. இதைத் தாண்டியதும் kernel அந்த cgroup-லிருந்து memory-ஐ தீவிரமாக reclaim செய்து, அதன் allocations-ஐ திட்டமிட்டு மெதுவாக்கும். Usage இந்த எண்ணைத் தாண்டியும் செல்லலாம்; எந்த process-மும் kill செய்யப்படாது.MemoryMax=என்பது hard cap. இதன் வரம்புக்குள் allocation-ஐ நிறைவேற்ற முடியாதபோது, OOM killer அந்த cgroup-க்குள் இயங்கி, அந்த unit-ன் சொந்த processes-ல் ஒன்றை kill செய்யும்.
எதன் மீது முழு நம்பிக்கை இல்லை என்றாலும் அதற்கு MemoryMax= அமைக்க வேண்டிய உண்மையான காரணம் இதுவே. Cap இல்லையெனில் memory பற்றாக்குறை முழு server-ஐ பாதிக்கும் பிரச்சினையாக மாறும். Global OOM killer, oom_score அடிப்படையில் victim-ஐ தேர்ந்தெடுக்கும்; நடைமுறையில் இது பெரும்பாலும் அதிக memory பயன்படுத்தும் process-ஐ குறிக்கும். அந்த அதிக memory பயன்படுத்தும் process பொதுவாக leak-ஐ உருவாக்கிய script அல்ல, உங்கள் database ஆக இருக்கும். Cap அமைத்தால், kill-ஆனது பிரச்சினையை ஏற்படுத்திய unit-க்குள்ளேயே நிகழும்.
இரண்டையும் அமைக்கவும். MemoryHigh=-ஐ MemoryMax=-ஐ விட சுமார் 20 முதல் 30 percent குறைவாக வைத்திருக்கவும். இந்த இடைவெளி warning zone ஆகும். மெதுவான memory leak High-ஐத் தாண்டி service-ஐ மெதுவாக்கும். திடீர் spike Max-ஐ நேரடியாகத் தாண்டி service-ஐ நிறுத்தும்.
Percentage values நிறுவப்பட்ட physical memory-ஐ அடிப்படையாகக் கொண்டு கணக்கிடப்படும். எனவே 4 GB plan-ல் MemoryMax=25% என்பது 1 GB ஆகும்; plan-ஐ resize செய்த பிறகும் அது server memory-ன் கால் பகுதியே இருக்கும். MemorySwapMax=0 அந்த unit swap-ஐ முழுமையாகப் பயன்படுத்தாமல் தடுக்கும். இதனால் நீண்ட நேரம் மெதுவாகச் செயல்படுவதற்குப் பதிலாக, வேகமாகவும் தெளிவாகவும் kill நிகழும்.
சில services அவற்றின் memory தேவையை முன்கூட்டியே தீர்மானிக்க அனுமதிக்கும். அவற்றை அளந்து பார்ப்பதற்குப் பதிலாக, முன்பே அமைக்கலாம். Ollama unit, நீங்கள் வழங்கும் context window-ஐ அடிப்படையாகக் கொண்டு அதன் KV cache-ன் அளவை நிர்ணயிக்கும். எனவே அதற்கான ceiling-ஐ தேர்வு செய்வதற்கு முன் num_ctx-ஐ உயர்த்துவதால் RAM-க்கு ஏற்படும் செலவு என்ன என்பதைப் பார்க்கவும்.
Cap-க்கு அருகில் restart policy இல்லையெனில், kill நிகழ்ந்த பிறகு service stopped நிலையில் மட்டும் இருக்கும்.
[Unit]
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Restart=on-failure
RestartSec=5sStartLimit* என்பது [Unit]-ல் இருக்க வேண்டும். Restart= என்பது [Service]-ல் இருக்க வேண்டும். இரண்டில் ஏதேனும் ஒன்றை தவறான section-ல் வைத்தால் systemd அதை புறக்கணிக்கும். ஐந்து நிமிடங்களில் ஐந்து restarts நிகழ்வது தற்காலிக blip அல்ல, memory leak-க்கான அறிகுறி. அதற்குப் பிறகு systemd முயற்சியை நிறுத்தி unit-ஐ failed நிலையில் விடும். பின்னர் கண்டறிய வேண்டிய நிலை இதுவே; பிரச்சினையை மறைக்கும் crash loop அல்ல.
CPUQuota மூலம் CPU-ஐ வரம்பிடுதல் அல்லது CPUWeight மூலம் பகிர்தல்
CPUQuota=, ஒரு CPU-ல் கிடைக்கும் நேரத்தின் குறிப்பிட்ட சதவீதத்தைப் பயன்படுத்தும். CPUQuota=50% என்பது ஒரு core-ன் பாதி. CPUQuota=200% என்பது இரண்டு cores-க்கு இணையானது; unit விரும்பும் அளவு threads-களில் அதை பகிர்ந்து இயக்கலாம். 2 vCPU plan-ல், CPUQuota=200% என்பது முழு machine-ஐ குறிக்கும்.
பெரும்பாலான services-க்கு CPUWeight= சிறந்த default தேர்வாகும். இது 1 முதல் 10000 வரையிலான relative share ஆகும்; kernel-ன் default மதிப்பு 100. வேறு process போட்டியிடும் நேரத்தில் மட்டுமே இதன் தாக்கம் தெரியும்: load இருக்கும் போது CPUWeight=20-ல் இயங்கும் backup job, 100 மதிப்பில் இயங்கும் web server-க்கு முன்னுரிமை விட்டுக்கொடுக்கும். machine idle-ஆக இருக்கும்போது அது முழு machine-ன் CPU-ஐயும் பயன்படுத்தும். கடுமையான quota, idle-ஆக இருக்கும் அந்த capacity-யை வீணாக்கும்.
CPU limit வழங்குவதன் பயனை யதார்த்தமாக மதிப்பிட வேண்டும். CPU-bound process பொதுவாக Linux-ஐ முடக்காது; scheduler அனைவருக்கும் தொடர்ந்து execution time வழங்கும். ஒரு machine-ஐ முடக்குவது பெரும்பாலும் memory பற்றாக்குறையே. Predictable ceiling தேவைப்படும் போது CPUQuota=-ஐ பயன்படுத்தவும். உதாரணமாக, ஒரு மணி நேரம் முழு CPU-யையும் பயன்படுத்தக்கூடிய build அல்லது agent-க்கு இது பொருந்தும். இத்தகைய workload-க்கான sizing தனியான கேள்வியாகும்; coding agent VPS-க்கு எவ்வளவு RAM மற்றும் CPU தேவை என்பதில் அது விளக்கப்பட்டுள்ளது.
உங்கள் processes எதுவும் அதிகமாக இயங்காதபோதும் CPU busy எனக் காட்டினால், காரணம் hypervisor-ன் மறுபுறத்தில் இருக்கலாம். இதுவே noisy neighbour காரணமான CPU steal time ஆகும். நீங்கள் அமைக்கும் எந்த quota-வும் இதை மாற்றாது.
TasksMax fork loop-ஐ நிறுத்துகிறது
TasksMax= என்பது ஒரு unit வைத்திருக்கக்கூடிய processes மற்றும் threads-ன் எண்ணிக்கையாகும். Threads-உம் கணக்கில் சேரும். எனவே, process list காட்டும் எண்ணிக்கையைவிட Java அல்லது Go service-க்கு அதிக headroom தேவைப்படும். Loop-ல் fork செய்யும் script-க்கு எதிரான குறைந்த செலவிலான பாதுகாப்பு இதுவாகும். ஏனெனில், முழு box-லும் process IDs தீர்ந்து போவதற்குப் பதிலாக, அந்த unit-க்குள் fork தோல்வியடையும்.
TasksMax=128ஒரு unit இந்த வரம்பை அடைந்ததும், kernel cgroup-ன் பெயரைக் குறிப்பிடும் ஒரு வரியை log செய்கிறது:
cgroup: fork rejected by pids controller in /system.slice/myapp.serviceபொதுவாக program தானாகவே fork: retry: Resource temporarily unavailable என்பதைத் தெரிவிக்கும். manager இயல்பாகப் பயன்படுத்தும் அமைப்பை systemctl show -p DefaultTasksMax மூலம் சரிபார்க்கவும்.
systemd-run மூலம் ஒரு முறை மட்டும் இயங்கும் job-ஐ வரம்புபடுத்துதல்
இதில் எதையும் பயன்படுத்த unit file தேவையில்லை. systemd-run, ஒரு command-ஐச் சுற்றி transient unit ஒன்றை உருவாக்குகிறது.
sudo systemd-run --scope -p MemoryMax=1G -p MemorySwapMax=0 -p CPUQuota=50% -p TasksMax=64 ./import-data.sh--scope, முதலில் Running scope as unit: run-r7c1a....scope-ஐ print செய்த பிறகு, உங்கள் terminal-ல் command-ஐ இயக்குகிறது. Output உங்கள் screen-லேயே இருக்கும். Command முடிந்ததும் limits நீக்கப்படும். systemd.resource-control-இல் உள்ள எந்த property-யும் -p-க்குப் பிறகு செயல்படும்.
நீண்ட நேரம் இயங்கும் job-க்கு --scope-ஐ நீக்கி, அதற்கு ஒரு பெயர் வழங்கவும். அப்போது அது transient service-ஆக background-ல் இயங்கி, journal-ல் logs எழுதும்:
sudo systemd-run --unit=nightly-import -p MemoryMax=1G -p CPUWeight=20 ./import-data.sh
journalctl -u nightly-import -froot ஆக இல்லாதபோதும் --user உடன் இதே options செயல்படும். ஆனால், உங்கள் user manager-க்கு delegate செய்யப்பட்ட controllers மட்டுமே இருக்கும். ஆகவே, ஒரு property அங்கு நிராகரிக்கப்படலாம். அது நடந்தால் sudo உடன் இயக்கவும். ஒரு job-க்கு நிரந்தரமான இடம் தேவைப்படும் நிலையில், settings மாற்றமின்றி உண்மையான unit-க்கு மாற்றப்படலாம்: script-ஐ systemd service மற்றும் timer ஆக இயக்குதல் என்பதைப் பார்க்கவும்.
Swap பற்றிய கேள்விக்கு நேர்மையான பதில்
Swap, தோல்வியைத் தடுக்காது; தோல்வி ஏற்படும் விதத்தை மாற்றும்.
Swap இல்லையெனில், memory leak வரம்பை அடைந்ததும் சில seconds-க்குள் ஏதாவது ஒன்று முடங்கும். Outage திடீரெனவும் குறுகியதாகவும் இருக்கும்; பின்னர் journal-ல் அதை எளிதாகப் புரிந்துகொள்ளலாம். Swap இருந்தால், kernel பயன்படுத்தப்படாத anonymous pages-ஐ disk-க்கு எழுதுகிறது; இதனால் சிறிது நேரம் கிடைக்கிறது. Process ஒரு நிலையான அளவில் நின்றுவிடும் நிலையில் இருந்தால், swap உங்களை காப்பாற்றும். ஆனால் அது runaway process ஆக இருந்தால், swap ஐந்து seconds-க்கான outage-ஐ இருபது minutes-க்கான stall-ஆக மாற்றும். அந்த stall இன்னும் மோசமானது. முடங்கிய process இருந்தாலும் செயல்படும் shell உங்களிடம் இருக்கும்; ஆனால் thrashing செய்யும் system அப்படி இருக்காது.
swapon --show
free -hசிறிய VPS-க்கு நடைமுறைக்கு ஏற்ற நடுநிலை அணுகுமுறை இதுவாகும்: ஒருமுறை allocate செய்யப்பட்டு பின்னர் மீண்டும் பயன்படுத்தப்படாத pages-க்காக அளவான swap file வைத்திருக்கவும். நீங்கள் நிறுத்தத் தயாராக இருக்கும் units-ல் MemorySwapMax=0 அமைக்கவும். முக்கியமான services-க்கு swap அனுமதிக்கவும். கணிக்க முடியாத services விரைவாக வரம்பை அடைந்து restart ஆகட்டும்.
vm.swappiness-ஐ குறைப்பது பலவீனமான கட்டுப்பாட்டு வழிமுறை. ஏன் என்பதை அறிந்திருக்க வேண்டும். இது page cache-ஐ வெளியேற்றுவதற்கும் anonymous pages-ஐ swap செய்வதற்கும் இடையிலான சமநிலையை மட்டுமே மாற்றும். இரண்டிற்கும் பின்னர் disk read தேவைப்படும். எந்த pages thrash ஆகின்றன என்பதை இது மாற்றும்; system thrash ஆகுமா என்பதை மாற்றாது.
நிலைமுடக்கத்திற்கு முன்பே கொல்லும் OOM daemon
Kernel reclaim செயல்முறை முழுமையாக தோல்வியடையும் வரை காத்திருக்கிறது. சிறிய VPS-ல், அந்தக் காத்திருப்பு நேரமே server-ஐ இழக்கும் சரியான இடைவெளியாக இருக்கும். Userspace-ல் இயங்கும் இரண்டு daemon-கள் memory-ஐ தாங்களே கண்காணித்து, செயல்முறைகளை முன்கூட்டியே நிறுத்துவதன் மூலம் இந்த இடைவெளியை மூடுகின்றன.
earlyoom available memory மற்றும் free swap-ஐ கண்காணிக்கும். இவற்றில் ஏதேனும் ஒன்று threshold-க்குக் கீழே சென்றால், அதிக score பெற்ற process-ஐ அது நிறுத்தும்.
sudo apt install earlyoom
systemctl status earlyoomDebian மற்றும் Ubuntu package install செய்யும் போது இந்த service-ஐ தொடங்குகிறது. இதன் options /etc/default/earlyoom-ல் உள்ளன:
EARLYOOM_ARGS="-m 5,2 -s 5,2 --avoid '^(sshd|systemd)$' --prefer '^(node|python3)$'"-m PERCENT available memory-க்கான குறைந்தபட்ச அளவையும், -s PERCENT free swap-க்கான குறைந்தபட்ச அளவையும் அமைக்கின்றன. இரண்டிற்கும் இயல்புநிலை மதிப்பு 10 percent. ஒவ்வொரு pair-லும் உள்ள இரண்டாவது எண் SIGKILL நிலையை குறிக்கும்: முதல் மதிப்புக்குக் கீழே சென்றவுடன் earlyoom SIGTERM அனுப்பும்; இரண்டாவது மதிப்புக்குக் கீழே சென்றால் SIGKILL அனுப்பும். இயல்புநிலையாக, இரண்டாவது மதிப்பு முதல் மதிப்பின் பாதியாக இருக்கும். மாற்றத்தை sudo systemctl restart earlyoom மூலம் செயல்படுத்தவும். எந்த process-ஐ அது நிறுத்தியது, அந்த process எவ்வளவு memory பயன்படுத்தியது என்பதைக் காண journalctl -u earlyoom-ஐப் படிக்கவும்.
systemd-oomd மற்றொரு option ஆகும். இதன் manual page இதை “kernel space-ல் OOM ஏற்படுவதற்கு முன் cgroups-v2 மற்றும் pressure stall information (PSI)-ஐப் பயன்படுத்தி கண்காணித்து, திருத்த நடவடிக்கை எடுக்கும் system service” என்று விவரிக்கிறது. இது தனிப்பட்ட processes-க்கு பதிலாக முழு cgroups மீது செயல்படும். எனவே, தனியே தவறிச் சென்ற child process-ஐ அல்ல, ஒரு unit-ஐ நிறுத்தும். Units ManagedOOMMemoryPressure=kill அல்லது ManagedOOMSwap=kill மூலம் opt in செய்யலாம். Thresholds /etc/systemd/oomd.conf-ல் உள்ளன.
systemctl status systemd-oomd
oomctloomctl தற்போது எதை கண்காணிக்கிறது என்பதை வெளியிடும். Server image-ல் இது பெரும்பாலும் எதையும் காட்டாது, ஏனெனில் இந்த setting ஒவ்வொரு unit-க்கும் opt-in முறையில் அமைக்கப்படுகிறது. ஒரு daemon-ஐ மட்டும் தேர்ந்தெடுத்து அதிலேயே நிறுத்தவும். இரண்டையும் இயக்கினால், victim-ஐ தேர்ந்தெடுக்க இரண்டு daemon-கள் போட்டியிடும். இதனால் எந்த kill-க்கான காரணம் என்பதைக் கண்டறிவது கடினமாகும்.
எந்த unit பொறுப்பாக இருந்தது?
முதலில் kernel-ஐச் சரிபார்க்கவும். அது ஏற்படுத்திய ஒவ்வொரு kill-ஐயும் பதிவு செய்கிறது.
journalctl -k --grep "Killed process" --since "2 hours ago"Global OOM killer மூலம் ஏற்பட்ட kill இவ்வாறு இருக்கும்:
Out of memory: Killed process 4127 (node) total-vm:2731084kB, anon-rss:1874232kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:4212kB oom_score_adj:0anon-rss என்பது process முடிவடைந்தபோது RAM-ல் அது வைத்திருந்த memory அளவு. இங்கு அது சுமார் 1.8 GB. Brackets-க்குள் உள்ள பெயரை எச்சரிக்கையுடன் வாசிக்கவும். அது kernel தேர்ந்தெடுத்த victim ஆகும். Kernel பொதுவாக அதிக memory பயன்படுத்திய process-ஐத் தேர்ந்தெடுக்கும். ஆனால் memory பற்றாக்குறையை ஏற்படுத்திய process அதுவாக இருக்க வேண்டிய அவசியமில்லை.
cgroup limit காரணமாக ஏற்பட்ட kill-க்கு வேறுபட்ட prefix இருக்கும். அதற்கு மேலே அச்சிடப்பட்ட report, தனது ceiling-ஐ எட்டிய cgroup-ன் பெயரைக் காட்டும்:
Memory cgroup out of memory: Killed process 8811 (python3) total-vm:1044320kB, anon-rss:769112kB, file-rss:0kB, shmem-rss:0kB, UID:998 pgtables:1720kB oom_score_adj:0அந்த prefix பெரும்பாலான diagnosis-ஐ வழங்குகிறது. Memory cgroup out of memory என்பது, நீங்கள் வழங்கிய MemoryMax=-ஐ ஒரு unit எட்டியது என்றும், box-ன் மீதிப் பகுதி இயல்பாக இருந்தது என்றும் பொருள். சாதாரண Out of memory என்பது machine முழுவதும் memory இல்லாமல் போனது என்று பொருள். எனவே உங்கள் caps அமைக்கப்படாமல் இருந்திருக்கலாம் அல்லது அவற்றின் மொத்த வரம்பு அதிகமாக இருந்திருக்கலாம்.
அடுத்து systemd பார்த்ததைச் சரிபார்க்கவும்:
systemctl status myapp.service
journalctl -u myapp.service -n 50myapp.service: A process of this unit has been killed by the OOM killer.
myapp.service: Main process exited, code=killed, status=9/KILL
myapp.service: Failed with result 'oom-kill'.systemctl status அதே தகவலை ஒரே வரியில், Active: failed (Result: oom-kill) ஆகக் காட்டுகிறது.
cgroup counters மூன்றாவது ஆதாரமாகும். Throttling-ஐப் பதிவு செய்யும் ஒரே ஆதாரமும் இதுவே. Throttling ஏற்பட்டால் எந்த log line-உம் உருவாகாது:
cat /sys/fs/cgroup/system.slice/myapp.service/memory.events
cat /sys/fs/cgroup/system.slice/myapp.service/memory.peaklow 0
high 4213
max 118
oom 12
oom_kill 12high என்பது unit MemoryHigh=-ஐ எத்தனை முறை மீறி throttled செய்யப்பட்டது என்பதை எண்ணுகிறது. max hard cap-ஐ எத்தனை முறை எட்டியது என்பதை எண்ணுகிறது. oom_kill உண்மையில் kill செய்யப்பட்ட processes-ன் எண்ணிக்கையைக் காட்டுகிறது. high அதிகமாகவும் oom_kill 0 உடன் இருந்தால், முன்பு குறிப்பிடப்பட்ட silent case அதுவாகும்: service இயங்கிக்கொண்டிருக்கிறது, அதன் வேகம் மிகவும் குறைந்துள்ளது, ஆனால் அது எந்த failure-ஐயும் யாரிடமும் தெரிவிக்கவில்லை. memory.peak (Linux 5.19 மற்றும் அதற்குப் பிந்தைய versions) cgroup எட்டிய அதிகபட்ச usage-ஐ வைத்திருக்கும். MemoryMax=-ஐ அளவிட வேண்டிய எண்ணிக்கை அதுவாகும். Unit restart செய்யப்படும் போது இரண்டு files-உம் reset ஆகும். காரணம், systemd cgroup-ஐ மீண்டும் உருவாக்குகிறது.
இவை அனைத்திற்கும் அடிப்படையாக ஒரு prerequisite உள்ளது. /var/log/journal இல்லை என்றால் journal RAM-ல் இருக்கும். Box-ஐ மீட்டெடுக்க வேண்டிய reboot முடிந்தவுடன் ஒவ்வொரு line-உம் அழிந்துவிடும்.
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --list-bootsjournalctl --list-boots current boot-ஐவிட அதிகமான boot-களைக் காட்டினால், history இப்போது நிலைத்திருக்கும். எனவே இறந்த boot-இன் kernel messages-ஐ journalctl -k -b -1 மூலம் பார்க்கலாம்.
சிறிய VPS-க்கான தொடக்க அமைப்பு
2 GB plan-ல் kernel மற்றும் page cache-க்காக 300 முதல் 400 MB வரை ஒதுக்கி வைக்கவும். Caps-ன் மொத்த அளவு முழு 2 GB-ஐ எட்டக்கூடாது. ஏனெனில் ஒவ்வொரு unit-மும் ஒரே நேரத்தில் peak நிலையை அடையலாம். முக்கியமான service-க்கு அதிகபட்ச memory share-ஐ வழங்கவும். அதைச் சுற்றியுள்ள ஊக அடிப்படையிலான services அனைத்திற்கும் cap அமைக்கவும்.
[Service]
MemoryHigh=256M
MemoryMax=384M
MemorySwapMax=0
CPUWeight=20
TasksMax=64
Restart=on-failure
RestartSec=5sஉள்ளே நுழைவதற்கான வழியை வைத்திருப்பதற்கு இன்னொரு setting பயனுள்ளதாக இருக்கும். OOMScoreAdjust=-500-ஐ ssh.service-க்கான drop-in-ல் அமைத்தால், global OOM killer உங்கள் SSH daemon-ஐ victim-ஆகத் தேர்ந்தெடுக்கும் வாய்ப்பு மிகவும் குறையும். இதனால் control panel-ல் இருந்து server-ஐ reboot செய்வதற்குப் பதிலாக, அதைச் சரிசெய்ய முடியும். இது kernel தேர்ந்தெடுக்கும் victim-ஐ மட்டுமே மாற்றும். Stall நீடிக்கும் நேரத்தை இது குறைக்காது.
Containers தங்களுக்கென தனிப்பட்ட cgroups-ல் இயங்குகின்றன. இவற்றை உங்கள் unit files உருவாக்குவதில்லை; container runtime உருவாக்குகிறது. எனவே docker.service-க்கு அமைக்கும் limit, ஒரு container-க்கான limit ஆகாது. MemoryMax= மற்றும் CPUQuota=-ன் container-தனிப்பட்ட equivalents, Docker Compose-ல் memory மற்றும் CPU limits அமைத்தல் பகுதியில் விளக்கப்பட்டுள்ளன.
FAQ
என் VPS runaway process-ஐ நிறுத்துவதற்குப் பதிலாக ஏன் freeze ஆனது?
Kernel, memory reclaim மூலம் pages திரும்பப் பெறப்படுகிறதா என்பதைக் கொண்டே progress-ஐ மதிப்பிடுகிறது; அதற்கு எவ்வளவு நேரம் ஆகிறது என்பதைக் கருத்தில் கொள்ளாது. Memory குறைவாக இருக்கும்போது, இயங்கும் programs-ன் executable pages உட்பட page cache-ஐ அது வெளியேற்றுகிறது. அடுத்த instruction தேவைப்படும் போது அவற்றை மீண்டும் வாசிக்கிறது. இதனால் அனைத்தும் storage-ஐ சார்ந்து காத்திருக்கின்றன. Allocation எந்த நிலையிலும் தொழில்நுட்ப ரீதியாக தோல்வியடையாததால், OOM killer அழைக்கப்படுவதில்லை. இது நடக்கும் நேரத்தில் /proc/pressure/memory-ஐ சரிபார்க்கவும்: full avg10 40-ஐ விட அதிகமாக இருந்தால், கடந்த பத்து seconds-ல் கிட்டத்தட்ட எந்த task-மும் இயங்கவில்லை. earlyoom போன்ற userspace daemon, இந்த நிலையை server அடையும் முன்பே process-ஐ நிறுத்தும்.
MemoryHigh மற்றும் MemoryMax ஆகியவற்றுக்கு என்ன வேறுபாடு?
MemoryHigh= என்பது throttling செய்யும் soft cap. Kernel அந்த unit-இலிருந்து memory-ஐ தீவிரமாக reclaim செய்து அதன் allocations-ஐ மெதுவாக்கும். ஆனால் usage அந்த எண்ணிக்கையை மீறலாம்; எந்த process-மும் கொல்லப்படாது. MemoryMax= என்பது hard cap. அதன் வரம்புக்குள் allocation-ஐ நிறைவேற்ற முடியாதபோது, அந்த unit-ன் சொந்த cgroup-க்குள் OOM killer இயக்கப்படும். இதனால் பிரச்சினையை ஏற்படுத்திய process-தான் நிறுத்தப்படும்; server-ல் அதிக memory பயன்படுத்தும் process நிறுத்தப்படாது. MemoryHigh=-ஐ MemoryMax=-க்கு கீழே அமைக்கவும். இரண்டிற்கும் இடையிலான இடைவெளியை warning zone-ஆக கருதவும்.
OOM killer எந்த service-ஐத் தாக்கியது என்பதை எப்படிக் கண்டறிவது?
journalctl -k --grep "Killed process" --since "2 hours ago"-ஐ இயக்கவும். Memory cgroup out of memory-ல் தொடங்கும் line, ஒரு unit அதன் சொந்த MemoryMax= வரம்பை எட்டியதைக் குறிக்கும். சாதாரண Out of memory என்பது முழு machine-ன் memory தீர்ந்ததைக் குறிக்கும். அதன் பிறகு journalctl -u <unit> -n 50-ஐ இயக்கி Failed with result 'oom-kill'-ஐத் தேடவும். உங்கள் server-ல் /var/log/journal இல்லை என்றால், journal RAM-ல் மட்டுமே இருந்துள்ளது. Reboot-உடன் அந்த evidence அழிந்துவிட்டது. எனவே அடுத்த incident-க்கு முன் அந்த directory-ஐ உருவாக்கவும்.
சிறிய VPS-க்கு swap சேர்க்க வேண்டுமா?
ஒருமுறை allocation செய்யப்பட்டு மீண்டும் பயன்படுத்தப்படாத cold pages-க்கு சிறிய swap file உதவும். Runaway process-க்கு இது உதவாது. இது process kill-ஐ தாமதப்படுத்தி, விரைவான outage-க்கு பதிலாக login செய்து சரிசெய்ய முடியாத நீண்ட stall-ஐ உருவாக்கும். Swap-ஐ மிதமான அளவில் வைத்திருக்கவும். நீங்கள் நிறுத்த அனுமதிக்கும் units-ல் MemorySwapMax=0-ஐ அமைக்கவும். இதனால் அவை தங்களுடைய ceiling-ஐ அடைந்து விரைவாக restart ஆகும்; முக்கியமான services தங்களுடைய swap-ஐ தொடர்ந்து பயன்படுத்தும்.
Unit file எழுதாமல் ஒரு command-ஐ வரம்புக்குள் இயக்க முடியுமா?
ஆம். sudo systemd-run --scope -p MemoryMax=1G -p CPUQuota=50% ./script.sh, அந்த command-ஐ உங்கள் terminal-ல் transient scope-க்குள் குறிப்பிட்ட limits-உடன் இயக்கும். அது வெளியேறியதும் அந்த limits நீங்கிவிடும். systemd.resource-control-ல் உள்ள ஒவ்வொரு property-யும் -p-க்குப் பிறகு கிடைக்கும். எனவே MemorySwapMax=, TasksMax= மற்றும் CPUWeight= அங்கேயும் செயல்படும். --scope-ஐ அகற்றி, --unit=name-ஐச் சேர்க்கவும். இதனால் job பின்னணியில் இயங்கும்; அதன் output journal-ல் சேமிக்கப்படும்.