[personal profile] iamjaph
Haskell не перестает удивлять меня!
Есть старый проект https://github.com/kni/redis-sharding-hs-strict.
В нем для определение типа команды используется поиск по списку пар:
https://github.com/kni/redis-sharding-hs-strict/blob/master/RedisSharding.hs#L59

Давном-давно [livejournal.com profile] thesz посоветовал заменить это на дата-тип.

Заменил на:
 data CmdType = 
    CmdToAll         -- На все сервера
  | CmdToOne         -- На конкретные сервер
  | CmdToMany        -- На множество серверов. CMD key1 ... keyN
  | CmdToManyValues  -- На множество серверов. CMD key1 value1 ... keyN valueN
  | CmdToManyTimeout -- На множество серверов. CMD key1 ... keyN timeout (блокирующие команды)
 
 
 cmdType "PING"             = Just CmdToAll
 cmdType "AUTH"             = Just CmdToAll
 ....

Ожидал рост производительности, но получил ухудшение на 20-25%!

Измерял при следующих условиях, и, разумеется несколько раз и разной очередности:
 cpuset -l 0 ./redis_sharding --port=8090 --nodes=127.0.0.1:8081,127.0.0.1:8082,127.0.0.1:8083,127.0.0.1:8084 +RTS -s -N1 -A10M -qa
 redis-benchmark -p 8090 -n 10000 -c 10 -q -t set,get,mset -P 10

Вот результат профилирования (при профилировании замедление меньше).

Старая версия:
 COST CENTRE                             MODULE                              %time %alloc
 throwSocketErrorIfMinus1RetryMayBlock   Network.Socket.Internal              12.2    0.5
 endOfLine                               Data.Attoparsec.ByteString.Internal  11.5    7.5
 servers_sender                          RedisSharding                        10.0   13.2

А вот - новая с data CmdType:
 COST CENTRE                             MODULE                              %time %alloc
 cmdType                                 RedisParser                          12.5   12.4
 throwSocketErrorIfMinus1RetryMayBlock   Network.Socket.Internal              11.9    0.4
 endOfLine                               Data.Attoparsec.ByteString.Internal   9.2    6.4

Почему?!

UPDATE.
Загвоздка была, в том, что cmdType, так как много строк, поместил в другой файл, а не в тот, где case cmdType cmd of

И Haskell не смог оптимизировать. Когда все слил в один - скорость вернулась!!!

Date: 2016-09-29 01:18 pm (UTC)
From: [identity profile] iamjaph.livejournal.com
Как тут не готовые строки?

cmdType "PING" = Just CmdToAll

Я думал, что строки тут, как и тут

l = [("PING", 1), ...]

"готовые"....
А почему они не готовые в первом случае?



Date: 2016-09-29 01:45 pm (UTC)
From: [identity profile] thesz.livejournal.com
Право слово, я должен попросить объяснить мне дизайн первого и нового варианта.

А то я что-то упускаю, наверняка. А внимательно смотреть у меня нет сил. :(

Date: 2016-09-29 02:30 pm (UTC)
From: [identity profile] iamjaph.livejournal.com
Первый вариант:

cmd_type = [("PING", 1), ...]

case lookup k cmd_type of Just v -> ...

Второй вариант:

data CmdType = CmdToAll | ...

cmdType "PING" = Just CmdToAll

case cmdType k of Just v -> ....

Только что сделал простые бенчмарки этих вариантов.
Ведут себя одинаково, второй даже быстрей, как и думал.

Загвоздка в том, что в приложении, а не в тесте, скорости другие.

Ну, да ладно....

Date: 2016-09-29 04:24 pm (UTC)
From: [identity profile] thesz.livejournal.com
А что дальше происходит с данными в первом и втором вариантах?

Я подозреваю, что часть исходной строки просто переносится в выход каким-то образом в первом, а во втором варианте выход создаётся "из чистого воздуха", приводя новой работе CPU по созданию и убиранию данных.

Причина загвоздки как раз в разнице в оставшейся части программы.

Date: 2016-09-29 05:07 pm (UTC)
From: [identity profile] iamjaph.livejournal.com
А другой разницы нет.
Вся разница - объявление типа и изменение case для выбора логики работы:
-   case lookup cmd cmd_type of
-           Just 1 -> do -- На все сервера
+   case cmdType cmd of
+           Just CmdToAll -> do -- На все сервера
....
-           Just 2 -> do -- На конкретные сервер
+           Just CmdToOne -> do -- На конкретные сервер
....

И все.
Edited Date: 2016-09-29 05:08 pm (UTC)

Date: 2016-09-29 05:12 pm (UTC)
From: [identity profile] thesz.livejournal.com
Дайте же мне побольше контекста.

Например, определение команд.

Его же на гитхабе нет.

Date: 2016-09-30 03:24 am (UTC)
From: [identity profile] iamjaph.livejournal.com
Тут команда просто строка из протокола http://redis.io
PING посылается на все сервера-ноды.
SET k v - на ноду, которую вычислили по ключу k

Есть догадка!
А может когда пишешь функцию
cmdType "PING" = Just CmdToAll
, то не смотря на {-# LANGUAGE OverloadedStrings #-}
тут "PING" - это обычные строки, а не ByteString.
Тогда все становиться на свои места: большое значение MUT.

Date: 2016-09-30 11:14 am (UTC)
From: [identity profile] thesz.livejournal.com
Догадка, скорее, неправильная.

Я склоняюсь к тому, что команда пересоздаётся.

Date: 2016-09-30 12:06 pm (UTC)
From: [identity profile] iamjaph.livejournal.com
Нашел.
Изменил ответ cmdType с
cmdType :: ByteString -> Maybe CmdType
на
cmdType :: ByteString -> Maybe Integer
И скорость вернулась на свои места.

Получается из-за типа данных.
data CmdType = CmdToAll | CmdToOne | CmdToMany | CmdToManyValues | CmdToManyTimeout

Но почему же?

Date: 2016-10-03 06:17 am (UTC)
From: [identity profile] iamjaph.livejournal.com
Загвоздка была, в том, что cmdType, так как много строк, поместил в другой файл, а не в тот, где case cmdType cmd of

И Haskell не смог оптимизировать. Косда все слил в один - скорость вернулась!!!

Profile

iamjaph

March 2025

S M T W T F S
      1
2345678
9101112131415
16171819 202122
23242526272829
3031     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 11th, 2025 06:06 pm
Powered by Dreamwidth Studios