csv から db にレコードを解析する perl プログラムを作成しました。
プログラムは問題なく動作しましたが、時間がかかりました。そこで、メインの解析プロセスをフォークすることにしました。
fork と少し格闘した後、正常に動作し、約 4 倍速く実行されます。主な解析方法は、かなりデータベースを集中的に使用します。便宜上、解析されるレコードごとに、次の db 呼び出しがあります。
1 - 一意に生成された base62 が baseid マップ テーブルに対して一意であることがチェックされます 2 - レコードが変更されたかどうかを確認するためにアーカイブ チェックが行われます 3 - レコードがデータベースに挿入されます
問題は、パーサーが fork モードで実行されている間に「Mysql has gone away」エラーが発生し始めたことです。
#
# * Fine Tuning
#
key_buffer = 10000M
max_allowed_packet = 10000M
thread_stack = 192K
thread_cache_size = 8
myisam-recover = BACKUP
max_connections = 10000
table_cache = 64
thread_concurrency = 32
wait_timeout = 15
tmp_table_size = 1024M
query_cache_limit = 2M
#query_cache_size = 100M
query_cache_size = 0
query_cache_type = 0
パーサーの実行中の問題は修正されたようですが、メインのパーサーの後に次のモジュールが実行されると、「Mysql server has gone away」というメッセージが表示されます。
奇妙な点は、現在 3 つのレコードしかないテーブルに対する非常に単純な SELECT クエリが問題を引き起こしているモジュールです。(パーサーの後ではなく) テストとして直接実行すると、問題なく動作します。
パーサー モジュールの実行後に 4 分間の一時停止を追加しようとしましたが、同じエラーが発生します。
これを含むメインの DBConnection.pm モデルがあります。
use DBI;
use PXConfig;
sub new {
my $class = shift;
## MYSQL Connection
my $config = new PXConfig();
my $host = $config->val('database', 'host');
my $database = $config->val('database', 'db');
my $user = $config->val('database', 'user');
my $pw = $config->val('database', 'password');
my $dsn = "DBI:mysql:database=$database;host=$host;";
my $connect2 = DBI->connect( $dsn, $user, $pw, );
$connect2->{mysql_auto_reconnect} = 1;
$connect2->{RaiseError} = 1;
$connect2->{PrintError} = 1;
$connect2->{ShowErrorStatement} = 1;
$connect2->{InactiveDestroy} = 1;
my $self = {
connect => $connect2,
};
bless $self, $class;
return $self;
}
次に、フォークされたパーサー モジュールを含むすべてのモジュールが、次を使用して DB への接続を開きます。
package Example;
use DBConnection;
sub new {
my $class = shift;
my $db = new DBConnection;
my $connect2 = $db->connect();
my $self = {
connect2 => $connect2,
};
bless $self, $class;
return $self;
}
問題は、Module3.pm を呼び出す Module2.pm を呼び出す Module1.pm があり、それぞれが上記のように (つまり、コンストラクターで) DB との接続をインスタンス化する場合、データベースへの異なる接続を使用するか、同じ接続を使用するかです。繋がり?
私が疑問に思ったのは、下位レベルのモジュールが「独自の」接続を確立しているにもかかわらず、db 接続へのトップレベルの呼び出しが下位レベルの db 接続をタイムアウトしている場合、スクリプトが完了するまでに 6 時間かかるかどうかです。
非常に長い解析プロセスを実行した後にしかエラーを再現できないため、問題を見つけようとするのは非常にイライラします。
長い質問で申し訳ありませんが、私にアイデアを提供できる人に事前に感謝します。
更新 1:
実際の分岐部分は次のとおりです。
my $fh = Tie::Handle::CSV->new( "$file", header => 1 );
while ( my $part = <$fh> ) {
if ( $children == $max_threads ) {
$pid = wait();
$children--;
}
if ( defined( $pid = fork ) ) {
if ($pid) {
$children++;
} else {
$cfptu = new ThreadedUnit();
$cfptu->parseThreadedUnit($part, $group_id, $feed_id);
}
}
}
そして、ThreadedUnit:
package ThreadedUnit;
use CollisionChecker;
use ArchiveController;
use Filters;
use Try::Tiny;
use MysqlLogger;
sub new {
my $class = shift;
my $db = new DBConnection;
my $connect2 = $db->connect();
my $self = {
connect2 => $connect2,
};
bless $self, $class;
return $self;
}
sub parseThreadedUnit {
my ( $self, $part, $group_id, $feed_id ) = @_;
my $connect2 = $self->{connect2};
## Parsing stuff
## DB Update in try -> catch
exit();
}
私が理解しているように、分岐後にDB接続が呼び出されています。
しかし、上で述べたように、上で概説したフォークされたコードは問題なく動作します。各ワーカーモジュールを一度に1つずつ実行するコントローラーモジュールから実行されているのは、機能しない次のモジュールです(パーサーはそれらの1つです)-コントローラーモジュールは、その構造またはどこにもDB接続を作成しませんそうしないと。
更新 2
完全なキューではなく少数のファイルのみを解析する場合、パーサーに続く「問題」モジュールでエラーが発生しないことを忘れていました。
そのため、フォークされた集中的な解析と DB へのアクセスにより、DB が終了した直後に通常のフォークされていないプロセスで利用できなくなるかのようです。
パーサーの実行が Mysql ステータスで終了したときに気付いた唯一のことは、Threads_connected が 500 前後にあり、しばらくの間減少しないことです。