我编写了一个perl程序,用于将csv中的记录解析为db。
该计划工作正常,但需要很长时间。所以我决定分叉主解析过程。
在用叉子进行一些争吵后,它现在运行良好,运行速度提高了约4倍。主要的解析方法是数据库密集型的。为了利益起见,对于每个解析的记录,都有以下数据库调用:
1 - 检查唯一生成的base62对于baseid映射表是唯一的 2 - 存档检查以查看记录是否已更改 3 - 将记录插入db
问题是当解析器以分叉模式运行时,我开始得到“Mysql已经消失”错误,所以经过多次摆弄后我想出了以下mysql配置:
#
# * 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服务器已经消失”。
奇怪的thinf是导致问题的模块涉及一个非常简单的SELECT查询,当前只有3条记录。直接作为测试运行(不在解析器之后),它可以正常工作。
我尝试在解析器模块运行后添加4分钟的暂停 - 但是我得到了同样的错误。
我有一个主DBConnection.pm模型: 包DBConnection;
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;
}
问题是我是否有Module1.pm调用Module2.pm调用Module3.pm并且每个都实例化与DB的连接,如上所示(即在构造函数中)然后他们使用不同的数据库连接或相同的连接?
我想知道的是,如果脚本需要6个小时才能完成,如果对数据库连接的最高级别调用是超时低级别数据库连接,即使较低级别模块正在进行“自己的”连接。
尝试找到问题非常令人沮丧,因为我只能在运行一个非常长的解析过程后重现错误。
很抱歉这个长期的问题,请提前感谢能给我任何想法的人。
这是实际的分叉部分:
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();
}
据我了解,在分叉后调用数据库连接。
但是,正如我上面提到的,上面概述的分叉代码工作正常。它是下一个无法运行的模块,它从一个控制器模块运行,该控制器模块一次只运行一个工作模块(解析器就是其中之一) - 控制器模块不在其构造中或任何地方创建数据库连接其他
我忘了提到我在解析器后面的'problem'模块中没有出现任何错误,如果我只解析少量文件而不是完整队列。
因此,几乎就像密集分叉解析和访问数据库一样,它在正常的非分叉进程刚刚结束一段时间后就不可用了。
当解析器运行完成Mysql状态时,我唯一注意到的是Threads_connected位于500左右,并且不会减少一段时间。
答案 0 :(得分:2)
这取决于你的程序的结构,这个问题并不清楚。
如果在fork
之前创建数据库连接,Perl将为每个进程制作数据库连接对象的副本。如果两个进程尝试使用相同的数据库连接同时访问数据库,则可能会出现问题。
另一方面,如果在fork
之后创建数据库连接,则每个模块都有自己的连接。这应该有效,但如果Module x创建连接,则可能会出现超时问题,然后等待很长时间才能完成模块y中的进程,然后尝试使用该连接。
总之,这是你想要的:
fork
点处没有任何打开的连接。子进程应该创建自己的连接。答案 1 :(得分:1)
阅读dan1111的答案,但我怀疑你正在连接然后分叉。当子进程完成DBI连接句柄超出范围并关闭时。正如dan1111所说,由于他说的所有原因,你最好连接孩子。阅读DBI中的InactiveDestroy和AutoInactiveDestroy,这将有助于您了解正在发生的事情。