エントリー

カテゴリー「サーバー」の検索結果は以下のとおりです。

Webアプリケーションへの同時アクセス対策メモ

Webアプリケーションへの同時アクセス対策メモ

XAMPPの Apache Bench で同時アクセスを再現するメモ。テストした環境はWindows7。Apache Bench の使い方は以下を参考に。

XAMPPをCドライブ直下にインストールした場合、以下の手順で Apache Bench を使える。

> cd C:\xampp\apache\bin
> ab -n 15 -c 15 http://localhost/~test/ab/

「-n 15 -c 15」で「15人が同時にアクセスする(合計15回アクセス)」状況がテストできる。(「-n 15 -c 1」なら「1人が合計15回アクセスする」状況になるので、同時アクセスにはならない。)

以下で同時アクセスのテストとその対策を行う。

ファイルを使った例

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

if ($fp = fopen('logs/count.log', 'r+')) {
  $data = '';
  while ($line = fgets($fp)) {
    list($id, $count) = explode("\t", rtrim($line));

    if ($id == 2) {
      if ($count < 100) {
        $data .= "$id\t" . ++$count . "\n";
      } else {
        exit('Limit');
      }
    } else {
      $data .= $line;
    }
  }

  rewind($fp);
  fwrite($fp, $data);
  ftruncate($fp, ftell($fp));

  fclose($fp);
} else {
  exit('Error');
}

exit('Complete');

logs/count.log の内容は以下のとおり。

1	10
2	20
3	30
4	40
5	50

これで上のPHPプログラムにアクセスすると、2の行が1カウントアップされる。何度もリロードすると、その回数だけカウントアップされる。

> ab -n 30 -c 30 http://localhost/~test/ab/count.php

30人の同時アクセスを発生させてみると、正しくカウントできないのが確認できる。

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

if ($fp = fopen('logs/count.log', 'r+')) {
  flock($fp, LOCK_EX);  //ファイルロック

  $data = '';
  while ($line = fgets($fp)) {
    list($id, $count) = explode("\t", rtrim($line));

    if ($id == 2) {
      if ($count < 100) {
        $data .= "$id\t" . ++$count . "\n";
      } else {
        exit('Limit');
      }
    } else {
      $data .= $line;
    }
  }

  rewind($fp);
  fwrite($fp, $data);
  ftruncate($fp, ftell($fp));

  fclose($fp);
} else {
  exit('Error');
}

exit('Complete');

ファイルロックを行えば、正しくカウントされるようになる。

データベースを使った例

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

try {
  $pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '1234', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
  $pdo->query('SET NAMES utf8');

  $stmt = $pdo->prepare('SELECT count FROM count_test WHERE id = :id');
  $stmt->bindValue(':id', 2, PDO::PARAM_INT);
  $stmt->execute();

  $data = $stmt->fetch(PDO::FETCH_ASSOC);

  if ($data['count'] < 100) {
    $stmt = $pdo->prepare('UPDATE count_test SET count = count + 1 WHERE id = :id');
    $stmt->bindValue(':id', 2, PDO::PARAM_INT);
    $stmt->execute();
  }
} catch (PDOException $e) {
  exit($e->getMessage());
}

exit('Complete');

count_test の定義は以下のとおり。

CREATE TABLE count_test(
  id    INT UNSIGNED NOT NULL,
  count INT UNSIGNED,
  PRIMARY KEY(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

これで上のPHPプログラムにアクセスすると、2の行が1カウントアップされる。何度もリロードすると、その回数だけカウントアップされる。

ab -n 200 -c 200 http://localhost/~test/ab/count.php

200人の同時アクセスを発生させてみると、正しくカウントできないのが確認できる。

<?php

/*
 * No.2をカウントアップ(最大値100)
 */

try {
  $pdo = new PDO('mysql:dbname=test;host=localhost', 'root', '1234', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
  $pdo->query('SET NAMES utf8');

  $pdo->beginTransaction();  //トランザクション開始

  $stmt = $pdo->prepare('SELECT count FROM count_test WHERE id = :id FOR UPDATE');  //行ロック
  $stmt->bindValue(':id', 2, PDO::PARAM_INT);
  $stmt->execute();

  $data = $stmt->fetch(PDO::FETCH_ASSOC);

  if ($data['count'] < 100) {
    $stmt = $pdo->prepare('UPDATE count_test SET count = count + 1 WHERE id = :id');
    $stmt->bindValue(':id', 2, PDO::PARAM_INT);
    $stmt->execute();
  }

  $pdo->commit();  //コミット
} catch (PDOException $e) {
  $pdo->rollBack();  //ロールバック

  exit($e->getMessage());
}

exit('Complete');

トランザクションと行ロックを行えば、正しくカウントされるようになる。

UNIXコマンドでサーバ監視して結果をグラフ表示

サーバの監視は普段Zabbixで「Load Average」「CUP Utilization」「Memory」「Disk Space」「Traffic」を監視しているけど、これらを監視する仕組みを一から自作したのでメモ。言わば超簡易Zabbix。

作る理由はただの興味。実際の監視は引き続きZabbixを使うのです。(`・ω・´)

大まかな方針は以下のとおり。

  • uptime などのUNIXコマンドをcronで5分ごとに実行して、結果をファイルに記録する
  • 結果をPHPプログラムで集計する
  • jqPlotでグラフ表示

監視には以下のコマンドを使ってみます。他にもっと適切なコマンドとかがあれば、こっそり教えてくれると喜びます。

■Load Average

$ uptime
 00:00:01 up 170 days,  5:24,  0 users,  load average: 0.00, 0.00, 0.00

■CUP Utilization

$ mpstat 10 5
Linux 2.6.32-504.1.3.el6.x86_64 (www.example.com) 	2015年05月23日 	_x86_64_	(2 CPU)

00時00分01秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
00時00分11秒  all    7.74    0.00    1.40    1.35    0.00    0.05    0.65    0.00   88.81
00時00分21秒  all    0.55    0.00    0.40    0.05    0.00    0.00    0.15    0.00   98.85
00時00分31秒  all    0.15    0.00    0.15    1.25    0.00    0.00    0.25    0.00   98.20
00時00分41秒  all    0.20    0.00    0.30    0.65    0.00    0.05    0.15    0.00   98.65
00時00分51秒  all    0.15    0.00    0.20    0.05    0.00    0.00    0.30    0.00   99.30
平均値:   all    1.76    0.00    0.49    0.67    0.00    0.02    0.30    0.00   96.76

■Memory

$ vmstat 10 5
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 7  2 259344 124540 174536 274200    3    1    56    63    1    1  1  0 97  1  1	
 0  0 259344 100656 174536 274276    0    0     0   236  383  269  8  1 89  1  1	
 0  0 259344 129760 174536 274272    0    0     0   209  148  155  1  0 99  0  0	
 0  0 259344 129884 174536 274272    0    0     0   233  121  143  0  0 98  1  0	
 0  0 259344 129760 174544 274272    0    0     0   324  127  141  0  0 99  1  0	

■Disk Space

$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/vda3      100762004 4012036  91624800   5% /
tmpfs             510084       0    510084   0% /dev/shm
/dev/vda1         243823  130875    100148  57% /boot

■Traffic

$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo: 22940909905 393345389    0    0    0     0          0         0 22940909905 393345389    0    0    0     0       0          0
  eth0: 20118935741 311131513    0    0    0     0          0         0 517575153 2149502    0    0    0     0       0          0
  eth1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth2:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

vmstatmpstat については、計測間隔と計測回数を指定しないと意図した値を得られなかった。また、/proc/net/dev に記録されているのは総トラフィック量なので、その時のトラフィック量を調べるには差分を計算する必要がある。

以下、具体的な記録方法。

まずはroot権限で、コマンドの結果を格納する場所を作ります。また、結果ファイルをPHPから読み出せるようにしておきます。(PHPはwebmasterの権限で実行するという想定。)

# cd /var/log
# mkdir command
# chown webmaster. command

以降はwebmasterユーザで作業。まずは command 内に、コマンドの結果を格納する場所を作ります。

$ mkdir uptime
$ mkdir mpstat_10_5
$ mkdir vmstat_10_5
$ mkdir df
$ mkdir cat_proc_net_dev

結果は /var/log/command/uptime/20150307/2215.log のようなディレクトリ名・ファイル名で格納するものとします。試しにコマンドを実行。

$ mkdir /var/log/command/uptime/`date +'%Y%m%d'`/
$ uptime > /var/log/command/uptime/`date +'%Y%m%d'`/`date +'%H%M'`.log

$ mkdir /var/log/command/mpstat_10_5/`date +'%Y%m%d'`/
$ mpstat 10 5 > /var/log/command/mpstat_10_5/`date +'%Y%m%d'`/`date +'%H%M'`.log

$ mkdir /var/log/command/vmstat_10_5/`date +'%Y%m%d'`/
$ vmstat 10 5 > /var/log/command/vmstat_10_5/`date +'%Y%m%d'`/`date +'%H%M'`.log

$ mkdir /var/log/command/df/`date +'%Y%m%d'`/
$ df > /var/log/command/df/`date +'%Y%m%d'`/`date +'%H%M'`.log

$ mkdir /var/log/command/cat_proc_net_dev/`date +'%Y%m%d'`/
$ cat /proc/net/dev > /var/log/command/cat_proc_net_dev/`date +'%Y%m%d'`/`date +'%H%M'`.log

問題なければ、これらのコマンドをcronに登録。(mkdir では、翌日用のディレクトリを作成するように変更しているので注意。当日用のディレクトリを作成して即結果を保存、は「ディレクトリがありません」のエラーになったため。)

# vi /etc/crontab

00 00 * * * webmaster mkdir /var/log/command/uptime/`date -d '1 days' +'\%Y\%m\%d'`/
*/5 * * * * webmaster uptime > /var/log/command/uptime/`date +'\%Y\%m\%d'`/`date +'\%H\%M'`.log

00 00 * * * webmaster mkdir /var/log/command/mpstat_10_5/`date -d '1 days' +'\%Y\%m\%d'`/
*/5 * * * * webmaster mpstat 10 5 > /var/log/command/mpstat_10_5/`date +'\%Y\%m\%d'`/`date +'\%H\%M'`.log

00 00 * * * webmaster mkdir /var/log/command/vmstat_10_5/`date -d '1 days' +'\%Y\%m\%d'`/
*/5 * * * * webmaster vmstat 10 5 > /var/log/command/vmstat_10_5/`date +'\%Y\%m\%d'`/`date +'\%H\%M'`.log

00 00 * * * webmaster mkdir /var/log/command/df/`date -d '1 days' +'\%Y\%m\%d'`/
*/5 * * * * webmaster df > /var/log/command/df/`date +'\%Y\%m\%d'`/`date +'\%H\%M'`.log

00 00 * * * webmaster mkdir /var/log/command/cat_proc_net_dev/`date -d '1 days' +'\%Y\%m\%d'`/
*/5 * * * * webmaster cat /proc/net/dev > /var/log/command/cat_proc_net_dev/`date +'\%Y\%m\%d'`/`date +'\%H\%M'`.log

これでコマンドの実行結果がどんどん記録されていくので、あとはPHPで読み出すプログラムを作成すればOK。

サーバメモ

今年の後半はサーバ関連の勉強をチョロチョロとしていたので、調べた内容のメモ。

割と色々試したつもりだったけど、サーバ運用の基本の基本でしかないという…。

ここに書いていないことは多分知らない(=設定していない)ことなので、「この設定は必須だろう」とかあればツッコミ歓迎です。
「こんなこともwww知らないのwww」
とかツッコミをくれたら、凹みながらこっそり糧にしておきます。

負荷対策のチューニングなどは、頭の中を整理して、色々実験してから加筆したい。

さくらのクラウドは勉強中。GAEはまだ手付かず。メールサーバも手付かず。セキュリティと負荷対策は随時勉強中。

自宅サーバーのハードディスクが損傷

したみたいです。前兆はあったので、遅かれ早かれハードディスクに問題が起こるとは思っていたけど。
以下、前兆の内容。

ログを監視して結果をメールで知らせてくれるツールを導入しているのですが、2009年1月3日に以下の警告がありました。

Device: /dev/hda, FAILED SMART self-check. BACK UP DATA NOW!

「ハードディスクがそろそろ危険だから、バックアップしておけ!」ということみたいです。それ以来、毎日この警告を送ってくるようになりました。

でも、具体的にどれくらいの期間でダメになるのか興味があったので、そのまま利用を継続。で、昨晩「カチカチ」という音がサーバーから聞こえてきました。そして今朝ご臨終…。
サーバーのモニターで直接確認すると、

end_request: I/O error, dev hda, sector 24627341

と表示されていました。ファイルシステムやディスクのセクタが損傷している可能性がある場合に表示されるらしいです。

2008年11月14日から稼動させていましたが、最初の警告までの時間は短かったなぁ…。中古パソコンだから仕方ないか。あと、たまに再起動する以外は連続稼動だから、負担も大きいのでしょう。

さて、復旧はどうするか…。ノートパソコンのハードディスク交換は大変かなぁ…。
まったく急がないので、またそのうちに考えるとします。

Baiduspiderをアクセス拒否

自宅サーバーのアクセスログを眺めていると、特定のホストからのアクセスが非常に多いです。そのアクセスのユーザーエージェントに Baiduspider という文字があったので調べてみたら…、「百度」という中国の検索サイトのクローラーのようです。

以前はこのクローラーからのアクセスが異常に多く、その負荷が問題になるほどだったので、色々なサイトがアクセス拒否の対策をとったらしい。

今は負荷が問題になるほどのアクセスではないけど、中国向けの情報は配信していないので、robots.txt に以下の記述を追加しておきました。

User-agent: baiduspider
Disallow: /

これでクローラーを拒否できるらしい。しばらく様子見。

自宅サーバー再開

デスクトップPCとともに落雷で駄目になったサーバーの代わりを、数日前に購入してきました。今回はIBMのThinkPadで、税込み16,800円でした。スペックは以下のとおり。

CPU Celeron 2.0GHz
メモリ 256MB
HDD 20GB

OSはCentOS5をインストール。WebサーバーやFTPサーバーなどをインストールしてみたけど、今のところ順調に動作しているようです。

これからまた、少しずつ勉強していくとします。

自宅サーバーをさらしてみる

連続稼動3日目。普通に接続できているので、そろそろさらしてみます。

http://www.favorite-labo.net/

コンテンツは、以前に作ったAmazonレビュー検索プログラムを置いているだけ。とりあえず、自分用ツールを色々置いていくとします。
突然サーバーダウンすることがあるかもしれませんが、OSの再インストールやハードの故障などで作業中だと思ってください。(^^;

もし、マズイ設定箇所などを見つけたら、メールでこっそり教えていただけると嬉しいです。

自宅サーバー再インストール完了

一応完了。あとは使いながら調整していくつもり。Perl5、PHP5、MySQL5 を使えるようにしておいたので、色々遊んでみます。

ポートは80番のみ開放。ファイルアップロードはFTPを使うけど、アクセスはLAN内のみに限定。モデム・ルータ・CentOS のファイヤーウォールは、それぞれできるだけ厳しく設定したつもり。勿論、ファイル改竄検知システムやアンチウィルスソフトなども導入済み。Apacheのアクセスログ解析のために、AWStats もインストールしておいた。

とは言え、PerlとPHPが実行できる環境だし、80番ポートから感染するウイルスもあるので安心はできません…。少しでも不審な事があれば、OSごとインストールしなおすとします。(まずは「不審な事」に気付くための知識が必要だけど。)

ちなみに、24時間稼動させるのは、もうしばらく先の予定。

自宅サーバー再インストール中

現在CentOS5インストール中。「色々いじってから、OSごと再インストール」を繰り返しているので、インストールは4回目だったりします。(CentOS4を2回、CentOS5を2回)
多少は慣れてきたので、今回は長期間稼動させるつもり。

メールは相変わらず外部に送信できないのですが、root宛てにサーバーの状態を通知する目的には使えるので、当分は現状のまま進めるとします。もともとメールサーバーを立てるつもりは無い(むしろ凄く大変そうなので立てたくない)ので、特に問題は無し。フォームメールは使いたいけど、メールサーバーを立てなくても色々やりようはあるのです。

自宅サーバーいじり中

UNIXの絵本を読みつつ基礎を勉強中。この本が一番解りやすいと思った。

PHPからのメール送信は試してみたけど、まだ送信できず…。
MAILER-DAEMONからエラーメールは送られてくるので、メールサーバーは動作しているはず。OP25B対策が不十分なんだろうか。

ページ移動

  • ページ
  • 1
  • 2

ユーティリティ

カテゴリー

検索

エントリー検索フォーム
キーワード

過去ログ

過去ログ表示フォーム
キーワード

Feed