systemd ద్వారా ప్రాసెస్ మెమరీ మరియు CPUని పరిమితం చేయడం
systemd unit ఫైల్లో MemoryMax, CPUQuota సెట్ చేయడం ద్వారా మీ VPS పనితీరును మెరుగుపరచండి. OOM kill ఎర్రర్స్ మరియు cgroup v2 పరిమితులను ఎలా సమర్థవంతంగా నిర్వహించాలో ఇక్కడ తెలుసుకోండి.
systemd drop-in ఫైల్ ద్వారా ప్రాసెస్ మెమరీ మరియు CPU పరిమితులను విధించడం
Linux VPSలో ఒక ప్రాసెస్ తీసుకునే మెమరీ మరియు CPUని, ఆ ప్రాసెస్ను రన్ చేసే unit ఫైల్కు కొన్ని లైన్లను జోడించడం ద్వారా పరిమితం చేయవచ్చు. MemoryMax= అనేది మెమరీపై విధించే గరిష్ట పరిమితి. CPUQuota= అనేది ప్రాసెసర్ సమయంపై విధించే పరిమితి. ఈ రెండింటినీ cgroup v2 (control groups, version 2) ద్వారా అమలు చేస్తారు. ఇది సర్వర్లోని ప్రతి సేవను పర్యవేక్షించడానికి systemd ఇప్పటికే ఉపయోగిస్తున్న కెర్నల్ ఫీచర్.
sudo systemctl edit myapp.serviceఇది సూచనలతో కూడిన drop-in ఫైల్ను తెరుస్తుంది. వాటి పైన ఈ క్రింది వాటిని జోడించండి:
[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 కమాండ్ మీరు ఇచ్చిన సంఖ్యలను కెర్నల్ యూనిట్లలోనే తిరిగి చూపాలి: MemoryMax=805306368 మరియు CPUQuotaPerSecUSec=800ms. ఒకవేళ అది MemoryMax=infinity అని చూపిస్తే, ఆ drop-in ఫైల్ లోడ్ కాలేదని అర్థం. ఫైల్ /etc/systemd/system/myapp.service.d/override.conf వద్ద సేవ్ అయిందో లేదో, మరియు అది [Service] హెడర్తో మొదలైందో లేదో తనిఖీ చేయండి. ఎందుకంటే, పైన సెక్షన్ హెడర్ లేకుండా సెట్టింగ్ లైన్ ఉంటే, systemd Assignment outside of section. Ignoring. అని లాగ్ చేసి, ఎటువంటి పరిమితులు లేకుండానే సేవను ప్రారంభిస్తుంది.
ఈ గైడ్లోని మిగిలిన భాగం ఆ సంఖ్యలను ఎలా ఎంచుకోవాలి మరియు సెట్ చేసిన తర్వాత కూడా ఏవైనా సమస్యలు వస్తే ఏమి చేయాలి అనే దాని గురించి వివరిస్తుంది.
ఒక runaway process VPS ను ఎందుకు స్తంభింపజేస్తుంది (అది మెమరీని పూర్తిగా నింపనప్పుడు కూడా)
ఒక process నిర్ణీత మెమరీ పరిమితిని దాటినప్పుడు, అది సెకనులోపు ఆగిపోయి, సేవ మళ్ళీ ప్రారంభమవుతుంది. ఇది మంచి పరిస్థితి. చెడు పరిస్థితి ఏమిటంటే, ఏదీ ఆగిపోదు: సర్వర్ ping కు స్పందిస్తుంది, SSH కనెక్షన్ను అంగీకరిస్తుంది, కానీ shell prompt మాత్రం రాదు. యంత్రం పని చేస్తూనే ఉంటుంది, కానీ ఆ పనిలో ఏదీ ఉపయోగకరంగా ఉండదు.
దీనికి కారణం స్పష్టంగా ఉండదు, కాబట్టి దీని వెనుక ఉన్న విధానాన్ని ఇక్కడ చూడండి. ఖాళీ మెమరీ తగ్గినప్పుడు, kernel కొత్త పేజీలను ఇచ్చే బదులు ఉన్న పేజీలను తిరిగి పొందుతుంది (reclaim). తిరిగి పొందడానికి సులభమైనవి file-backed పేజీలు, మరియు నడుస్తున్న ప్రతి ప్రోగ్రామ్ యొక్క executable code page cache లో ఉంటుంది. కాబట్టి kernel sshd యొక్క text పేజీలను తొలగిస్తుంది. ఆ తర్వాత sshd ఏ instruction ను రన్ చేయాలన్నా, అది page fault అవుతుంది మరియు ఆ bytes ను storage నుండి మళ్ళీ చదవాల్సి వస్తుంది. ప్రతి process రన్ అవ్వడానికి బదులుగా disk కోసం వేచి ఉంటుంది. ఒకే పేజీలు బయటకు వెళ్లడం, మళ్ళీ లోపలికి రావడం ఒక చక్రంలా జరుగుతుంది, దీన్నే thrashing అంటారు.
ల్యాప్టాప్ కంటే VPS లో ఈ సమస్య రెండు కారణాల వల్ల తీవ్రంగా ఉంటుంది. Storage తరచుగా network attached లేదా shared గా ఉంటుంది, కాబట్టి స్థానిక NVMe పరికరంతో పోలిస్తే ప్రతి fault కు ఎక్కువ మిల్లీసెకన్లు పడుతుంది. మరియు 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 అంటే గత పది సెకన్లలో, సర్వర్లోని ప్రతి runnable task మెమరీ పని కోసం వేచి ఉంటూ 48% సమయం వృథా అయ్యిందని, కాబట్టి ఏదీ రన్ అవ్వలేదని అర్థం. ఆరోగ్యకరమైన సర్వర్లో full విలువ సున్నాకి దగ్గరగా ఉంటుంది. 10 కంటే ఎక్కువ ఉంటే వినియోగదారుకు నెమ్మదిగా అనిపిస్తుంది, మరియు 40 లేదా అంతకంటే ఎక్కువ ఉంటే సర్వర్ స్తంభించిపోయినట్లుగా అనిపిస్తుంది.
అందుకే కేవలం ఒక పరిమితి (limit) మాత్రమే హామీ కాదు. MemoryHigh= కింద ఉన్న unit ను ఆపివేయడానికి బదులుగా throttled చేస్తారు, కాబట్టి అది నెమ్మదిగా ఉన్నా నడుస్తూనే ఉంటుంది. systemd దృష్టిలో అది ఎప్పుడూ విఫలం కాలేదు కాబట్టి, ఏదీ దాన్ని రీస్టార్ట్ చేయదు. Swap చేయడానికి అనుమతించబడిన ఒక capped unit, ఒకే shared పరికరం ద్వారా సర్వ్ చేయబడే reads మరియు writes ను సృష్టిస్తుంది. దీనివల్ల సర్వర్లోని ప్రతి ఇతర సేవకు /proc/pressure/io పెరిగిపోవచ్చు. పరిమితులు కొరతకు ఎవరు బాధ్యత వహించాలో నిర్ణయిస్తాయి, కానీ అవి సామర్థ్యాన్ని (capacity) సృష్టించలేవు.
మీ VPS cgroup v2 లో నడుస్తుందో లేదో తనిఖీ చేయండి
stat -fc %T /sys/fs/cgroupcgroup2fs అనేది unified hierarchy, ఇది కింద పేర్కొన్న ప్రతి సెట్టింగ్కు అవసరం. tmpfs అంటే సర్వర్ పాత v1 లేఅవుట్తో బూట్ అయిందని అర్థం, అక్కడ MemoryHigh= మరియు MemorySwapMax= ఉండవు మరియు ప్రతి unit కి సంబంధించిన OOM ప్రవర్తన భిన్నంగా ఉంటుంది. Ubuntu 22.04 మరియు ఆ తర్వాతి వెర్షన్లు, అలాగే Debian 11 మరియు ఆ తర్వాతి వెర్షన్లు డిఫాల్ట్గా v2ని ఉపయోగిస్తాయి. పాత ఇమేజ్ లేదా systemd.unified_cgroup_hierarchy=0 తో బూట్ అయిన కెర్నల్ v2ని ఉపయోగించవు.
cgroup v2 లో systemd ప్రతి unit కి డిఫాల్ట్గా memory accounting ని ఆన్ చేస్తుంది, కాబట్టి గణాంకాలు ఇప్పటికే అక్కడ ఉంటాయి:
systemd-cgtop -mఇది మెమరీ వినియోగం ఆధారంగా cgroups ను క్రమబద్ధీకరిస్తుంది. సర్వర్ స్పందిస్తున్నంత సేపు, "సర్వర్లో మెమరీని ఏది ఎక్కువగా వాడుతోంది" అని తెలుసుకోవడానికి ఇది అత్యంత వేగవంతమైన మార్గం. సర్వర్ కొత్తదైతే, కొత్త VPS లో మొదటి పది నిమిషాలు లో చేసే అకౌంట్ మరియు ఫైర్వాల్ సెటప్ దీనికంటే ముందే పూర్తి చేయాలి.
MemoryHigh మరియు MemoryMax ల మధ్య వ్యత్యాసం.
ఈ రెండు memory సెట్టింగ్ల మధ్య ఉన్న తేడా, ఒక అప్లికేషన్ విఫలమైనప్పుడు అది ఎలా కనిపిస్తుందో నిర్ణయిస్తుంది.
MemoryHigh=అనేది ఒక soft cap. దీనిని దాటినప్పుడు, kernel ఆ cgroup నుండి memoryని వేగంగా తిరిగి పొందుతుంది మరియు కేటాయింపులను (allocations) ఉద్దేశపూర్వకంగా నెమ్మదిస్తుంది. వినియోగం ఈ పరిమితిని దాటి వెళ్లవచ్చు, కానీ ఏ ప్రక్రియ (process) నిలిపివేయబడదు.MemoryMax=అనేది ఒక hard cap. దీని పరిమితిలో memory కేటాయింపు సాధ్యం కానప్పుడు, OOM killer ఆ cgroup లోపలే పనిచేసి, ఆ unit కి చెందిన ఏదో ఒక process ని నిలిపివేస్తుంది.
మీరు పూర్తిగా నమ్మని దేనికైనా 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 నుండి పూర్తిగా దూరంగా ఉంచుతుంది, దీనివల్ల సేవ నెమ్మదించడం కంటే, త్వరగా మరియు స్పష్టంగా నిలిచిపోవడం జరుగుతుంది.
ఒక 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% అంటే ఒక కోర్లో సగం అని అర్థం. CPUQuota=200% అంటే రెండు కోర్లకు సమానం, దీనిని ఆ unit తనకు నచ్చినన్ని threads కి విస్తరించుకోవచ్చు. 2 vCPU ప్లాన్ ఉన్నప్పుడు, CPUQuota=200% అంటే మొత్తం సర్వర్ సామర్థ్యం అని అర్థం.
చాలా సేవలకు CPUWeight= ఒక మెరుగైన డిఫాల్ట్ ఎంపిక. ఇది 1 నుండి 10000 వరకు ఉండే సాపేక్ష వాటా (relative share), మరియు కెర్నల్ డిఫాల్ట్ విలువ 100. వనరుల కోసం పోటీ ఉన్నప్పుడు మాత్రమే ఇది పనిచేస్తుంది: లోడ్ ఎక్కువగా ఉన్నప్పుడు CPUWeight=20 వద్ద ఉన్న బ్యాకప్ జాబ్, 100 వద్ద ఉన్న వెబ్ సర్వర్కు ప్రాధాన్యతనిస్తుంది, అదే సమయంలో సర్వర్ ఖాళీగా ఉన్నప్పుడు ఆ బ్యాకప్ జాబ్ మొత్తం సామర్థ్యాన్ని వాడుకోగలదు. హార్డ్ కోటా (hard quota) ఇలాంటి ఖాళీ సామర్థ్యాన్ని వృథా చేస్తుంది.
CPU పరిమితి వల్ల మీకు ఏమి లభిస్తుందో స్పష్టంగా అర్థం చేసుకోండి. CPU-bound ప్రాసెస్ లైనక్స్ను స్తంభింపజేయడం చాలా అరుదు, ఎందుకంటే షెడ్యూలర్ అందరికీ సమయాన్ని కేటాయిస్తూనే ఉంటుంది. సర్వర్ డౌన్ అవ్వడానికి కారణం సాధారణంగా మెమరీ (RAM). ఒక బిల్డ్ ప్రాసెస్ లేదా ఏజెంట్ వంటివి గంటల తరబడి పూర్తి సామర్థ్యంతో పనిచేసేటప్పుడు, వాటికి ఒక ఊహించదగిన పరిమితిని విధించడానికి CPUQuota= ని ఉపయోగించండి. అటువంటి వర్క్లోడ్ పరిమాణాన్ని నిర్ణయించడం అనేది ఒక ప్రత్యేక అంశం, దీని గురించి కోడింగ్ ఏజెంట్ VPS కి ఎంత RAM మరియు CPU అవసరం లో వివరించబడింది.
మీ ప్రాసెస్లు ఏమీ చేయనప్పుడు కూడా CPU బిజీగా కనిపిస్తుంటే, దానికి కారణం హైపర్వైజర్ (hypervisor) అవతలి వైపు ఉండవచ్చు. దీనినే noisy neighbour నుండి CPU steal time అంటారు, మీరు ఎంత కోటా సెట్ చేసినా దీనిని మార్చలేరు.
TasksMax ఫోర్క్ లూప్ను నిరోధిస్తుంది
TasksMax= అనేది ఒక unit కలిగి ఉండగలిగే processes మరియు threads సంఖ్య. Threads కూడా లెక్కించబడతాయి కాబట్టి, Java లేదా Go సర్వీసులకు process జాబితా సూచించే దానికంటే ఎక్కువ సామర్థ్యం అవసరం. లూప్లో ఫోర్క్ అయ్యే స్క్రిప్ట్ నుండి రక్షణ పొందడానికి ఇది అత్యంత చౌకైన మార్గం, ఎందుకంటే బాక్స్లోని మొత్తం process IDs అయిపోవడానికి బదులుగా, ఆ unit లోపలే ఫోర్క్ విఫలమవుతుంది.
TasksMax=128ఒక unit పరిమితిని చేరుకున్నప్పుడు, kernel ఆ cgroup పేరుతో ఒక లైన్ను log చేస్తుంది:
cgroup: fork rejected by pids controller in /system.slice/myapp.serviceసాధారణంగా ప్రోగ్రామ్ స్వయంగా fork: retry: Resource temporarily unavailable అని రిపోర్ట్ చేస్తుంది. systemctl show -p DefaultTasksMax ద్వారా manager డిఫాల్ట్గా ఏమి వర్తింపజేస్తుందో తనిఖీ చేయండి.
systemd-run తో ఒకేసారి జరిగే పనిని పరిమితం చేయడం
దీని కోసం మీకు unit file అవసరం లేదు. systemd-run ఒకే కమాండ్ చుట్టూ తాత్కాలిక (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 ను ప్రింట్ చేసిన తర్వాత మీ టెర్మినల్లో రన్ అవుతుంది. అవుట్పుట్ మీ స్క్రీన్పైనే ఉంటుంది మరియు కమాండ్ ముగియగానే పరిమితులు తొలగిపోతాయి. -p తర్వాత systemd.resource-control లోని ఏ ప్రాపర్టీ అయినా పనిచేస్తుంది.
సుదీర్ఘమైన పని కోసం, --scope ను తొలగించి దానికి ఒక పేరు ఇవ్వండి. అప్పుడు అది బ్యాక్గ్రౌండ్లో తాత్కాలిక సర్వీస్గా రన్ అవుతుంది మరియు journal లోకి లాగ్ అవుతుంది:
sudo systemd-run --unit=nightly-import -p MemoryMax=1G -p CPUWeight=20 ./import-data.sh
journalctl -u nightly-import -fమీరు root కానప్పుడు కూడా --user తో ఇదే ఆప్షన్లు పనిచేస్తాయి, అయితే మీ user manager కు కేటాయించిన controllers మాత్రమే అందుబాటులో ఉంటాయి, కాబట్టి కొన్నిసార్లు ప్రాపర్టీ తిరస్కరించబడవచ్చు. అలా జరిగినప్పుడు దానిని sudo తో రన్ చేయండి. ఒక పనికి శాశ్వతమైన స్థానం అవసరమైనప్పుడు, సెట్టింగ్లను మార్చకుండానే ఒక నిజమైన unit లోకి తరలించవచ్చు: systemd service మరియు timer గా స్క్రిప్ట్ను రన్ చేయడం చూడండి.
Swap గురించి నిజాయితీగా సమాధానం
Swap అనేది వైఫల్యాన్ని నివారించదు, కేవలం దాని రూపాన్ని మారుస్తుంది.
Swap లేనప్పుడు, మెమరీ లీక్ పరిమితిని తాకగానే ఏదో ఒక ప్రక్రియ సెకన్లలో ఆగిపోతుంది. ఈ అంతరాయం స్పష్టంగా, తక్కువ సమయంలో జరుగుతుంది మరియు ఆ తర్వాత journal లో దాన్ని సులభంగా గుర్తించవచ్చు. Swap ఉన్నప్పుడు, kernel తక్కువగా ఉపయోగించే anonymous pages ను డిస్క్లోకి రాసి సమయాన్ని కొనుగోలు చేస్తుంది. ఒకవేళ ఆ ప్రక్రియ మెమరీ వినియోగం ఒక స్థాయి వద్ద ఆగిపోయేది అయితే, swap మిమ్మల్ని కాపాడుతుంది. కానీ అది అదుపులేని లీక్ అయితే, swap ఐదు సెకన్ల అంతరాయాన్ని ఇరవై నిమిషాల స్తంభనగా మారుస్తుంది. ఈ స్తంభన మరింత ప్రమాదకరం, ఎందుకంటే ఒక ప్రక్రియ ఆగిపోతే కనీసం మీకు పని చేసే shell అందుబాటులో ఉంటుంది, కానీ సిస్టమ్ మొత్తం thrashing కు గురైతే ఏదీ పని చేయదు.
swapon --show
free -hచిన్న VPS లలో ఒక ఆచరణాత్మక మార్గం: ఒకసారి కేటాయించి మళ్ళీ ఎప్పుడూ ఉపయోగించని pages కోసం తక్కువ పరిమాణంలో swap file ను ఉంచండి, మరియు మీరు కోల్పోవడానికి సిద్ధంగా ఉన్న units పై MemorySwapMax=0 ను సెట్ చేయండి. ముఖ్యమైన సేవలు వాటి swap ను కలిగి ఉంటాయి. అంచనా వేయలేని సేవలు త్వరగా పరిమితిని తాకి restart అవుతాయి.
vm.swappiness ను తగ్గించడం అనేది ఒక బలహీనమైన పద్ధతి, దీనికి కారణం తెలుసుకోవడం ముఖ్యం. ఇది కేవలం page cache ను తొలగించడానికి మరియు anonymous pages ను swap చేయడానికి మధ్య సమతుల్యతను మాత్రమే మారుస్తుంది, రెండింటికీ తర్వాత డిస్క్ రీడ్ అవసరమవుతుంది. ఇది ఏ pages thrash అవుతాయో మారుస్తుంది తప్ప, సిస్టమ్ thrashing కు గురికాకుండా ఆపలేదు.
స్టాల్ అవ్వకముందే OOM డెమన్ ప్రాసెస్లను నిలిపివేస్తుంది
కెర్నల్ మెమరీని తిరిగి పొందే ప్రయత్నం పూర్తిగా విఫలమయ్యే వరకు వేచి ఉంటుంది. చిన్న VPS సర్వర్లలో, ఆ వేచి ఉండే సమయమే సర్వర్ క్రాష్ అవ్వడానికి కారణమవుతుంది. రెండు యూజర్స్పేస్ డెమన్లు మెమరీని నిరంతరం పర్యవేక్షించి, ముందే ప్రాసెస్లను నిలిపివేయడం ద్వారా ఈ సమస్యను పరిష్కరిస్తాయి.
earlyoom అందుబాటులో ఉన్న మెమరీని మరియు ఖాళీ swap ను పర్యవేక్షిస్తుంది. ఏదైనా ఒక విలువ నిర్ణీత పరిమితి కంటే తగ్గితే, అత్యధిక స్కోరు ఉన్న ప్రాసెస్ను ఇది నిలిపివేస్తుంది.
sudo apt install earlyoom
systemctl status earlyoomDebian మరియు Ubuntu ప్యాకేజీలు ఇన్స్టాల్ చేసిన వెంటనే ఈ సర్వీస్ను ప్రారంభిస్తాయి. దీని ఆప్షన్లు /etc/default/earlyoom లో ఉంటాయి:
EARLYOOM_ARGS="-m 5,2 -s 5,2 --avoid '^(sshd|systemd)$' --prefer '^(node|python3)$'"-m PERCENT అందుబాటులో ఉండాల్సిన కనీస మెమరీని, -s PERCENT కనీస ఖాళీ swap ను సెట్ చేస్తాయి. డిఫాల్ట్గా ఇవి 10 శాతంగా ఉంటాయి. ప్రతి జంటలో రెండవ సంఖ్య SIGKILL పాయింట్ను సూచిస్తుంది: మెమరీ మొదటి విలువ కంటే తగ్గితే earlyoom మొదట SIGTERM పంపుతుంది, ఆపై రెండవ విలువ కంటే తగ్గితే SIGKILL పంపుతుంది. రెండవ విలువ సాధారణంగా మొదటి దానిలో సగం ఉంటుంది. మార్పులను అమలు చేయడానికి sudo systemctl restart earlyoom వాడండి. ఏ ప్రాసెస్ను నిలిపివేసిందో మరియు అది ఎంత మెమరీని వాడుతుందో తెలుసుకోవడానికి journalctl -u earlyoom చదవండి.
systemd-oomd మరొక ఎంపిక. దీని మాన్యువల్ పేజీ ప్రకారం, ఇది "cgroups-v2 మరియు pressure stall information (PSI) ఉపయోగించి, కెర్నల్ స్పేస్లో OOM జరగకముందే పర్యవేక్షించి చర్యలు తీసుకునే సిస్టమ్ సర్వీస్". ఇది విడి ప్రాసెస్ల కంటే cgroups మొత్తాన్ని పరిగణనలోకి తీసుకుంటుంది, కాబట్టి ఇది ఒక యూనిట్ను నిలిపివేస్తుంది కానీ విడిపోయిన చైల్డ్ ప్రాసెస్లను కాదు. యూనిట్లు ManagedOOMMemoryPressure=kill లేదా ManagedOOMSwap=kill ద్వారా దీనిని ఎంచుకోవచ్చు, మరియు పరిమితులు /etc/systemd/oomd.conf లో ఉంటాయి.
systemctl status systemd-oomd
oomctloomctl ప్రస్తుతం దేనిని పర్యవేక్షిస్తుందో చూపిస్తుంది. సర్వర్ ఇమేజ్లలో ఇది తరచుగా ఏమీ చూపదు, ఎందుకంటే ప్రతి యూనిట్ దీనిని ప్రత్యేకంగా ఎంచుకోవాల్సి ఉంటుంది (opt-in). ఏదైనా ఒక డెమన్ను మాత్రమే ఎంచుకోండి. రెండింటినీ ఒకేసారి రన్ చేస్తే, ఏది ప్రాసెస్ను నిలిపివేయాలో పోటీ పడతాయి, దీనివల్ల ప్రాసెస్ ఎందుకు నిలిచిపోయిందో కనుగొనడం కష్టమవుతుంది.
ఏ యూనిట్ బాధ్యత వహించింది?
కర్నల్ ప్రతి కిల్ (kill) ను రికార్డ్ చేస్తుంది కాబట్టి, దానితోనే ప్రారంభించండి.
journalctl -k --grep "Killed process" --since "2 hours ago"గ్లోబల్ OOM కిల్లర్ నుండి వచ్చే కిల్ ఈ విధంగా కనిపిస్తుంది:
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 అనేది ఆ ప్రాసెస్ మరణించినప్పుడు RAMలో కలిగి ఉన్న మెమరీ, ఇక్కడ ఇది సుమారు 1.8 GB. బ్రాకెట్లలో ఉన్న పేరును అనుమానంతో చూడండి. కర్నల్ ఎంచుకున్న బాధితుడు అదే, మరియు కర్నల్ సాధారణంగా అతిపెద్ద ప్రాసెస్ను ఎంచుకుంటుంది, కానీ అది ఎల్లప్పుడూ కొరతకు కారణమైనది కాకపోవచ్చు.
cgroup పరిమితి నుండి వచ్చే కిల్ వేరే ప్రిఫిక్స్ను కలిగి ఉంటుంది, మరియు దానికి పైన ముద్రించిన నివేదిక దాని స్వంత పరిమితిని తాకిన 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ఆ ప్రిఫిక్స్ రోగ నిర్ధారణలో ఎక్కువ భాగాన్ని తెలియజేస్తుంది. Memory cgroup out of memory అంటే ఒక యూనిట్ మీరు ఇచ్చిన MemoryMax= ని తాకిందని మరియు మిగిలిన సర్వర్ బాగుందని అర్థం. సాధారణ Out of 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 కౌంటర్లు మూడవ మూలం, మరియు థ్రోట్లింగ్ (throttling) ను రికార్డ్ చేసే ఏకైక మార్గం ఇదే, ఇది ఎటువంటి లాగ్ లైన్ను సృష్టించదు:
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 అనేది ఆ యూనిట్ ఎన్నిసార్లు MemoryHigh= ని దాటి థ్రోట్ల్ చేయబడిందో లెక్కిస్తుంది. max అనేది అది హార్డ్ క్యాప్ను ఎన్నిసార్లు చేరుకుందో లెక్కిస్తుంది, మరియు oom_kill అనేది వాస్తవానికి చంపబడిన ప్రాసెస్లను లెక్కిస్తుంది. oom_kill 0 తో కూడిన పెద్ద high అనేది ఇంతకు ముందు చెప్పిన నిశ్శబ్ద సందర్భం: సర్వీస్ నడుస్తోంది, చాలా నెమ్మదించింది, మరియు ఎవరికీ ఎటువంటి వైఫల్యాన్ని నివేదించలేదు. memory.peak (Linux 5.19 మరియు అంతకంటే కొత్తవి) cgroup చేరుకున్న గరిష్ట వినియోగాన్ని కలిగి ఉంటుంది, దీనిని MemoryMax= ని నిర్ణయించడానికి ఉపయోగించవచ్చు. యూనిట్ రీస్టార్ట్ అయినప్పుడు ఈ రెండు ఫైళ్లు రీసెట్ అవుతాయి, ఎందుకంటే systemd మళ్ళీ cgroup ను సృష్టిస్తుంది.
వీటన్నింటికీ ఒక ముందస్తు అవసరం ఉంది. /var/log/journal లేకపోతే, జర్నల్ RAMలో ఉంటుంది, మరియు సర్వర్ను రికవర్ చేయడానికి మీరు చేసిన రీబూట్ తర్వాత ప్రతి లైన్ తొలగించబడుతుంది.
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --list-bootsjournalctl --list-boots ప్రస్తుత బూట్ కంటే ఎక్కువ చూపిస్తుందంటే, హిస్టరీ ఇప్పుడు భద్రంగా ఉందని అర్థం, కాబట్టి journalctl -k -b -1 మీకు క్రాష్ అయిన బూట్ నుండి కర్నల్ సందేశాలను చూపగలదు.
చిన్న VPS కోసం ఒక ప్రారంభ బిందువు
2 GB ప్లాన్ ఉన్నప్పుడు, kernel మరియు page cache కోసం 300 నుండి 400 MB వదిలివేయండి. అన్ని యూనిట్ల మొత్తం పరిమితులు కలిపి 2 GB కి చేరకుండా చూసుకోండి, ఎందుకంటే అన్ని యూనిట్లు ఒకే సమయంలో గరిష్ట వినియోగానికి చేరుకోవచ్చు. అత్యంత ముఖ్యమైన సేవకు ఎక్కువ వనరులను కేటాయించి, దాని చుట్టూ ఉన్న ఇతర అదనపు సేవలకు పరిమితులను విధించండి.
[Service]
MemoryHigh=256M
MemoryMax=384M
MemorySwapMax=0
CPUWeight=20
TasksMax=64
Restart=on-failure
RestartSec=5sసర్వర్లోకి ప్రవేశించే మార్గాన్ని కాపాడుకోవడం మరొక ముఖ్యమైన సెట్టింగ్. ssh.service కోసం ఒక drop-in ఫైల్లో OOMScoreAdjust=-500ని సెట్ చేయడం వల్ల, global OOM killer మీ SSH daemon ను బాధితుడిగా ఎంచుకునే అవకాశం చాలా తగ్గుతుంది. సర్వర్ను రీబూట్ చేయాలా లేదా సమస్యను పరిష్కరించాలా అనే తేడా ఇక్కడే ఉంటుంది. ఇది కేవలం kernel ఎంచుకునే బాధితుడిని మాత్రమే మారుస్తుంది, కానీ సిస్టమ్ ఆగిపోయే సమయాన్ని తగ్గించదు.
Containers వాటి స్వంత cgroups లో నడుస్తాయి, వీటిని మీ unit files కాకుండా container runtime సృష్టిస్తుంది. కాబట్టి docker.service పై విధించే పరిమితి ఒక container కు వర్తించదు. MemoryMax= మరియు CPUQuota= లకు సమానమైన container-స్థాయి సెట్టింగ్ల గురించి Docker Compose లో memory మరియు CPU పరిమితులను సెట్ చేయడం లో వివరించబడింది.
FAQ
రన్-అవే ప్రాసెస్ను కిల్ చేయకుండా నా VPS ఎందుకు ఫ్రీజ్ అయింది?
మెమరీ రీక్లెయిమ్ (reclaim) ప్రక్రియ ఎంత సమయం తీసుకుంటుందనే దానితో సంబంధం లేకుండా, పేజీలు తిరిగి వస్తున్నాయా లేదా అనే దానిపైనే కెర్నల్ పనితీరును అంచనా వేస్తుంది. మెమరీ తక్కువగా ఉన్నప్పుడు, అది రన్ అవుతున్న ప్రోగ్రామ్ల ఎగ్జిక్యూటబుల్ పేజీలతో సహా పేజీ క్యాచీని తొలగిస్తుంది, ఆపై తదుపరి ఇన్స్ట్రక్షన్లో వాటిని తిరిగి చదువుతుంది. అన్నీ స్టోరేజ్ కోసం వేచి ఉంటాయి మరియు సాంకేతికంగా ఏ కేటాయింపు (allocation) విఫలం కాలేదు కాబట్టి, OOM కిల్లర్ ఎప్పుడూ పిలవబడదు. ఇది జరుగుతున్నప్పుడు /proc/pressure/memoryని తనిఖీ చేయండి: full avg10 40 కంటే ఎక్కువగా ఉంటే, గత పది సెకన్లలో దాదాపు ఏ టాస్క్ కూడా రన్ కాలేదని అర్థం. earlyoom వంటి యూజర్ స్పేస్ డెమోన్, సర్వర్ ఆ స్థితికి చేరుకోకముందే ప్రాసెస్లను కిల్ చేస్తుంది.
MemoryHigh మరియు MemoryMax మధ్య తేడా ఏమిటి?
MemoryHigh= అనేది థ్రాట్లింగ్ (throttle) చేసే ఒక సాఫ్ట్ క్యాప్. కెర్నల్ ఆ యూనిట్ నుండి మెమరీని గట్టిగా రీక్లెయిమ్ చేస్తుంది మరియు దాని కేటాయింపులను నెమ్మదిస్తుంది, కానీ వినియోగం ఆ సంఖ్యను మించవచ్చు మరియు ఏదీ కిల్ చేయబడదు. 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ని సెట్ చేయండి, తద్వారా అవి వాటి పరిమితిని చేరుకుని త్వరగా రీస్టార్ట్ అవుతాయి, అదే సమయంలో ముఖ్యమైన సర్వీసులు వాటి swapను కలిగి ఉంటాయి.
యూనిట్ ఫైల్ రాయకుండానే ఒక కమాండ్ను పరిమితం చేయవచ్చా?
అవును. sudo systemd-run --scope -p MemoryMax=1G -p CPUQuota=50% ./script.sh మీ టెర్మినల్లోని కమాండ్ను ఆ పరిమితులతో ఒక ట్రాన్సియెంట్ స్కోప్లో రన్ చేస్తుంది, మరియు అది ముగిసినప్పుడు ఆ పరిమితులు తొలగిపోతాయి. systemd.resource-control నుండి ప్రతి ప్రాపర్టీ -p తర్వాత అందుబాటులో ఉంటుంది, కాబట్టి MemorySwapMax=, TasksMax= మరియు CPUWeight= అక్కడ కూడా పనిచేస్తాయి. --scopeని వదిలేసి, జాబ్ను బ్యాక్గ్రౌండ్లో రన్ చేయడానికి మరియు దాని అవుట్పుట్ను జర్నల్లో ఉంచడానికి --unit=nameని జోడించండి.