当社はIT技術のオンライン教育を得意としたセミナー専門会社です。 | 一戸英男

ITエンジニアの技術力UPをお約束します。

Linux OS Tuning関連テクニック

Linux OS Tuning関連テクニック


Linux OS Tuning チップス(記事が古いので現状のLinuxカーネルと差異があります)

巨大なシステム、あるいは人気のあるサイトを運営するサーバ管理者の多くは、Linux上で稼動する様々なサーバを高速にかつスケーラビリティを拡張するために、サーバの設定パラメータにある「最大同時接続数」という類の意味に近い「キーワード」を探すことでしょう。


しかし、実はこの設定値を見つけて、値を大きくした所で必ずしもサーバの処理能力は向上しません。さて、これは何故でしょうか?。サーバはあくまでもLinuxのOS上で動いているプログラムのひとつに過ぎません。答えはプログラムのリソース制限を制御するのはやはりOSのリソースに関わるカーネル設定に関係してきます。
たとえば送信可能なメッセージの最大長、メッセージキューidの最大値、メッセージキューの大きさ等です。ここでは以降の内容を説明しながらチューニングの考え方を解説していきます。


最大同時接続数に関するパフォーマンスチューニング

  • File Descriptorと最大接続数の関係
  • メモリの効率化
  • DISKのチューニング
  • 最大同時接続数に関するパフォーマンスチューニング

「同時接続数を増やすことの良さってなんだろう?」そう考える人もいることでしょう。この値を増やすということは、サーバからのサービスをほとんど待たずに受けられるということです。体感上、おそらくスピードが速くなったと感じる人もいるはずです。


実際は速くはなっていなくても、サービスの結果が短い時間で得られるとそのような錯覚をもってしまうのです。これは、すなわち顧客満足につながる内容にほかなりません。実は、ここで、これから説明するFile Descriptorは、サーバに対し多くのクライアントがアクセスする際、サーバプロセスがハンドル(制御)できるコネクションの数と関わりのある重要な設定です。


File Descriptorと最大接続数の関係

 C言語でプログラムを組んだことが、ある方ならご存知のかたもいると思いますが、ファイルをオープンする際にopen関数で、最初に設定する第一引数がこれに相当します。元々、プロセス、プログラムが複数のファイルや標準入出力をオープンし、書き込んだり、読み込んだりするのを間違えないように、区別するための識別子として使っているものです。


しかしネットワークSocketプログラミングをした人なら、わかるはずですが、ソケットもファイルとして扱うのが UNIX/Windowsの特徴です。write関数を使ってデータを書き込んであげると、これが結果的に送付先にデータを送信する行為と同等となります。接続とFileDescriptorは、密接な関係にあります。 重要なことは「接続の影に FileDescriptorあり」です。これを呪文のごとく、頭に叩き込みましょう。


それでは、本題のチューニングのやり方です。次の1~2はどれも同じ結果が得られます。若干使いかたがことなるので、特徴を捕まえて使用してください。


1. /etc/rc.sysinitとか/etc/rc.localに記述すると毎回起動時に自動的に実行します。

2. 一度設定すると起動時に実行されます。

3. コマンドラインでその場限りで値を変えるのに最適な方法です。実験の際、評価として値を色々変えてみるのには便利です。

まめ知識(inode)

今は、もう使わなくなったカーネルパラメータのチューニングに次の設定があります。inodeもディスクのディレクトリツリーの枝の本数を決める要素であるため、同時接続数が増えると、当然この値も圧迫してきます。


この設定はカーネル2.2時代までは使っていましたが、2.4以降は不要です。一部のチューニングサイトの情報では、まだ根強く残っていますが、実質書いたところで全く影響はありません。


ここで、このような設定があったことを書いてある理由ですが、やはり接続が一つ増えるとファイルも少なくとも1つ以上生成されます。この感覚は、様々なトラブルシューティングを行うフェーズで必ず役に立つはずです。


メモリの効率化

メモリ空間の調整)

実は、あまり知られていませんがデフォルトで扱えるLinuxのメモリ管理範囲はカーネルバージョンの変遷とディストリビューションにより微妙に違いがあります。一昔前はデフォルトは880MByteとなっていました。もしこのような場合1GByte以上のメモリを搭載しようとしたらまずカーネルをコンパイルする必要があります。

下記の設定はカーネル2.4及び2.6の両方で使うことができます。

SWAPの調整

上記の拡張により、搭載メモリを使いきれるようになったら、次に考えなくてはならないのは、SWAPの調整です。カーネル2.4の頃までは、 SWAPINGの頻度を調整することは困難でしたが、現在のカーネル2.6以降ではswapinnessを使ってswapの頻度を制御できるようになりました。


swappinessに設定できる値は0~100となっています。値が大きいほどSWAPの頻度が多くなります。通常デフォルトでは 60で設定されていますが、256MBの搭載マシンであればデスクトップでは20以下でもよいかもしれません。仮にサーバでもマシンが使っているメモリ容量の統計をとって平均的なメモリのトップ位置を知っているなら、この値を低くして調整してみることも良いでしょう。


以降にswapの頻度を変更するにあたって方法を示します。

①コマンドラインで変更する場合

起動時のスクリプトに組み込んで実行するのでも良いでしょう。

②恒久的に値を変更したい場合

malloc()を使ってメモリーを確保しようとする場合の挙動として、腑に落ちない点があるとお思いの方も多いと思います。 具体的には、malloc()がfreeコマンドや「cat /proc/meminfo」等から確認できるメモリーの空き容量を、大幅に超えて確保できてしまうという現象。勿論、システムがSWAP領域を確保している場合は当然の挙動ですが、SWAP領域を確保していないシステムでも同様の現象が発生します。 次の行を探します。値は0から100まで使用できますがこの値を小さくすることで頻度が低くなります。

# Control how much the kernel should favor swapping out applications (0-100)
vm.swappiness = 30

【スレッドの調整】

マルチスレッドという言葉は、かなり一般的に定着してきたので、ここではおさらい程度に解説しておきます。 一昔前のサーバプログラムは圧倒的にプロセス方式のサーバが多かっのです 最近のサーバプログラムでは大半がマルチスレッド方式のプログラムであることが多くなっています。

そのためサーバのチューニングを行う大前提として、OSのスレッドに関するチューニングが必要になってきます。 それではマルチプロセスとマルチスレッドの挙動はどこがちがうのか考えてみましょう。


まずは、マルチプロセス方式のプログラムは複数起動してもメモリの共有は行わないのです。しかし、マルチスレッドは起動したプロセスの中でスレッドと言う単位の処理でプログラムを実行し、これを並行して処理を行い、この際メモリを共有して処理を行うことができるのです。


これは言い換えるとメモリ上に共通で使用するデータが存在した場合どちらが有利なのか想像できるでしょう。当然マルチスレッドの方が効率が良いにきまっています。


又起動時のオーバヘッドやメモリ空間の消費でもプロセス方式より有利と言われているため、このことより最近のサーバは軒並みスレッド方式のものが多くなっています。


ただし、サーバによってはプロセス方式の方が安定しているという意見もあります。私個人の意見としてはサーバ間連携が発生する場合にお互いにマルチプロセス方式なのか、マルチスレッド方式になっているかの統一が大前提と考えています。そして発生するコネクションに対し相手の受けるコネクションの本数が一致していなければ結果的に失敗してしまうからです。


またセッション管理の仕方も関係します。 それ故にApache Webサーバのように1.3 or 2.xの二つのバージョンが現役で存在しているサーバも中にはあります。 以降ではスレッドのチューニング行うにあたって必要となる関連パラメータを確認する。 スレッド動作に関わる要素)
  • ファイルデスクリプターの上限値
  • プロセス数の上限値
  • メモリ上限値
  • mutex/semaphore/shm/ipc
  • コンパイル時のスレッド上限値
結局の所、スレッドの値を大きくしてもプロセスのメモリ消費量はホールドできる最大コネクション数や一プロセスあたりの共有メモリ容量の設定で総合的に考える必要があります。 スレッドの根幹となるパラメータ) 下記のパラメータは/proc配下のリソース値を直接書き換えるか、sysctl.confを書き換えて変更します。
  • threads-max
  • shmall
  • shmni
  • shmmax
  • msgmax
  • msgmni
  • msgmnb

【threads-maxについて】

/proc/sys/kernel/threads-maxはシステム全体で扱えるスレッドの最大値を示しています。 しかしこれを考える際に1プロセスあたりのスレッド最大値も理解する必要があります。要するに1プロセスで全てのスレッド数を扱えるわけではないからです。 確認方法としてはglibcのソースコードをオープンしそこにコーディングされている値が1プロセスあたりのスレッドの最大値です。私が過去に経験しているケースでは一般的に1024で定義されているようです。


【shmall,shmni,shmmax】

共有メモリ空間の値を指し示しています。shmallはシステム全体の共有メモリ空間、shmmaxは1プロセスごとのメモリ空間、 shmmniは1プロセスごとの共有メモリセグメント(メモリブロック)の数の上限を示しています。 サーバに様々なアプリケーションが存在し共有メモリを使う際は、個々のアプリケーション毎に設定はできないので、全てのアプリケーションで網羅できるように値を設定を修正する必要がでてくるかもしれません。


【msgmax,msgmni,msgmnb】

送信可能なメッセージの最大長、メッセージキューidの最大値、メッセージキューの大きさを指定できます。

メモリオーバコミットへの対処

アプリケーション開発をされている人はよく、メモリー消費に気を使って開発されている方も多いかと思いますが、C言語でプログラムを組まれている方であればよく使う関数malloc()関数の問題で悩まれるケースがあるはずです。 何をいいたいのかというとmalloc()が現在の使用リソースを越えてメモリを取得しようとすることです。swapの利用があればそれも問題ないのですが、最近ではswapを使わずメモリを増やしてマシンを構成する場合もしばしばあります。こんな時でもメモリオーバコミットの現象が発生する場合があります。ここでは、このような現象に対応するための情報を提供します。

  • 対処方法)
  • カーネルのパラメータを変更し対処を行います。
  • malloc_limit[MB] = swapサイズ[MB] + (物理メモリサイズ[MB] * overcommit_ratio / 100)
実は、overcommit_memoryは計算されている範囲がとても微妙というか、計算範囲外部分があるためその部分も考慮に入れて設計しなくてはいけないのです。
  • 使用量にカウントされる
  • データセグメント
  • ヒープ
  • スタック
  • 使用量にカウントされない
  • テキストセグメント
  • MMUが消費するメモリ
  • kernelが消費する各種メモリ
  • バッファーキャッシュ・ページキャッシュのサイズ
  • tmpfsが消費するメモリ

こう考えると、かなり予測がつかなくなってきます。正直いってvm.overcommit_ratioに決定的な値を設定するには運用テスト等で実験して不具合がでないか何度か設定しなおしが必要なのかもしれません。まあ、とりあえずは下記のように仮に設定したとして話を進めていきます。下記例は計算するとわかると思いますがswapパーティションサイズでしかmalloc()お許さないということになります。

# sysctl -w vm.overcommit_ratio=0
# sysctl -w vm.overcommit_memory=2

確認方法は直接/proc配下のカーネルパラーメータを叩いて確認しましょう。
cat /proc/sys/vm/overcommit_ratio
cat /proc/sys/vm/overcommit_memory

ちなみに、上記パラメータの設定の際どのような値を設定するべきかなのですがmanページを抜粋すると以下のように書かれています。

0: 発見的なオーバーコミット (heuristic overcommit) (これがデフォルトである)
1: 常にオーバーコミットし、チェックしない。
2: 常にチェックし、オーバーコミットしない。

モード 0 では、MAP_NORESERVE を設定して呼び出された mmap(2) はチェックされない。またデフォルトのチェックはとても脆弱で、プロセスを “OOM-kill” してしまうリスクを引き起こす。 Linux 2.4 では 0 以外の値はモード 1 を意味する。


(Linux 2.6 以降で利用可能な) モード 2 では、システム上の仮想アドレス空間の合計が (SS + RAM*(r/100)) に制限されている。 ここで、 SS はスワップ空間のサイズ RAM は物理メモリのサイズ r はファイル /proc/sys/vm/overcommit_ratio の内容である。

タグ: , , ,