Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Алексей Созыкин. Asynchronous frameworks battle

Алексей Созыкин. Asynchronous frameworks battle

Все мы любим, когда наше приложение работает быстро, обрабатывает много запросов, и код для него приятно и удобно писать. В асинхронном мире python для этих целей существуют такие фреймворки как tornado, aiohttp и sanic. Но так ли они хороши как популярны? Есть ли другие инструменты, способные с ними потягаться? За счет каких опций одни предпочтительней других? В своем докладе я постараюсь дать ответы на эти вопросы.

More Decks by Python Community Chelyabinsk

Other Decks in Technology

Transcript

  1. Asynchronous frameworks
    battle

    View Slide

  2. Участники
    1. Tornado
    2. sanic
    3. aiohttp
    4. japronto
    5. vibora
    6. FastAPI
    7. starlette
    8. Quart

    View Slide

  3. Турнирная сетка

    View Slide

  4. Benchmarks config
    CPU: AMD FX(™) 6300 3.5Ghz 1 core, MEM: 2Gb, Ubuntu 18.04
    Повышаем число соединений, пока не упремся в
    80ms на персентиле 90.
    Как тестируем
    wrk -d300s -c100 -t1 --latency

    View Slide

  5. aiohttp vibora

    View Slide

  6. aiohttp
    ● Не совсем framework
    ● Миллион расширений (asyncpg,
    aiohttp_swagger, aiohttp_cors…)
    ● Streaming responses
    ● Websockets
    ● Сигналы
    ● Поддержка Context Variables (3.7 python)
    ● ready for prod

    View Slide

  7. Vibora
    ● Cython
    ● Свой шаблонизатор (похож на jinja2)
    ● Свои схемы (асинхронные)
    ● Поддержка Streaming responses
    ● Type hints components
    ● Не готов к проду (Заново переписывается)

    View Slide

  8. Vibora type hints components
    from vibora import Vibora, Request, Response
    from vibora import Route
    class Config:
    def __init__(self):
    self.name = 'Vibora Component'
    app = Vibora()
    app.add_component(Config())
    @app.route('/')
    async def handler(request: Request, config: Config):
    current_config = request.get_component(Config)
    assert current_config is config
    return Response(config.name)

    View Slide

  9. Результаты
    RPS p50 p90 p99
    aiohttp c100 4324 22.14ms 25.42ms 39.41ms
    vibora c100 32867 2.89ms 3.76ms 9.48ms
    aiohttp
    cmax(300)
    4012 71.45ms 84.64ms 103.38ms
    vibora
    cmax(1000)
    30489 31.57ms 46.02ms 63.6ms

    View Slide

  10. aiohttp vibora

    View Slide

  11. tornado starlette

    View Slide

  12. Tornado
    ● Python
    ● Streaming responses
    ● Websockets
    ● Свой шаблонизатор
    ● Ready for prod
    ● Ветеран труда

    View Slide

  13. Starlette
    ● Python
    ● Под капотом ASGI (uvicorn, hypercorn, daphne)
    ● Не имеет жестких зависимостей. Опционально:
    ○ aiofiles для FileResponse и StaticFiles
    ○ jinja2 для Jinja2Templates
    ○ ujson для UJSONResponse
    ● CORS, GZip, Streaming responses
    ● Ready for prod

    View Slide

  14. Результаты
    RPS p50 p90 p99
    tornado c100 1875 51.7ms 57.93ms 73.29ms
    starlette c100 9674 9.8ms 11.16ms 22.44ms
    tornado
    cmax(140)
    1844 73.28ms 83.81ms 101.52ms
    starlette
    cmax(500)
    8625 50.22ms 87.02ms 122.54ms

    View Slide

  15. tornado starlette

    View Slide

  16. sanic quart

    View Slide

  17. Sanic
    ● Python
    ● Свой вебсервер на uvloop + httptools
    ● Не поддерживает HTTP2
    ● Поддерживает Websockets
    ● Поддерживает стримы (request, response, file)
    ● Нет встроенного шаблонизатора (есть
    jinja2-sanic)
    ● Ready for prod

    View Slide

  18. Quart
    ● Python
    ● Под капотом ASGI
    ● Асинхронная версия Flask (можно мигрировать
    с Flask)
    ● Поддерживает Websockets и HTTP2
    ● Streaming responses
    ● Шаблонизатор jinja2
    ● Ready for prod

    View Slide

  19. Результаты
    RPS p50 p90 p99
    quart c100 2476 38.57ms 43.93ms 73.07ms
    sanic c100 9976 9.4ms 11.12ms 22.33ms
    quart
    cmax(150)
    2228 61.01ms 80.58ms 145.75ms
    sanic
    cmax(500)
    9247 45.79ms 81.42ms 108.3ms

    View Slide

  20. sanic quart

    View Slide

  21. japronto FastAPI

    View Slide

  22. japronto
    ● C
    ● uvloop + picohttpparser
    ● Конвейерный HTTP сервер
    ● Поддержка Streaming responses
    ● Не готов к проду

    View Slide

  23. FastAPI
    ● Python
    ● Под капотом ASGI (uvicorn, hypercorn, daphne)
    ● Starlette + pydantic
    ● Валидация данных на type hints
    ● SwaggerUI
    ● Ready for prod

    View Slide

  24. Результаты
    RPS p50 p90 p99
    japronto
    c100
    28627 3.34ms 3.7ms 7.57ms
    fastapi c100 7033 13.71ms 14.89ms 24.69ms
    japronto
    cmax(1000)
    27920 30.05ms 51.16ms 71.47ms
    fastapi
    cmax(350)
    6470 49.68ms 72.86ms 107.72ms

    View Slide

  25. japronto FastAPI

    View Slide

  26. Турнирная сетка

    View Slide

  27. Как тестируем
    echo "request" | vegeta attack -duration 300s -rate 300
    pyflame -p PID -s 300 | flamegraph.pl > result.svg

    View Slide

  28. starlette aiohttp

    View Slide

  29. starlette

    View Slide

  30. aiohttp

    View Slide

  31. starlette aiohttp

    View Slide

  32. sanic fastapi

    View Slide

  33. sanic

    View Slide

  34. fastapi

    View Slide

  35. fastapi

    View Slide

  36. Турнирная сетка

    View Slide

  37. ● async/await интерфейс (можно и в trio, и в curio)
    ● Общие серверные реализации (uvicorn,
    hypercorn, daphne, etc.)
    ● Общие middlwares
    ● Явное отделение сервера от приложения
    Немного про ASGI

    View Slide

  38. async def read_body(receive):
    body = b''
    more_body = True
    while more_body:
    message = await receive()
    body += message.get('body', b'')
    more_body = message.get('more_body', False)
    return body
    Пример
    async def app(scope, receive, send):
    body = await read_body(receive)
    await send({
    'type': 'http.response.start',
    'status': 200,
    'headers': [
    [b'content-type', b'text/plain'],
    ]
    })
    await send({
    'type': 'http.response.body',
    'body': body,
    })

    View Slide

  39. Аргументы:
    ● scope - словарь, содержащий информацию о
    входящем соединении
    ● receive - канал, по которому можно получать
    входящие сообщения с сервера
    ● send - канал, по которому отправляются
    исходящие сообщения на сервер

    View Slide

  40. Scope
    {
    'type': 'http',
    'scheme': 'http',
    'root_path': '',
    'server': ('127.0.0.1', 8000),
    'http_version': '1.1',
    'method': 'GET',
    'path': '/',
    'headers': [
    [b'host', b'127.0.0.1:8000'],
    [b'user-agent', b'curl/7.51.0'],
    [b'accept', b'*/*']
    ]
    }

    View Slide

  41. ASGI всех победит?

    View Slide

  42. ASGI в PEP?

    View Slide

  43. Sanic тоже

    View Slide

  44. И вот теперь...
    ASGI mode is still in “beta” as of
    Sanic v19.6.

    View Slide

  45. Результаты
    Победитель: Starlette
    Достойный противник: Sanic
    3-4 место: aiohttp, FastAPI
    5-8 место: Tornado, Vibora, japronto, Quart

    View Slide

  46. Спасибо за внимание!
    Лайки, подписки, колокольчики :)

    View Slide