created: 2019-06-20 24:00, tags: laravel, server, supervisor,

Laravel と supervisor で設定が悪いと CPU 負荷が酷い

特に面白みはないけど、負荷を気にしない人が設定すると酷い事になる話。

ここで出しているデータ自体は後で再現用に用意したものなので実際とは違う (大体似た感じだけど)。

キッカケ

調べるはめになったのは、先日開発中のシステムのステージングが遅すぎてなんなんだろうと調べたのが始まり (ステージングのアクセス権を貰ったのが最近で、遅いという話自体はずっと前からあった)。

調査

サーバの WEB レスポンスが非常に遅いという事で、とりあえず SSH でログインし、top で確認。

$ top -c

-c オプションを付けるのは、詳細なコマンドオプション等が見たいため。 実際今回のケースは Laravel の queue の実行処理に悪い点があり、-c を付けない場合は単に php の実行プロセスとしか表示されない。

top - 04:30:55 up 3 days,  8:43,  3 users,  load average: 5.45, 4.57, 2.98
Tasks: 179 total,   1 running, 136 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.7 us, 22.0 sy,  0.0 ni, 76.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   493016 total,     7144 free,   376804 used,   109068 buff/cache
KiB Swap:  1003516 total,   324772 free,   678744 used.   103420 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
10427 vagrant   20   0  358856  41500  23700 S  3.0  8.4   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge1                                                                        
10417 vagrant   20   0  358856  41508  23708 S  2.6  8.4   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge1                                                                        
10418 vagrant   20   0  358856  41820  24020 S  2.6  8.5   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge2                                                                        
10421 vagrant   20   0  358856  41512  23712 S  2.6  8.4   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge2                                                                        
10424 vagrant   20   0  358856  41812  24012 S  2.6  8.5   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge3                                                                        
10425 vagrant   20   0  358856  41596  23796 S  2.6  8.4   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge3                                                                        
10426 vagrant   20   0  358856  41560  23756 S  2.6  8.4   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge4                                                                        
10429 vagrant   20   0  358856  41616  23812 S  2.6  8.4   0:00.42 /usr/bin/php7.3 artisan queue:listen --queue=hoge4

この内容を見ると、load average が異常に高く、5 を叩き出している (これはローカルで同様の状態を表現したもので、実際遭遇したものも 5 強だった)。 プロセスを見ると CPU リソースを食っていたのは queue 用に上げているプロセスだった (queue:listen を使用していた)。

Laravel では、supervisor を使ってプロセスの管理を推奨しているため、当 PJ も同様の方法でセットアップしていた。 その時の conf がこれ。

[program:laravel-queue-1]
command=php /home/vagrant/laravel/artisan queue:listen --queue=hoge1

process_name=%(program_name)s_%(process_num)02d
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=vagrant
numprocs=2

要所で変更はしているが、このファイルが 1~4 まで 4 つあり、queue をそれぞれのファイルで 1 つ指定していた。また、supervisor の conf で numprocs を 2 としているため、4 * 2 で 8 つのプロセスを上げる設定となる。 その上、queue:listen を使っているため、フレームワークの再起動コストが重く、結果 load average が高くなるという現象が発生していた。

下記ページのデーモンキューリスナーを参照

解決策

今回の問題は下記 3 点。

  1. numprocs を不用意に 2 にしていた
  2. supervisor のハンドルををキュー毎に作っていた
  3. work ではなく listen を使っていた

そのため、上記をそれぞれ実行環境のスペックや要求に合わせて調整する。 今回はステージングという事もあり、それ程潤沢なスペックを持つサーバではない上に、キューの処理を裁く事に神経質になる必要がない環境である (キューに対して高負荷がかかる事は意図的に実行しない限りない)。

そのため、numprocs を 1 に、supervisor のハンドルを 1 つに、queue:listen を止め、queue:work を使うように、それぞれ変更した。

変更すると下記のようになる。

[program:worker-326007-1]
command=php /home/vagrant/laravel/artisan queue:listen --queue=hoge1,hoge2,hoge3,hoge4

process_name=%(program_name)s_%(process_num)02d
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=vagrant
numprocs=1
top - 06:15:38 up 3 days,  9:52,  3 users,  load average: 0.00, 0.02, 0.65
Tasks: 156 total,   1 running, 113 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.7 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   493016 total,   143084 free,   196636 used,   153296 buff/cache
KiB Swap:  1003516 total,   429916 free,   573600 used.   283396 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND 
  741 redis     20   0   51444    144      0 S  0.3  0.0   6:39.60 /usr/bin/redis-server 127.0.0.1:6379                                                                                                                                       
  827 mysql     20   0 1163452  33840      0 S  0.3  6.9   5:07.49 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid                                                                                                             
 4205 vagrant   20   0  358848  41408  23556 S  0.3  8.4   0:01.06 php /home/laravel/artisan queue:work --queue=hoge1,hoge2,hoge3,hoge4                                                                                       
 4370 vagrant   20   0   44236   4000   3312 R  0.3  0.8   0:00.07 top -c                                                                                                                                                                     
    1 root      20   0  225464   4812   3136 S  0.0  1.0   0:34.44 /sbin/init                                                                                                                                                                 
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 [kthreadd]                                                                                                                                                                 
    4 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 [kworker/0:0H]                                                                                                                                                             
    6 root       0 -20       0      0      0 I  0.0  0.0   0:00.00 [mm_percpu_wq]                  

supervisor を再起動して設定を読み込み直し、10 分程度放置した状態がこちら。 load average が見事に 0.00 まで下がっている。

当該のサーバへのアクセスが遅い問題もこの件を解決する事で無事解決された。