Linuxのカーネルパラメータについて

最近、カーネルパラメータを見直す機会があったのでメモしておきます。

# カーネルパラメータを設定する目的

* サーバのパフォーマンスを最大限に引き出す
* セキュリティ強化
* TCP/IPなどプロトコルレベルでのチューニングによる効率化

# 注意事項

* カーネルパラメータはサーバの用途や環境によって最適な設定が変わるため、一部の設定値については言及しません
  * 設定値列に `要検証` と記載します
* カーネルパラメータを変更することによるリスクもあるため、充分検証して値を設定して下さい

# カーネルパラメータ

ここ数年のチューニング情報を色々調べてみて、以下を設定すると良さそうでした。

## パフォーマンス

| パラメータ名                   | 設定値 | 説明                                                         |
| ------------------------------ | ------ | ------------------------------------------------------------ |
| fs.file-max                    | 要検証 | システム全体のファイルディスクリプタの上限                   |
| kernel.threads-max             | 要検証 | システム全体のプロセス数の上限                               |
| net.core.netdev_max_backlog    | 要検証 | カーネルがキューイング可能なパケットの最大個数               |
| net.netfilter.nf_conntrack_max | 要検証 | netfilterでの最大同時コネクション数を調整する                |
| vm.swappiness                  | 0      | SWAPされやすさを設定する<br />※0でもSWAPされるときはSWAPする |

## セキュリティ

| パラメータ名                          | 設定値 | 説明                                       |
| ------------------------------------- | ------ | ------------------------------------------ |
| kernel.sysrq                          | 0      | SysRq(システム要求)キーを無効にする        |
| net.ipv4.conf.all.accept_source_route | 0      | ソースルーティングを無効にする             |
| net.ipv4.conf.all.rp_filter           | 1      | rp_filter(reverse path filter)を有効にする |
| net.ipv4.conf.default.rp_filter       | 1      | rp_filter(reverse path filter)を有効にする |
| net.ipv4.ip_forward                   | 0      | IPの転送を無効にする                       |
| net.ipv4.tcp_syncookies               | 1      | tcp_syncookiesを有効にする ※SYN FLOOD対策  |

## TCP/IPチューニング

| パラメータ名                       | 設定値   | 説明                                                         |
| ---------------------------------- | -------- | ------------------------------------------------------------ |
| net.core.rmem_max                  | 要検証   | TCPの受信バッファサイズの最大値を設定する                    |
| net.core.somaxconn                 | 要検証   | TCPソケットが受け付けた接続要求を格納するキューの最大長      |
| net.core.wmem_max                  | 要検証   | TCPの送信バッファサイズの最大値                              |
| net.ipv4.ip_local_port_range       | 要検証   | TCP/IPの送信用ポート範囲の変更                               |
| net.ipv4.tcp_fin_timeout           | 5〜30    | FINパケットのタイムアウト時間                                |
| net.ipv4.tcp_keepalive_intvl       | sec<75   | TCP keepalive packetを送信する間隔(秒単位)                   |
| net.ipv4.tcp_keepalive_time        | sec<7200 | TCP keepalive packetを送信するまでの時間(秒単位)             |
| net.ipv4.tcp_keepalive_probes      | count<9  | keepalive packetを送信する回数                               |
| net.ipv4.tcp_max_syn_backlog       | 要検証   | ソケット当たりのSYNを受け付けてACKを受け取っていない状態のコネクションの保持可能数 |
| net.ipv4.tcp_max_tw_buckets        | 要検証   | システムが同時に保持するTIME_WAITソケットの最大数            |
| net.ipv4.tcp_orphan_retries        | 要検証   | こちらからクローズしたTCPコネクションを終了する前の再送回数  |
| net.ipv4.tcp_rfc1337               | 1        | RFC1337に準拠させる<br />※TIME_WAIT状態のときにRSTを受信した場合、TIME_WAIT期間の終了を待たずにそのソケットをクローズする |
| net.ipv4.tcp_slow_start_after_idle | 0        | 通信がアイドル状態になった後のスロースタートを無効にする     |
| net.ipv4.tcp_syn_retries           | 3        | tcpのSYNを送信するリトライ回数                               |
| net.ipv4.tcp_tw_reuse              | 1        | TIME_WAIT状態のコネクションを再利用                          |

# tunedのプロファイルを参考にチューニングする項目を検討する

カーネルパラメータの設定項目はかなり数が多く、人間が管理しやすいようにするツールとしてtunedというものがあります。

tunedではサーバ種別に応じたプロファイルによってチューニングが行えるようになっており、それらの設定値を参考にチューニングする項目を検討してみました。

## プロファイルについて

以下の通り、サーバ種別に応じたプロファイルが用意されています。

プロファイルにはチューニングにおける代表的なカーネルパラメータが記載されているので、こちらを参考にカーネルパラメータを検討してみます。

```bash
$ ls -l /usr/lib/tuned/
total 56
drwxr-xr-x. 2 root root  4096 Sep  9  2019 balanced
drwxr-xr-x. 2 root root  4096 Sep  9  2019 desktop
-rw-r--r--  1 root root 14413 Mar 14  2019 functions
drwxr-xr-x. 2 root root  4096 Sep  9  2019 latency-performance
drwxr-xr-x. 2 root root  4096 Sep  9  2019 network-latency
drwxr-xr-x. 2 root root  4096 Sep  9  2019 network-throughput
drwxr-xr-x. 2 root root  4096 Sep  9  2019 powersave
drwxr-xr-x. 2 root root  4096 Sep  9  2019 recommend.d
drwxr-xr-x. 2 root root  4096 Sep  9  2019 throughput-performance
drwxr-xr-x. 2 root root  4096 Sep  9  2019 virtual-guest
drwxr-xr-x. 2 root root  4096 Sep  9  2019 virtual-host
```

## 試しにvirtual-guestのテンプレートを見てみる

`include=throughput-performance` という記載により、`throughput-performance`のテンプレートをインクルードしていることが解ります。

**※設定値のみ表示するためコメント行は非表示にしています**

```bash:/usr/lib/tuned/virtual-guest/tuned.conf
[main]
summary=Optimize for running inside a virtual guest
include=throughput-performance

[sysctl]
vm.dirty_ratio = 30
vm.swappiness = 30
```

インクルードしてる`throughput-performance`のテンプレートはこちらです。

カーネルパラメータ以外にも、CPUやディスクの設定値が含まれていることが解ります。

```bash:/usr/lib/tuned/throughput-performance/tuned.conf
[main]
summary=Broadly applicable tuning that provides excellent performance across a variety of common server workloads

[cpu]
governor=performance
energy_perf_bias=performance
min_perf_pct=100

[disk]
readahead=>4096

[sysctl]
kernel.sched_min_granularity_ns = 10000000
kernel.sched_wakeup_granularity_ns = 15000000
vm.dirty_ratio = 40
vm.dirty_background_ratio = 10
vm.swappiness=10
```

## virtual-guestの場合のカーネルパラメータ設定

tunedで設定されているカーネルパラメータを試しに設定し、実際に設定された値を以下の通り一覧にしてみました。

Includeしているテンプレートと同じ設定値があった場合はマージしてくれるようなのですが、`vm.swappiness=30`になっていることから必ずしもInclude後に上書きするわけでは無いようです。

| パラメータ名                       | 設定値   | 説明                                                         |
| ---------------------------------- | -------- | ------------------------------------------------------------ |
| vm.dirty_ratio                     | 40       | ディスクにコミットされる前にダーティページで満たすことができるシステムメモリの絶対最大量 |
| vm.swappiness                      | 30       | SWAPされやすさを設定する                                     |
| kernel.sched_min_granularity_ns    | 10000000 | 単一のタスクが実行されるターゲットの最小スケジューラ期間     |
| kernel.sched_wakeup_granularity_ns | 15000000 | タスクが起動したときのプリエンプションの粒度                 |
| vm.dirty_background_ratio          | 10       | ダーティーページの割合がこの値に達すると優先度の低いバックグラウンドでpdflushが書き出し動作する |

## 試しにnetwork-throughputのテンプレートを見てみる

`include=throughput-performance` という記載により、`throughput-performance`のテンプレートをインクルードしていることが解ります。

**※設定値のみ表示するためコメント行は非表示にしています**

```bash:/usr/lib/tuned/network-throughput/tuned.conf
[main]
summary=Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks
include=throughput-performance

[sysctl]
net.ipv4.tcp_rmem="4096 87380 16777216"
net.ipv4.tcp_wmem="4096 16384 16777216"
net.ipv4.udp_mem="3145728 4194304 16777216"
```

インクルードしている`throughput-performance`のテンプレートは前項にて記載済みのため割愛します。

## network-throughputの場合のカーネルパラメータ設定

tunedで設定されているカーネルパラメータを試しに設定し、実際に設定された値を以下の通り一覧にしてみました。

Includeしているテンプレートと同じ設定値があった場合はマージしてくれるようなのですが、`vm.swappiness=30`になっていることから必ずしもInclude後に上書きするわけでは無いようです。

| パラメータ名                       | 設定値                   | 説明                                                         |
| ---------------------------------- | ------------------------ | ------------------------------------------------------------ |
| vm.dirty_ratio                     | 40                       | ディスクにコミットされる前にダーティページで満たすことができるシステムメモリの絶対最大量 |
| vm.swappiness                      | 30                       | SWAPされやすさを設定する                                     |
| kernel.sched_min_granularity_ns    | 10000000                 | 単一のタスクが実行されるターゲットの最小スケジューラ期間     |
| kernel.sched_wakeup_granularity_ns | 15000000                 | タスクが起動したときのプリエンプションの粒度                 |
| vm.dirty_background_ratio          | 10                       | ダーティーページの割合がこの値に達すると優先度の低いバックグラウンドでpdflushが書き出し動作する |
| net.ipv4.tcp_rmem                  | 4096 87380 16777216      | TCPソケットの受信バッファサイズ(min, default, max)           |
| net.ipv4.tcp_wmem                  | 4096 16384 16777216      | TCPソケットの送信バッファサイズ(min, default, max)           |
| net.ipv4.udp_mem                   | 3145728 4194304 16777216 | UDPソケットのバッファサイズ(min, default, max)               |

## tunedのプロファイルを参考にカーネルパラメータを設定するか否か

* 結論
  * プロファイルとサーバ用途によって参考にするものを選択する
* 理由
  * `virtual-guest`プロファイルの場合は基本的にサーバ構築時のデフォルト(サーバごとに変わる)と同じものが設定されている
  * `network-throughput`プロファイルの場合はバッファサイズがデフォルトから引き上げられている
      * スループットが求められるサーバに設定する時の参考にする
  * `vm.swappiness`や`vm.dirty_ratio`については利用する環境に応じて適宜変える方針が良さそう
  * CPUやディスクの項目については別途検討の余地あり

# おわりに

サーバごとにカーネルパラメータを適正に設定することは、セキュリティ・パフォーマンスの観点で意味のあることだと思います。

昨今、k8sなどコンテナ技術の人気が上昇していますが、そうは言ってもオンプレ・クラウドに限らずサーバを運用する機会はまだまだあると思われるので、適切に設定していきたいですね。

# 参考リンク

* CentOS7 カーネルパラメータ チューニング
  * https://qiita.com/transformation33/items/92a9568c0dd708508880
* webのためのカーネルパラメータ
  * https://ryuichi1208.hateblo.jp/entry/2019/11/27/204706