アドバンスド・スクリプティング

このチュートリアルでは、Traffic Sentinelのスクリプティング・メカニズムを用いて行われるクエリーの拡張性や速度を大幅に向上させる、高度なスクリプティング機能について説明します。説明を始める前に、Traffic Sentinelのスクリプティング機能の基本を説明したクエリのスクリプト化を参照ください。.

注意: このチュートリアルは、Traffic Sentinel 4.0に新たに追加された機能について説明するものです。旧バージョンのTraffic Sentinelをお使いの場合は、これらの機能を使用するには、アップグレードが必要です。

マルチ・クエリ

マルチクエリー・メカニズムは、複数のクエリーを平行して実行するものです。マルチコア・サーバーの場合、たいていはディスク・アクセスがボトルネックになっていますから、通常、マルチクエリーに要する時間は、1つのクエリーが完了するまでにかかる時間と、ほとんど変わりません。

例えば、下記のスクリプトでは、複数のIPアドレスについて、それぞれのアドレスがアクセスした上位5位までのサーバーと上位5位までのサービスを検出します。このスクリプトでは、各アドレスについて2つのクエリー、すなわち、合計で6つのクエリーが必要です。

var hosts    = ["10.0.0.50","10.0.0.51","10.0.0.52"];
var interval = "today";
var n        = 5;

var report = Report.current();
var q, filter, t;
for each (var host in hosts) {
  report.heading("Client: " + host);
  filter = "ipclient = " + host;
  q = Query.topN("historytrmx",
                 "serveraddress,bytes",
                 filter,
                 interval,
                 "bytes",
                 n);
  t = q.run();
  report.table(t);

  q = Query.topN("historytrmx",
                 "serverport,bytes",
                 filter,
                 interval,
                 "bytes",
                 n);
  t = q.run();
  report.table(t);
}

下記のスクリプトでは、6つのクエリーを、1つのマルチクエリーにまとめています。これによって、実行速度は6倍、速くなりました。

var hosts    = ["10.0.0.50","10.0.0.51","10.0.0.52"];
var interval = "lastweek";
var n        = 5;

var selects  = [];
var filters  = [];

var q = Query.topN("historytrmx",
                   selects,
                   filters,
                   interval,
                   "bytes",
                   n);
q.multiquery = true;

for each (var host in hosts) {
  var filter = "ipclient = " + host;

  selects.push("serveraddress,bytes");
  filters.push(filter);

  selects.push("serverport,bytes");
  filters.push(filter);
}

var tables = q.run();

var report = Report.current();
var i = 0;
for each (var host in hosts) {
  report.heading("Client: " + host);

  report.table(tables[i++]);
  report.table(tables[i++]);
}

マルチクエリーは、1つ、または複数のクエリー・プロパティのアレイを用いて指定します。また、multiquery(マルチクエリー)プロパティを、true(真)に設定しておかなければなりません。マルチクエリーが実行されると、パラメータ値のアレイに対応した結果のアレイを返します。アレイとして、指定できないクエリー・パラメーターは、view(ビュー)、interval(インターバル)、multiquery(マルチクエリー)だけです。

結果のストリーミング

クエリーを実行すると、通常は、結果がテーブル(表)として得られます。クエリーが生成するテーブルが大きい場合には、サーバーにかなりのメモリーが必要です。結果をストリーミングすることで、テーブル全体を保存するのではなく、結果が生成されるにしたがって、ロー(横列)ごとに処理できます。

例えば、100MByteを超えるトラフィックを送信した全てのIPアドレスを返すようなクエリーを実行したいとしましょう。しきい値を超えるアドレスが、いくつあるかは分かりません。ですから、クエリーtruncate(切捨て)パラメータを設定することはできません。その代わりに、各アドレスについて、トラフィックの合計を要求し、しきい値を適用することで、該当するアドレスを特定しなければならないのです。下記のスクリプトは、どうすれば、大きな結果テーブルが生成されるのを避け、結果のストリーミングを利用できるかを示しています。.

var interval = "today";
var threshold = 100000000;

var q = Query.topN("historytrmx",
                 "ipsource,bytes",
                 null,
                 interval,
                 "bytes",
                 100000);

var t = q.run(
  function(row,table) {
    if(row[0] && row[1] >= threshold) table.addRow(row);
  }
             );
t.printCSV(true);

結果のストリーミングは、Query run()メソッドに関数が引数として渡された時に呼び出されます。その後、その関数は、各ローのデータに適用されます。この例では、関数は、しきい値を適用し、バイト数がしきい値を超えた場合だけ、ローを結果テーブルに加えます。

注意: truncate(切捨て)値は、100000に設定されています。truncate(切捨て)値を、-1にすると、結果がどのような数になっても、全て返されます。例えそれが大きな数であっても、truncate(切捨て)値を設定することを、強く推奨します。そうすることで、クエリーが中間結果を保存するのに使用するメモリー量に、一定の制限を課すことができるからです。.

結果のストリーミングをマルチクエリーに適用することができます。下記の例では、各アドレスが送信あるいは受信した合計バイトを計算し、合計値にしきい値を適用しています。

var interval = "today";
var threshold = 100000000;

var q = Query.topN("historytrmx",
                 ["ipsource,bytes","ipdestination,bytes"],
                 null,
                 interval,
                 "bytes",
                 100000);
q.multiquery = true;

var totals = {};
var t = q.run(
  function(row,table) {
    if(row[0]) {
      if(totals[row[0]]) totals[row[0]] += row[1];
      else totals[row[0]] = row[1];
    }
  }
             );

var result = Table.create(["Address","Bytes"],["address","double"]);
for (var addr in totals) {
   if(totals[addr] >= threshold) result.addRow([addr,totals[addr]]);
}
result.sort(1);
result.printCSV(true);

最後に、マルチクエリーを使用する際、各クエリーに異なる関数を適用するため、Query run()コマンドに複数の関数を引数として渡すことも可能です。