Typo 5.3がメモリを使い過ぎる
二、三日前から時々oom-killerが出るようになった。なんでかなと見てみたらずいぶんと太ったTypoのプロセスサイズがいくつか。一つあたり500MBとか……。
今までなんともなかったのになと思ったものの、それほど考えてみれば気にしていなかっただけで、実はけっこう前からこういう状態だったのかもしれないということに気付いた。おおむね自分が困るだけとはいえ、ちょっとほったらかしすぎた。動きを見てみると、プロセスが生成されて少しして数秒かけてプロセスサイズが大きくなっていくことがわかった。どうやら何かを読み込んでいるように見える。
実はこのことに気付くほんの少し前のタイミングでPassengerのバージョンを変えたり、他のアプリケーションの配置を変えたり、GEM_HOMEを変えたりということをしている。そのため、まず疑ってしまったのはそのあたりだった。その次に疑ったのは自家製コードのいくつか。といってもTypoのためには数十行のコードを書いた程度で、特別に問題になりそうなものは見付からない。
動いているプロセスにコードをつっこんでオブジェクトの様子を見てみるかとも思い始めていたのだが、ここでscript/consoleでも同じ現象が出ていることに気付いた(遅い!)。そしてconfig/environment.rbを読み込み終えるまでにプロセスサイズが育っていることがわかった。printfデバッグで絞り込みをかけたところ、以下のコードにいたった。
if RAILS_ENV != 'test'
begin
ActiveRecord::Base.connection.select_all("select * from sessions")
rescue
begin
ActiveRecord::Base.connection.current_database
Migrator.migrate
rescue
# if there are no database, migrator doesn't no start
# use case : rake db:create in rails tasks
end
end
end
このコードが加えられたのはこのあたり。これなら、とりあえずはlimit 1でも付けておけばよいだろうか。もっとやりようがありそうなものではあるが。
結局、問題が顕在化したのは保存しているセッションの数が多くなってきたからであった。実に602,788レコードもある。セッションデータの掃除は今でも(Typo 5.3ではRails 2.2を使っているが)手作業でやるのかな? (セッションだからdelete_allで十分かしら?)
$ script/runner -e production 'CGI::Session::ActiveRecordStore::Session.destroy_all(["updated_at
追記
問題として報告しておいたところgithub上のリポジトリでは引用したブロックはコメントアウトされたようだ。5.3.1では直っているのかな。なんだか他のチケットも動き出したので、ちょうどそんなタイミングだったらしい。
Flickr APIの変化とTypo 5.3のflickr.rb
Typo 5.3で使っている自作のFlickrプラグインで写真を引っぱれなくなった。「Flie does not exist」という例外が起きている。ファイル?
追ってみたところ、vendor/flickr/flickr.rbで使っているXmlSimple.xml_inの中での起きている例外だった。xml_inは与えられた文字列がXMLっぽかったらXMLとして、そうでなければファイル名として処理しようとする。えぇー、と思ったが、まあそれはおいていおく。
実際にアクセスしているURLを取り出してwgetしてみたところ、きちんとレスポンスが得られる。けれどもxml_inには空文字列が渡っている。おかしいなと思い、flickr.rbではどのようにアクセスしているか見てみるとNet::HTTP.get_responseを使っていた。それではと同メソッドでアクセスしてみると302が返ってきていることがわかった。なるほど。
では302が返ってきたらそれを追いかけるように書き換えて、などとしかけたのだが、open-uriでよいではないかと思いとどまった。こんな感じ。
def http_get(url)
# Net::HTTP.get_response(URI.parse(url)).body.to_s # 元のコード
open(URI.parse(url)) {|i| i.read}
end
Typoインストールメモ
まずTypoのコードを入手する。いろいろなも味に依存しているのでRubyGemsを使うのが楽。
$ GEM_HOME=/tmp/GEM gem install typo
Typoではサイトをセットアップするときに必要なものをすべてコピーするので、インストールしたgem群への依存関係は一応なくなる。ただし、typoコマンドを通じてバックアップなどの管理操作ができる。そしてそのような操作のためにはインストールされたgemが必要となる)。
$ sudo -u www-data \
env GEM_HOME=/tmp/GEM \
/tmp/GEM/bin/typo install path/to/install/dir \
db_user=dbuser \
db_password=dbpass \
db_name=dbname \
web-server=external # FastCGIの場合
これでTypoが動作する環境ができるが、.htaccessは作ってくれないのでこれを作っておく(FastCGIで動かそうと思うので)。また、Rails 2.x系ではw3mなどでアクセスすると406エラーになるので回避コードを入れておく。
$ rails /tmp/t $ sudo -u www-data \ cp /tmp/t/public/.htaccess path/to/install/dir/public $ rm -rf /tmp/t $ sudo -u www-data \ vi path/to/install/dir/putlic/.htaccess # 調整 $ cat <path/to/install/dir/config/initializers/w3m.rb
Mime::HTML.instance_eval { @synonyms << "text/*" }
Mime::LOOKUP["text/*"] = Mime::HTML
E
今回、tDiaryから移行したデータがあるので、一部の表現のために書いた互換プラグインを置いておく。
$ sudo -u www-data \
cp -a typo_textfilter_{asin,tdiarycompat} \
path/to/install/dir/vendor/plugin
最後にApache HTTPサーバ側のその他の調整をしてリロードする。
$ sudo vi /etc/apache2/sites-available/site # その他調整 $ sudo /etc/init.d/apache2 reload
ブラウザでアクセスすると最初のユーザ登録ができる。tDiaryからのデータ移行の都合のためspamまわりの設定を残して、その他の設定をしておく。その後でデータを流し込む。
$ sudo -u www-data \ path/to/install/dir/script/runner td2typo.rb tdiary.dump
終了後、残しておいたspamまわりの設定をし、動作確認をする。
この環境ではFastCGIをmod_fcgidで運用しているのだけど、外部リソースにアクセスしまくるページなどでIPCCommTimeoutにひっかかることがあるようだった。tDiaryをFastCGIで動かそうとしたときにはIPCConnectTimeoutを大きめにしなければならなかったのだけど、ここではCommのほうを大きめに設定した。
実はnet/httpのタイムアウトのところでエラーになっていたのを勘違いしてしって、ずいぶん遠まわりをしてからこのことに気付いた。いかんいかん。


