CPU は 2つなのに、なぜか 1つしか使われていない

Nginx でウェブサーバのベンチマーク中に top コマンドで CPU 使用率を見てたら CPU は 2つなのに、なぜか 1CPU しか使われてないことに気がつきました。

仕事で検証用として使っていたサーバだったのですが、とりあえず nginx サービスを再起動するも状況変わらず。

おかしいな。。と思いながら /etc/nginx/nginx.conf の中身を確認中に worker_cpu_affinity が設定されてないことに気がつきました。

設定方法については後ほど詳しく説明しますが、2CPU のサーバだったので、とりあえず以下の設定でちゃんと 2CPU 仲良く使えるようになりました。

/etc/nginx/nginx.conf
#### Context : main
・・・
worker_processes 2;
worker_cpu_affinity 01 10;
・・・

#### Context : events
events {
    ・・・
}

#### Context : http
http {
    ・・・
}

worker_cpu_affinity

worker_cpu_affinity は、Nginx で個々のワーカプロセスが特定の CPU を使うように指定する設定です。

worker_cpu_affinity のデフォルト値について

それで、worker_cpu_affinity のデフォルト値って一体どうなってんだ?! と思い、公式ドキュメントを確認したところ。

worker_cpu_affinity

Syntax: worker_cpu_affinity cpumask ...;

    worker_cpu_affinity auto [cpumask];

Default: —

Context: main

Binds worker processes to the sets of CPUs. Each CPU set is represented by a bitmask of allowed CPUs. There should be a separate set defined for each of the worker processes. By default, worker processes are not bound to any specific CPUs.

抜粋 : Nginx : Core functionality

そしたらなんとデフォルト値は なし。。

worker_cpu_affinity明示的に設定しないと特定 CPU にワーカプロセスがバインドされることはないということになりますね。

worker_cpu_affinity の設定方法

上記の文法を見ると値として auto 設定もできると書いてあります。

ただ、worker_cpu_affinity auto 設定は、nginx 1.9.10 からサポートされるので、設定する際には注意が必要です。

個人的には CPU 変更作業自体が頻繁に行われる作業でもないですし、auto よりも Nginx のバージョンに関係なく、パッと見て実際の設定方法が明確にわかるように明示的に設定した方が良いのではないかと思います。

worker_cpu_affinity の基本的な設定方法は以下になります。

  • CPU コア数に合わせて worker_processes (ワーカプロセスの数) を設定する
  • それに合わせて、各ワーカプロセスがどの CPU コアを使うか worker_cpu_affinity を設定
  • worker_cpu_affinity は、2進数を使って「コア数 = 桁数」で指定し、割り当てる CPU のビットを立てる
Core 数worker_processesworker_cpu_affinity
2201 10
33001 010 100
440001 0010 0100 1000
・・・・・・・・・
8800000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000
・・・・・・・・・
16160000000000000001 0000000000000010 0000000000000100 0000000000001000 0000000000010000 0000000000100000 0000000001000000 0000000010000000 0000000100000000 0000001000000000 0000010000000000 0000100000000000 0001000000000000 0010000000000000 0100000000000000 1000000000000000

worker_processes のデフォルト値は 1 なので、1CPU の場合には、特に設定する必要はないと思います。

3CPU の worker_cpu_affinity 設定例

以下は、3CPU の worker_cpu_affinity 設定例です。

設定が終わったら設定を反映するためにサービスを再起動し、taskset コマンドを使って各ワーカプロセスが各 CPU コアにちゃんと割り当てられていることを確認します。

/etc/nginx/nginx.conf
・・・
worker_processes 3;
worker_cpu_affinity 001 010 100;
・・・
設定反映
# service nginx restart
CPU コア数確認
$ cat /proc/cpuinfo | grep "processor"
processor       : 0
processor       : 1
processor       : 2
affinity list 確認
$ ps -ef | grep "worker" | grep -v "grep"
nginx     1821  1820  0 Mar12 ?        00:00:55 nginx: worker process
nginx     1822  1820  0 Mar12 ?        00:00:57 nginx: worker process
nginx     1823  1820  0 Mar12 ?        00:01:00 nginx: worker process

$ taskset -pc 1821
pid 1821's current affinity list: 0

$ taskset -pc 1822
pid 1822's current affinity list: 1

$ taskset -pc 1823
pid 1823's current affinity list: 2

終わりに

これで各 CPU コアにバランスよく仕事を分担させることができます。

worker_cpu_affinity は明示的に設定すべきか?

はい。 worker_cpu_affinity はデフォルト値「なし」です。

設定しないと特定の CPU にワーカプロセスがバインドされないので、明示的に設定すべきです。

ちなみに、worker_processes に実際のコア数を超える値は設定できません。 以下のようなエラーで失敗します。

/etc/nginx/nginx.conf : 実際は 2コアなのに 4コアを設定した場合
#### Context : main
・・・
worker_processes 4;
worker_cpu_affinity 01 10;
・・・
nginx 再起動
# service nginx restart
nginx: [warn] the number of "worker_processes" is not equal to the number of "worker_cpu_affinity" masks, using last mask for remaining worker processes
nginx を停止中:    [  OK  ]
nginx を起動中: nginx: [warn] the number of "worker_processes" is not equal to the number of "worker_cpu_affinity" masks, using last mask for remaining worker processes

以上、Nginx なぜか CPU が一つしか使われていない でした。