Анализ производительности WSGI-серверов: вернем uWSGI на место

    На прошлой неделе был опубликован перевод статьи двухлетней давности Анализ производительности WSGI-серверов: Часть вторая, где незаслужено был обделен славой uWSGI.


    Необходимо срочно перепроверить тесты!



    Цели


    Я давно использую uWSGI, и хочу показать, что он не такой плохой, как описано в тестах 2016 года.
    Изначально, я просто хотел воспроизвести тесты, и разобраться, что не так с uWSGI.
    В коде отсутствуют версии используемых пакетов и модулей.


    Поэтому, запустить тесты и получить аналогичные результаты — не получиться.
    Далее мой квест, по запуску тестов и сравнение результатов на графиках.
    По просьбе читателей, добавлен NginX Unit.


    Шаги


    wrk 4.1.0


    Найти спеки, пропатчить, собрать
    Информация добавлена в readme.rd.


    docker stats


    За 2 года изменился вывод статистики.


    Была добавлена вторая колонка NAME, и это сломало парсер статистики.


    Что бы через два года не встретить подобную проблему, будем использовать форматированный вывод:


    - docker stats > "$BASE/$1.$2.stats" &
    + docker stats --format "{{.CPUPerc}} {{.MemUsage}}" > "$BASE/$1.$2.stats" &

    И соответственно, немного упростим код парсера.


    debian


    Сейчас latest образ debian соответствует версии 9.5, отобразим это в Dokerfile:


    - FROM debian
    + FROM debian:9.5

    В апреле 2016 latest соответствовал версии 8.4


    Тем не менеее, Аpache остался почти тем-же: сейчас версия Apache 2.4.25, а в 2016 это был Apache 2.4.10.


    cherrypy tornado uwsgi gunicorn bjoern meinheld mod_wsgi


    Даже нет смысла говорить о том, что модули изменились.
    Укажем текущие версии:


    - RUN pip install cherrypy tornado uwsgi gunicorn bjoern meinheld mod_wsgi
    + RUN pip install cherrypy==17.4.0 \
    +                 uwsgi==2.0.17.1 \
    +                 gunicorn==19.9.0 \
    +                 bjoern=2.2.3 \
    +                 meinheld==0.6.1 \
    +                 mod_wsgi==4.6.5

    Что там делает tornado, где запуск wsgi-файл для запуска tornado? Удаляем артефакт.
    Было бы не плохо вынести это в отдельный requirements.txt, но пока оставим так.


    cherrypy -> cheroot.wsgi


    Как было показно выше, актуальная версия 17.4.0.
    В апреле 2016 вероятно использовалась версия v5.1.0.
    А в 2017 году, в версии 9.0 произошли изменения, что отразилось на импорте сервера:


    - from cherrypy import wsgiserver
    - server = wsgiserver.CherryPyWSGIServer(
    + from cheroot.wsgi import Server as WSGIServer
    + server = WSGIServer(

    Socket errors: read 100500


    После описанных выше правок был запущен первый полноценный тест.
    Результаты были хороши: uwsgi выдавал не 3...200, а 7500...5000 запросов в секунду.
    Но при детальном рассмотрении полученных графиков, оказалось, что все ответы wrk детектил как ошибки чтения.


    После проверки десятка ключей запуска uwsgi, выяснилось, что ошибок нет при включении http1.1: --http-keepalive и --http11-socket.
    Причем, первый дает 7500...5000 запросов в секунду, а второй стабильные 29 тысяч!


    что же изменилось в uWSGI на данный момент


    Наиболее вероятно, что в августе 2016 использовалась версия uWSGI 2.0.12 (20151230).
    После, в мае, вышла uWSGI 2.0.13.


    Это было знаковое событие, но проблему производительности по версии wrk это не решало вплоть до 2018 года, выходом uWSGI 2.0.16:


    Back-ported HTTP/1.1 support (--http11-socket) from 2.1

    Вот почему uWSGI рекомендовали использовать с NginX,
    А почему это важно в рамках статьи, можно понять из этого тикета 2012 года.


    Почему тогда были такие результаты


    Я пробовал такие версии:


    • 2.0.12 для debian 8.4, на девятке она не собирается из-за свежей openssl.
    • 2.0.13...2.0.17 для debian 8.4 и 9.5

    Но таких плохих результатов, как 3...200 запросов в секунду, мне получить не удалось.
    Внимание привлекла строка запуска приложения:


    uwsgi --http :9808 --plugin python2 --wsgi-file app.py --processes ...

    Указание подключаемого плагина, говорит об установке uwsgi из репозитория, а не pip.
    Это может свидетельствовать об отсутствии у автора необходимого опыта работы с данным стеком.


    Поэтому, допускаю несколько возможностей:


    • тест каждого из uwsgi-серверов производился по отдельности, в разное время.
    • имел место какой-то конфликт системной версии uwsgi, и установленой через pip.
    • версия wrk автора в 2016, имела какие-то особенности для работы по http1.0
    • uwsgi запускался с другим набором параметров
    • заказная статья, цифры с потолка.

    Какие результаты сейчас


    uWSGI на графиках несколько:
    Первые два uWSGI и uWSGIbase (v2.0.17.1), выполнялись в долгом тесте, со своими конкурентами, с параметрами:
    --http11 :9808 --processes 5 --threads 2 --enable-threads.
    --http11 :9808 --processes 5.
    Как показала практика, качественной разницы НЕТ, для теста приложения пустышки.


    И, отдельно, версиии uWSGI 2016 года:
    uWSGI-v2.0.12th-old и uWSGI-v2.0.12nt-old — соответственно v2.0.12 с тредами и без в контейнере debian 8.4.
    --http :9808 --http-keepalive --processes 5 --threads 2 --enable-threads
    --http :9808 --http-keepalive --processes 5


    RPS 2018 ALL
    uWSGI занимает 2е место, не снижая результатов при увеличении нагрузки.
    На третьем месте — NginX Unit.


    RPS 2018 LOW
    В low-сегменте uWSGI-v2.0.12 лучше всех, даже при увеличении нагрузки.


    LATENCIES 2018 ALL
    Тут видим, как не с лучшей стороны показал себя Unit.


    LATENCIES 2018 LOW
    uWSGI и CherryPy несомненные победители по latency.



    Эта картинка аналогична 2016-му году.



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



    А новый uWSGI, gunicorn, mod_wsgi — уверенно "держат планку", и это о многом говорит.



    Cтарые uWSGI начинают резко набирать ошибки уже после 300 открытых соединений.



    Unit и CherryPy — без ошибок!
    Bjoern начинает сдавать с 1000 соединений.
    А вот с новым uWSGI странности, начиная 200 соединений, мы получаем 50 ошибок, и число больше не увеличивается. Этот момент требует детального рассмотрения.


    Все данные собраны тут
    Все изменения кода можно увидеть в RP.


    Выводы


    uWSGI не так уж плох, или даже очень хорош!
    Если вам не нравятся результаты тестов WRK, попробуйте возпользоваться другими инструментами.

    Only registered users can participate in poll. Log in, please.

    Каким wsgi-сервером вы пользуетесь?

    • 64.3%uWSGI36
    • 39.3%gunicorn22
    • 0.0%meinheld0
    • 0.0%bjorn0
    • 3.6%cherrypy2
    • 5.4%NGINX-unit3
    • 5.4%tornado3
    • 10.7%другой вариант, напишу в комментариях6
    • +18
    • 5.6k
    • 9
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 9

      0
      Спасибо, сам хотел проверить, но вы спасли моё время.
      Общий вывод для себя сделал такой: даже не смотря на то, что uWSGI иногда проигрывает на некоторых тестах, он делает это не на порядок, и выдаёт более стабильные характеристики в зависимости от нагрузки, а значит пока с него некуда переезжать.
        0
        Еще есть unit от nginx, нет желание добавить его в сравнение?

          0

          Может быть, но не обещаю. Цель "отбелить uWSGI" — достигнута.
          Так я хотел написать и поставить точку.


          Но вот тут оказалась интересная статья.
          Тестировали ApacheBench, но там те-же знакомые цифры… 7500 и 30 000.
          Поэтому — да, интересно, будет.

            0

            Готово.
            Результаты в целом совпадают с https://itnext.io/performance-comparison-between-nginx-unit-and-uwsgi-python3-4511fc172a4c
            Но там нет показателей памяти и отклика, а это согласитесь, тоже важно.

          0
          Internet Information Services)
            0
            Пара вопросов:

            1. Почему ни в оригинальном бенчмарке, ни в свежем, не сконфигурирован thread_pool у CherryPy (по умолчанию 10 + только один процесс)?
            2. Аналогичный вопрос по meinheld серверу, его никто не запускает без gunicorn'а, см. официальную документацию.

            Выглядит очень странно, когда только gunicorn & uwsgi имеют относительно корректную конфигурацию в плане cpu/threads, а остальное предоставлено «из коробки», при условии, что практически все указанные сервера обычно запускаются под gunicorn. Как можно сравнивать uWSGI в конфигурации «PROCESSOR_COUNT * 2 + 1, да по 2 треда, пожалуйста»?

            Попробую поиграться и сделать PR. Было бы неплохо сравнить с Py3/PyPy (повлияет на некоторые сервера) и отдельно сравнить с ASGI (uvicorn тот же, или hypercorn)

            P.S. Тот же gunicorn default 1 thread per worker (не уверен, как повлияет, надо тестировать).
              +1
              Пара вопросов: — Почему… CherryPy… Аналогичный вопрос по meinheld ...

              ДА, в целом, я с вами согласен.
              Но, я в описал Свои Цели — это uWSGI. Были проделаны минимальные изменения кода автора, аналитика причин плохих результатов uWSGI 2016 и всежие результаты по методике автора.
              Кроме того, разныцы между uWSGI и uWSGIbase (без тредов) в этом тесте нет.
              Но, она будет, на реальном приложении…
              Поэтому не думаю, что что-то изменится при тюнинге CherryPy и meinheld.


              Попробую поиграться и сделать PR.

              Я обновил статью, добавлен NGINX Unit и PR автору оригинала.
              Можете отталкиваться от моего PR.
              Но заранее предупреждаю, запуск всех тестов — долгий процесс. Тестировал на ноуте без DE.

                0
                И у вас отлично получилось, спасибо за статью. Только век ASGI уже пришел, Andrew пилит Django в async стиле, есть Channels 2, есть куча ASGI серверов на вкус и цвет, да и событийные лупы разные бывают нынче. Видел попытку добавить поддержку ASGI в uWSGI, посмотрим, что выйдет. Спасибо еще раз!

            Only users with full accounts can post comments. Log in, please.