gpt4 book ai didi

mysql - Perl 模块实例化 + DBI + fork "Mysql server has gone away"

转载 作者:可可西里 更新时间:2023-11-01 07:35:27 29 4
gpt4 key购买 nike

我编写了一个 perl 程序,可以将记录从 csv 解析到数据库中。

该程序运行良好,但需要很长时间。所以我决定 fork 主要的解析过程。

在与 fork 进行了一些争论之后,它现在运行良好并且运行速度提高了大约 4 倍。主要的解析方法是相当数据库密集型的。为了方便起见,对于解析的每条记录,都有以下数据库调用:

1 - 检查唯一生成的 base62 与 baseid 映射表是否唯一2 - 有一个存档检查以查看记录是否已更改3 - 记录被插入数据库

问题是,当解析器以 fork 模式运行时,我开始收到“Mysql has gone away”错误,所以经过多次摆弄后,我想出了以下 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 服务器已经消失”。

奇怪的是,导致问题的模块涉及对当前只有 3 条记录的表进行非常简单的 SELECT 查询。直接作为测试运行(不在解析器之后)它工作正常。

我尝试在解析器模块运行后添加 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;
}

然后所有模块,包括 fork 的解析器模块,使用以下命令打开到数据库的连接:

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 并且它们每个都实例化与数据库的连接,如上所示(即在构造函数中)那么它们是否使用不同的数据库连接还是相同的连接?

我想知道脚本是否需要 6 个小时才能完成,如果对数据库连接的顶级调用超时了较低级别的数据库连接,即使较低级别的模块正在建立其“自己的”连接。

试图找到问题是非常令人沮丧的,因为我只能在运行很长的解析过程后才能重现错误。

很抱歉问了这么长的问题,在此先感谢任何能给我任何想法的人。


更新 1:

这是实际的 fork 部分:

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();
}

据我了解, fork 后将调用数据库连接。

但是,正如我上面提到的,上面概述的 fork 代码工作正常。它是下一个不工作的模块,它是从 Controller 模块运行的, Controller 模块一次只运行一个工作模块(解析器是其中之一)—— Controller 模块不会在其构造中或任何地方创建数据库连接否则。


更新2

我忘了说,如果我只解析少量文件而不是整个队列,我不会在解析器之后的“问题”模块中收到任何错误。

因此,几乎就好像密集的 fork 解析和访问数据库使得正常的非 fork 进程在它结束一段不确定的时间后就无法使用它。

当解析器在 Mysql 状态下运行完成时,我唯一注意到的是 Threads_connected 大约为 500,并且在一段时间内不会减少。

最佳答案

这取决于您的程序的结构,问题中并不清楚。

如果您在fork 之前创建数据库连接,Perl 将为每个进程制作数据库连接对象的副本。如果两个进程尝试使用同一个数据库连接同时访问数据库,这可能会导致问题。

另一方面,如果您在forking 之后创建数据库连接,每个模块都会有自己的连接。这应该可行,但如果模块 x 创建连接,然后等待很长时间以等待模块 y 中的进程完成,然后尝试使用连接,则可能会出现超时问题。

总而言之,这是您想要的:

  • 在您fork 时没有任何打开的连接。子进程应创建自己的连接。
  • 仅在您要使用之前打开连接。如果您的程序中有一个点需要等待,请在等待完成后打开连接。

关于mysql - Perl 模块实例化 + DBI + fork "Mysql server has gone away",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15966168/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com