вторник, 8 января 2013 г.

Redis Sharding: Lazy vs Strict

Так как у Redis команда KEYS достаточна требовательна к CPU, а сам Redis - однопоточен, где-то два года назад для одного проекта меня попросили распараллелить запросы к Redis на несколько экземпляров (node), по одному на каждое ядро CPU.

Так появился Redis Sharding (https://github.com/kni/redis-sharding). Он был написан на Perl. Но так как Perl не отдает память назад OS, при обработке команд MSET с большим количеством длинных ключей и значений процесс Redis Sharding разрастался в размерах и оставался таким.

В связи с этим появилась Haskell версия Redis Sharding (https://github.com/kni/redis-sharding-hs). Она не только красиво работала с памятью, но была быстрей в 2-4 раза.

Haskell версия была основана на Data.ByteString.Lazy. Ленивы строки очень удобны в работе. Ведь у нас есть как-бы все данные сразу, а фактически они подчитываются из сокета по мере необходимости. Однако что-бы отправкой данных из ленивой строки в сокет, создается массив из обычных ByteString, для которых и вызывается системный вызов writev. Именно эти дополнительные выделения памяти и копирование данных из Lazy ByteString в Strict ByteString существенно снижали производительность Redis Sharding.

И так, спустя два года, я решил попытаться ускорить Redis Sharding, используя Strict версию ByteString и Data.Attoparsec. Так под новогодние праздники появилась Strict версия Redis Sharding (https://github.com/kni/redis-sharding-hs-strict).

Однако существенно увеличения производительности добиться не удалось.
Strict версия на маленьких данных быстрей до 20% и в несколько раз меньше занимает памяти, но с ростом размера данных, это преимущество все уменьшается, а потребление памяти возрастает и перегоняет Lazy версию.

По видимому, это происходит из-за того, что при парсинге иногда происходит объединение нераспарсенного хвоста со следующим входным буферов.

Если сделать размер входного буфере не 4k, а 32k (это размер defaultChunkSize для Data.ByteString.Lazy), то скорости одинаковые, но Strict версия все еще использует меньше памяти (на 30%), но с ростом размера данных lazy версия начинает потреблять меньше памяти.


Вывод.
Когда размеры порций данных меньше, чем размер оптимального буфера, то предпочтительней Strict версия. Иначе - Lazy.

Комментариев нет:

Отправить комментарий