まだ重たいCMSをお使いですか?
毎秒1000リクエスト を捌く超高速CMS「adiary

2010/08/12(木)Digest::SHA を使って HMAC-SHA1 を生成するPerlのコード

Digest::SHA ないしは Digest::SHA::PurePerl を使います。よって PurePerl でも動作します。

HMAC署名についてはwikipediaを参照

sub hmac_sha1 {
	# my $self = shift;
	my ($key, $msg) = @_;
	my $sha1;

	if ($Digest::SHA::PurePerl::VERSION) {
		$sha1 = Digest::SHA::PurePerl->new(1);
	} else {
		eval {
			require Digest::SHA;
			$sha1 = Digest::SHA->new;
		};
		if ($@) {
			require Digest::SHA::PurePerl;
			$sha1 = Digest::SHA::PurePerl->new(1);
		}
	}

	my $bs = 64;
	if (length($key) > $bs) {
		$key = $sha1->add($key)->digest;
		$sha1->reset;
	}
	my $k_opad = $key ^ ("\x5c" x $bs);
	my $k_ipad = $key ^ ("\x36" x $bs);
	$sha1->add($k_ipad);
	$sha1->add($msg);
	my $hk_ipad = $sha1->digest;
	$sha1->reset;
	$sha1->add($k_opad, $hk_ipad);

	my $b64d = $sha1->b64digest;
	$b64d = substr($b64d.'====', 0, ((length($b64d)+3)>>2)<<2);
	return $b64d;
}

最後に「====」を付けてやるのがポイントで、これがないとOAuthで盛大にコケます。

なおこのソースコードはPDS扱いとします。

2010/04/20(火)ApacheのRLimitMEMが効かない

CGI開発中についうっかり無限ループを生成するなんて経験のある人も多いと思いますが、つい最近2回連続でサーバごと落としてしまったので*1本格的に対策しました。

*1 : メモリオーバーフローでカーネルが端からプロセスを殺し始めてサーバ停止

RLimitMEMとRLimitCPU

ApacheにはもともとCGIのメモリやCPU使用量を制限する設定があります。それがRLimitMEMとRLimitCPUです

それぞれ「メモリ(リソース)使用量」と「CPU時間使用量を制限する」もので、制限値を超えた瞬間にプロセスを殺してくれます便利なものです。*2

# 256MB limit(unit Byte)
RLimitMem 268435456
RLimitCPU 30

もちろんこれは設定していたのですが……。

*2 : kernelの機能によります。

RLimitMemが効かない

top コマンドで監視していいたら普通に500MBのメモリを食ってます。どうやら、RLimitMemやRLimitCPUが効かないようです。

  • mod_perl / mod_perl2
  • FastCGI(mod_fastcgi) / mod_fcgid

では効きません。ちょうどmod_fcgidを使用していました。Perl自体は別プロセスで起動しているので効くのかと思ったのですが、どうやら無効なようです(汗)。ちなみに通常CGIの他、SpeedyCGIは効きます。*3

*3 : 普段はSpeedyCGIで開発するのですがImageMagick問題のせいでFastCGIを使っていました。

Apache自体に制限を掛ける

Apache自体のメモリ消費量に制限をかければ、万が一無限ループなどで暴走してもサーバ落ちを防ぐことができます。Apache自体は落ちてしまいますが、サーバが落ちるよりは100倍マシです。

Apacheの起動スクリプト(シェルスクリプト)に

# 1GB limit(unit KByte)
ulimit -v 1048576

と記述することで制限を加えることができます。

Ubuntu/Debian系の場合は /etc/apache2/envvars に ulimit を書き加えればよいようです。これでApache自体が落ちると思ったのですが、mod_fcgid の場合 fcgi プロセスのみが落ちてくれました。

ちょっと謎は残るけど、とりあえず目的は達成したのでこれで。

2010/02/22(月)SpeedyCGI で ImageMagick が動かない

Webアプリ開発中に ImageMagick(perlmagick)が SpeedyCGI 環境でまともに動かない不具合に当たりました。

問題の詳細

  • Image::Magick をロードして何かしら処理を行うルーチンを SpeedyCGI で実行する時、2回目以降のキャッシュされた状態で不具合が起こる*1
  • 問題確認環境
    • Perl 5.8.8 + SpeedyCGI 2.22
    • ImageMagick 6.3.7 および 6.5.9

この問題は FastCGI や mod_perl2 では起きません。

*1 : スクリプトの処理が停止してしまう。もしくは処理中のまま返ってこなくなる

問題の症状

スクリプト

#!/usr/bin/speedy

use Image::Magick();

print "Content-Type: text/plain\n\n";
print "Image::Magick Version $Image::Magick::VERSION \n";
my $image = Image::Magick->new;
$image->Read( 'x.png' );

実行結果。

~$ test.pl
Image::Magick Version 6.3.7
~$ test.pl
Segmentation fault
~$ test.pl
Image::Magick Version 6.5.9
~$ test.pl
Segmentation fault

問題の原因

不明。

問題の解決法 2014/08/18

#!/usr/bin/speedy

delete $INC{'Image/Magick.pm'};
require Image::Magick;

print "Content-Type: text/plain\n\n";
print "Image::Magick Version $Image::Magick::VERSION \n";
my $image = Image::Magick->new;
$image->Read( 'x.png' );

requireで毎回確実にロードさせる細工をすることで問題は起こらなくなりました。Image::Magickモジュールがキャッシュされませんが、evalを飛び越えてSpeedyCGIごと落ちるよりはマシということで……。

まとめ

gccの(ライブラリlibgomp )バグのようです。gcc 4.3より前のVersion(4.2以下)で、amd64環境の時起こる模様。

gcc 4.4でも起きたので関係ないようです。4年経っても解決されてないとは思わなかった(汗)

メモ

256色png(8bitカラーパレット)で保存する方法。

$image->Read( 'x.png' );
$image->Resize(width=>133, height=>100);
$image->Quantize(colorspace=>'RGB',colors=>256);
$image->Set(depth => 8); 
$image->Write( 'y.png' );

2010/02/18(木)画像の縦横中央配置 / CSS / クロスブラウザ

画像の縦横中央配置

HTMLのソース。余計な改行やスペースを入れないこと。

<div class="image"><span class="dummy"></span><img src="xxx.png" /></div>

CSS。

div.image {
	border:		1px solid #8ff;

	min-width:	320px;
	width:		320px;
	height:		240px;
	_width:		322px;
	_height:	242px;

	text-align:	center;
	display:	block;
}
div.image span.dummy {
	height:		240px;
	width:		0px;
	vertical-align:	middle;
	display:	inline-block;
}
div.image img {
	max-width:	320px;
	max-height:	240px;
	vertical-align:	middle;

	/* IE6 hack */
	_margin-top:	-1px;
	/* IE6 でアスペクト比保存縮小のためのhack */
	_width:		expression(this.height>240 && this.width*3<this.height*4 ? Math.floor(this.width*240/this.height) : (this.width > 320 ? 320: true ));
	_height:	expression(this.height>240 ? 240: true );
}
*:first-child+html div.image img { /* IE7 hack */
	margin-top:	-1px;
}
  • 画像領域は320*240。
  • モダンブラウザは問題なく表示。
  • IE6は後方互換モード、IE7は標準準拠モード+ie8.js。
  • "margin-top: -1px;"してあげないと画像がなぜか下に1pxずれてしまう。

「span.dummy」を「display: inline-block」するのが縦方向センタリングのポイントです。

IE6で縦横比保存なmax-width, max-height

img {
	max-width:	320px;
	max-height:	240px;
	_width:		expression(this.height>240 && this.width*3<this.height*4 ? Math.floor(this.width*240/this.height) : (this.width > 320 ? 320: true ));
	_height:	expression(this.height>240 ? 240: true );
}

240と320を好みのサイズに変更してください。

2010/01/30(土)JavaScriptでオブジェクト指向なメモ

適当に追記します。

雑多なおさらい

  • JavaScriptのクラスの概念はないらしい。
  • プリミティブな数字や文字列など意外は、すべてオブジェクトであり参照。
  • 参照なので代入した側でメンバ変数をいじると、代入元も書き換わる。
  • 関数を変数に代入できる。
    var f = function (x){ alert(x); }
    f("msg");    // "msg"と表示される
    

Perl5のオブジェクトに似たところがありますが、クラス名前空間(パッケージ)を持たないため、Perl5よりも簡素な実装と言えそうです。

続きを読む