特定プロセスのcpu利用率を制限するcpulimitを試す

先日mysqldump + xz 圧縮の間に pv を挟んで帯域制限をして xz の負荷を下げました．

mysqldump を pv で制限 – matoken’s meme

しかしこの方法ではそんなに負荷がない mysqldump もずっと動かしっぱなしで db にもよろしく無いです．mysqldump は先に済ませて xz だけを制限することにします．

before

umask 0266 && nice -n 19 ionice -c 3 /usr/bin/mysqldump --defaults-file=/mnt/backup/micro/.my-backup.cnf --single-transaction --quick --all-databases --events | pv -L 128k 2>/dev/null | nice -n 19 ionice -c 3 /usr/bin/xz -9 > /mnt/backup/micro/`date +\%F_\%T_$$`.sql.xz

after

DUMP="/mnt/backup/micro/`date +\%F_\%T_$$`.sql"; umask 0266 && nice -n 19 ionice -c 3 /usr/bin/mysqldump --defaults-file=/mnt/backup/micro/.my-backup.cnf --single-transaction --quick --all-databases --events > ${DUMP} && pv -L 128k nice -n 19 ionice -c 3 /usr/bin/xz -9 > ${DUMP}.xz && rm ${DUMP}

一応動くけどcrontabなので１行で書いてあって見にくいしあまりいけてないですね．
せめてファイルに分けたほうが良さそう．

LimitCPU

pvでもいいのですが，cpu利用率を制限できないかなと思いました．xzのオプションでは見当たらずLinux環境なので cgroups で制限しようかとも思ったのですが， LimitCPU というものを見つけました．これは SIGSTOP と SIGCONT のPOSIXシグナルをプロセスに送信することにより実現しているので，POSIX環境ならどこでも動きそうなのでこちらを試してみました．

LimitCPUはメンテされなくなったCPUlimitのフォークでコマンドやパッケージ名は cpulimit です．(混乱する><)

LimitCPU

GitHub – opsengine/cpulimit: CPU usage limiter for Linux

導入

$ sudo apt install cpulimit

usage

$ cpulimit -h
CPUlimit version 2.1
Usage: cpulimit TARGET [OPTIONS...] [-- PROGRAM]
TARGET must be exactly one of these:
-p, --pid=N pid of the process
-e, --exe=FILE name of the executable program file
The -e option only works when
cpulimit is run with admin rights.
-P, --path=PATH absolute path name of the
executable program file
OPTIONS
-b --background run in background
-c --cpu=N override the detection of CPUs on the machine.
-l, --limit=N percentage of cpu allowed from 1 up.
Usually 1 - 200, but can be higher
on multi-core CPUs (mandatory)
-q, --quiet run in quiet mode (only print errors).
-k, --kill kill processes going over their limit
instead of just throttling them.
-r, --restore Restore processes after they have
been killed. Works with the -k flag.
-s, --signal=SIG Send this signal to the watched process when cpulimit exits.
Signal should be specificed as a number or
SIGTERM, SIGCONT, SIGSTOP, etc. SIGCONT is the default.
-v, --verbose show control statistics
-z, --lazy exit if there is no suitable target process,
or if it dies
-- This is the final CPUlimit option. All following
options are for another program we will launch.
-h, --help display this help and exit

制限はプロセスIDでの制限，プログラム名での制限，指定したプログラムを制限することが可能です．
cpuが複数ある場合は -l の値はcpu 1つあたり100として，100 * cpu数 を元に指定します．cpu 2つで 50% 利用したい場合は -l 100 になると思います．

プロセスID 1234 のプログラムをcpuを2つ利用，ｃｐｕを50%(2コアなので実際は100%分)

$ cpulimit -c 2 -p 1234 -l 50

xzというプログラムをcpu利用率を25%に制限

$ cpulimit -c 2 -l 50 - xz

※xzの前の - はなくてもいいが cpulimit のオプションの最後を示す．

cpuを1つだけ利用．cpu利用率を25%に制限しつつxzを実行できます．

$ cpulimit -c 1 -l 25 -z - xz -9 datafile

-c : 利用するｃｐｕ数

-p : 制限するプロセスID

-l : 制限するcpu利用率

-z : 指定したプロセスが完了したらcpulimitも終了する(通常は関しを続けて同じ条件に一致するプロセスが現れたら制限する)

今回はxzを制限したいのでこんな感じに．
あまり変わりませんね……．

DUMP="/mnt/backup/micro/`date +\%F_\%T_$$`.sql"; umask 0266 && nice -n 19 ionice -c 3 /usr/bin/mysqldump --defaults-file=/mnt/backup/micro/.my-backup.cnf --single-transaction --quick --all-databases --events > ${DUMP} && nice -n 19 ionice -c 3 cpulimit -c1 -l 25 - /usr/bin/xz -9 ${DUMP}

バックアップ専用ユーザとして分けてあるのでそのユーザで cpulimit -c 1 -l 25 - xz とかしてxzという名前のプロセスを全部制限してしまうのもありかもしれません．monit とかで監視させればいい感じかも?そうすると，

DUMP="/mnt/backup/micro/`date +\%F_\%T_$$`.sql"; umask 0266 && nice -n 19 ionice -c 3 /usr/bin/mysqldump --defaults-file=/mnt/backup/micro/.my-backup.cnf --single-transaction --quick --all-databases --events > ${DUMP} && /usr/bin/xz -9 ${DUMP}

あまり変わりませんね……．

環境

$ dpkg-query -W cpulimit xz-utils
cpulimit 2.2-1
$ lsb_release -d
Description: Ubuntu 16.04.5 LTS
$ uname -m
x86_64