【问题标题】:Perl Mojolicious + PgAsync plugin -- Leaking database connections?Perl Mojolicious + PgAsync 插件——泄露数据库连接?
【发布时间】:2013-11-27 21:01:36
【问题描述】:

我正在使用 Mojolicious 和一个名为 pgAsync 的插件来侦听从 Postgres 数据库发出的 NOTIFY 事件。我目前拥有的代码运行良好,但我看到数据库连接的数量只会不断增加。

后端

#!/usr/bin/env perl

use Mojolicious::Lite;
use Mojo::IOLoop;
use Mojolicious::Plugin::PgAsync;

app->secret('awdawdawdawd');

plugin PgAsync => {dbi => ['dbi:Pg:dbname=;host=;port=;', '', '', {AutoCommit => 0, RaiseError => 1}]};

any '/api/listen' => sub {
  my $self = shift;

  my $saved_tx = $self->tx;

  Mojo::IOLoop->stream($self->tx->connection)->timeout(300);

  $self->res->headers->add('Content-Type' => 'text/event-stream');
  $self->res->headers->add('Cache-Control' => 'no-cache');
  $self->res->headers->add('Access-Control-Allow-Origin' => '*');

  # required for IE
  $self->write(" " x 2048);
  $self->write("\nretry: 2000\n\n");

  my $drain_cb;
  $drain_cb = sub {
    my $c = shift;
    $c->render_later;
    $c->tx($saved_tx);
    $c->pg_listen('foo', sub {
      my $notify = shift;
      my $payload = $notify->{payload};
      $c->write("id:1\ndata:$payload\n\n", $drain_cb);
    });
  };

  $self->pg_listen('foo', sub {
    my $notify = shift;
    my $payload = $notify->{payload};
    $self->tx($saved_tx);
    $self->write("id:1\ndata:$payload\n\n", $drain_cb);
  });

};

app->start;

如您所见,我需要做一些小技巧才能让它按我的意愿工作。 pg_listen 似乎在每次通话后都未定义回调。当我再次调用pg_listen 时,这导致了一个错误(因为它未定义),我不得不修改PgAsync::Db.pm 的第34 行来添加一个检查:

$self->callback->($notify_hash, $notify_hash);

->到->

$self->callback->($notify_hash, $notify_hash) if defined $self->callback

前端

我正在使用带有 EventSource 对象的 JavaScript 来监听来自 Mojolicious 脚本的推送通知:

var es = new EventSource("/api/listen");
var listener = function (event) {
  console.log(event.data);
};
es.addEventListener("open", listener);
es.addEventListener("message", listener);
es.addEventListener("error", listener);

问题

仔细观察,这个系统似乎在不断地创建更多的数据库连接:

  1. 从无到有,有1个数据库连接,这是我用select count(*) from pg_stat_activity;查看有多少数据库连接

  2. 我用 DEBUG_PG=1 morbo mojopush.pl 启动 morbo 和 Mojolicious 脚本。现在有2个数据库连接(第一个是psql中的me,第二个是morbo)

  3. 我用 EventSource 对象打开网页。它使用text/event-stream 的内容类型正确设置GET 请求并保持连接打开。现在有 3 个数据库连接

  4. 我进入psql并发送NOTIFY foo, 'test',Mojo脚本检测到它,网页显示'test.还有 3 个 db 连接。

  5. 我刷新页面,现在有 4 个数据库连接。我等待 300 秒不活动超时,然后创建另一个数据库连接,导致 5 个连接。

如果有人能帮助我指出正确的方向,那将不胜感激!

【问题讨论】:

    标签: perl postgresql mojolicious event-stream


    【解决方案1】:

    不是 100% 肯定,所以根据提供的信息,这有点猜测,但我想知道每个页面加载是否正在启动一个新的数据库连接,然后该连接正在侦听通知。如果是这种情况,我想知道 db 连接是否已从池中有效删除,并在下一页加载时创建。

    如果是这种情况,我的建议是有一个单独的 DBI 数据库句柄专门用于监听通知,以便这些在队列中不活动。这可能在您的页面工作流程之外完成。

    【讨论】:

      【解决方案2】:

      我知道这是迟到的答案,但我使用 Mojolicious 的时间不超过两周。这个问题似乎没有解决,我有一些关于 PgAsync 的观察可以分享。

      在使用 PgAsync 进行一些练习后,我在谷歌上搜索时发现了这篇文章。我还可以观察到“连接泄漏”,不是使用监听/通知案例,而是使用“pg”帮助程序执行一系列独立查询,类似于此处给出的场景:https://groups.google.com/forum/#!topic/mojolicious/titaWRImLt0

      特别是,当同时发出多个请求时会发生泄漏。同时,我可以看到两个同时连续运行的请求循环中的一些请求,留下了未完成的查询执行和超时。

      仍然不太了解插件机制,通常是 Mojo:: 事件处理,我猜可能刚刚释放的数据库连接可能太快被选择用于另一个请求。

      因此,在进行了一些或多或少的盲目黑客攻击之后,我尝试在数据库连接完成其请求和返回空闲池之间引入一个愚蠢的延迟。我通过更改这行代码来做到这一点:

      https://metacpan.org/source/ROMANENKO/Mojolicious-Plugin-PgAsync-0.03/lib/Mojolicious/Plugin/PgAsync/Db.pm#L49

      到:

      $reactor->timer(1 => sub { $self->make_free->($self) });
      

      在那之后,连接泄漏和不完整的请求都消失了。这绝对不是修复,而是一种解决方法。也许这也适用于您的情况。

      但是,我可以看到在执行查询时客户端断开连接 (Ctrl+C) 的情况下仍然存在连接泄漏。这种情况会使数据库连接在 db_pool 处“孤立”,并且永远不会返回到 db_free。

      除非作者更快,否则我希望更深入地研究插件的代码,找到真正的修复,并可能添加一些增强功能。我目前的工作非常需要这个插件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-18
        • 2014-02-25
        • 1970-01-01
        相关资源
        最近更新 更多