設定ファイルいらずのハイパフォーマンス分散メモリオブジェクトキャッシュシステム。 Perl、PHP、Python、Java、Ruby、C#、C用のAPIが既に提供されている。
Memcached はメモリ上にキャッシュし特にファイルへ書き出したりしない。
拙作の WikiEngine 「WiKicker」も WikiPage の HTML 変換結果を Memcached 上にキャッシュする機能を備えている。
mixi やはてなブックマークでも利用されている (記事1、記事2)。
WiKicker の機能のうち、ヘビーな処理が必要なものの筆頭に検索機能がある。 今のところ単純に全ページに対してマッチング処理を行うのでページ数が増えるに従い遅くなってくる。 ロボットの総ナメが怖い*1ので NaneyOrgWiki では load average が 5 を越えたら一時的に検索機能が停止するようになっている。
そこで Memcached を使って検索結果をメモリキャッシュするようにしてみた。 本当はWikiPageのパース・レンダリング結果をキャッシュして、通常のページ表示を高速化したいと考えているのだが、今はまず影響の少ないところから(何でもいいから Memcached を使ってみたいというのが本音)。
で、実装してみた。 キャッシュがヒットすればすばやくレスポンスを返せるはずなのだが...やはり微妙だな。 速くなった気もするのだが、サーバの状態によってかなり遅い時もあるようだし。 まずはこれでしばらく運用テストしてみて、効果がありそうだったら他の部分にも適用することにしよう。
ようやく、HTMLレンダリング結果のキャッシュに着手。 cookie ベースでユーザ毎のカスタマイズ(名前やTZ)があるので、デフォルトのまま表示リクエストのみキャッシュが効くようにする。 キャッシュによる高速化を受けるのでは投稿してくれている常連ではなく検索エンジンから飛んできた一見さんということになるが、サーバの負荷が下がれば間接的に常連さんへのレスポンスも良くなるかと。
変換されたHTMLフラグメントをMemcachedにキャッシュ。 最初、キャッシュを有効にすると逆に遅くなってしまって「まいったな」と思ったが、リクエスト処理終了毎にdisconnect_all するようにしたら、キャッシュの効果を体感できるぐらいの速度が出るようになった。
Memcached まわりをいじったので、キャッシュ具合をテストしていたら変な現象が。 WikiPage が表示されるべきところに、検索結果が表示されている。 あれ?
WiKicker では WikiPage のレンダリング結果も検索結果もキャッシュしているが、それぞれ別のキャッシュキーになるようにしている (WiKickerのバージョンを $V とすると、'$V:h:ページ名' と '$V:s:検索語')ので混ざるはずがないんだけれどな。 キャッシュしているデータの形式も違うし。
最初は Memcached まわりのアップデートで不具合がでたのかと思ったが、戻しても変わらない。ということは、ずっと以前からこの問題が発生していたのか。 やば。 設定でニックネームを設定している(cookie に保存している)と、その Web ブラウザに対してはキャッシュ機能が働かないようになっているので発見が遅れてしまった。
で結局コードをチェックしてみたら「WikiPage 表示と検索結果表示の View クラスを同じにしていたため、検索結果のレンダリングが WikiPage レンダリング結果と同じ領域にキャッシュされる」という風になってしまっていた。 ということで誰かがページ名で検索するとそれがキャッシュされてしまい、ページを読もうとしてもキャッシュ破棄されるまで検索結果が表示されてしまうというひどい状況になっていたと。
修正。
Memcached の出力をチェックしていたら、たまにエラーが起きていることを確認。 Memcached のプロトコルをチェックしたら、キーには制御文字と空白は使えないとある。 Cache::Memcached を見たらキーはそのまま through するだけ。 ということでページ名に空白が含まれている場合などの時には、まずい事になっていたようだ。 こちらは、キーを自前でエンコーディング(ページデータベースファイル名の作成に使っている base64 の亜種)するように修正。
WiKicker で使用しているキャッシュシステム Memcached 用の Perl API Cache::Memcached が新しくなっていたので、入れ換え。
1月に入れた時と同様、Perl 5.005_03 ではそのまま動かないので一部を修正。 前回はCVSスナップショット(Memcached.pm revision 1.8)に対する修正だったので手元で修正しただけだったが、今回はパッチも作っておく。
修正点は
といったところ(WiKicker で使っているところのみ修正)。
以前は Use of uninitialized value がかなり出ていたのだが、 Cache::Memcached のコード自体が綺麗になったのかこれらも出なくなっていい感じ。
Perl API (Cache::Memcached)のアップデートのついでに、Memcached 自体もアップデート。
cd /tmp wget http://www.monkey.org/~provos/libevent-0.8.tar.gz tar zxvf libevent-0.8.tar.gz cd libevent-0.8 ./configure make cd .. wget http://www.danga.com/memcached/dist/memcached-1.1.11.tar.gz tar zxvf memcached-1.1.11.tar.gz cd memcached-1.1.11 CFLAGS='-L../libevent-0.8 -I../libevent-0.8' ./configure --prefix=$HOME/local/memcached-1.1.11 make make install
1.14 が 7月27日にリリースされていたのでパッチ作成。 1.13 用のパッチがあたったのでそのままいけるかなと思ったが、テストしたところまたいくつかの非互換コードが増えていたのでそれらの修正を行う。
tar zxvf Cache-Memcached-1.14.tar.gz cp -a Cache-Memcached-1.14 Cache-Memcached-1.14.orig patch -d Cache-Memcached-1.14 -p1 \ < Cache-Memcached-1.13-5.005_03-20040605.diff find Cache-Memcached-1.14 -name '*.orig' -exec rm {} ';' emacs Cache-Memcached-1.14/Memcached.pm LC_ALL=C TZ=UTC0 diff -Naur \ Cache-Memcached-1.14.orig Cache-Memcached-1.14 \ > Cache-Memcached-1.14-5.005_03-20040731.diff
新規修正点は
2004-07-19 * don't use pos() because it doesn't seem to work in taint mode. use $+[0] instead. (Dave Evans <..@djce.org.uk>)
それからパッチの作り方を変更。patch の man の通り LC_ALL=C TZ=UTC0 にするのとオプションを -Naur を使うように。
また 1.14 から String::CRC32 が必要になった。
今年の大事件、マイブームなど。
2月22日にハイパー日記システムから DiKicker へ移行。 自分で開発しているので好きなように改良ができて楽しい。 比較的すんなり安定したので最近はあまりコードをいじらず。
WiKicker の方も安定し、(管理をのぞいて)必要な機能もだいたい実装された感じ。 秋ぐらいから NaneyOrgWiki の方にも spam 的な書き込みが多発。 パターンによる書き込み拒否の実装で年末それなりに収束しつつある感じ。
orkut、mixi に登録。 前者はそれほどはまらずフェードアウト。
mixi の方は結構面白い。
というのが遊んでみるのに良かった。
ついついチェックしてしまうのは
の存在。 オフィスで広まったことで楽しさも増した。
来年の今ごろも継続しているだろうか? 今後カスタマイズ機能とかが充実してくれると嬉しい。
(SNSではないが)Gmailの方は登録したけどまだ活用できていない。
導入。 USの小切手からの入金用にシティバンクの口座を開いたものの、シティバンクには数ヶ月後に4拠点閉鎖の命令がくだるなど安心できない状況ではある。
PEG-TJ25を購入し、Palm OS 生活復活。 最初はおもちゃのつもりで買ったのだが、プロジェクトマネジメントなどにシフトした仕事のスケジュール管理などで大活躍。
PDA 市場の明るい話はあまり聞かないが、末長く製品が出て続けて欲しい。
朝 www.naney.org の過去記事を確認しつつ作業をしていたら、9:00 前に急にアクセスできなくなった。 ping も通らない。 9:20 ぐらいに 1度復帰したが、また10:00 前にダウン。
それから何度も落ちては復帰を繰り返すようになってしまっている。 SSH で接続している途中にも突然刺ささるし、傍から見ていても原因が良くわからない。
昨日 WiKicker をアップデートしたから「もしかしてうちが原因?」とちょっと心配もしたりするのだが、無限ループに入ったりメモリを使い尽すようなコードが追加してはいないはずだしなぁ(ローカルでのテストではそのような現象は見られない)。
落ちる直前まで見ていてもそれほど load average が高いわけでもないようだしなぁ。
とまぁ、しばらく様子を見ているうちに NaneyOrgWiki と nDiki が Internal Server Error。 止められた。 正確には SpeedyCGI のフロントエンド speedy コマンドの実行権限を管理者に落とされた。
ということもあって疑われたと推測。
一応こちらでも SpeedyCGI を使わないで直接 Perl で実行するように変更してみたり、Memcached を起動するのをやめてみたりなど設定を変更してみたりするのだけれど、関係なく落ちる落ちる。
管理者がシステムの設定を変えていないで発生するようになったのなら、ハードウェア障害が起きているんじゃないかと想像してしまうのだが、実際どうなんだろうか。
結局夜 23:00 過ぎだかに落ちたあとは復帰する様子がないので(管理者が落ちたかな?)、今日はあきらめ。
www.naney.org を収容しているサーバの負荷が高い状態。
という対処をしたけれどそれでもなかなか負荷が落ちつかない。
傾向としては SpeedyCGI のバックエンド側(speedy_backend)が MaxBackends まで起動して処理が追いつかないと、起動しているフロントエンド側 (speedy) がどんどん増えてしまうという状況のようだ。
DiKicker の高速化も順次着手しているのだけれど追いつきそうにもないので、loave average が高い時は頑張らずに無条件に 503 を返すように修正して対応(以前ハイパー日記システムの時にも同じことをした)。
本当は SpeedyCGI フロントエンドの数に応じて負荷の軽い処理に切り換える等工夫したいんだけれど、フロントエンドの数を取得する方法は簡単にはなさそうなんだよなあ。
Naney (なにい)です。株式会社ミクシィで SNS 事業の部長をしています。
nDiki は1999年1月に始めたコンピュータ日誌を前身とする Naney の Web 日記(兼パーソナルナレッジベース)です。ちょっとしたノートは nNote にあります。
※内容は個人的見解であり所属組織とは関係ありません。