毎秒1000リクエスト を捌く超高速CMS「adiary」
2010/08/18(水)Pure PerlでのOAuth実装メモ
adiaryに、twitter投稿のためのOAuthを実装したときのメモです。PurePerl動作。
OAuthモジュール(OAuth::Lite::Consumer)を使わずに実装したので、同じことをやりたい人には参考になるかと思います。*1
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本格的に対策しました。
RLimitMEMとRLimitCPU
ApacheにはもともとCGIのメモリやCPU使用量を制限する設定があります。それがRLimitMEMとRLimitCPUです。
それぞれ「メモリ(リソース)使用量」と「CPU時間使用量を制限する」もので、制限値を超えた瞬間にプロセスを殺してくれます便利なものです。*2
# 256MB limit(unit Byte) RLimitMem 268435456 RLimitCPU 30
もちろんこれは設定していたのですが……。
RLimitMemが効かない
top コマンドで監視していいたら普通に500MBのメモリを食ってます。どうやら、RLimitMemやRLimitCPUが効かないようです。
- mod_perl / mod_perl2
- FastCGI(mod_fastcgi) / mod_fcgid
では効きません。ちょうどmod_fcgidを使用していました。Perl自体は別プロセスで起動しているので効くのかと思ったのですが、どうやら無効なようです(汗)。ちなみに通常CGIの他、SpeedyCGIは効きます。*3
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 では起きません。
問題の症状
スクリプト
#!/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
問題の原因
不明。
問題の解決法
#!/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を好みのサイズに変更してください。