パフォーマンス・テストの種類

ひとくちにパフォーマンス・テストと言っても、何を目的とするかによって、いろいろな種類のテストがあります。パフォーマンスにまつわる会話を関係者間でしていると、そこに期待するものが違うために、時折話が食い違うこともあります。

パフォーマンス・テストを行うにあたって、どのように設計し、計画を立てるべきかを考えるのに先立って、求められている要件が何なのか整理し、目的をはっきりさせておくべきだと思います。

Performance Testing Guidance for Web Applications にアップされているドキュメントの Chapter 2 には、目的の違いによってそれぞれ種類の異なるパフォーマンステストの定義が説明されています。

自分のアタマの整理も兼ねて、主な4種類のテストが説明されている箇所を大雑把に翻訳・要約してみました。これらを念頭に置いて、ともすれば要件が混乱してしまいそうなパフォーマンステストについて、自分が行おうとしている内容の目的を見失わず、適切な手法を用いるように気をつけたいところです。

Performance Test : パフォーマンステスト

目的、メリット
  • 速度、スケーラビリティ、安定性を決定・検証するための技術的調査
    • ユーザが満足するパフォーマンスがでるかどうか検証する
    • チューニングや最適化を支援する
難しいところ、目的としないところ
  • 機能的な不具合を検出できるとは限らない
  • 注意深く設計しないと、運用シナリオのほんの一部しかカバーできない
  • 実運用で用いるハードウェアと全く同様の環境でない限り、結果にはある程度の不確かさが付きまとう
象徴的な質問
  • 「十分な速度(レスポンス)が出るか?」

Load Test : 負荷テスト

目的
  • 実運用での、通常時/ピーク時の負荷に対して耐えうるかの検証
    • ピーク時に十分なスループットが発揮できるか
    • ハードウェアやロードバランサーが適切か
    • 並行処理にまつわる問題や機能的なエラーを検出する
    • パフォーマンスが劣化する前にサポートできるユーザ数の測定や、ハードウェアのリソースが限界に達する負荷量の計測を助ける
  • しばしばSLAで定義されたパフォーマンス要求を目的とする
  • 耐久テスト(endurance test) はこれのサブセット。長期間の負荷下での振る舞いの診断に特化したもの
難しいところ、目的としないところ
  • レスポンスの速さを見ることを優先して設計されるものではない
  • テスト結果は、他の関連する負荷テストと相対的な比較でのみ有効
  • 負荷がノーマルの状態→ピークの状態と推移させて、想定負荷に耐えられるか検証する
象徴的な質問
  • 「全ユーザをサポートできるか?」

Stress Test : ストレステスト

  • 実運用での想定利用モデル下で、負荷量と負荷サイズの増大させ、過負荷な状態で発生するバグ(同期の問題、競合条件、メモリーリークなど)を検出するため
    • どの程度の状況で、(遅くなるだけではなく)エラーが起こるか
    • 過負荷時にデータの破損やセキュリティ的な脆弱性が発生しないか
    • エラーの事前検知のために何をモニタリングしておくべきか
  • Spike test*1 はこれのサブセット。短時間に繰り返し急な負荷を与えた場合の検証に特化したもの
難しいところ、目的としないところ
  • 仮定するストレスの状態が非現実的なため、テスト結果が関係者に無視されるかも
  • どれくらいのストレスを与えるのが適切なのか知るのは難しい
  • テスト環境が独立していないと、アプリケーションやネットワークなどに深刻な被害をもたらす可能性がある
象徴的な質問
  • 「何かおかしくなったとき何が起こるか?」

Capacity Test : キャパシティ(処理能力)テスト

目的
  • パフォーマンス要件を満たしつつ、どの程度のユーザやトランザクションをさばけるか検証するため
    • 将来的なユーザ数やデータ量の増加に対して、どういったリソース(CPU性能、メモリ使用量、HDD容量、ネットワーク帯域など)を拡充すべきかのプランニングのための調査となる
    • プランニングのために、現在のリソースの使われ方や処理能力の傾向をつかめる
難しいところ、目的としないところ
  • 処理能力の検証モデルの構築は難しい
  • 一回のテストで、処理能力のすべての面を検証することはできない
象徴的な質問
  • 「ユーザが増えたとき何を増やせばいいか?」

*1:適切な訳語が分からない。ちなみに [http://eow.alc.co.jp/spike/UTF-8/:title=spike の意味]の中では「〔グラフなどの〕急な山形」がこの場合、負荷のかたちを示すものということで適切か

Selenium RC 0.9.2 の captureScreeshot 機能を使ってみる

そういえば去年リリースされた Selenium RC 0.9.2 で追加された、画面キャプチャをとるらしい機能を使ってみようと思ってずっと忘れていたことに気付いた。

試してみたところ、実行は簡単で、Perlのクライアントを使った場合は、'capture_screenshot' というサブルーチンを使います。引数にはキャプチャした画像の保存先を渡します。たとえば以下のような感じ。

#!/usr/bin/perl

use strict;
use warnings;
use Test::More tests => 1;
use Test::WWW::Selenium;
use utf8;

my $sel = Test::WWW::Selenium->new(
        host => '192.168.123.123',
        port => 24444,
        browser => '*iehta',
        browser_url => 'http://www.google.co.jp',
);

$sel->start();
$sel->open('http://www.google.co.jp');
$sel->type("q", "hello");
$sel->click("btnG");
$sel->wait_for_page_to_load(5000);
$sel->title_like(qr/Google 検索/);
$sel->capture_screenshot('C:\hoge.png');   # ←スクリーンショットとる
sleep 30;
$sel->stop();

'192.168.123.123' のポート '24444' で、RCサーバが起動しているという前提です。今回なぜか、ブラウザの指定を '*iexplore' にしてもふつうの Internet Explorer がラウンチされなかったので、 '*iehta' で試してます。

で、実際試してから気付いたことが、考えてみればあたりまえなのですが、ブラウザの表示内容だけではなく、画面全体のキャプチャがとれてしまう、ということ。
なので、

  • 他のウィンドウが前面に出てるとそれがブラウザを隠してしまう
  • スクロールするような画面では、画面の下のほうが見られない
  • スクリーンセイバーがかかっているとその画面になってしまう

といったことがあります。最後のスクリーンセイバーのことは、 http://d.hatena.ne.jp/w650/20071115/p1 の内容を見て、自分でも試してみたところそのとおりで、ばっちりスクリーンセイバーの画面がとれてました。。これ、スクリーンセイバーの設定が義務付けられているうちの会社では地味に障害となるなぁ。。

画面キャプチャの融通を利かすのであれば、 http://hoshinanonikki.net/20070627.html#p01 で述べられているような外部アプリを駆動するほうが、用途によっては良い場合があるかもしれません。

とは言っても、「テストがエラーで落ちたときにどういった画面だったのか知りたい」とか、「システムエラーの画面が出ていないか」とかいったことのチェックのために画面キャプチャをとりたいといった要件であれば、上記の点に気をつけて使う限り、このSeleniumの機能もかなり役に立つ場面はあると思います。

半角カナってなんでダメなんだっけ?

うちの会社で作っているアプリケーションは昔からフレームワークのレベルで半角カナの入力を受け付けないようにエラーチェックがかかるようになってますが、今日、とっさにその理由を聞かれて答えられない自分に気付きました。。

そんなときのWikipedia半角カナのページに、よくまとまっていました。

メールで半角カナが使えないと言われるのは、ISO-2022-JISに、JIS X 0201の片仮名が含まれていないことによるもの。WEBアプリで一般的に使わないのは、EUC-JP と Shift_JISの間で文字コードの範囲がかぶって自動認識に失敗することがあるから、ということっぽい。

・・・ということでいいのだろうか?半角カナを禁止してるWEBアプリなんて最近はもうあまりない気もするが、主にビジネスユースのアプリでわざわざ開放することはないだろうし、とりあえずなぜ禁止されているか、と聞かれれば、このへんを経緯として話して、無難だから、といえばいい気はする。なんか妥協っぽいけど。

mysql の last insert id

mysql だと、最後に登録された auto_increment の主キーのIDを LAST_INSERT_ID() という関数で取得できるのだと知りました。

→ 参考: http://it.kndb.net/entry/show/id/78

Perl のプログラムで DBD::mysql を利用している場合、$dbh がDB接続のハンドルだとして、

 my $last_id = $dbh->{'last_insertid'}

とすればINSERT直後のIDが取得できるみたい。

→ 参考: http://search.cpan.org/dist/DBD-mysql/lib/DBD/mysql.pm#DATABASE_HANDLES

こういう細かい知識が、日ごろコーディングしてないと全然身につかない。。今後積極的にメモしていこう。

The Future of JavaScript の個人的なメモ

少し時間が空いてしまいましたが、先週金曜日(2007-11-02)、Mozilla & Shibuya.js によるトークイベント"The Future of JavaScript"に行って話を聞いてきました。
普段コーディングをしていない人間なので、理解しきってない部分が多々ありますが、個人的なメモをdumpしておきます。自分自身で理解できず書いてる部分あるので、あまり参考にしないでください。

ES4については、一言で言うと、下位互換を重視しつつ、固くオブジェクティブに作ろうと思えば作れるように拡張していく、といった感じでしょうか。

堅苦しい言語になってしまうのでは?と懸念する空気が会場にありましたが、クラス定義などはあくまで拡張であり、それを使うかどうかは書き手次第、逆に使わなければこれまでどおり柔軟なものとして扱えるよ、ということを主張されていたと思います。

たとえば、class 型で宣言したものはかなり堅牢に隠蔽化がされるようですが、dynamic class という型もあり、それを使えば property の動的な割り当てもできる、さらにその中でも、private を指定すればプライベートな変数も宣言できる、といった感じで、利用シーンや必要に応じて使い分けることが重要そうです。

その他、Class関連の言語仕様について。。。

  • 継承とインタフェースがサポートされる
  • final で継承されるのをブロックできる
  • 継承は1つ(多重継承はできない)、インタフェースは複数OK
  • Catch-All = rubyでいう"Method Missing"(methodがなかった場合の振る舞いを定義)

さらにそれ以外の細かな言語仕様について。。。

  • type と interface の違い?
    • type は構造定義のみ、like で一致をみる
    • interface は is で一致をみる
  • this: 受け取る引数の形式を指定(違ったらエラーを返す)
  • arguments は fake array じゃなくて実際の array になる
  • Map = key と value を保持する
    • key には Object も使える
  • let は Perl でいう my みたいなものっぽい
  • Package →隠蔽化。public のものだけが外から呼べる。
  • multimethod → いわゆるオーバーロード ?
  • Unit ≠ Package (このへんがよくわからない…). Unit はインポートに使う

その他、ES4をとりまく環境などについて

  • IEにも "Screaming Monkey" というサブプロジェクトを通じて互換性のあるエンジンを搭載させる
  • ActionScript 4 は、ECMAScript 4に沿うために ActionScript3 との互換性を捨てた
  • 各ブラウザが対応して、実際に動作環境が普及してくるのは2009年ごろでしょう
  • 型指定しなくても、Tamarinのエンジン内で最適化してるから速度は出るけど、指定したほうが速い
  • グローバルなクラスは直接いじれないけど、グローバルなオペレーションはいじれる
    • たとえば「+」は intrinsic namespace (?)