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

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

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

Transcript

  1. Asynchronous frameworks battle

  2. Участники 1. Tornado 2. sanic 3. aiohttp 4. japronto 5.

    vibora 6. FastAPI 7. starlette 8. Quart
  3. Турнирная сетка

  4. Benchmarks config CPU: AMD FX(™) 6300 3.5Ghz 1 core, MEM:

    2Gb, Ubuntu 18.04 Повышаем число соединений, пока не упремся в 80ms на персентиле 90. Как тестируем wrk -d300s -c100 -t1 --latency
  5. aiohttp vibora

  6. aiohttp • Не совсем framework • Миллион расширений (asyncpg, aiohttp_swagger,

    aiohttp_cors…) • Streaming responses • Websockets • Сигналы • Поддержка Context Variables (3.7 python) • ready for prod
  7. Vibora • Cython • Свой шаблонизатор (похож на jinja2) •

    Свои схемы (асинхронные) • Поддержка Streaming responses • Type hints components • Не готов к проду (Заново переписывается)
  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)
  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
  10. aiohttp vibora

  11. tornado starlette

  12. Tornado • Python • Streaming responses • Websockets • Свой

    шаблонизатор • Ready for prod • Ветеран труда
  13. Starlette • Python • Под капотом ASGI (uvicorn, hypercorn, daphne)

    • Не имеет жестких зависимостей. Опционально: ◦ aiofiles для FileResponse и StaticFiles ◦ jinja2 для Jinja2Templates ◦ ujson для UJSONResponse • CORS, GZip, Streaming responses • Ready for prod
  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
  15. tornado starlette

  16. sanic quart

  17. Sanic • Python • Свой вебсервер на uvloop + httptools

    • Не поддерживает HTTP2 • Поддерживает Websockets • Поддерживает стримы (request, response, file) • Нет встроенного шаблонизатора (есть jinja2-sanic) • Ready for prod
  18. Quart • Python • Под капотом ASGI • Асинхронная версия

    Flask (можно мигрировать с Flask) • Поддерживает Websockets и HTTP2 • Streaming responses • Шаблонизатор jinja2 • Ready for prod
  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
  20. sanic quart

  21. japronto FastAPI

  22. japronto • C • uvloop + picohttpparser • Конвейерный HTTP

    сервер • Поддержка Streaming responses • Не готов к проду
  23. FastAPI • Python • Под капотом ASGI (uvicorn, hypercorn, daphne)

    • Starlette + pydantic • Валидация данных на type hints • SwaggerUI • Ready for prod
  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
  25. japronto FastAPI

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

  27. Как тестируем echo "request" | vegeta attack -duration 300s -rate

    300 pyflame -p PID -s 300 | flamegraph.pl > result.svg
  28. starlette aiohttp

  29. starlette

  30. aiohttp

  31. starlette aiohttp

  32. sanic fastapi

  33. sanic

  34. fastapi

  35. fastapi

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

  37. • async/await интерфейс (можно и в trio, и в curio)

    • Общие серверные реализации (uvicorn, hypercorn, daphne, etc.) • Общие middlwares • Явное отделение сервера от приложения Немного про ASGI
  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, })
  39. Аргументы: • scope - словарь, содержащий информацию о входящем соединении

    • receive - канал, по которому можно получать входящие сообщения с сервера • send - канал, по которому отправляются исходящие сообщения на сервер
  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'*/*'] ] }
  41. ASGI всех победит?

  42. ASGI в PEP?

  43. Sanic тоже

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

    of Sanic v19.6.
  45. Результаты Победитель: Starlette Достойный противник: Sanic 3-4 место: aiohttp, FastAPI

    5-8 место: Tornado, Vibora, japronto, Quart
  46. Спасибо за внимание! Лайки, подписки, колокольчики :)