Написах програма на perl, която анализира записи от csv в db.
Програмата работи добре, но отне много време. Затова реших да разклоня основния процес на анализиране.
След малко спорове с вилицата сега работи добре и работи около 4 пъти по-бързо. Основният метод за анализиране е доста интензивен в базата данни. За интереси, за всеки запис, който се анализира, има следните db извиквания:
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 сървърът е изчезнал“, когато следващият модул се изпълнява след основния анализатор.
Странното е, че модулът, причиняващ проблеми, включва много проста заявка 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 часа, за да завърши, дали повикването от най-високо ниво към db връзката изтича времето за изчакване на db връзката от по-ниско ниво, въпреки че модулът от по-ниско ниво прави своя „собствена“ връзка.
Много е разочароващо да се опитвам да намеря проблема, тъй като мога да възпроизведа грешката само след като стартирам много дълъг процес на анализ.
Извинете за дългия въпрос, благодаря предварително на всеки, който може да ми даде някакви идеи.
АКТУАЛИЗАЦИЯ 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 връзката се извиква след разклонението.
Но, както споменах по-горе, раздвоеният код, очертан точно по-горе, работи добре. Това е следващият модул, който не работи, който се изпълнява от модул на контролер, който просто преминава през всеки работен модул един по един (парсерът е един от тях) - модулът на контролера не създава DB връзка в своята конструкция или навсякъде друго.
Актуализация 2
Забравих да спомена, че не получавам никакви грешки в модула „проблем“ след анализатора, ако анализирам само малък брой файлове, а не цялата опашка.
Така че е почти като че ли интензивното разклонено анализиране и достъп до DB я прави недостъпна за нормални неразклонени процеси веднага след като приключи за известно неопределено време.
Единственото нещо, което забелязах, когато изпълнението на анализатора завърши в Mysql състояние, е, че Threads_connected стои около, да речем, 500 и не намалява известно време.