Linuxでネットワークブリッジ接続を行う


ここ1週間仕事終わりに寝る間を惜しんで再び自宅のサーバを整理することを決意。
ウトウトしながらバックアップを取り、一番メモリが多いサーバに集約することにしました。

何故かというと
ここ数年間、PCをハイスペックにするためパーツを買い替え余りもので
無計画にサーバを作った結果、ゴチャ混ぜになって何処に何が入っているのかわからないことに...
久しぶりに起動したらfdiskで約10分...

という事でKVMのホストOSに幾つかのゲストOSをインストール。
ブリッジ接続の設定を行ったので次回用にメモ。

※ 参考にする場合は自分の環境に置き換えてください。

# vi /etc/sysconfig/network-scripts/ifcfg-br0
--
DEVICE="br0"
TYPE="Bridge"
ONBOOT="yes"
BOOTPROTO="static"
IPADDR="192.168.0.50"
NETWORK="192.168.0.0"
NETMASK="255.255.255.0"
BROADCAST="192.168.0.255"
--

# vi /etc/sysconfig/network-scripts/ifcfg-eth0
--
DEVICE="eth0"
TYPE="Ethernet"
ONBOOT="yes"
BOOTPROTO="none"
BRIDGE="br0"
HWADDR="XX:XX:XX:XX:XX:XX"
IPV6INIT="no"
--

> XをインスコしていたのでNetworkManagerが邪魔している
# /etc/rc.d/init.d/network restart
--
インターフェース eth0 を終了中:  エラー: デバイス 'eth0' (/org/freedesktop/NetworkManager/Devices/0) の切断に失敗しました: This device is not active
                                                           [失敗]
ループバックインターフェースを終了中                       [  OK  ]
ループバックインターフェイスを呼び込み中                   [  OK  ]
インターフェース eth0 を活性化中:  エラー: 接続のアクティベーションに失敗: Master connection not found or invalid
                                                           [失敗]
インターフェース br0 を活性化中:  エラー: 接続のアクティベーションに失敗: Faild to determine connection’s virtual interface name
                                                           [失敗]
--

> 不要なので停止します
# /etc/rc.d/init.d/NetworkManager stop
# chkconfig NetworkManager off

# /etc/rc.d/init.d/network restart
--
ループバックインターフェースを終了中                       [  OK  ]
ループバックインターフェイスを呼び込み中                   [  OK  ]
インターフェース eth0 を活性化中:                          [  OK  ]
インターフェース br0 を活性化中:                           [  OK  ]
--

MessagePackのPHP用拡張モジュールを試してみた

久しぶりに時間が出来たのでMessagePackをPHP拡張モジュールとして追加してみました。

MessagePackはgithubでダウンロード出来ます。
PHP以外の言語に追加する場合も同じ場所からダウンロード出来ます。便利ですね!

MessagePack - github -< https://github.com/msgpack >

サクッと追加出来るのも良いですね!
手順は以下の通りです。

> githubからMessagePackを取得
# git clone https://github.com/msgpack/msgpack-php.git

> PHPの拡張モジュール追加準備
# phpize
-----
Configuring for:
PHP Api Version:         20090626
Zend Module Api No:      20090626
Zend Extension Api No:   220090626
-----

> チェック・Makefile生成
# ./configure
-----
configure: creating ./config.status
config.status: creating config.h
config.status: executing libtool commands
-----

> コンパイル
# make
-----
Build complete.
-----

> インストール
# make install
-----
Installing shared extensions:     /usr/lib/php/modules/
Installing header files:          /usr/include/php/
-----

> PHPの拡張設定ファイルを追加

> messagepackを読み込む
# vi /etc/php.d/msgpack.ini
-----
extension=msgpack.so
-----

> Apacheの再起動
# /etc/rc.d/init.d/httpd restart

適当に以下のファイルを作成してJSONと比較してみました。
シリアライズとデシリアライズを行っているので不要な場合はコメントアウトしてください。

<?php

$limit  = 50;
$pass   = 0;
$result = array();
for ($i = 1; $i <= $limit; $i++) {

	// random string.
	$random_string   = randomString(100000);

	// MessagePack.
	$start           = getTimes();
	$tmp             = msgpack_serialize($random_string);
	$res             = msgpack_unserialize($tmp);
	$end             = getTimes();
	$result['m'][$i] = benchMark($start, $end);

	// Json.
	$start           = getTimes();
	$tmp             = json_encode($random_string);
	$res             = json_decode($tmp);
	$end             = getTimes();
	$result['j'][$i] = benchMark($start, $end);
	
	// print.
	if (!$pass) {
		$sign = benchSign($result['m'][$i], $result['j'][$i]);
		print sprintf("%s\tM:%s\t%s\tJ:%s\n", $i, $result['m'][$i], $sign, $result['j'][$i]);
	}

}

if (!$pass) print "-----------------\n";

// max.
$total['m'] = max($result['m']);
$total['j'] = max($result['j']);
$sign       = benchSign($total['m'], $total['j']);
print sprintf("max\tM:%s\t%s\tJ:%s\n", $total['m'], $sign, $total['j']);

// avg.
$total['m'] = number_format(array_sum($result['m']) / $limit, 10);
$total['j'] = number_format(array_sum($result['j']) / $limit, 10);
$sign       = benchSign($total['m'], $total['j']);
print sprintf("avg\tM:%s\t%s\tJ:%s\n", $total['m'], $sign, $total['j']);

exit(0);

function benchSign ($left, $right) {
	$sign = '';
	if ($left === $right) $sign = '==';
	else if ($left > $right) $sign = '>';
	else $sign = '<';
	return $sign;
}
function benchMark ($start, $end) {
	return number_format(($end[0] - $start[0]) + ($end[1] - $start[1]), 10);
}
function getTimes () {
	return array(time(), microtime());
}
function randomString ($length, $res = null, $i = 0) {
	$str = array_merge(range('a', 'z'), range('0', '9'), range('A', 'Z"'));
	for ($i; $i < $length; $i++) {
		$rand = rand(0, count($str));
		$res .= isset($str[$rand]) ? $str[$rand] : '' ;
	}
	return $res;
}

結果は以下の通りです。

1       M:0.0005350000  <       J:0.0045480000
2       M:0.0000520000  <       J:0.0040560000
3       M:0.0001310000  <       J:0.0039100000
4       M:0.0000510000  <       J:0.0033410000
5       M:0.0000460000  <       J:0.0031090000
6       M:0.0000630000  <       J:0.0031980000
7       M:0.0000450000  <       J:0.0032470000
8       M:0.0000490000  <       J:0.0032170000
9       M:0.0000500000  <       J:0.0032100000
10      M:0.0000500000  <       J:0.0037790000
11      M:0.0000460000  <       J:0.0033240000
12      M:0.0000480000  <       J:0.0032200000
13      M:0.0000500000  <       J:0.0032390000
14      M:0.0000520000  <       J:0.0031910000
15      M:0.0000440000  <       J:0.0032710000
16      M:0.0000740000  <       J:0.0032020000
17      M:0.0000520000  <       J:0.0031850000
18      M:0.0000540000  <       J:0.0032210000
19      M:0.0000630000  <       J:0.0031990000
20      M:0.0000480000  <       J:0.0032300000
21      M:0.0000500000  <       J:0.0032070000
22      M:0.0000490000  <       J:0.0031880000
23      M:0.0000540000  <       J:0.0033780000
24      M:0.0000480000  <       J:0.0031370000
25      M:0.0000410000  <       J:0.0032060000
26      M:0.0000520000  <       J:0.0036880000
27      M:0.0001430000  <       J:0.0038180000
28      M:0.0001470000  <       J:0.0032570000
29      M:0.0002290000  <       J:0.0037570000
30      M:0.0001640000  <       J:0.0032160000
31      M:0.0000500000  <       J:0.0035160000
32      M:0.0000490000  <       J:0.0036790000
33      M:0.0001490000  <       J:0.0039440000
34      M:0.0001640000  <       J:0.0031720000
35      M:0.0002360000  <       J:0.0037250000
36      M:0.0001640000  <       J:0.0038990000
37      M:0.0001500000  <       J:0.0039100000
38      M:0.0001630000  <       J:0.0033860000
39      M:0.0000490000  <       J:0.0031770000
40      M:0.0000440000  <       J:0.0037490000
41      M:0.0001570000  <       J:0.0031860000
42      M:0.0002380000  <       J:0.0039040000
43      M:0.0001610000  <       J:0.0039150000
44      M:0.0001570000  <       J:0.0038990000
45      M:0.0001620000  <       J:0.0033680000
46      M:0.0000540000  <       J:0.0037850000
47      M:0.0000490000  <       J:0.0032220000
48      M:0.0001580000  <       J:0.0031660000
49      M:0.0000450000  <       J:0.0039660000
50      M:0.0001500000  <       J:0.0039230000
-----------------
max     M:0.0005350000  <       J:0.0045480000
avg     M:0.0001025800  <       J:0.0034848000

こうして実際に比較してみるとやっぱり速いな〜と思いました。

PHP is_file関数の落とし穴

以下、ハマってしまいましたので久々の投稿です。


is_file関数は引数に指定したパスがファイルであるか調べる場合に使用しますが
大きいファイルを扱う場合、正確な判定が行えない場合があります。


以下、マニュアルの投稿より

Be careful with big files. I get a

Warning: is_file(): Stat failed for all.rar (errno=75 - Value too large for defined data type) in /.../test.php on line 3

and FALSE as result for a file of 3,5 GB.



3.5GBを超えるとfalseを返す事にご注意を。
因みに、file_exists関数は3.5GB以上のファイルでも正常に判定出来ました。

VMware Infrastructure Web Accessが表示されない

久しぶりに自宅のサーバを整理する事が出来ました。


整理していると2008年に作ったプログラムが見つかり、思わず他人の書いたプログラムかと疑ってしまう程
違う事に一人ウケしました。


もろもろ整理後、VMware Serverをインスコする事に。


VMをインストールしたサーバ(Linux)から確認したところ表示がされず orz
ログを辿ってみると以下のようなエラーが出ていました。

# tail -f /var/log/vmware/hostd.log
[2010-06-17 XX:XXXX.XXX .....] Handshake on client connection failed: SSL Exception: error:...

あれま、接続に失敗していました。
IEから確認し直したところ、正常に表示されました。

サーバにログインしているユーザの監視方法

複数人でサーバを運用・構築する場合、誰がログインしているのか分からず不安になる時ありませんか?
僕はあります。


とわいえ、常にログインユーザを監視する事は非常に難しいので今回はログイン時に実行するメール送信シェルを作る事にしました。
まずは以下のシェルスクリプトをユーザのホームディレクトリへ作成。


login.sh

#!/bin/sh
subject="【報告】[username]ユーザがログインしました"
address="info@example.com"

echo "Reported login: $address"
mail -s `echo $subject | nkf -j` $address << EOF
` w | nkf -j`
EOF
exit



あ、nkfが入ってない場合はインスコしてください。
次にログイン時に自動実行される「.bash_profile」へ追記します。

$ vi /home/[username]/.bash_profile
〜〜〜↓ファイルの最後に追加〜〜〜
./login.sh



以上で完了です。
メール本文には「w」コマンドの実行結果が入るので、メール送信時点での全てのユーザ情報を確認する事が出来ます。
送信先メールアドレスはメーリングリストなんかが良いでしょうね。

Apache+RailsのPassengerが無事にインスコ出来ましたので、インストール手順を出来るだけわかりやすくエントリーします。

以下のエントリーはPassengerのインストール手順になるので、「RubyRails、Gem、Rake」などのインストール方法については他の方のブログを参考に行ってください。


インストールを行ったディストリビューションFedoraCentOSの2つで、DBはSqliteを使用する事にします。
結論として当然ですが、問題無くインストール出来ました。Apacheなのでサクサク動きます。
rubyなどのバージョンは同じ(2010/01現在の最新版)です。


基本的にオレンジの項目に沿ってインストールを行います。
もし、問題が発生した場合は青の項目を参考にしてください。


それでは、最初に現状把握。

コマンドとバージョンの確認

# ruby -v
ruby 1.9.1p376 (2009-12-07 revision 26041) [i686-linux]
#rails -v
Rails 2.3.5
# gem -v
1.3.5
# rake -V
rake, version 0.8.7

この時点でインスコしていない物は入れておきます。
コマンドが認識されない場合はwhichコマンドで環境変数を登録します。

コマンドが認識されない場合、whichコマンドで環境変数の登録
# which ruby
/usr/local/ruby/bin/ruby
# export PATH=/usr/local/ruby/bin/ruby:$PATH
# ruby -v
ruby 1.9.1p376 (2009-12-07 revision 26041) [i686-linux]

インストールしているにも関わらず、それでもコマンドが認識されない場合(殆ど無いと思いますが僕の場合rakeコマンドが認識されませんでした)は直接パスを指定して実行してみます。

どうしてもコマンドが認識されない場合、直接パスを指定して実行
# /usr/local/ruby/bin/rake -V
rake, version 0.8.7

一通りの確認は出来、問題は無いのでPassengerをインストールします。

Passengerのインストール

# gem install passenger
# passenger-install-apache2-module

もし、passengerのApacheモジュールコマンド(passenger-install-apache2-module)が実行出来ない場合は、パスを直接指定して実行します。

PassengerのApacheモジュールコマンドが実行出来ない場合
# find / -name 'passenger-install-apache2-module'
# /usr/local/ruby/bin/passenger-install-apache2-module
>> ↑findコマンドで検索した結果に出てきたパスを指定して実行

passenger-install-apache2-moduleが実行されると下記のような文字が出ます。

Passengerインストール

Welcome to the Phusion Passenger Apache 2 module installer, v2.2.9.

This installer will guide you through the entire installation process. It
shouldn't take more than 3 minutes in total.

Here's what you can expect from the installation process:

 1. The Apache 2 module will be installed for you.
 2. You'll learn how to configure Apache.
 3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you on how to
solve any problems.

Press Enter to continue, or Ctrl-C to abort.

そのままEnterキーを押します。

Passengerインストール前確認
--------------------------------------------

Checking for required software...

 * GNU C++ compiler... not found
 * Ruby development headers... found
 * OpenSSL support for Ruby... found
 * RubyGems... found
 * Rake... found at /usr/local/ruby/bin/rake
 * rack... found
 * Apache 2... found at /usr/sbin/httpd
 * Apache 2 development headers... not found
 * Apache Portable Runtime (APR) development headers... not found
 * Apache Portable Runtime Utility (APU) development headers... not found

Some required software is not installed.
But don't worry, this installer will tell you how to install them.

Press Enter to continue, or Ctrl-C to abort.

「not found」となっている物が足りないので「CtrlとC」キーを押して一時中断します。
(全てインストール済みの場合は以下省略)

Passengerインストールに足りないパッケージのインストール
>> GNU C++ compiler... not foundの場合
# yum install gcc
# yum install gcc-c++
>> OpenSSL support for Ruby... not foundの場合
# yum install openssl
# yum install openssl-devel
>> Apache 2 development headers... not foundの場合
# yum install httpd-devel

Apache Portable Runtime」系は「Apache 2 development headers」と同じく「httpd-devel」をインストールすれば大丈夫です。
以上、準備が完了したら再度「passenger-install-apache2-module」コマンドを実行します。

再度Passengerのインストールを実行

# passenger-install-apache2-module
------- 以下省略 ------
--------------------------------------------
The Apache 2 module was successfully installed.

Please edit your Apache configuration file, and add these lines:

   LoadModule passenger_module /usr/local/ruby/lib/ruby/gems/1.9.1/gems/passenger-2.2.9/ext/apache2/mod_passenger.so
   PassengerRoot /usr/local/ruby/lib/ruby/gems/1.9.1/gems/passenger-2.2.9
   PassengerRuby /usr/local/ruby/bin/ruby

After you restart Apache, you are ready to deploy any number of Ruby on Rails
applications on Apache, without any further Ruby on Rails-specific
configuration!

最後に上記のような文字が表示されればインストールは完了です。
ここで、もしsqliteがインストールされていない場合はインストールしておきます。

sqliteが入っていない場合はインストール
# yum install sqlite
# yum install sqlite-devel
# gem install sqlite3-ruby

ついでにrailsアプリケーションが生成されていなければ確認用として先に生成しておきます。

動作確認用railsアプリケーションの生成
# cd /home/htdocs/
# rails rails.example.com
# rake db:create

次に、Apacheにpassengerの設定を行います。

httpd.confへの移動
# cd /etc/httpd/conf
# vi httpd.conf

httpd.conf」ファイルの最下部へ以下の設定を追加します(バーチャルホストの場合です)。

httpd.confの編集

# ↓バーチャルホストの場合はこんな感じです
<VirtualHost *:80>
    DocumentRoot /home/htdocs/rails.example.com/public
    ServerName rails.example.com
    RailsEnv development
    <Directory /home/htdocs/rails.example.com/public>
       AllowOverride all
       Options -MultiViews
    </Directory>
</VirtualHost>
# ↓ここはpassengerインスコ完了時に表示されたモジュールのパスを記述します
LoadModule passenger_module /usr/local/ruby/lib/ruby/gems/1.9.1/gems/passenger-2.2.9/ext/apache2/mod_passenger.so
PassengerRoot /usr/local/ruby/lib/ruby/gems/1.9.1/gems/passenger-2.2.9
PassengerRuby /usr/local/ruby/bin/ruby

上記を記述したらApacheを再起動します。

Apacheの再起動

# /etc/rc.d/init.d/httpd restart

以上で完了です。
この例の場合は「rails.example.com」をブラウザから表示させます。
(当然ApacheRailsを実行しているのでWEBrickサーバの起動などは行わなくて良いです)

ActionScript3でデバッグを行う スタックトレースを表示

ActionScript3でデバッグを行う場合、殆どの人はtraceを使って値や処理を確認していると思います。
単純な値の確認だけであれば問題は無いのですが、ファイルやメソッドの数が多くなり、ついでに非同期処理を入れたりして複雑になってくると
何処のメソッドから実行されたのか分からなくなる場合があります。

そんな時は下記のようにgetStackTraceを使えばスタックトレースを表示する事が出来ます。

	public static function __debug_printStackTrace():void
	{
		try {
			throw new Error("trace");
		} catch (e:Error) {
			trace(e.getStackTrace());
		}
	}

クラス化したりすると良いかもですが簡易的なデバッグであれば、この程度で十分だと思います。

そういえば、AS3を始めた頃にBulkLoaderを解析した事がきっかけでASでスタックトレースを行う時はいつも「__debug_printStackTrace」で統一してしまうクセが出来ていました。