systemdలో process memory, CPU limits ఎలా పెట్టాలి
MemoryHigh, MemoryMax, CPUQuota, TasksMax అమర్చినా VPS ఎందుకు స్తంభించవచ్చో తెలుసుకోండి. cgroup v2 unitsలో limits తనిఖీ చేసి OOM killను చదవండి.
systemd drop-in తో process memory మరియు CPUని పరిమితం చేయడం
Process ను నడిపించే unit కు కొన్ని పంక్తులు జోడించడం ద్వారా Linux VPSలో process memory మరియు CPUని పరిమితం చేయవచ్చు. MemoryMax= అనేది memoryకి గరిష్ఠ పరిమితి. CPUQuota= అనేది processor timeకి గరిష్ఠ పరిమితి. ఈ రెండింటినీ cgroup v2 (control groups, version 2) అమలు చేస్తుంది. ప్రతి service వినియోగాన్ని systemd ఇప్పటికే పర్యవేక్షించడానికి kernelలో ఉపయోగించే feature ఇదే.
sudo systemctl edit myapp.serviceఇది commentsలో instructions ఉన్న drop-in fileను తెరుస్తుంది. ఆ comments పైభాగంలో ఈ పంక్తులను జోడించండి:
[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 మీ సంఖ్యలను 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ను ప్రారంభిస్తుంది.
ఈ guideలోని మిగిలిన భాగం ఆ సంఖ్యలను ఎలా ఎంచుకోవాలి, limits అమర్చిన తర్వాత కూడా ఏ సమస్యలు కొనసాగవచ్చు అనే విషయాలను వివరిస్తుంది.
ఒక runaway process VPS ను ఎందుకు స్తంభింపజేస్తుంది (అది నిండకపోయినా)
ఒక process నిర్ణీత memory పరిమితిని దాటినప్పుడు, అది సెకనులోపు ఆగిపోయి సేవ పునఃప్రారంభం అవుతుంది. ఇది మంచి పరిస్థితి. చెడు పరిస్థితి ఏమిటంటే, ఏదీ ఆగిపోదు: సర్వర్ ping కు స్పందిస్తుంది, SSH కనెక్షన్ను అంగీకరిస్తుంది, కానీ shell prompt మాత్రం రాదు. యంత్రం పని చేస్తూనే ఉంటుంది, కానీ ఆ పనిలో ఏదీ ఉపయోగకరంగా ఉండదు.
దీనికి కారణం స్పష్టంగా ఉండదు, కాబట్టి ఆ విధానం ఇక్కడ ఉంది. ఉచిత memory తగ్గినప్పుడు, kernel కొత్త పేజీలను ఇచ్చే బదులు ఉన్న పేజీలను తిరిగి పొందుతుంది (reclaim). తిరిగి పొందడానికి సులభమైనవి file-backed పేజీలు, మరియు నడుస్తున్న ప్రతిదాని executable code ను page cache కలిగి ఉంటుంది. కాబట్టి kernel sshd యొక్క text పేజీలను తొలగిస్తుంది, మరియు sshd తదుపరి instruction ను అమలు చేసేటప్పుడు page fault ఏర్పడి, ఆ bytes ను storage నుండి తిరిగి చదవాల్సి వస్తుంది. ప్రతి process రన్ అవ్వడానికి బదులుగా disk కోసం వేచి ఉంటుంది. ఒకే పేజీలు బయటకు వెళ్లడం మరియు తిరిగి రావడం లూప్లో జరుగుతుంది, దీనినే thrashing అంటారు.
laptop తో పోలిస్తే VPS లో రెండు విషయాలు దీనిని మరింత దారుణంగా మారుస్తాయి. storage తరచుగా network attached లేదా shared గా ఉంటుంది, కాబట్టి ప్రతి fault కు స్థానిక NVMe పరికరం కంటే ఎక్కువ milliseconds పడుతుంది. మరియు kernel సమయాన్ని కొలవదు, అది వైఫల్యాన్ని కొలుస్తుంది: reclaim ఎంత నెమ్మదిగా పేజీని తిరిగి ఇచ్చినా, kernel తాను పురోగతి సాధిస్తున్నానని నమ్ముతుంది మరియు out of memory (OOM) killer ను పిలవదు. ఏదైనా ఆగిపోయే ముందు ఒక బాక్స్ ఆ స్థితిలో చాలా నిమిషాల పాటు ఉండవచ్చు.
ఇది ఎలా జరుగుతుందో మీరు చూడవచ్చు. Linux 4.20 మరియు అంతకంటే కొత్త వెర్షన్లలో 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 లైన్ ముఖ్యమైనది. full avg10=48.15 అంటే గత పది సెకన్లలో 48% సమయం, బాక్స్లోని అన్ని non-idle tasks ఒకే సమయంలో memory కోసం నిలిచిపోయాయని అర్థం, కాబట్టి మీ పని ఏదీ పురోగతి సాధించలేదు. ఆరోగ్యకరమైన సర్వర్లో full విలువ సున్నాకి దగ్గరగా ఉంటుంది. 10 కంటే ఎక్కువ ఉంటే మనుషులకు నెమ్మదిగా అనిపిస్తుంది, మరియు 40 లేదా అంతకంటే ఎక్కువ ఉంటే ప్రజలు దానిని స్తంభించిపోయినట్లు (frozen) వర్ణిస్తారు.
అందుకే పరిమితి (limit) అనేది ఒక హామీ కాదు. MemoryHigh= కింద ఉంచబడిన unit ను చంపే బదులు throttled చేస్తారు, కాబట్టి అది బతికే ఉంటుంది మరియు నెమ్మదిగా ఉంటుంది, మరియు systemd దృష్టిలో అది ఎప్పుడూ విఫలం కాలేదు కాబట్టి ఏదీ దానిని పునఃప్రారంభించదు. swap చేయడానికి అనుమతించబడిన పరిమితి గల unit, shared పరికరం ద్వారా అందించబడే reads మరియు writes ను సృష్టిస్తుంది, కాబట్టి ఇది బాక్స్లోని ప్రతి ఇతర సేవ కోసం /proc/pressure/io ను పెంచుతుంది. పరిమితులు కొరతకు ఎవరు మూల్యం చెల్లించాలో నిర్ణయిస్తాయి, కానీ అవి సామర్థ్యాన్ని (capacity) సృష్టించలేవు.
మీ VPS cgroup v2 రన్ అవుతుందో లేదో తనిఖీ చేయండి
stat -fc %T /sys/fs/cgroupcgroup2fs అనేది ఏకీకృత క్రమానుగత పద్ధతి (unified hierarchy), దీనికి కింద పేర్కొన్న memory సెట్టింగ్లు అవసరం. tmpfs అంటే సర్వర్ పాత v1 లేఅవుట్తో బూట్ అయిందని అర్థం, అక్కడ MemoryHigh= మరియు MemorySwapMax= సపోర్ట్ చేయబడవు మరియు ప్రతి యూనిట్ యొక్క OOM ప్రవర్తన భిన్నంగా ఉంటుంది, అయితే CPUQuota= ఇప్పటికీ పాత cpu.cfs_quota_us ఫైల్ ద్వారా అక్కడ పనిచేస్తుంది. Ubuntu 22.04 మరియు ఆ తర్వాత వచ్చిన వెర్షన్లు, అలాగే Debian 11 మరియు ఆ తర్వాత వచ్చిన వెర్షన్లు డిఫాల్ట్గా v2ని ఉపయోగిస్తాయి. పాత ఇమేజ్లు దీనిని ఉపయోగించవు, మరియు systemd 257 లేదా అంతకంటే పాత వెర్షన్లలో systemd.unified_cgroup_hierarchy=0 తో బూట్ చేసిన కెర్నల్ కూడా దీనిని ఉపయోగించదు. systemd 258 వెర్షన్ cgroup v1 సపోర్ట్ను తొలగించింది మరియు బూట్ సమయంలో ఎల్లప్పుడూ ఏకీకృత క్రమానుగత పద్ధతిని మౌంట్ చేస్తుంది, కాబట్టి ఆ వెర్షన్ ఉన్న రిలీజ్లలో ఆ ఆర్గ్యుమెంట్ v1ని తిరిగి తీసుకురాదు.
cgroup v2లో systemd ప్రతి యూనిట్కు డిఫాల్ట్గా memory accountingని ఆన్ చేస్తుంది, కాబట్టి ఆ సంఖ్యలు ఇప్పటికే అక్కడ ఉంటాయి:
systemd-cgtop -mఇది memory వినియోగం ఆధారంగా cgroupsని క్రమబద్ధీకరిస్తుంది, సర్వర్ స్పందిస్తున్నంత సేపు "ఈ బాక్స్లో దేనివల్ల మెమరీ ఖర్చవుతోంది" అని తెలుసుకోవడానికి ఇది అత్యంత వేగవంతమైన మార్గం. సర్వర్ కొత్తదైతే, కొత్త VPSలో మొదటి పది నిమిషాలు లో చేసే అకౌంట్ మరియు ఫైర్వాల్ పనులు దీనికంటే ముందే పూర్తి చేయాలి.
MemoryHigh మరియు MemoryMax ల మధ్య తేడాలు.
ఈ రెండు memory సెట్టింగ్ల మధ్య ఉన్న వ్యత్యాసం, ఒక వైఫల్యం ఎలా సంభవిస్తుందో నిర్ణయిస్తుంది.
MemoryHigh=అనేది ఒక soft cap. దీనిని దాటినప్పుడు, kernel ఆ cgroup నుండి memoryని వేగంగా తిరిగి పొందుతుంది మరియు దాని allocations ను ఉద్దేశపూర్వకంగా నెమ్మదిస్తుంది. వినియోగం ఈ పరిమితిని దాటి వెళ్లవచ్చు, కానీ ఏ ప్రక్రియ (process) ఆగిపోదు.MemoryMax=అనేది ఒక hard cap. దీని పరిధిలో memory కేటాయింపు సాధ్యం కానప్పుడు, OOM killer ఆ cgroup లోపలే పనిచేసి, ఆ unit కి చెందిన ఏదో ఒక process ను నిలిపివేస్తుంది (kill చేస్తుంది).
మీరు పూర్తిగా నమ్మని దేనికైనా MemoryMax= సెట్ చేయడానికి ఈ రెండో అంశమే అసలైన కారణం. ఎటువంటి పరిమితి లేకపోతే, memory కొరత అనేది మొత్తం సర్వర్కు సంబంధించిన సమస్యగా మారుతుంది. అప్పుడు global OOM killer తన బాధితుడిని oom_score ఆధారంగా ఎంచుకుంటుంది, అంటే సాధారణంగా ఎక్కువ memory వాడుతున్న process ను ఎంచుకుంటుంది. ఆ పెద్ద process సాధారణంగా మీ database అయి ఉంటుంది, memory leak కి కారణమైన script కాదు. పరిమితిని సెట్ చేయడం ద్వారా, ఆ kill అనేది సమస్యను సృష్టించిన unit లోపలే జరుగుతుంది.
రెండింటినీ సెట్ చేయండి, MemoryHigh= ని MemoryMax= కంటే సుమారు 20 నుండి 30 శాతం తక్కువగా ఉంచండి. ఈ మధ్య ఉన్న ఖాళీ ఒక హెచ్చరిక ప్రాంతం: నెమ్మదిగా జరిగే leak High ని దాటినప్పుడు, సేవ నెమ్మదించినట్లు కనిపిస్తుంది. అదే అకస్మాత్తుగా పెరిగే spike నేరుగా Max ని దాటి, సేవ ఆగిపోయేలా చేస్తుంది.
శాతపు విలువలు ఇన్స్టాల్ చేయబడిన physical memory ఆధారంగా లెక్కించబడతాయి. కాబట్టి 4 GB ప్లాన్ మీద MemoryMax=25% అంటే 1 GB అవుతుంది, మీరు ప్లాన్ సైజు మార్చినా అది సర్వర్లో నాలుగో వంతుగానే ఉంటుంది. MemorySwapMax=0 ఆ unit ని swap కి వెళ్లకుండా పూర్తిగా నిరోధిస్తుంది. కాబట్టి అది MemoryMax= కి చేరుకున్నప్పుడు, swap లో నెమ్మదిగా తిరగకుండానే త్వరగా kill జరుగుతుంది. ఆ స్థాయి కంటే తక్కువలో MemoryHigh= దానిని నెమ్మదింపజేయగలదు, మరియు high limit దాటినప్పుడు OOM killer ఎప్పటికీ పనిచేయదు. కాబట్టి ఈ రెండింటి మధ్య ఊగిసలాడే unit ఆగిపోకుండా, నెమ్మదిగా పనిచేస్తుంది.
కొన్ని సేవలు వాటి అవసరాలను ముందే నిర్ణయించుకోవడానికి అనుమతిస్తాయి: ఒక Ollama unit మీరు ఇచ్చే context window నుండి దాని KV cache ని సైజు చేసుకుంటుంది. కాబట్టి దానికి ఒక పరిమితిని నిర్ణయించే ముందు num_ctx ని పెంచడం వల్ల RAM పై పడే ప్రభావం గురించి చదవండి.
ఒక పరిమితి (cap) ఉన్నప్పుడు, దాని పక్కనే restart policy కూడా ఉండాలి, లేకపోతే kill జరిగిన తర్వాత సేవ ఆగిపోయి ఉంటుంది.
[Unit]
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Restart=on-failure
RestartSec=5sStartLimit* అనేది [Unit] లో ఉండాలి మరియు Restart= అనేది [Service] లో ఉండాలి. వీటిని తప్పు విభాగంలో ఉంచితే systemd వాటిని పట్టించుకోదు. ఐదు నిమిషాల్లో ఐదుసార్లు restart అవ్వడం అనేది ఒక చిన్న సమస్య కాదు, అది leak అని అర్థం. కాబట్టి ఆ తర్వాత systemd ప్రయత్నాన్ని ఆపివేసి, unit ని failed స్థితిలో ఉంచుతుంది. సమస్యను దాచిపెట్టే crash loop కంటే, మీరు తర్వాత వచ్చి చూసేటప్పుడు ఈ failed స్థితి ఉండటమే మంచిది.
CPUQuotaతో CPUని పరిమితం చేయడం లేదా CPUWeightతో పంచుకోవడం
CPUQuota= ఒక CPUపై అందుబాటులో ఉన్న సమయానికి శాతాన్ని కేటాయిస్తుంది. CPUQuota=50% ఒక coreలో సగం. CPUQuota=200% రెండు coreలకు సమానం. Unit అవసరమైతే ఈ సామర్థ్యాన్ని ఎన్ని threadsకైనా పంచవచ్చు. 2 vCPU planలో CPUQuota=200% మొత్తం machine సామర్థ్యానికి సమానం.
చాలా servicesకు CPUWeight= మెరుగైన default. ఇది 1 నుంచి 10000 వరకు ఉండే relative share. Kernel default 100. ఏదైనా పోటీ ఉన్నప్పుడే ఇది ప్రభావం చూపుతుంది. Load సమయంలో CPUWeight=20 వద్ద నడిచే backup job, 100 వద్ద ఉన్న web serverకు తక్కువ ప్రాధాన్యత పొందుతుంది. Machine idleగా ఉన్నప్పుడు backup job మొత్తం సామర్థ్యాన్ని ఉపయోగించగలదు. Hard quota idleగా ఉన్న సామర్థ్యాన్ని వృథా చేస్తుంది.
CPU limit వల్ల ఏమి లభిస్తుందో వాస్తవికంగా అంచనా వేయాలి. CPU-bound process సాధారణంగా Linuxను పూర్తిగా నిలిపివేయదు, ఎందుకంటే scheduler అందరికీ సమయాన్ని కేటాయిస్తూనే ఉంటుంది. Machineను నిలిపివేసేది సాధారణంగా memory. Predictable ceiling కావాలంటే CPUQuota= ఉపయోగించాలి. ఉదాహరణకు, ఒక build లేదా సాధారణంగా ఒక గంటపాటు పూర్తి CPU సామర్థ్యంతో నడిచే agent కోసం ఇది ఉపయోగపడుతుంది. ఇలాంటి workloadకు అవసరమైన పరిమాణాన్ని నిర్ణయించడం వేరే విషయం. దీనిని coding agent VPSకు ఎంత RAM మరియు CPU అవసరంలో వివరించాం.
మీ processesలో ఏదీ ఎక్కువ CPU ఉపయోగించకపోయినా CPU busyగా కనిపిస్తే, కారణం hypervisorకు అవతలి వైపు ఉండవచ్చు. దీనిని noisy neighbour వల్ల కలిగే CPU steal time అంటారు. మీరు అమర్చే quota దానిని మార్చదు.
TasksMax ఒక fork loop ను ఆపుతుంది
TasksMax= అనేది ఒక unit కలిగి ఉండగల processes మరియు threads సంఖ్య. Threads కూడా ఇందులో లెక్కించబడతాయి. అందువల్ల process list సూచించే సంఖ్యకంటే Java లేదా Go సేవకు ఎక్కువ headroom అవసరం. Loopలో fork చేసే script నుంచి రక్షణ కల్పించడానికి ఇది తక్కువ ఖర్చుతో కూడిన మార్గం. ఎందుకంటే మొత్తం సిస్టమ్లో process IDs అయిపోకముందే, ఆ unit లోనే fork విఫలమవుతుంది.
TasksMax=128ఒక unit ఈ పరిమితిని చేరుకున్నప్పుడు, kernel cgroup పేరును పేర్కొంటూ ఒక log line రాస్తుంది:
cgroup: fork rejected by pids controller in /system.slice/myapp.serviceసాధారణంగా ప్రోగ్రామ్ స్వయంగా 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 ను ప్రింట్ చేసి, మీ terminal లో command ను నడుపుతుంది. Output మీ screen పైనే ఉంటుంది. Command ముగిసినప్పుడు limits తొలగిపోతాయి. systemd.resource-control లోని ఏ property అయినా -p తర్వాత పనిచేస్తుంది.
దీర్ఘకాలం నడిచే job కోసం --scope ను తొలగించి, దానికి ఒక పేరు ఇవ్వండి. అప్పుడు అది transient service గా background లో నడుస్తుంది. Logs journal లో నమోదు అవుతాయి:
sudo systemd-run --unit=nightly-import -p MemoryMax=1G -p CPUWeight=20 ./import-data.sh
journalctl -u nightly-import -fమీరు root కాకపోయినా అదే options ను --user తో ఉపయోగించవచ్చు. అయితే మీ user manager కు అప్పగించిన controllers మాత్రమే ఉంటాయి. అందువల్ల అక్కడ ఒక property తిరస్కరించబడవచ్చు. అలా జరిగితే sudo తో నడపండి. ఒక job కు శాశ్వత స్థానం అవసరమైనప్పుడు, ఈ settings ను మార్పులేకుండా నిజమైన unit లోకి తరలించవచ్చు: systemd service మరియు timer గా script ను నడపడం చూడండి.
Swap గురించిన ప్రశ్న, నిజాయితీగా సమాధానం
Swap అనేది వైఫల్యాన్ని నివారించదు, కానీ అది సంభవించే విధానాన్ని మారుస్తుంది.
Swap లేనప్పుడు, మెమరీ లీక్ పరిమితిని చేరుకోగానే ఏదో ఒక ప్రక్రియ సెకన్లలో ఆగిపోతుంది. ఈ అంతరాయం స్పష్టంగా, తక్కువ సమయంలో జరుగుతుంది మరియు ఆ తర్వాత journal లో దాన్ని గుర్తించడం సులభం. Swap ఉన్నప్పుడు, kernel తక్కువగా ఉపయోగించే anonymous pages ను డిస్క్లోకి రాసి సమయాన్ని కొనుగోలు చేస్తుంది. ఒకవేళ ఆ ప్రక్రియ మెమరీ వినియోగం ఒక స్థాయి వద్ద ఆగిపోయేది అయితే, swap మిమ్మల్ని కాపాడుతుంది. ఒకవేళ అది అదుపులేని లీక్ అయితే, swap ఐదు సెకన్ల అంతరాయాన్ని ఇరవై నిమిషాల స్తంభనగా మారుస్తుంది. ఈ స్తంభన మరింత ప్రమాదకరం, ఎందుకంటే ఒక ప్రక్రియ ఆగిపోతే కనీసం మీకు పని చేసే shell అందుబాటులో ఉంటుంది, కానీ సిస్టమ్ thrashing కు గురైతే ఏదీ పని చేయదు.
swapon --show
free -hచిన్న VPS లలో ఆచరణాత్మక మార్గం ఇది: ఒకసారి కేటాయించి మళ్ళీ ఎప్పటికీ ఉపయోగించని పేజీల కోసం ఒక చిన్న swap file ను ఉంచండి, మరియు మీరు కోల్పోవడానికి సిద్ధంగా ఉన్న units పై MemorySwapMax=0 ను సెట్ చేయండి. ముఖ్యమైన సేవలు వాటి swap ను కలిగి ఉంటాయి. ఊహించని విధంగా ప్రవర్తించే సేవలు త్వరగా పరిమితిని తాకుతాయి, మరియు వాటి cap పక్కన ఉన్న restart policy వాటిని తిరిగి ప్రారంభిస్తుంది.
vm.swappiness ను తగ్గించడం అనేది ఒక బలహీనమైన పద్ధతి, ఎందుకంటే దీని వెనుక ఉన్న కారణం తెలుసుకోవడం ముఖ్యం. ఇది కేవలం page cache ను తొలగించడానికి మరియు anonymous pages ను swap చేయడానికి మధ్య సమతుల్యతను మాత్రమే మారుస్తుంది, రెండింటికీ తర్వాత డిస్క్ రీడ్ అవసరమవుతుంది. ఇది ఏ పేజీలు thrash అవుతాయో మారుస్తుంది తప్ప, సిస్టమ్ thrashing కు గురికాకుండా ఆపలేదు.
స్టాల్కు ముందే ఒక ముందస్తు OOM daemon ప్రక్రియను నిలిపివేస్తుంది
Reclaim పూర్తిగా విఫలమయ్యే వరకు kernel వేచి ఉంటుంది. చిన్న VPSలో ఆ వేచిచూసే సమయమే మీరు machine ను కోల్పోయే ఖచ్చితమైన వ్యవధి. Userspace daemons memory ను స్వయంగా పర్యవేక్షించి, ముందుగానే ప్రక్రియలను నిలిపివేయడం ద్వారా ఈ వ్యవధిని తగ్గిస్తాయి.
earlyoom అందుబాటులో ఉన్న memory మరియు free swap ను సెకనుకు పది సార్లు వరకు తనిఖీ చేస్తుంది. రెండూ తమ thresholds కంటే దిగువకు వచ్చినప్పుడు మాత్రమే అత్యధిక oom_score ఉన్న ప్రక్రియను నిలిపివేస్తుంది. swap లేని machineలో memory threshold ఒక్కటే నిర్ణయాత్మకం.
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 అందుబాటులో ఉన్న memory కనిష్ఠాన్ని, -s PERCENT free swap కనిష్ఠాన్ని నిర్దేశిస్తాయి. రెండింటి default విలువ 10 percent. ప్రతి జతలోని రెండవ సంఖ్య SIGKILL పరిమితి. Memory మరియు swap రెండూ వాటి మొదటి విలువల కంటే దిగువకు వచ్చినప్పుడు earlyoom SIGTERM పంపుతుంది. రెండూ రెండవ విలువ కంటే దిగువకు వచ్చినప్పుడు SIGKILL పంపుతుంది. ఈ రెండవ విలువ defaultగా మొదటి విలువలో సగం ఉంటుంది. --avoid మరియు --prefer patterns ను quotation marks లేకుండా, spaces లేకుండా ఉంచండి. systemd quotation marks ను అక్షరాలుగానే పంపుతుంది. అందువల్ల quoted pattern ఎప్పుడూ match కాదు. మార్పును sudo systemctl restart earlyoom తో అమలు చేయండి. ఏ ప్రక్రియను నిలిపివేసిందో, ఆ ప్రక్రియ ఎంత memory ఉపయోగిస్తోందో చూడటానికి journalctl -u earlyoom ను చదవండి.
systemd-oomd మరొక option. దీని manual page దీనిని "kernel spaceలో OOM సంభవించే ముందు cgroups-v2 మరియు pressure stall information (PSI) ఉపయోగించి పర్యవేక్షించి, సరిదిద్దే చర్య తీసుకునే system service"గా వివరిస్తుంది. ఇది ఒకే ప్రక్రియలపై కాకుండా మొత్తం cgroupsపై పనిచేస్తుంది. అందువల్ల ఇది stray child ను కాకుండా ఒక 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 ను ఎంచుకోవడానికి రెండు daemons పోటీపడతాయి. దాంతో ఏ 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 లో కలిగి ఉన్న anonymous memory (ఉదాహరణకు heap), ఇక్కడ ఇది సుమారు 1.8 GB. Resident file mappings మరియు shared memory లు విడిగా file-rss మరియు shmem-rss గా లెక్కించబడతాయి. బ్రాకెట్లలో ఉన్న పేరును జాగ్రత్తగా గమనించండి. Kernel ఎంచుకున్న బాధితుడు అదే, మరియు kernel సాధారణంగా అతిపెద్ద process ను ఎంచుకుంటుంది; కానీ అది ఎప్పుడూ మెమరీ కొరతకు కారణమైన process కాకపోవచ్చు.
Cgroup పరిమితి వల్ల జరిగిన kill కు వేరే prefix ఉంటుంది, మరియు దానికి పైన ఉన్న నివేదిక దాని స్వంత పరిమితిని దాటిన 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 లోనే రోగనిర్ధారణకు కావాల్సిన సమాచారం ఉంటుంది. Memory cgroup out of memory అంటే ఒక unit మీరు ఇచ్చిన MemoryMax= పరిమితిని దాటిందని, మిగిలిన సర్వర్ బాగుందని అర్థం. సాధారణ Out of memory అంటే మొత్తం సర్వర్లోనే మెమరీ అయిపోయిందని అర్థం, అంటే మీరు పెట్టిన పరిమితులు లేవు లేదా అవి చాలా ఎక్కువగా ఉన్నాయి.
ఆ తర్వాత 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 లైన్ రాదు:
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 అనేది ఎన్ని process లు నిజంగా kill అయ్యాయో లెక్కిస్తుంది. oom_kill 0 తో కూడిన పెద్ద high అనేది పైన పేర్కొన్న silent case: cgroup సృష్టించబడినప్పటి నుండి ఆ unit ఒక్క kill కూడా లేకుండా పదేపదే throttled అవుతూనే ఉంది, కాబట్టి systemd ఎటువంటి వైఫల్యాన్ని రికార్డ్ చేయలేదు. ఈ counter ఎప్పుడూ పెరుగుతూనే ఉంటుంది, కాబట్టి ఒక నిమిషం వ్యవధిలో రెండుసార్లు చదవండి: పెరుగుతూనే ఉన్న high అంటే throttling ప్రస్తుతం జరుగుతోందని అర్థం. memory.peak (Linux 5.19 మరియు అంతకంటే కొత్తవి) ఆ cgroup చేరుకున్న గరిష్ట వినియోగాన్ని చూపుతుంది, MemoryMax= ను నిర్ణయించడానికి ఈ సంఖ్యను ఉపయోగించాలి. Unit restart అయినప్పుడు systemd మళ్ళీ cgroup ను సృష్టిస్తుంది కాబట్టి, ఈ రెండు ఫైళ్లు reset అవుతాయి.
వీటన్నింటికీ ఒక ప్రాథమిక అవసరం ఉంది. /var/log/journal లేకపోతే, journal RAM లోనే ఉంటుంది, మరియు సర్వర్ను recover చేయడానికి మీరు చేసే reboot తర్వాత ప్రతి లైన్ తొలగించబడుతుంది.
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --list-bootsjournalctl --list-boots ప్రస్తుత boot కంటే ఎక్కువ చూపిస్తుందంటే, చరిత్ర ఇప్పుడు భద్రంగా ఉందని అర్థం, కాబట్టి journalctl -k -b -1 ద్వారా మీరు క్రాష్ అయిన boot కి సంబంధించిన kernel సందేశాలను చూడవచ్చు.
చిన్న VPS కోసం ప్రారంభ అమరిక
2 GB ప్లాన్లో kernel మరియు page cache కోసం 300 నుంచి 400 MB వరకు వదిలివేయండి. అన్ని పరిమితుల మొత్తం 2 GBకు సమానంగా ఉండనివ్వకండి. ప్రతి unit ఒకేసారి గరిష్ఠ వనరులను ఉపయోగించవచ్చు. ముఖ్యమైన సేవకు ఎక్కువ భాగం కేటాయించండి. దాని చుట్టూ ఉన్న అనిశ్చిత అవసరాల సేవలకు పరిమితులు పెట్టండి.
[Service]
MemoryHigh=256M
MemoryMax=384M
MemorySwapMax=0
CPUWeight=20
TasksMax=64
Restart=on-failure
RestartSec=5sసిస్టమ్లోకి ప్రవేశించే మార్గాన్ని ఉంచడానికి మరో అమరిక ఉపయోగపడుతుంది. OOMScoreAdjust=-500 ను ssh.service కోసం drop-in లో అమర్చితే, global OOM killer మీ SSH daemon ను victim గా ఎంచుకునే అవకాశం గణనీయంగా తగ్గుతుంది. దీని వల్ల control panel నుంచి reboot చేయాల్సిన బదులు సర్వర్ సమస్యను పరిష్కరించవచ్చు. ఇది kernel ఎంచుకునే victim ను మాత్రమే మారుస్తుంది. stall వ్యవధిని తగ్గించదు.
Containers వాటి స్వంత cgroups లో నడుస్తాయి. వీటిని మీ unit files కాకుండా container runtime సృష్టిస్తుంది. అందువల్ల docker.service పై పెట్టిన పరిమితి ఒక container పై పరిమితిగా మారదు. ప్రతి container కు సంబంధించిన MemoryMax= మరియు CPUQuota= సమానమైన అమరికలు Docker Composeలో memory మరియు CPU పరిమితులను అమర్చడం లో వివరించబడ్డాయి.
FAQ
రన్అవే ప్రాసెస్ (runaway process) ను ఆపడానికి బదులుగా నా VPS ఎందుకు ఫ్రీజ్ అయింది?
ఎందుకంటే మెమరీని తిరిగి పొందే ప్రక్రియ (reclaim) ఎంత సమయం తీసుకుంటుందనే దానితో సంబంధం లేకుండా, అది పేజీలను తిరిగి ఇస్తుందా లేదా అనే దానిపైనే కెర్నల్ పురోగతిని అంచనా వేస్తుంది. మెమరీ తక్కువగా ఉన్నప్పుడు, అది రన్ అవుతున్న ప్రోగ్రామ్ల ఎగ్జిక్యూటబుల్ పేజీలతో సహా పేజీ కాష్ను తొలగిస్తుంది, ఆపై తదుపరి ఇన్స్ట్రక్షన్లో వాటిని తిరిగి చదువుతుంది. అన్నీ స్టోరేజ్ కోసం వేచి ఉంటాయి మరియు సాంకేతికంగా ఏ కేటాయింపు (allocation) విఫలం కాలేదు, కాబట్టి OOM కిల్లర్ ఎప్పుడూ పిలవబడదు. ఇది జరుగుతున్నప్పుడు /proc/pressure/memory ని తనిఖీ చేయండి: full avg10 40 కంటే ఎక్కువగా ఉందంటే, గత పది సెకన్లలో 40% కంటే ఎక్కువ సమయం పాటు, ఐడిల్గా లేని ప్రతి టాస్క్ ఒకే సమయంలో మెమరీ కోసం నిలిచిపోయిందని అర్థం. earlyoom వంటి యూజర్స్పేస్ డెమోన్, సర్వర్ ఆ స్థితికి చేరుకోకముందే ప్రాసెస్ను నిలిపివేస్తుంది.
MemoryHigh మరియు MemoryMax మధ్య తేడా ఏమిటి?
MemoryHigh= అనేది థ్రోటిల్ చేసే సాఫ్ట్ క్యాప్. కెర్నల్ ఆ యూనిట్ నుండి మెమరీని గట్టిగా తిరిగి పొందుతుంది మరియు దాని కేటాయింపులను నెమ్మదిస్తుంది, కానీ వినియోగం ఆ సంఖ్యను మించవచ్చు మరియు ఏదీ నిలిపివేయబడదు. MemoryMax= అనేది హార్డ్ క్యాప్: దీని పరిమితిలో నెరవేర్చలేని కేటాయింపు జరిగినప్పుడు, ఆ యూనిట్ యొక్క సొంత cgroup లోపల OOM కిల్లర్ ప్రేరేపించబడుతుంది. దీనివల్ల బాక్స్లో ఉన్న అతిపెద్ద ప్రాసెస్ కాకుండా, సమస్యకు కారణమైన ప్రాసెస్ మాత్రమే నిలిపివేయబడుతుంది. MemoryHigh= ని MemoryMax= కంటే తక్కువగా సెట్ చేయండి మరియు వాటి మధ్య ఉన్న వ్యత్యాసాన్ని హెచ్చరిక జోన్గా పరిగణించండి.
OOM కిల్లర్ ఏ సర్వీస్ను ప్రభావితం చేసిందో నేను ఎలా కనుగొనాలి?
journalctl -k --grep "Killed process" --since "2 hours ago" ని రన్ చేయండి. Memory cgroup out of memory తో ప్రారంభమయ్యే లైన్ అంటే ఒక యూనిట్ దాని సొంత MemoryMax= ని తాకిందని అర్థం, అదే సాధారణ Out of memory అంటే మొత్తం మెషీన్లో మెమరీ అయిపోయిందని అర్థం. ఆ తర్వాత journalctl -u <unit> -n 50 ని రన్ చేసి Failed with result 'oom-kill' కోసం వెతకండి. మీ సర్వర్లో /var/log/journal లేకపోతే, జర్నల్ RAM లో ఉండి ఉంటుంది మరియు రీబూట్తో సాక్ష్యాలు పోయి ఉంటాయి, కాబట్టి తదుపరి సంఘటనకు ముందే ఆ డైరెక్టరీని సృష్టించండి.
చిన్న VPS కి నేను swap ని జోడించాలా?
ఒకసారి కేటాయించబడి మళ్ళీ ఎప్పుడూ ఉపయోగించని కోల్డ్ పేజీల కోసం చిన్న swap ఫైల్ సహాయపడుతుంది. ఇది రన్అవే ప్రాసెస్ విషయంలో సహాయపడదు: ఇది నిలిపివేతను ఆలస్యం చేస్తుంది మరియు తక్కువ సమయం ఉండే అంతరాయాన్ని, మీరు లాగిన్ అయి పరిష్కరించలేని సుదీర్ఘమైన స్టాల్గా మారుస్తుంది. swap ని తక్కువగా ఉంచండి మరియు మీరు కోల్పోవడానికి సిద్ధంగా ఉన్న యూనిట్లపై MemorySwapMax=0 ని సెట్ చేయండి. తద్వారా అవి త్వరగా తమ పరిమితిని చేరుకుంటాయి మరియు Restart=on-failure సెట్ చేయబడి ఉంటే, ముఖ్యమైన సర్వీసులు తమ swap ని కలిగి ఉన్నప్పుడు ఇవి స్వయంచాలకంగా తిరిగి వస్తాయి.
యూనిట్ ఫైల్ రాయకుండానే నేను ఒక కమాండ్ను పరిమితం చేయవచ్చా?
అవును. sudo systemd-run --scope -p MemoryMax=1G -p CPUQuota=50% ./script.sh ఆ పరిమితులతో మీ టెర్మినల్లోని తాత్కాలిక స్కోప్ (transient scope) లో కమాండ్ను రన్ చేస్తుంది, మరియు అది ముగిసినప్పుడు ఆ పరిమితులు తొలగిపోతాయి. systemd.resource-control నుండి ప్రతి ప్రాపర్టీ -p తర్వాత అందుబాటులో ఉంటుంది, కాబట్టి MemorySwapMax=, TasksMax= మరియు CPUWeight= అక్కడ కూడా పనిచేస్తాయి. --scope ని వదిలేసి, జాబ్ను బ్యాక్గ్రౌండ్లో రన్ చేయడానికి మరియు దాని అవుట్పుట్ను జర్నల్లో ఉంచడానికి --unit=name ని జోడించండి.