2 September 2017

klopp: (размахиваю кувалдой)
На самом деле не хак, а вовсе документированная возможность.

Имеем: около 500 тысяч (полмиллиона) селектов в час. Внутри каждого из них prepared statements кэшируются внутри DBI. В результате чего часов через 10 работы скрипт разбухает так, что всем вокруг плохеет. Отменить кэширование нельзя, изменить архитектуру тоже (на самом деле нужно, но это не в обозримом будущем, а работать должно сейчас).

Напрашивается простое решение: периодически закрывать соединение с базой (что автоматом очищает память) и соединяться снова. Но возникает вопрос: когда переподключаться? По времени не вариант, нагрузка плавающая, зависит от кучи внешних факторов и не прогнозируется. Значит, надо считать селекты. Но как? Выискивать по 50k cloc все места - убиться проще.

Вот тут и пригождается атрибут DBI::Callbacks. Сразу после соединения с базой вешаем на ключевые функции DBI коллбэки, в которых дёргаем счётчик (его ID передаётся явно, так как в общем случае можем подключаться не к одной базе):

sub set_dbh_callbacks
{
    my ( $self, $dbh, $counter_name ) = @_;
    
    $dbh->{Callbacks} = 
    {
        do                 => sub { ++$self->{$counter_name}; return; },
        prepare            => sub { ++$self->{$counter_name}; return; },
        selectrow_array    => sub { ++$self->{$counter_name}; return; },
        selectrow_arrayref => sub { ++$self->{$counter_name}; return; },
        selectrow_hashref  => sub { ++$self->{$counter_name}; return; },
        selectall_arrayref => sub { ++$self->{$counter_name}; return; },
        selectall_hashref  => sub { ++$self->{$counter_name}; return; },
        selectall_array    => sub { ++$self->{$counter_name}; return; },
        selectcol_arrayref => sub { ++$self->{$counter_name}; return; },
    };
    $self->{$counter_name} = 0;
}


Voilà! В любой (удобный нам) момент мы можем проверить значение счётчика и что-то предпринять. Значение, при котором это нужно делать, подбирается экспериментально :)

Expand Cut Tags

No cut tags

February 2018

S M T W T F S
    123
45678910
11121314151617
181920212223 24
25262728