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

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

しかしこの方法ではそんなに負荷がない 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なので1行で書いてあって見にくいしあまりいけてないですね.
せめてファイルに分けたほうが良さそう.

LimitCPU

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

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

導入
$ 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つ利用,cpuを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 : 利用するcpu数

  • -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