斎藤です。

今日は、RRDToolを使って、今後かかる負荷を手軽に予測する方法をご紹介します。あわせて、プログラムと連携して性能限界を越えそうなサーバがあるかを判定してみます。人手ではまかないきれない数のサーバに対して、一台ずつ問題の予兆を調べるときなどにお試しください。

※CentOS 6.3 (64bit) + RRDTool の2013/2/20頃の最新ソースを用いて試しています

「限界」を早く知りたい!

ITインフラを運用している方の多くは、Cacti, Munin等で負荷を日々モニタリングされているかと思います。モニタリングしたデータを用いて今後を予測する際、どのようにされていらっしゃいますでしょうか?描かれたチャートの動きをもとに、経験と勘を駆使して「ヨイショ!」っとされている方も、いらっしゃるのではないでしょうか。

特に、ディスク容量やネットワークトラフィック等、根本的な対策に一定の時間が必要なものほど、早めに手を打ちたいものです。監視ツールが通知してきた時には、時既に遅し!という事になりかねません。

また、サーバの台数が何十台、何百台となると、人力だけで判定するのは現実的ではありません。AWSをはじめとしたIaaSが普及している現在、サーバは手軽に増やせるようになった一方、台数の増減をどうすれば良いのかは、悩みの種ですよね。

RRDTool を用いて予測する

CactiやMuninの裏側で、RRDToolが動いている事をご存知の方もいると思います。RRDToolは様々なデータを継続的に収集し、グラフに描画することができるツールですが、このグラフの描画機能には様々なメソッドが存在します。

その中で、今回は「予測」に使えるメソッドを中心に、使い方を紹介していきます。

予測を行う前に、今回利用するデータについて説明します。下記のグラフは、あるサーバのLoad Average (1分)のデータです。出力範囲は1週間です。CPUは2コアですので、2が上限の目安となります。このグラフから、感覚としては負荷は上昇気味で、ひょっとするとCPUの性能が足らなくなるかも?という事がわかります。

predict0.png

また、グラフ出力時、次のコマンドを実行しています。

$ rrdtool graph ./graph.png \
    --start="1360892438-1w" \
    --end="1360892438+1w" \
    --imgformat=PNG \
    --title="Load Average (1min)" \
    --height=200 \
    --width=500 \
    --lower-limit=0 \
    DEF:load=test.rrd:load_1min:MAX \
    AREA:load#CC0000:"Load Average (1min)" \
    LINE2:2#CCCCCC:"Limit"

"1360892438"(2013/02/15 10:40)はRRDToolが最後にデータを収集した時のUNIX秒です。次のコマンドで知る事が出来ます。これを指定しない場合、コマンドを実行した日を基準にグラフが描画されます。

$ rrdtool info test.rrd | grep last_update
last_update = 1360892405

さて、これから「感覚」で理解したグラフの動きを、定量的に把握してみましょう。

直線回帰を試してみる

一つ目は直線回帰です。負荷の傾向、即ち「上がっている」「下がっている」または「一定」かを調べます。

predict1.png

「何となく上昇している」感覚を、定量的に示す事が出来ました。コマンドは次の通りです。

$ rrdtool graph ./graph.png \
    --start="1360892438-1w" \
    --end="1360892438+1w" \
    --imgformat=PNG \
    --title="Load Average (1min)" \
    --height=200 \
    --width=500 \
    --lower-limit=0 \
    DEF:load=test.rrd:load_1min:MAX \
    VDEF:a=load,LSLSLOPE \
    VDEF:b=load,LSLINT \
    CDEF:ls=load,POP,a,COUNT,*,b,+ \
    AREA:load#CC0000:"Load Average (1min)" \
    LINE1:ls#00CC00:"Least Squares Method" \
    LINE2:2#CCCCCC:"Limit" 

4行、増えています。

最小二乗法のグラフの傾きを"LSLSLOPE"、切片を"LSLINT"を利用して算出しています。そして、逆ポーランド記法を用いて"CDEF:ls=load,POP,a,COUNT,*,b,+"にてグラフの線を算出しています。意味は"y = a * loadの順番 + b"となっています。

曲線回帰を試してみる

二つ目は、曲線回帰です。直線回帰ではわかりづらい、負荷の「波」を予測してみましょう。

predict2.png

何時頃が負荷の山か、定量的に示す事が出来ました。コマンドは次の通りです。

$ rrdtool graph ./graph.png \
    --start="1360892438-1w" \
    --end="1360892438+1w" \
    --imgformat=PNG \
    --title="Load Average (1min)" \
    --height=200 \
    --width=500 \
    --lower-limit=0 \
    DEF:load=test.rrd:load_1min:MAX \
    CDEF:sm=load,10800,TREND \
    CDEF:cf=86400,-8,3600,sm,PREDICT \
    AREA:load#CC0000:"Load Average (1min)" \
    LINE1:sm#00CC00:"Smoothing" \
    LINE1:cf#0000CC:"Curve Fitting" \
    LINE2:2#CCCCCC:"Limit"

今回も4行増えています。

"CDEF:sm=load,10800,TREND"は、10800秒(3時間)単位の移動平均線を算出しています。"CDEF:cf=86400,-8,3600,sm,PREDICT"は最も肝心な所で、RRDToolが持っている曲線回帰のメソッドを通じてデータを算出しています。86400(1日)は1周期の間隔、-8はさかのぼる日数、3600(1時間)は平均する間隔です。

少し応用: 最高値を予測してみよう

ここまで、2つの予測手法を紹介しました。直線回帰で傾向を、曲線回帰で山が見えてきます。しかし、これだけでは上限にいつ達するかはわかりません。

そこで、直線回帰のデータを利用して、ざっくりと今後の最高値を予測してみましょう。

predict3.png

グラフを見ると、早くとも1ヶ月以内にLoad Averageが2を越えそうですね。やっている事は単純で、最小二乗法の傾きはそのままに、切片をLoad Averageの最高値にし、さらに1週間分グラフをずらしています。これで、負荷の最大値を予測する定量的な判断材料ができあがりました。

コマンドは次の通りです。

$ rrdtool graph ./graph.png \
    --start="1360892438-1w" \
    --end="1360892438+1w" \
    --imgformat=PNG \
    --title="Load Average (1min)" \
    --height=200 \
    --width=500 \
    --lower-limit=0 \
    DEF:load=test.rrd:load_1min:MAX \
    VDEF:a=load,LSLSLOPE \
    VDEF:b=load,100,PERCENTNAN \
    CDEF:predict=load,POP,a,COUNT,*,b,+ \
    SHIFT:predict:604800 \
    AREA:load#CC0000:"Load Average (1min)" \
    LINE1:predict#00CC00:"Predict" \
    LINE2:2#CCCCCC:"Limit" \

コマンドは直線回帰のときと大きくは変わりませんが、2点違う所があります。

"VDEF:b=load,100,PERCENTNAN"は、Load Averageの100%(最高値)の値を取得しています。尚、100の部分を90とすると、90%値を返します。"SHIFT:predict:604800"は、604800秒(1週間)分グラフを右にずらします。

データをエクスポートしてプログラムで解析する

RRDToolはグラフとして描画するだけでなく、描画しているグラフのデータをXMLやJSON(1.4.6以降)形式でエクスポートする事が出来ます。特に、JSONは各種プログラムですぐに読む事ができ、便利です!エクスポート機能を使って、先の予測した最高値が上限を越えるか調べてみましょう。

コマンドは次の通りです。

$ rrdtool xport \
    --start="1360892438-1w" \
    --end="1360892438+1w" \
    --json \
    DEF:load=test.rrd:load_1min:MAX \
    VDEF:a=load,LSLSLOPE \
    VDEF:b=load,100,PERCENTNAN \
    CDEF:predict=load,POP,a,COUNT,*,b,+ \
    SHIFT:predict:604800 \
    XPORT:load:"Load Average (1min)" \
    XPORT:predict:"Predict" \
    > test.json

次のデータが出力されます。

$ cat test.json
{ "about": "RRDtool xport JSON output",
  "meta": {
    "start": 1360288800,
    "step": 3600,
    "end": 1360288800,
    "legend": [
      "Load Average (1min)",
      "Predict"
          ]   
     },  
  "data": [
    [ null, null ],
    [ 3.0380000000e-01, null ],
    [ 5.7200000000e-01, null ],
                :
              (中略)
                :
    [ null, 2.1571609160e+00 ],
    [ null, 2.1585614770e+00  ]
  ]
}

さて、解析するプログラムを用意しましょう。今回はPythonで簡単なチェックプログラムを作成しました。ファイル名を"check.py"としています。

 #!/usr/bin/env python

import json
import datetime
import sys

file = open( sys.argv[1] )
json = json.loads( file.read() )
file.close()

step = 0
max  = 2.0

for line in json[ "data" ]:
    if line[1] is None:
        pass
    elif line[1] >= max:
        date = datetime.datetime.fromtimestamp(
            json[ "meta" ][ "start" ]
            + json[ "meta" ][ "step" ] * step
            )
        print u"NG: %s" % date.strftime( "%Y/%m/%d" )
        sys.exit(1)
    step += 1

print "OK"

これを動かしますと、2月17日頃に問題が出る事がわかります。グラフで上限値と最高値予測が重なった点とも合致します。

$ python check.py test.json 
NG: 2013/02/17

こうして、RRDToolと簡単なプログラムを組み合わせる事で、リソースの上限値を越えそうなサーバを自動的に見つける事もできるようになります。

注意点

RRDTool、特にエクスポート機能を使う際、注意していただきたい事があります。

  • JSONの書式がおかしい

出力する書式に問題があり、Pythonで読み込めない症状が発生します。これは、現行の安定板である1.4.7でも発生します。従って、この機能を利用する場合はgithubにあがっている最新のコードを利用するか、1.4.7にパッチを当てる必要があります。

  • ゴミデータが混じる

"SHIFT"コマンドを利用した際、エクスポートしたデータにゴミデータが混じる事があります。先ほど例示したエクスポートデータも、次のようなゴミが混じっていました。177〜179をご覧ください。

176     [ 5.4183333333e-01, null ],
177     [ 5.4183333333e-01, 0.0000000000e+00 ],
178     [ 2.6950000000e-01, 0.0000000000e+00 ],
179     [ 3.0680000000e-01, 1.3364475720e-320 ],
180     [ 3.2716666667e-01, 1.9232672277e+00 ],
181     [ null, 1.9246677887e+00 ],

場合によっては、プログラム側でフィルタした方が良いかと思います。尚、グラフの描画では問題ないようです。

  • エクスポート可能なのはCDEF, DEFで定義した変数のみ

エクスポート可能なデータは、"CDEF"と"DEF"で定義した変数のみです。"VDEF"で定義した変数はエクスポートできません。ただ、回避方法があります。

CDEF:new=old,1,*

元の値に1をかけて(すなわち数値をいじらない)、新しい値に代入します。

  • RRDToolのバージョンについて

Cacti等のモニタリングツールが入っているサーバで新バージョンを使う場合、念のためモニタリングツールが使うRRDToolは残しつつ、別の場所にRRDToolをインストールした方が良いかと思います。

おわりに

今回は、CactiやMuninが収集したデータをもとに、RRDToolを使って今後かかる負荷を予測する手法を紹介しました。あわせて、予測した負荷の数値をもとに、上限値を越えるかプログラムで判定する事で、問題発見を自動化する手法を取り上げました。

今まで人力でやっていたサーバのリソース増強・縮小の判断を自動化する事で、日々の運用が少しでも楽にできる一助になれば幸いです。

また、統計やオペレーションズ・リサーチに強い方は、ご自分で作ったモデルを"CDEF"の式として組み立てて分析する事も可能です。"CDEF"の記述方法は逆ポーランド記法なので、LispやHP電卓に慣れている方にとっては親しみやすいかと思います。

それでは、ごきげんよう。

参考文献

株式会社ハートビーツのインフラエンジニアから、ちょっとした情報をお届けします。