Làm cách nào để giới hạn tổng tài nguyên (bộ nhớ) của một tiến trình và con của nó


16

Có rất nhiều câu hỏi và câu trả lời về việc hạn chế tài nguyên của một quy trình, ví dụ RLIMIT_AS có thể được sử dụng để hạn chế bộ nhớ tối đa được phân bổ bởi một quy trình có thể được xem là VIRT top. Thông tin thêm về chủ đề, ví dụ ở đây Có cách nào để giới hạn dung lượng bộ nhớ mà một quy trình cụ thể có thể sử dụng trong Unix không?

setrlimit(2) tài liệu nói:

Một tiến trình con được tạo thông qua fork (2) kế thừa các giới hạn tài nguyên của cha mẹ nó. Giới hạn tài nguyên được bảo toàn trên thực thi (2).

Nó nên được hiểu theo cách sau:

Nếu một quá trình có RLIMIT_AS là 2GB, thì nó không thể phân bổ nhiều bộ nhớ hơn 2GB. Khi nó sinh ra một đứa trẻ, giới hạn không gian địa chỉ là 2GB sẽ được truyền cho đứa trẻ, nhưng việc đếm bắt đầu từ 0. Hai quá trình cùng nhau có thể chiếm tới 4GB bộ nhớ.

Nhưng điều gì sẽ là cách hữu ích để hạn chế tổng số bộ nhớ được phân bổ bởi toàn bộ cây quy trình?



7
Tôi sẽ xem xét các nhóm .
slm

@slm Cảm ơn! Âm thanh như cgroups là một cái gì đó để thử. Giải pháp hoạt động duy nhất cho đến nay (bên cạnh cách tổng hợp bộ nhớ xấu xí bằng cách sử dụng PS và giết tiến trình cha nếu vượt quá giới hạn) có thể hoạt động là sử dụng một số dạng của một thùng chứa (lxc hoặc lượt thích).
JPE

Vâng - các công cụ mà tôi biết là không thực hiện một nhóm, chỉ là các quy trình đơn lẻ, nhưng được đưa ra cách các nhóm hoạt động cho các công nghệ VM như LXC và Docker tôi mong muốn nó sẽ làm những gì bạn muốn.
slm

1
Nếu đó là Linux, hãy đặt bộ cha mẹ vào không gian tên của chính nó và điều khiển nó và tất cả các con của nó theo cách đó. Đây là câu trả lời giới thiệu cho khái niệm đó: unix.stackexchange.com/a/124194/52934
mikeerv

Câu trả lời:


8

Tôi không chắc chắn nếu điều này trả lời câu hỏi của bạn, nhưng tôi đã tìm thấy tập lệnh perl này tuyên bố sẽ làm chính xác những gì bạn đang tìm kiếm. Kịch bản thực hiện hệ thống riêng của mình để thực thi các giới hạn bằng cách thức dậy và kiểm tra việc sử dụng tài nguyên của quy trình và các phần tử con của nó. Nó dường như được ghi chép lại và giải thích, và đã được cập nhật gần đây.

Như slm đã nói trong bình luận của mình, cgroups cũng có thể được sử dụng cho việc này. Bạn có thể phải cài đặt các tiện ích để quản lý các nhóm, giả sử bạn đang dùng Linux, bạn nên tìm kiếm libcgroups.

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

Hãy chắc chắn $USERlà người dùng của bạn.

Người dùng của bạn sau đó sẽ có quyền truy cập vào cài đặt bộ nhớ cgroup /sys/fs/cgroup/memory/myGroup.

Sau đó, bạn có thể đặt giới hạn thành, giả sử 500 MB, bằng cách thực hiện việc này:

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

Bây giờ hãy chạy Vim:

cgexec -g memory:myGroup vim

Quá trình vim và tất cả các con của nó bây giờ sẽ được giới hạn trong việc sử dụng 500 MB RAM. Tuy nhiên , tôi nghĩ giới hạn này chỉ áp dụng cho RAM và không trao đổi. Khi các quá trình đạt đến giới hạn, chúng sẽ bắt đầu hoán đổi. Tôi không chắc chắn nếu bạn có thể khắc phục điều này, tôi không thể tìm cách hạn chế sử dụng trao đổi bằng cách sử dụng các nhóm.


Giải pháp đề xuất không cho phép giới hạn kích thước cài đặt thường trú của cây quy trình. Hành vi dường như khác với RLIMIT_AS: có thể malloc nhiều bộ nhớ hơn giới hạn, tuy nhiên dường như không thể thực sự sử dụng nhiều hơn.
JPE

Theo mặc định, giới hạn bộ nhớ cgroup chỉ áp dụng cho (khoảng) việc sử dụng RAM vật lý. Có một tùy chọn kernel (CONFIG_MEMCG_SWAP) để cho phép kế toán hoán đổi; xem tài liệu kernel để biết chi tiết.
Søren Løvborg

1
Trên fedora,sudo yum install libcgroup-tools
jozxyqk

2

Tôi đã tạo một tập lệnh thực hiện điều này bằng cách sử dụng cgmanager được sử dụng trong Ubuntu. Một lợi thế là điều này không yêu cầu quyền truy cập root. Lưu ý rằng quản lý nhóm là một phân phối cụ thể một chút, vì vậy tôi không biết nếu điều này hoạt động trên các phân phối sử dụng quản lý nhóm hệ thống.

#!/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

cách sử dụng: lưu như limitmemtrong đường dẫn của bạn và làm cho nó thực thi được. Sau đó chạy ví dụ limitmem 1G command.... Điều này giới hạn bộ nhớ thực sự được sử dụng. Nếu điều đó đạt được, kẻ giết người OOM sẽ giết chết quá trình hoặc một trong những đứa con của nó, nhưng không phải là thứ gì đó ngẫu nhiên không liên quan gì đến lệnh này.


Cảm ơn đã cgmhướng dẫn ngắn , nó rất hữu ích
Vitaly Isaev

1

/unix//a/536046/4319 :

Trên bất kỳ bản phân phối dựa trên hệ thống nào, bạn cũng có thể sử dụng các nhóm trực tiếp thông qua hệ thống chạy. Ví dụ: đối với trường hợp giới hạn pdftoppm500M RAM, hãy sử dụng:

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

...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.