オフィシャルサイト: Ferora Tuned
その他役に立つドキュメント: RHEL6 Power Management Guide
開発ツリー: Fedora Git - tuned.git

Tuned

移転しました

独自ドメインサイトへ移行しました。5秒後に

https://straypenguin.winfield-net.com/

へジャンプします。

sysctludevルール、rc.local などばらばらのファイルで設定していたカーネルやデバイスのチューニングを、Profile という単位でまとめて集中管理できるツール。CPUの負荷などに応じて動的なチューニングを行うことも可能だが、今のところ自分はスタティックな用法にのみフォーカスして使っている。これがなかなか使える。提供されているドキュメントや情報が不足しているのが難点。また、まだ成熟しきっていないところがあり、ちょっとばかしイナしながら使ってやる必要がある。

Table of Contents

Tunedのメリット

CentOS 7 をインストールした時、パッケージグループ選択の結果たまたま入ったのをきっかけに触り始めた。実は RHEL/CentOS 6 の時代から存在していたようだ。tuned はデーモンとして動作し、負荷状況に応じた動的なチューニングもできる。それが tuned の主な使い方だと思い込んで毛嫌いしていたのだが、スタティックな使い方をすると、とくに出しゃばらず非常に便利であることが分かった。

Tunedを使うことによって解消できる従来の管理方法のデメリット

プロファイルの作成

Tuned は主に以下のコンポーネントから成る。

Tuned 本体

systemdtuned サービスユニットから呼ばれている /usr/sbin/tuned は、python で書かれたスクリプトだ。

Tunedグローバル動作設定ファイル

/etc/tuned/tuned-main.conf に、動的チューニングを行うかどうかなど、基本的な動作設定が定義されている。

システムプロファイル

/usr/lib/tuned/ 配下に、既製のプロファイルが各々ディレクトリとして存在する。ディレクトリ名 = プロファイル名 だ。また、プロファイルから共用するための環境変数やシェルファンクションを定義したスクリプトインクルードファイルもここにある。

カスタムプロファイル

カスタムプロファイルやカスタムスクリプトファンクションファイルなどは /etc/tuned/ 配下に置くことが推奨されている。こちらの方が /usr/lib/tuned/ にあるものよりも優先される。プロファイルは別のプロファイルの内容を継承したり特定の項目をオーバーライドしたりすることもできる (カスタムプロファイルに限った話ではないが)。

プラグイン

チューニングは tunedプラグイン を介して行う仕組みになっている。主なところでは、sysctl, disk(I/OスケジューラやReadAheadなど), cpu(governor等)、それに、既存のプラグインで網羅されていないことをカスタムスクリプトで行うための script プラグインがある。プラグインの実体は /usr/lib/python2.x/site-packages/tuned/plugins/plugin_*.py という名前で格納されている。

プロファイルの作り方

プロファイルは、プロファイル名を名前としたディレクトリと、そこにある tuned.conf が最低限の構成となる。ここからは customserver というプロファイルを作成するものとして説明する。

プロファイルディレクトリの作成

Tuned はドキュメントが甚だ不足していて、既存のサンプルコンフィギュレーションを見本にするしか確実な方法がないのが実情。どうせなら、あらかじめ、既製のどのプロファイルを下地にするのが最適か選んでおくとよい。システムプロファイルディレクトリ /usr/lib/tuned/ 配下を物色して、新しく作ろうとするプロファイルの性質に似たものを探す。ここでは throughput-performance プロファイルを叩き台にすることにして、それをカスタムプロファイルディレクトリへ新しい名前でコピーする。

# cp -a /usr/lib/tuned/throughput-performance /etc/tuned/customserver
CentOS 7 で見たところ、例えば Oracleデータベース用プロファイルが tuned-profiles-oracle.noarch というパッケージで標準パッケージとして提供されている。`yum list tuned-profiles-*' でちょうど良さそうなプロファイルが見つかれば、それをインストールして雛形にすると楽だ。

tuned.conf の作成

/etc/tuned/customserver/tuned.conf を編集する。コンフィグは [name] ブロックで構成される。[main] ブロックを除いては、プラグイン毎にひとつのブロックを構成する。例えばこんな塩梅だ。これは単なる例であり項目数もかなり絞っているし、最適値はマシンの用途や仮想か物理かによっても全く異なるので、このまま使おうとしないでいただきたい。

#
# tuned configuration
#
 
[main]
include=throughput-performance        <- 継承するプロファイル。他のどのプロファイルも継承しないのなら[main]ブロック自体不要。
 
[cpu]
replace=1                             <- ※
force_latency=1
governor=performance
energy_perf_bias=performance
min_perf_pct=100
 
[sysctl]
replace=1
vm.dirty_ratio = 30
vm.min_free_kbytes = 131072
vm.swappiness = 30
 
kernel.shmall = 939524096
kernel.shmmax = 939524096
kernel.sem = "250 32000 100 128"
fs.file-max = 6815744
 
[vm]
replace=1
transparent_hugepages=never
 
[disk]
replace=1
device=sd*                           <- ※
elevator=deadline
 
[netif_ringsz]
enabled=false                        <- ※
verbose=true                         <- ※Tunedのデバグ にて解説
logging=debug                        <- ※Tunedのデバグ にて解説
type=script
script=set-ringsz.sh

プラグインブロックは [PluginName] とするのが通常だが、[my_data_disk] などという全く別の名前にしてその中で type=disk のようにプラグインを指定する方法もある。ただし、継承元に [disk] という標準名の diskプラグインブロックがあって、継承先の diskプラグインブロックは [data_disk] + type=disk で指定した時、後者のパースの結果が「適用対象デバイスなし」(後述のdeviceパラメータ参照) となってしまった。継承元と継承先に同じプラグインのブロックがある時は [ブロック名] は合わせた方が無難なようだ。

replace=1 (つまりtrue) は、他のプロファイルを継承 (include) している場合に、項目を置き換えることを意味する。replace=1 が指定されていないブロックは、「マージとなる」とマニュアルに書いてある。しかし、どこを見ても説明が不十分。継承を使っている場合で、継承元にも同じ名前のあるブロックは、必ず replace=1 にしておくのが間違いないと、筆者は思っている。実験してみると、replace について以下のことくらいしか分からなかったからだ。

というわけで、どんなケースでどのようにマージされるのかわけが分からず、意図せぬ値の結合を避けるため、今のところ replace=1 は常に宣言するべきとの結論に至った。

先ほども話に出た devices= パラメータは、そのプラグインブロックの適用対象にするデバイスを限定したい時に使う。ワイルドカード "*" も使用可能だ。プラグイン毎に、例えば diskプラグインなら sd[a-z], hd[a-z], vd[a-z] などディスクデバイスと思しきブロックデバイス名のルールがあらかじめ決められていて、devices= パラメータを指定しなければ、マシンに存在するそれら全てのデバイスが適用の対象となる。これは "devices=*" と指定したのと同じだ。また、カンマ区切りのリストも指定可能で、例えば "devices=sda,sdb" となる。さらに、除外指定も可能で、その場合 "devices=!sdc,!sdd" といった記述になる。

[netif_ringsz] ブロックの記載例のように、ブロックに enabled=false を宣言すると、そのプラグインブロックの適用を無効にすることができる。継承元にも同じ名前のブロックがあれば、継承元のブロックも適用されない。

カスタムスクリプトブロックの使用

例の最後にある [netif_ringsz] は、ネットワークインターフェイスのリングバッファ(ハードウェアバッファ) をチューニングしたくて筆者が独自に作ったシェルスクリプトを駆動する scriptプラグインブロックだ。従来なら udevルールか/sbin/ifup-local でやっていたことである。

script= の右辺には、絶対パスではなく、プロファイルディレクトリ内に存在するファイル名を書かなければならない。set-ringsz.sh は、ここで言う /etc/tuned/customserver/ に置くことになる。カスタムスクリプトを書くに当たっては、いくつかお約束事がある。スクリプト例を示しながら説明しよう。

#!/bin/sh
. /usr/lib/tuned/functions
. /etc/tuned/my_functions
 
start() {
    save_ringsz
    set_ringsz 2048 1024
}
 
stop() {
    restore_ringsz
}
 
process ${1:+"$@"}

必ず、`source /usr/lib/tuned/functions' で tuned のシステムプロファイルディレクトリにあるシェルインクルードファイルを読み込むこと。

スクリプトには、start() ファンクションと stop() ファンクションが定義されていること。scriptプラグインでは、tuned がプロファイルの適用時に "start" 引数、適用解除時や別のプロファイルへの推移の際に "stop" 引数を付けてスクリプトを呼んでくる。stop/start 引数の振り分け処理には、tunedfunctionsインクルードで定義されている process() ファンクションを使う。最初は知らずに case ステートメントで直接書いてみたが動きが安定しない - "reinventing the wheel" というやつで無意味なのでやめておくこと。

もうひとつの約束事は、start の際には、これから変更しようとしている値の現在値をキャッシュファイルに記録し、stop の際にはそれをリストアすることだ。これらの処理は、自力で書く必要がある。このケースでは、それらのファンクションは my_functions という別体ファイルに書いた。必ず分けなければいけないというわけではないが、他にもスクリプトを書いた時に使い回せるという思惑からだ。キャッシュファイルディレクトリとファイルの拡張子は tuned 作りつけの functions の中で、それぞれ変数 $STORAGE$STORAGE_SUFFIX にアサインされているのでそれを利用する。

プロファイルの適用

tuned の管理には tuned-adm コマンドを使う。tuned 本体同様これも python でできている。

利用可能なプロファイルのリストを得るには、

# tuned-adm list

現在適用されているプロファイルを知るには、

# tuned-adm active

前述で作ったプロファイルを適用するには、

# tuned-adm profile customserver

プロファイルをアンロードしてシステムのデフォルトに戻すには、

# tuned-adm off

プロファイルの設定内容を書き換えたからといって、一旦 off して剥ぎ取る必要はなく、customserver プロファイルがアクティブな状態で再度 `tuned-adm profile customserver' してやれば、プロファイルはアンロード->リロードされて更新後の設定が反映される。

動的チューニングを使わなくても、起動時にプロファイルを適用させるためには、tuned サービスはスタートアップするようにしておく必要がある。つまり RHEL/CentOS 7 ならば `systemctl enable tuned.service' だ。起動時には、最後に適用されていたプロファイルが適用される。ただし、最後に `tuned-adm off' しておいてシステムを再起動すると、謎のお勧め(recommend) 機能のお節介なのか、balanced プロファイルあるいは virtual-guest プロファイル (おそらく試験環境が仮想マシンだから) が勝手に適用されていたりする。プロファイルの適用をやめたくなったら、きっぱり tuned.service のスタートアップを disable すべきだ。

メモリを節約したいシステム管理者は、プロファイルをシステムに適用した後に tuned.service を止めたらどうなのかと考えるかもしれない。やってみると、`tuned-adm active' の出力結果は (ここで言うなら) customserver のままでありながら、実際に sysctl コマンドで proc の値などを確認してみるとシステムの既定値に戻ってしまっている。tuned は本来、D-Bus を使うデーモンとして作られており、tuned.service ユニットファイルの "Type" は "dbus" となっている。tuned-main.confdaemon=1 というグローバルパラメータがあるので、これを daemon=0 に変更した上でユニットファイルを Type=oneshot にすれば、tunedD-Bus に繋ぐのをやめ、プロファイルの適用だけしてEXITするようになる。ただし、tuned-adm コマンドは tuned のステータスをまず D-Bus 経由で知ろうとする仕組みになっていて(結果は出るが)エラーメッセージを伴うし、tuned-main.conf には「デーモン動作を無効にするのはお勧めしない」と書かれている。

当ページのように tunedsysctl.conf の延長あるいは代替と考えて多岐にわたる sysctl パラメータを tuned.conf に入れ込む場合、チューニングのメインターゲットと目するサービスと tuned サービスとの起動順に気を付けなければならない。その典型が net.ipv4.tcp_rmemtcp_wmem など。例えば httpd プロセス起動時に割り当てられるリードバッファメモリ量の初期値は、その時の proc の値によって決まる。つまり、tunedhttpd よりも先に起動されなければならないわけだ。具体的には、/etc/systemd/system/httpd.service.d/override.conf を作り、[Unit] ブロックに After=tuned.service と書いておけばよい。それで、/usr/lib/systemd/system/httpd.service ファイル内に書かれている "After=network.target 云々" とマージされる。

Tunedのデバグ

tuned は、ジャーナルやSYSLOGを通さずに直接 /var/log/tuned/tuned.log にログを吐く。

tuned.conf で使えるパラメータに、verbose=, logging= という汎用パラメータがある。verbose はブーリアン値で truefalse のいずれかで既定値は falselogging は重篤順に critical, error, warning, info, debug のいずれかで既定値は info[main] ブロックに書けばそのプロファイル全体で効かせることができるし、特定のプラグインブロックで唱えればそのブロックに対してのみ効くことになる...とマニュアル等に書かれているが、CentOS 7.2 で試した限り、全く効かない。結局、tuned の起動オプションに -D を指定することによってログにデバグ情報も出力され、verbose=true にしようが false にしようが、logging=debug だろうと info だろうと、ログの冗長性に全く変化は見られなかった。

サービスを systemd で制御している RHEL/CentOS 7 では、tuned のランタイムオプションをうまく指定するためにちょっとした工夫が要る。tuned のサービスユニットに、追加のランタイムオプションを読み込む仕組みがないからだ。しかし、大元の /usr/lib/systemd/system/tuned.service ファイルを変更するのは行儀が悪い。代わりに /etc/systemd/system/tuned.service.d/override.conf を作り一部設定をオーバーライドする。直接作っても構わないのだが、`systemctl edit tuned.service' とやると override.conf の一時ファイルがテキストエディタ (既定では nano で開く - 珍しい) で開かれるので、下記の内容を打ち込み、言われるままの一時ファイル名で保存する。そうすると /etc/systemd/system/tuned.service.d/ ディレクトリと override.conf が出来上がる。

[Service]
EnvironmentFile=-/etc/sysconfig/tuned
ExecStart=
ExecStart=/usr/sbin/tuned -l -P $OPTIONS

一旦 ExecStart= を空にしてから宣言しなおすのがポイント。さもないとエラーでユニットが起動しない。あとは /etc/sysconfig/tuned ファイルを作り OPTIONS="-D" と書けば準備OK。`systemctl daemon-reload && systemctl restart tuned' すれば、以降 tuned.log にはデバグ情報が出てくる。デバグが済んだら、sysconfig/tunedOPTIONS 行をコメントアウトするかファイルごと削除すればいい (EnvironmentFile= の指定に "-" を入れているのでファイルがなくてもエラーにはならない)。