mysql - 带线程的 Perl 邮件队列 'out of memory'

标签 mysql multithreading bash perl email

我创建了一个邮件队列脚本,用于检查 MySQL 表中是否有过去要发送的时间戳的邮件。有时,“邮件队列”中的邮件可能比我一次想要发送的邮件多,因此我使用线程批量发送邮件。有时,当没有太多邮件要发送时,系统会稳定运行,但有时,这个始终运行的邮件队列进程(通过每 30 秒调用它一次的 bash 脚本)会被终止,因为系统内存不足。我想防止“邮件队列”内存不足。

我想请你们中的任何人看看我下面的代码,也许我做错了什么。

提前致谢。

~$ htop
PID  USER       PRI  NI VIRT  RES   SHR  S  CPU% MEM%   TIME+   Command
5675 root       20   0  969M  528M  3744 S  0.0  14.1   2:33.05  perl /path/mailqueue.pl

Server specs: 1 vCPU; 3.75 Gib Memory;
sub start_threads {

    my @threads;

    # records found
    my $found = 0;

    my $sth = $dbh->prepare("SELECT mail_queue_id, project_id, type, name, email FROM mail_queue WHERE timestamp < NOW() AND active = 1 ORDER BY timestamp ASC LIMIT 10");
    $sth->execute();

    while (my $ref = $sth->fetchrow_hashref()) {
        # set if records are found
        $found = 1;

        # set email variables 
        my $id = $ref->{'mail_queue_id'};
        my $project_id = $ref->{'project_id'};
        my $type = $ref->{'type'};
        my $name = $ref->{'name'};
        my $email = $ref->{'email'};

        # create array with data
        my @select_arr = ($id, $project_id, $type, $name, $email);

        # start thread to send mail
        my $t = threads->new(\&sendmail, @select_arr);
        push(@threads,$t);
    }

    foreach (@threads) {
        # mail_queue_id
        my $id = $_->join;

        print "set email $id in queue inactive\n";  

        # set mail_queue record inactive -> MYSQL(event) mailqueue cleanup every 10 minutes
        my $sth = $dbh->prepare("UPDATE mail_queue SET active = 0 WHERE mail_queue_id = ? ");
        $sth->execute($id);
    }

    if($found eq 1) { # return rows in mail_queue < 1

        sleep(10);
        &start_threads;
    }
    else { # skip thread, wait 1 minut = sleep(1) to select new rows;
        sleep(30);
        &start_threads;
    }
}

# prepare send e-mail
sub sendmail {
    my @select_arr = @_; 

    # queue variables
    my $id = $select_arr[0];
    my $project_id = $select_arr[1];
    my $type = $select_arr[3];
    my $name = $select_arr[4];
    my $email = $select_arr[5];

    print "started sending email " . $id . " \n";

    # call function which sends the mail out 
    my $send = &email(@select_arr);

    # if mail is sent
    if($send eq 1) {
        print "done with sending email " . $id . "\n";

        sleep (1);

        # return unique id
        return $id;
    }
}

&start_threads;

最佳答案

您正在做的事情可能相当昂贵 - 当 Perl 线程时,它会创建您的进程的副本 - 包括导入的模块、数据状态等。如果您的表返回很多行,您将很快耗尽内存。

您可以通过执行 ps -efT 来查看这一点。

对于你正在做的事情,你做事的方式是一个坏主意。我建议两种选择:

  • 坚持使用线程,开始一个固定的数字(比如 10)并使用 Thread::Queue序列化您的数据。这限制了进程副本的数量和线程启动开销。

  • 切换到使用fork()Parallel::ForkManager或多或少会在这里做你想做的事。 fork() 是一种更有效的进程克隆方式 - 它只会按需复制内存,这意味着您的子进程要小得多。

我将提供一些我在之前的回答中给出的例子: Perl daemonize with child daemons

关于mysql - 带线程的 Perl 邮件队列 'out of memory',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26572016/

相关文章:

bash - 递归循环特定的扩展名和子文件夹

mysql - Tomcat Jdbc连接池事件连接

php - Codeigniter - 将列的值传递给另一个表的列

python - 带装饰器的线程

c++ - 包含 boost/thread.cpp 时出现编译错误

bash - 从行号grep中提取最小值和最大值

c# - MySql Connection 未使用 .net MySql Connector 关闭

python - sqlalchemy 中是否有一种解决方法可以在没有任何主键的情况下从数据库加载表?

Java : How to implement Multi-Threading into a recursive folder size finder algorithm?

linux - 如何在不终止正在运行的作业的情况下终止 GNU parallel?