Lühidalt: PHP2Shelli üleminekumeetme memory_limit=-1 jaoks vajab PHP-FPM PHP-st väljaspool asuvat mälupiiri. systemd all seate selle sättega MemoryHigh= pidurina ja MemoryMax= kõva ülempiirina FPM-teenuse täienduskaustas. ulimit, LimitAS= või LimitDATA= ei sobi selleks php.net'i järgi. Kontrollige lisaks OOMPolicy=, et üks töölisprotsess ei lõpetaks kogu teenust.
Soovitus, mis esmalt hämmastab
php.net'i 21. oktoobril 2026 PHP2Shelli kohta avaldatud üleminekumeetmete hulgas on üks, mis pani paljud administraatorid imestama: memory_limit=-1, see tähendab mälupiiri puudumist PHP-s endas. Aastaid peeti vastupidist heaks tavaks.
Seos augu kirjeldusega on ilmne. CVE-2026-109618 puhul võib mälupuuduse olek PHP katkestada, kui päringuandmed on vaid osaliselt lähtestatud. Üleminekumeede nihutab mälupiiri PHP-st välja operatsioonisüsteemi. php.net seob selle otsesõnu kahe tingimusega: väärtus peab olema ülekirjutamise vastu lukustatud ja piir peab tulema konteineri või cgroup'i kaudu, mitte RLIMIT_AS või RLIMIT_DATA kaudu.
Kes rakendab ainult esimese poole, on saanud serveri ilma ühegi mälupiirita. See artikkel näitab teist poolt. Ka koos jääb meede üleminekuks: auk on parandatud alles versioonidega PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 või kinnitatud tagasiportimisega.
cgroup'id kahes lauses
Control Groups, lühidalt cgroup'id, on Linuxi tuuma funktsioon, mis rühmitab protsesse ja piirab nende ressursse. systemd loob iga teenuse jaoks automaatselt oma cgroup'i ja kõik teenuse protsessid, FPM-teenuse puhul peaprotsess ja kõik töölised, kuuluvad sinna.
systemd mälusuvandid seavad cgroup v2 mälukontrolleri väärtusi. Kas teie süsteem kasutab cgroup v2, näitab lühike käsk:
# "cgroup2fs" tähendab: cgroup v2 on aktiivne
stat -fc %T /sys/fs/cgroup/
Levinumate distributsioonide praegused versioonid kasutavad cgroup v2 vaikimisi. Kui käsk näitab midagi muud, selgitage see enne ümberlülitust, sest systemd dokumentatsioon kirjeldab vanu v1-suvandeid aegunutena.
systemd MemoryMax seadmine PHP-FPM-ile
Piir läheb täienduskausta, nn drop-in'i. Nii jääb paketi unit-fail muutmata ja uuendus teie sätet üle ei kirjuta. Teenuste nimed erinevad distributsiooniti; näide kasutab Debiani ja Ubuntut PHP 8.3-ga.
# Avab drop-in'i redaktori: sudo systemctl edit php8.3-fpm
# Tulemus: /etc/systemd/system/php8.3-fpm.service.d/override.conf
[Service]
MemoryAccounting=yes
MemoryHigh=1536M
MemoryMax=2G
MemorySwapMax=0
OOMPolicy=continue
Suvandite ülevaade systemd dokumentatsiooni järgi:
| Suvand | Mõju | Märkus PHP-FPM-i kohta |
|---|---|---|
MemoryHigh= |
piduripiir: protsesse pidurdatakse tugevalt, mälu võetakse tagasi | tegelik juhtsuurus, veidi MemoryMax all |
MemoryMax= |
absoluutne piir: kui seda ei suudeta hoida, aktiveerub teenuses OOM-killer | viimane kaitseliin |
MemorySwapMax= |
väljalaadimise piir | 0 takistab teenusel selle asemel swapi poole põigata |
OOMPolicy= |
käitumine pärast OOM-sündmust: continue, stop või kill |
continue laseb ülejäänud töölistel edasi töötada |
LimitAS=, LimitDATA= |
rlimitid protsessi kohta | php.net'i järgi selle meetme jaoks sobimatud |
OOMPolicy= väärib erilist tähelepanu. Väärtuse stop või kill korral lõpetab systemd pärast OOM-sündmust kogu teenuse ja kõik selle FPM-teenuse veebisaidid kukuvad välja. Millist väärtust kasutatakse ilma oma määranguta, määrab süsteemi vaikesäte DefaultOOMPolicy=. Kontrollige kehtivat väärtust seetõttu, selle asemel et seda eeldada.
Seejärel taaskäivitage teenus ja lukustage poolis memory_limit:
sudo systemctl restart php8.3-fpm
systemctl show php8.3-fpm -p MemoryHigh -p MemoryMax -p MemorySwapMax -p OOMPolicy -p MemoryCurrent
; Pooli fail, nt /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_value[memory_limit] = -1
Kuidas lukustamine töötab, kirjeldab php_admin_value: sätete kaitsmine ülekirjutamise eest.
Õige väärtuse leidmine
Liiga napp piir tekitab katkestusi tavatöös, liiga helde ei kaitse peaaegu üldse. Lähtekoht on tegelik tarbimine.
- Jälgige kõigi FPM-protsesside tegelikku mälutarvet mõne päeva jooksul, ka koormushetkedel.
- Selgitage välja ühe töölise tüüpiline vajadus ja korrutage see teenuse kõigi poolide
pm.max_childrenväärtustega. - Planeerige juurde peaprotsessi, OPcache'i ja tippude jaoks.
- Seadke
MemoryHigh=mõõdetud tipuväärtusest napilt kõrgemale,MemoryMax=veidi kaugemale selle kohale. - Kohandage väärtusi nädala pärast mõõtmiste ja OOM-sündmuste põhjal.
# Kõigi PHP-FPM-protsesside mälu MB-des (Resident Set Size)
ps -C php-fpm8.3 -o rss= | awk '{s+=$1} END {printf "%.0f MB\n", s/1024}'
# Kõigi cgroup'ide jooksev ülevaade mälu järgi sorteeritult
systemd-cgtop -m
memory_limit väärtuse märkige enne ümberlülitust üles. Pärast uuendust saate pöörduda tagasi PHP kindla piiri juurde; kuidas seda mõistlikult valida, on kirjas artiklis memory_limit õige seadistamine.
Seire: millal piir rakendub
Mälupiir, mille rakendumist keegi ei märka, on vaikne veaallikas. Tuum loendab OOM-sündmusi cgroup'i kaupa ning systemd ja tuumaprotokoll märgivad need üles.
# Teenuse cgroup'i OOM-loendur (tee cgroup v2 korral)
cat /sys/fs/cgroup/system.slice/php8.3-fpm.service/memory.events
# OOM-killeri teated tuumaprotokollis
journalctl -k --since "-1 day" | grep -i "out of memory"
Kui loendur oom_kill kasvab, lõpetab tuum töölisi. See võib viidata liiga napile piirile, vigasele rakendusele või ebatavalistele päringutele. Praeguses olukorras tasub selliseid sündmusi samaaegsete pöördusprotokollidega võrrelda.
Mälupiir on üleminekumeede ega asenda PHP uuendust. Planeerige uuendus paralleelselt ja taaskäivitage seejärel kõik PHP protsessid. Kõik üleminekumeetmed ülevaatlikult on lehel Kiirmeetmed, kui te ei saa veel paikama hakata.
Mis juhtub PHP sees mälupuuduse korral, selgitab memory_limit ja Out-of-Memory. Apache'i puhul mod_php-ga kehtib sama tehnika Apache'i teenuse kohta, ent PHP jagab piiri siis veebiserveri endaga.
Kokkuvõte: ärge unustage teist poolt
memory_limit=-1 on põhjendatav üleminekumeede ainult koos välise piiriga. systemd teeb selle piiri võimalikuks mõne reaga: MemoryHigh pidurina, MemoryMax kõva ülempiirina, MemorySwapMax swapi poole põikamise vastu ja teadlikult valitud OOMPolicy. Mõõtke enne, jälgige pärast ja pidage meeles, et ühe teenuse kõik poolid jagavad piiri.
Peamine aga: planeerige meetme lõpp. Pärast uuendust parandatud PHP versioonile pöörduge tagasi kindla memory_limit juurde. cgroup'i piiri võite säilitada täiendava kaitsena väljaulatuvate protsesside vastu.
Kuidas PHP SOS konkreetselt aitab?
- Mõõta: kaardistame teie PHP teenuste mälutarbe ja tuletame sellest sobivad piirid.
- Rakendada: seame drop-in'id sätetega
MemoryHigh,MemoryMaxja sobivaOOMPolicy, lukustame poolismemory_limitja taaskäivitame teenused kontrollitult. - Jälgida: põimime OOM-sündmused seiresse ja kohandame väärtusi.
- Viia paigani: PHP paigateenuse kaudu paigaldame uuenduse ja võtame üleminekuväärtused seejärel korrapäraselt tagasi.
Korduma kippuvad küsimused
Miks peab memory_limit olema -1? Kas see pole ohtlik?
Üksi oleks. php.net soovitab memory_limit=-1 üleminekumeetmena otsesõnu koos mälupiiriga konteineri või cgroup'i kaudu. Piiramine liigub niimoodi PHP-st välja operatsioonisüsteemi. Ilma selle välise piirita ei tohiks väärtust seada.
Kas saan selle asemel kasutada ulimit'i või LimitAS=?
Ei. php.net soovitab RLIMIT_AS-i ja RLIMIT_DATA-t otsesõnu mitte kasutada ning just neid piire seavad ulimit -v, LimitAS= ja LimitDATA=. systemd dokumentatsioon juhib lisaks tähelepanu, et LimitAS= piirab aadressiruumi, mitte mälukasutust.
Mis juhtub, kui PHP-FPM piirini jõuab?
MemoryHigh puhul pidurdab tuum protsesse ja võtab mälu tagasi. MemoryMax puhul aktiveerub teenuse sees OOM-killer ja lõpetab ühe protsessi, enamasti suure töölise. Kas kogu teenus pärast seda peatub, reguleerib OOMPolicy=.
Kas piir kehtib iga pooli kohta eraldi?
Ei. Ühe FPM-teenuse kõik poolid jagavad ühte cgroup'i ja seega ühist piiri. Veebisaitide kaupa eraldi piirid vajavad eraldi FPM-teenuseid või konteinereid.
Kuidas seada piir Dockeris või Kubernetes'es?
Konteineri mälupiirangu kaudu, näiteks valikuga --memory käsus docker run või resources.limits.memory Kubernetes'es. Mõlemad kasutavad samuti cgroup'e. Põhimõte jääb samaks: piir väljaspool PHP-d, memory_limit PHP-s lukustatud.