воскресенье, 13 апреля 2014 г.

Оценка производительности aiozmq

Сделал "пузомерку" для сравнения производительности aiozmq и просто pyzmq.

aiozmq использует pyzmq в своих внутренностях и стало интересно узнать, какие тормоза добавляет связка aiozmq + asyncio по сравнению с "простыми zmq сокетами".

Тест делался для пары DEALER/ROUTER (RPC) в разных режимах.

Результаты запуска измерителя производительности:

(aiozmq)andrew@tiktaalik2:~/projects/aiozmq (master)$ python benchmarks/simple.py -n 10000
Run tests for 10*10000 iterations: ['aiozmq.rpc', 'core aiozmq', 'single thread raw zmq', 'single thread zmq with poller', 'zmq with threads']
..................................................

Results for aiozmq.rpc
RPS: 2469,   average: 0.405 ms

Results for core aiozmq
RPS: 5064,   average: 0.197 ms

Results for single thread raw zmq
RPS: 9895,   average: 0.101 ms

Results for single thread zmq with poller
RPS: 12574,  average: 0.080 ms

Results for zmq with threads
RPS: 9702,   average: 0.103 ms

zmq шустрее, естественно. Обработка request-response на zmq в одном потоке примерно вдвое быстрее той же работы, которую делает aiozmq на своих транспортах и протоколах, плюс еще asyncio добавляет тормозов.

Даже на нитях (threads) zmq уверенно побеждает. В этом заслуга libzmq, которая создает свой внутренний thread для обработки send и в результате для Питона send получается неблокирующим.

aiozmq.rpc добавляет тормозов по сравнению с aiozmq.core примерно в два раза. Я считаю это приемлемой платой за прозрачную упаковку/распаковку аргументов вызываемой функции, поиск обработчика на стороне сервера, проверку сигнатур для параметров, пробрасывания исключения назад вызывающей стороне.

Если всю эту необходимую работу сделать на zmq -- думаю, получится не сильно быстрее.

Результат

aiozmq.core дает примерно 5000 requests per second, что довольно неплохо.

aiozmq.rpc способен выжать примерно 2500 rps.

То есть если вас устраивает обработка запроса к aiozmq.rpc меньше чем за одни милисекунду -- aiozmq вам подойдёт.

И, самое главное: если на стороне RPC сервера вы делаете запросы в redis, mongo, postgresql, mysql или обращаетесь каким другим внешним для вашего процесса ресурсам -- скорее всего тормоза будут именно в этом месте.

Почему это не очень важно

Да, я знаю что redis неимоверно быстр: показывает 70000+ rps на простых запросах. Но скорее всего вам таких обращений потребуется несколько, и делать вы их будете из питона используя библиотеку вроде asyncio-redis.

Которая добавляет немало приятных плюшек и расплачивается за это производительностью.

Это не значит что за скорость не нужно бороться. Просто для меня aiozmq показала ожидаемые и вполне неплохие результаты. Самый простой путь к ускорению лежит в оптимизации asyncio путём создания optional C Extensions для event loop и selector. Возможно, я этим займусь, или сделают другие Python Core Developers. Как это произошло с модулем io из стандартной библиотеки: после того как его переписали на С в Python 3.2 получили 30% ускорение.

6 комментариев:

  1. Если убрать queue то результат для aiozmq улучшится.

    ОтветитьУдалить
  2. Андрей, спасибо за проделанную работу!

    Могли бы вы добавить описание машины и ОС на которой производили тестирование?

    И, если возможно, добавьте возможность запуска отдельно сервера и отдельно клиента для каждого теста, чтобы была возможность погонять на физически разных машинах в сети и возможность выбора протокола (tcp://, ipc://, inproc://).

    ОтветитьУдалить
  3. Олег, я не понял о какой queue идет речь.

    ОтветитьУдалить
  4. В тесте "core aiozmq" используется queue, а в "zmq" нет. Он дает оверхед.
    Вот вариант без queue: https://gist.github.com/anonymous/10650805

    В результате "core aiozmq" вырос от 4600rps до 6100rps против 5600rps для zmq (single/threaded).
    Т.е. queue "съел" 25% производитльности.
    Так же заметил, что при этом варианте, результаты для pyzmq немного проседают.

    ОтветитьУдалить
  5. Kentzo: машинка самая обычная. На разных машинах меняются конкретные цифры но не их соотношение.

    Другие протоколы делать не очень-то хочу прямо сейчас. С другой стороны если будет pull request -- вклею с удовольствием.

    Раздельный клиент и сервер мелать хочется еще меньше. Просто потому что, как мне кажется, получившимся инструменом будет не очень удобно пользоваться. Опять же если будет толковый pull request....

    ОтветитьУдалить