MySQLだと問題ないみたい。あと、job の引数に何を渡すかで変わってくるらしい……
[2010-2-16 追記]
追記時点での DBD::Pg と DBD::SQLite の最新版 (DBD::Pg-2.16.1, DBD::SQLite-1.29) では、以下に記述されているメモリリークは解消されています。記事自体は記録の意味も兼ねているので消さずに残しますが、ご注意ください。
ちなみに SQLite 用のスキーマは TheSchwartz 自身に同梱されていて t/schema-sqlite.sql に、PostgreSQL 用のはリポジトリの trunk にあります。doc/schema-postgres.sql
検証用のスクリプトは最後に載せますが、単に client が job を突っ込んで、worker が job を取り出して $job->completed() するだけのものです。
Gtop を使って、Worker プロセスのメモリ使用量を表示するようにしてみました。
環境は以下。
- CentOS-4
- Perl-5.8.5
- mysql-5.0.58-1.el4.centos
- postgresql-7.4.16-1.RHEL4.1
- DBD::mysql 4.007
- DBD::Pg 2.008001
- DBD::SQLite 1.14
1. $arg = { now => time() } の場合
jobs mysql Pg SQLite 0 9957376 12713984 13180928 100 14295040 15949824 34889728 1000 14295040 15949824 35254272 2000 14295040 15949824 35717120
MySQL, PostgreSQL はメモリサイズが増えないが、SQLite は徐々に増えるし妙にでかい。
2. $arg = { now => DateTime->now() } の場合
jobs mysql Pg SQLite 0 12640256 12312576 13574144 100 16977920 16945152 35401728 1000 16977920 22568960 35815424 2000 16977920 29491200 36208640
MySQL は一定だが、PostgreSQL は job を処理するごとにどんどんメモリサイズが増える。
SQLite も 1. の場合と同様に、徐々に増えている。
ということで、TheSchwartz の DB に MySQL 以外を使う場合は要注意かも。
TheSchwartz の worker を安全に停止する の対処をした上で、定期的に worker を再起動しています。
[2008-7-2 追記]
http://d.hatena.ne.jp/tokuhirom/20080629/1214748832 で DBD::SQLite のメモリリークが原因だと突き止めて頂きました。ありがとうございます。
とすると DBD::Pg もリークを疑うべきなんだろうけど、1. の場合には起きてないので、単にループするだけとかでは再現しないみたい。また後で追ってみよう。
[2010-2-16 追記]
DBD::Pg を現時点での最新版 2.16.1 にしたところ、PostgreSQL でもリークはなくなりました。
手元で検証できたバージョンについては、少なくとも 2.13.1 では解消されていたようです。
client.pl
use TheSchwartz; use strict; use DateTime; $|=1; my $count = 0; my ( $dsn, $user, $pass ) = @ARGV; my $client = TheSchwartz->new( databases => [{ dsn => $dsn, user => $user, pass => $pass }] ); while (1) { for ( 1 .. 20 ) { $client->insert( MyWorker => { now => DateTime->now(), } ); $count++; } sleep 1; print "$count jobs inserted.\n" if $count % 100 == 0; }
worker.pl
package MyWorker; use strict; use warnings; use base qw( TheSchwartz::Worker ); use GTop; use DateTime; my $gtop = GTop->new; my $count = 0; printf "%d,%d\n", $count, $gtop->proc_mem($$)->size; sub work { my ($class, $job) = @_; $job->completed(); $count++; printf "%d,%d\n", $count, $gtop->proc_mem($$)->size if $count % 100 == 0; } package main; use TheSchwartz; my ( $dsn, $user, $pass ) = @ARGV; my $client = TheSchwartz->new( databases => [{ dsn => $dsn, user => $user, pass => $pass }] ); $client->can_do('MyWorker'); $client->work();