Bagaimana membatasi sumber daya total (memori) dari suatu proses dan anak-anaknya

16

Ada banyak pertanyaan dan jawaban tentang membatasi sumber daya dari satu proses, misalnya RLIMIT_AS dapat digunakan untuk membatasi memori maksimum yang dialokasikan oleh suatu proses yang dapat dilihat sebagai VIRT pada suka top. Lebih lanjut tentang topik misalnya di sini. Apakah ada cara untuk membatasi jumlah memori proses tertentu dapat digunakan di Unix?

setrlimit(2) dokumentasi mengatakan:

Proses anak yang dibuat melalui fork (2) mewarisi batasan sumber daya orang tuanya. Batas sumber daya dipertahankan di seluruh eksekutif (2).

Ini harus dipahami dengan cara berikut:

Jika suatu proses memiliki RLIMIT_AS misalnya 2GB, maka itu tidak dapat mengalokasikan lebih banyak memori dari 2GB. Ketika memunculkan anak, batas ruang alamat 2GB akan diteruskan ke anak, tetapi penghitungan dimulai dari 0. Kedua proses tersebut secara bersamaan dapat memakan memori hingga 4GB.

Tetapi apa cara yang bermanfaat untuk membatasi jumlah total memori yang dialokasikan oleh seluruh pohon proses?

Jpe
sumber
7
Saya akan melihat cgroups .
slm
@ sdm Terima kasih! Kedengarannya seperti cgroup adalah sesuatu untuk dicoba. Satu-satunya solusi yang bekerja sejauh ini (selain cara jelek menjumlahkan memori menggunakan PS dan membunuh proses induk jika di atas batas) yang mungkin bekerja menggunakan beberapa bentuk wadah (lxc atau sejenisnya).
jpe
Ya - alat yang saya sadari tidak melakukan grup, hanya proses tunggal, tetapi mengingat bagaimana cgroup bekerja untuk teknologi VM seperti LXC dan Docker saya berharap untuk melakukan apa yang Anda inginkan.
slm
1
Jika itu Linux, letakkan PID induk di namespace-nya sendiri dan kendalikan dan semua anak-anaknya dengan cara itu. Inilah jawaban pengantar untuk konsep itu: unix.stackexchange.com/a/124194/52934
mikeserv

Jawaban:

8

Saya tidak yakin apakah ini menjawab pertanyaan Anda, tetapi saya menemukan ini skrip perl yang mengklaim melakukan persis apa yang Anda cari. Script mengimplementasikan sistemnya sendiri untuk menegakkan batas dengan bangun dan memeriksa penggunaan sumber daya proses dan anak-anaknya. Tampaknya telah didokumentasikan dengan baik dan dijelaskan, dan telah diperbarui baru-baru ini.

Seperti yang dikatakan slm dalam komentarnya, cgroup juga dapat digunakan untuk ini. Anda mungkin harus menginstal utilitas untuk mengelola cgroup, dengan asumsi Anda menggunakan Linux yang harus Anda carilibcgroups .

sudo cgcreate -t $USER:$USER -a $USER:$USER -g memory:myGroup

Pastikan $USERpengguna Anda.

Pengguna Anda kemudian harus memiliki akses ke pengaturan memori cgroup di /sys/fs/cgroup/memory/myGroup .

Anda kemudian dapat menetapkan batas menjadi, katakanlah 500 MB, dengan melakukan ini:

echo 500000000 > /sys/fs/cgroup/memory/myGroup/memory.limit_in_bytes

Sekarang mari kita jalankan Vim:

cgexec -g memory:myGroup vim

Proses vim dan semua anak-anaknya sekarang harus dibatasi untuk menggunakan 500 MB RAM. Namun , saya pikir batas ini hanya berlaku untuk RAM dan bukan swap. Setelah proses mencapai batas mereka akan mulai bertukar. Saya tidak yakin apakah Anda dapat menyiasati hal ini, saya tidak dapat menemukan cara untuk membatasi penggunaan swap menggunakan cgroup.

arnefm
sumber
Solusi yang diajukan memang memungkinkan untuk membatasi ukuran set penduduk dari pohon proses. Perilaku ini tampaknya berbeda dari RLIMIT_AS: mungkin untuk malloc lebih banyak memori daripada batasnya, namun tampaknya tidak mungkin untuk benar-benar menggunakan lebih banyak.
jpe
Secara default, batas memori cgroup hanya berlaku untuk (kurang-lebih) penggunaan RAM fisik. Ada opsi kernel (CONFIG_MEMCG_SWAP) untuk mengaktifkan akuntansi swap; lihat dokumentasi kernel untuk detailnya.
Søren Løvborg
1
Pada fedora,sudo yum install libcgroup-tools
jozxyqk
2

Saya membuat skrip yang melakukan ini, menggunakan cgmanager yang digunakan di Ubuntu. Satu keuntungan adalah bahwa ini tidak memerlukan akses root. Perhatikan bahwa manajemen cgroup sedikit spesifik untuk distro, jadi saya tidak tahu apakah ini berfungsi pada distro yang menggunakan manajemen cgroup systemd.

#!/bin/sh

set -eu

if [ "$#" -lt 2 ]
then
    echo Usage: `basename $0` "<limit> <command>..."
    exit 1
fi

limit="$1"
shift
cgname="limitmem_$$"
echo "limiting memory to $limit (cgroup $cgname) for command $@"

cgm create memory "$cgname" >/dev/null
cgm setvalue memory "$cgname" memory.limit_in_bytes "$limit" >/dev/null
# try also limiting swap usage, but this fails if the system has no swap
cgm setvalue memory "$cgname" memsw.limit_in_bytes "$limit" >/dev/null 2>&1 || true

# spawn subshell to run in the cgroup
set +e
(
set -e
cgm movepid memory "$cgname" `sh -c 'echo $PPID'` > /dev/null
exec "$@"
)
# grab exit code
exitcode=`echo $?`

set -e

echo -n "peak memory used: "
cgm getvalue memory "$cgname" memory.max_usage_in_bytes | tail -1 | cut -f2 -d\"

cgm remove memory "$cgname" >/dev/null
exit $exitcode

penggunaan: simpan seperti limitmemdi jalur Anda dan membuatnya dapat dieksekusi Kemudian jalankan mis limitmem 1G command.... Ini membatasi memori yang sebenarnya digunakan. Jika itu tercapai, pembunuh OOM akan membunuh proses atau salah satu dari anak-anaknya, tetapi bukan sesuatu yang acak yang tidak ada hubungannya dengan perintah ini.

JanKanis
sumber
Terima kasih untuk cgmpanduan singkatnya , ini berguna
Vitaly Isaev
1

/unix//a/536046/4319 :

Pada setiap distro berbasis systemd Anda juga dapat menggunakan cgroup secara tidak langsung melalui systemd-run. Misalnya untuk kasus Anda membatasi pdftoppm500M RAM, gunakan:

systemd-run --scope -p MemoryLimit=500M pdftoppm

...

imz - Ivan Zakharyaschev
sumber