私はApache + PHP-FPMであるLinux Webサーバー(もしあればDebian)を持っています。各Apacheは、VirtualHost
専用システムユーザーとして実行される専用のPHP-FPMプール(専用のUnixソケット経由)を使用します。
たとえば、example.comがあるとしますVirtualHost
。その後、VirtualHost
Apacheの設定には次のものがあります。
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php7.3-fpm-examplecom.sock|fcgi://127.0.0.1:9000/home/examplecom/htdocs/www.example.com/
そして、/etc/php/7.3/fpm/pool.d/
PHP-FPMプールに対応する設定ファイルがあります。つまり、次examplecom.conf
が含まれます。
[examplecom]
user = examplecom
listen = /run/php/php7.3-fpm-examplecom.sock
; and other things...
頻繁に発生することは、一部のWebサイトがハッキングされ(更新するのを忘れてしまい、安全でないプラグインをインストールするなど)、利用可能なサーバーリソースを占有し始めることです。私の場合、ハードドライブのI / O帯域幅は最も一般的でした。
同じサーバー上のすべてのWebサイトにDoSingを防ぐためにハッキングされたWebサイトのみがクラッシュし、他のすべてのWebサイトに影響を与えないように、各WebサイトのハードドライブI / O帯域幅を制限したいと思います。
WebサイトあたりのハードディスクI / O帯域幅を制限する方法は?さて、各ユーザーにVirtualHost
専用のユーザーがいるので、ユーザーごとに制限できるようです。どうすればいいですか?まあ、Googleはcgroupを使うように提案しました。
しかし、追加する方法については何も見つかりません。ユーザー、プロセスIDの代わりに制御グループに渡されます。
私は間違ったものを探していますか?それとも私が間違ってキーワードを検索したのでしょうか?よくわかりませんが、質問は次のとおりです。 Linuxでcgroupを使用して各ユーザーのハードディスクI / O帯域幅を制限する方法は?
答え1
ありがとうLL3私の質問に対するコメントに応じてカスタムスクリプトを使用する必要があることを知りました。だからそれはすべてです。 PHP-FPMプロセスを照会し、その実行ユーザーとPIDを取得し、cgroups
PIDを生成して正しいcgroups
。
crontab
その後、スクリプトが毎時間実行されるようにエントリを設定しましたが、私の場合は十分でした。 Linuxは自動的に子プロセスを親プロセスに入れるcgroup
ので、スクリプトは実際にPHP-FPMが再起動するたびに実行するだけです。起動後に 1 回実行 (たとえば、起動時や新しいサイト/ユーザーを追加する場合) 毎時間実行されるので、スケジュールされた時間に手動で実行することを忘れないようにします。
スクリプトはディレクトリ/cgroups
がファイルシステムとしてマウントされていると仮定するcgroup2
ため、事前に準備する必要があります。/etc/fstab
カーネルがcgroups
デフォルトでバージョン1をインストールしている場合は、/etc/default/grub
v1を無効にして再起動するように設定するエントリを追加できます(ヒント:cgroup_no_v1=all
に追加してGRUB_CMDLINE_LINUX_DEFAULT
実行update-grub && reboot
)。
現在、1 か月間本番環境で稼働しており、機能しているようです。私はこれを配置した2つのサーバーの少なくとも1つに破損したサイトがあると確信しており、ダメージを制限するのにかなり効果的です(関連していないサイトは時々数秒間ダウンします)。
このスクリプトの最初のバージョン以降は、ディスクI / O監視だけでは不十分であるため、CPUとメモリも監視するように編集する必要がありました。
#!/bin/bash
DEVICE="254:0" # see /proc/partitions, this is /dev/vda in my case
WRITE_IOLIMIT=2097152 # 2MB/s, choose this as a fraction of your disk max write rate, I tested mine with `dd if=/dev/vda of=/testmaxspeed.dd bs=1M count=10000 status=progress`
READ_IOLIMIT=4194304 # 4MB/s, choose this as a fraction of your disk max read rate, I tested mine with `dd if=/dev/vda of=/dev/null bs=1M count=10000 status=progress`
function cleanup
{
rm -f "$PLISTFILE" >/dev/null 2>&1
}
trap cleanup INT TERM EXIT
PLISTFILE=$(mktemp)
ps axo user:40,pid,comm | grep php-fpm | grep -v 'grep php-fpm' | grep -v '^root ' | tr -s ' ' | cut -d' ' -f 1-2 | sort | uniq > $PLISTFILE
cat $PLISTFILE | while read ROW ; do
USERNAME=$(echo "$ROW" | cut -d' ' -f1)
mkdir /cgroups/$USERNAME 2>/dev/null
echo "$DEVICE rbps=$READ_IOLIMIT" > /cgroups/$USERNAME/io.max
echo "$DEVICE wbps=$WRITE_IOLIMIT" > /cgroups/$USERNAME/io.max
echo 402653184 > /cgroups/$USERNAME/memory.high # throttle when user is above 384MB of RAM
echo 603979776 > /cgroups/$USERNAME/memory.max # OOM-Kill when user is above 576MB of RAM
done
echo "+io" > /cgroups/cgroup.subtree_control
echo "+cpu" > /cgroups/cgroup.subtree_control
echo "+memory" > /cgroups/cgroup.subtree_control
cat $PLISTFILE | while read ROW ; do
USERNAME=$(echo "$ROW" | cut -d' ' -f1)
PROCESSID=$(echo "$ROW" | cut -d' ' -f2)
echo $PROCESSID > /cgroups/$USERNAME/cgroup.procs
done