среда, 24 декабря 2014 г.

HTTP content encoding

Решил прикрутить к AnyEvent::HTTP Accept-Encoding и к LWP в response_data handler, но перед этим выяснить какой процент серверов понимает gzip и deflate.

deflate кодирование реализовано в серверах двумя способами и поэтому авторы nginx отказались от его реализации и используют только gzip
(http://sysoev.ru/mod_deflate/readme.html#mehtods).

Под рукой оказался файл с 53587 доменами со следующим распределением по зонам:
  29244 com    1000 de      627 it
   3102 org     935 info    553 ca
   2786 uk      861 nl      504 si
   2734 net     853 au      467 fr
   1315 ru      682 br      368 ua

Для каждого домена запрашивал HTTP содержимое с указанием "Accept-Encoding" в трех различных вариантах: "gzip, deflate" (приоритет gzip), "deflate, gzip" (приоретет deflate) и "deflate". Результаты как закодировал ответ сервер представлены в нижеприведенной таблице (прочерк означает, что сервер вернул не закодированное содержимое):
             | "gzip, deflate" | "deflate, gzip" | "deflate"
 ------------|-----------------|-----------------|----------
 -           |     22888       |     22764       |  50462
 gzip        |     30612       |     30442       |    145
 deflate     |        67       |       361       |   2959
 iso-8859-1  |         1       |         1       |      1
 none        |        16       |        16       |     16
 none;       |         1       |         1       |      1
 UTF-8       |         2       |         2       |      2

Как видим, можно ограничиться поддержкой лишь одного gzip.

Заодно узнал популярность серверов:
                Все зоны | ru зона | ua зона
 ------------------------|---------|--------
 Apache            27327 |     978 |    443 
 nginx              6924 |     922 |    332
 Microsoft-IIS      6886 |     323 |    148
 -                  6116 |     212 |    103

пятница, 13 июня 2014 г.

COW in perl-5.20

В perl-5.20 реализовали механизм копирования при записи (copy-on-write) для строк. Теперь при присвоении одному скаляру значения другого, копирования буфера строки сразу не происходит. Это значительно повышает производительность и снимает необходимость передачи аргументов функций по ссылке (если они не будут изменяться).

Сравним скорость вызова подпрограмм с различными комбинация передачи параметра и возвращения результата для предыдущей версии perl и для версии с COW:
> perlbrew use perl-5.18.2
> perl ref_and_val.pl
                  Rate val -> val   val -> ref   ref -> val   ref -> ref  
val -> val     68213/s           --         -51%         -51%         -97%
val -> ref    138122/s         102%           --          -1%         -93%
ref -> val    139276/s         104%           1%           --         -93%
ref -> ref   2000000/s        2832%        1348%        1336%           --

> perlbrew use perl-5.20.0
> perl ref_and_val.pl
            (warning: too few iterations for a reliable count)
            (warning: too few iterations for a reliable count)
            (warning: too few iterations for a reliable count)
                  Rate ref -> val   val -> val   ref -> ref   val -> ref  
ref -> val   2083333/s           --         -17%         -21%         -29%
val -> val   2500000/s          20%           --          -5%         -15%
ref -> ref   2631579/s          26%           5%           --         -11%
val -> ref   2941176/s          41%          18%          12%           --
Результаты впечатляют, так как длина тестируемой строки 100000 символов!

А теперь возьмем реальное приложение. Оно сетевое, занимается "перекладыванием байтиков" с одного источника в 4 на основе srs32.
Ниже приведены количество запрос в секунду для 3 различных типов запросов в простом и pipeline режимах. Уточнение: сеть не является узким местом.
                 1     2     3
perl-5.14.4   7272  6134  3886
perl-5.18.2   7610  6439  4139
perl-5.20.0   7581  6459  4338

pipeline mode:
perl-5.14.4  21141 13869  5998
perl-5.18.2  21367 14025  6269
perl-5.20.0  21598 14367  6518
Как видим, в реальном приложении выигрыш от COW не заметен.

понедельник, 12 ноября 2012 г.

Деструкторы для замыканий, часть 2

Первая часть.

А если замыкание используется лишь в самом начале блока, то рациональней сразу после использования освободить ресурсы, а не в конце.

 use Carp;

 sub with_foo {
  my $foo = shift;
  my $sub = shift;
  print "INIT\n";
  my $destroyed = 0;
  my $closure = sub {
   unless ($destroyed) {
    $foo += shift;
    print $foo, "\n";
   } else {
    carp "Already destroyed";
   } 
  };
  my $destructor = sub {
   unless ($destroyed) {
    $destroyed = 1;
    print "DESTROY\n";
   } else {
    carp "Already destroyed";
   }
  };
  eval { $sub->($closure, $destructor) };
  $destructor->() unless $destroyed;
 }
 
 {
  with_foo(3, sub {
   my ($foo, $_foo) = @_;
   $foo->(1);
   $foo->(1);
   $foo->(2);
   $foo->(2);
   $_foo->();
   print "END\n"
  });
 }

четверг, 27 сентября 2012 г.

Very simple Multithreading with Continuation-passing style

{
 my @cc = ();

 sub cc(&) {
  my ($sub) = @_;
  push @cc, $sub;
 }

 sub cc_run() {
  while (my $sub = shift @cc) {
   $sub->();
   sleep 1;
  }
 }
}


sub first {
 my ($thread) = @_;
 print "$thread: 1 first\n";
 cc { third($thread) };
}

sub second {
 my ($thread) = @_;
 print "$thread: 2 second\n";
 cc { fourth($thread) };
}

sub third {
 my ($thread) = @_;
 print "$thread: 3 third\n";
 cc { first($thread) };
}

sub fourth {
 my ($thread) = @_;
 print "$thread: 4 fourth\n\n";
 cc { second($thread) };
}


cc { first("+") };
cc { second("*") };
cc_run;

понедельник, 24 сентября 2012 г.

Добавил quit в IPC::MPS

Очень плотно и давно использую модуль IPC::MPS для распараллеливания задач, но только сейчас понадобился выход из receive блока (из вложенного receive). Поэтому добавил подпрограмму quit.

пятница, 22 июня 2012 г.

Сравниваем MongoDB с MySql как Key-Value

Уговорили меня включить MongoDB в сравнение баз данных для Key-Value (смотрите PostgreSQL, MySql and MariaDB as Key-Value storage).

Оказалось, что MongoDB использует для хранения данных отображение памяти в файлы, поэтому для баз больше 2G, надо использовать 64-bit архитектуру.
После того как узнал это, надо было сразу выкинуть MongoDB, но все таки решил проложить. Поставил FreeBSD 9.0 amd64 и для чистоты эксперимента прогнал некоторые тесты для MySql и PostgreSql.

Решил тестировать только на коротких ключах (подробности смотрите тут BerkeleyDB и TokyoCabinet).

Обнаружил, что MongoDB занимает всю память, поэтому рекомендуют запускать его на выделенной машине.
Также, когда работает MongoDB, отзывчивость диска намного хуже, чем при работе других баз.

Результаты:
Чтение где-то в 2 раза медленней, чем у MySql.
Вставка также медленней, но периодически скорость вставки настолько замедляется, что даже не удается вставить запись в течении 30 секунд!

Поиск информации интернете показал, что это проблеме не связана с FreeBSD и наблюдается и под Linux.
А может это такой Perl модуль? Но ведь автор его является также разработчиком ядра MongoDB!

Некоторые значения полей отличаются после извлечения из базы. Может MongoDB чудит, считая, что это utf8.

Выводы.
MongoDB, с диском надо работать как с диском, а не как с памятью!
MySql и PostgreSql - фавориты. А в PostgreSql 9.2 появился index only scan, - так что PostgreSql еще повысил свою привлекательность.

Как люди работают с MongoDB? Или у них базы маленьких относительно оперативной памяти?