MySQL maxconnections
CentOSだと設定場所は/etc/my.cnf
[mysqld] max_connections=100
perlからDBI使って、DBハンドル取得&SELECTした時にどういう挙動をするのか調べてみた。
実験に使ったプログラム。
#!/usr/bin/perl use strict; use DBI; use Parallel::ForkManager; #適当に複数プロセス起動し、それぞれでSELECT my $pm = Parallel::ForkManager->new(500); for (1..2000) { my $pid; $pid = $pm->start && next; eval { &select; }; print $@ if ($@); $pm->finish; } $pm->wait_all_children; sub select { my $dbh = &getHandle; # dataテーブルには30万行のレコード # limit 2000は適当に my $sth = $dbh->prepare(<<'SQL'); select * from data limit 2000 SQL $sth->execute; sleep(1); print "select: $dbh", "\n"; }
SELECTした後のスリープ時間を1にするとこれくらい。
| Max_used_connections | 14 | | Threads_cached | 0 | | Threads_connected | 10 |
SELECTした後のスリープ時間を3にするとこれくらい。
| Max_used_connections | 40 | | Threads_cached | 0 | | Threads_connected | 39 |
SELECTした後のスリープ時間を10にするとToo Many Connection。
DBI connect('dbname=db;host=localhost;mysql_connect_timeout=10','user',...) failed:
スリープなしにすると、すんなり。
| Max_used_connections | 11 | | Threads_cached | 0 | | Threads_connected | 1 |
ちょっとプログラムを変更して、スリープ前にundefでも同様の結果を得られる。
| Max_used_connections | 11 | | Threads_cached | 0 | | Threads_connected | 1 |
つまり、取得したハンドルオブジェクトがスコープから外れてメモリから消えると、
PerlがうまくMySQLとのコネクションを切ってくれるということだ。
切断されたコネクションはMySQLが新たなプロセスに割り当ててくれるので、
sleep(0);のケースでは10程度に抑えられる。
逆にハンドル握りっぱなし(メモリにオブジェクト残したまま)で時間のかかる処理をする(今回はsleepでエミュレート)と、いつまでもコネクションが解放されないので、コネクション数が逼迫するという結果に。
まとめ
ハンドル取得後に長い処理を実行する場合は、適切にハンドルを解放せよ。