- PVSM.RU - https://www.pvsm.ru -
asyncpg [1] — новая Python open-source библиотека для работы с PostgreSQL. Она была написана с использованием syncio и Python 3.5. asyncpg — самый быстрый драйвер для работы с PostgreSQL среди похожих реализаций в на Python, NodeJS и Go.
Мы создаем EdgeDB [2] — базу данных нового поколения, с PostgreSQL на бэкенде. Нам необходима высокая производительность, низкая задержка доступа и дополнительные возможности самого PostgreSQL.
Самый очевидный вариант – использовать psycopg2 — популярнейший драйвер Python для работы с PostgreSQL. У него отличное комьюнити, он стабильный и проверенный временем. Также есть aiopg, который реализует асинхронный интерфейс, поверх psycopg2. Тогда очевиден вопрос — зачем писать свой велосипед? Короткий ответ: производительность и поддержка возможностей PostgreSQL. Ниже мы рассмотрим это более детально.
Наше основное недовольство psycopg2 заключалось в посредственной обработке различных типов данных, в т.ч. массивов и составных типов. Множество различных типов данных — одна из отличительных особенностей PostgreSQL. И еще, из коробки psycopg2 поддерживает только простые типы данных — целые числа, строки, время и даты. Это заставляет писать свои типы, для чего-то другого.
Основная же причина этого кроется в том, что psycopg2 обменивается с сервером БД данными в текстовом формате, из-за чего немало данных приходится парсить, особенно это касается составных типов данных.
В отличие от psycopg2, asyncpg использует бинарный I/O протокол PostgreSQL, который, помимо преимуществ в производительности, также имеет родную поддержку контейнерных типов данных (массивы, диапазонные и составные типы).
Также asyncpg использует подготовленные операторы PostgreSQL. Это отличная возможность для оптимизации, так как это позволяет избежать повторного парсинга, анализа и построения плана запроса. Кроме того, asyncpg кэширует I/O данные для каждого подготовленного оператора.
Подготовленные операторы в asyncpg могут быть созданы и использоваться напрямую. Они предоставляют API к получению и анализу результатов запроса. Большинство методов запроса создают подключение напрямую, и asyncpg создает и хранит в кэше подготовленные запросы.
Другой важной особенностью asyncpg является отсутствие зависимостей. Непосредственная реализация протокола PostgreSQL означает, что вам не нужно устанавливать libpq. Достаточно просто выполнить pip install asyncpg
. Кроме того, мы предоставляем пакет и для ручной сборки на Linux и macOS (Windows планируется в будущем).
Вскоре нам стало ясно, что реализуя протокол PostgreSQL напрямую, мы можем добиться значительного увеличения в скорости. Наш прошлый опыт [3] с uvloop показал, что с помощью Cython можно создавать эффективные и производительные библиотеки. asyncpg полностью написан на Cython с управлением памятью и высокой оптимизацией. В результате asyncpg оказался в среднем в 3 раза быстрее, чем psycopg2 (или aiopg).
Так же, как и для uvloop [4], мы создали отдельную утилиту для тестирования pgbench [5] и создания отчетов для asyncpg и других реализаций драйвера PostgreSQL. Мы замеряли скорость выполнения запроса (строк в секунду) и задержку. Основная цель этих тестов — узнать накладные расходы для данного драйвера.
Если честно, то все тесты были запущены в одном потоке (GOMAXPROCS=1 в случае с Golang) в асинхронном режиме. Python драйвера были запущены с использованием uvloop.
Данное тестирование проходило на чистом сервере с данной конфигурацией:
Используемые драйвера:
Графики показывают средние значения по результатам, полученные запуском 4 различных типов запросов:
— Прямой запрос по выбору всех строк из таблицы pg_type (около 350 строк). Он довольно близок к общему числу запросов приложения. В этом тесте asyncpg показывает указанную в заголовке производительность в 1 млн строк в секунду. Подробнее. [6]
— Запрос генерирует 1000 строк, состоящих из одного целого числа. Этот тест предназначен для просмотра производительности при создании записей и получении результата. Подробнее. [7]
— Запрос возвращает 100 строк, каждая из которых содержит 1 КБ бинарных данных (blob). Это стрессовый I/O тест. Подробнее. [8]
— Запрос возвращает 100 строк, каждая из которых содержит массив из 100 целых чисел. Этот тест предназначен для проверки скорости декодирования массивов. Здесь asyncpg оказался медленнее, нежели более быстрая реализация на golang. Это связанно с расходами на создание и удаление кортежей в Python. Подробнее. [9]
Мы уверены, что с помощью Python возможно создавать высокопроизводительные и масштабируемые системы. Для этого нам нужно приложить усилия к созданию быстрых, высококачественных драйверов, циклов событий, фреймворков.
asyncpg — один из шагов в этом направлении. Это результат осмысленного проектирования, питаемый нашим опытом создания uvloop, а также эффективного использования Cython и asyncio.
Перевод статьи 1M rows/s from Postgres to Python [10]
Автор: seleznev_nvkz
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/219839
Ссылки в тексте:
[1] asyncpg: https://github.com/magicstack/asyncpg
[2] EdgeDB: https://edgedb.com/
[3] прошлый опыт: https://magic.io/blog/uvloop-blazing-fast-python-networking/
[4] uvloop: https://github.com/magicstack/uvloop
[5] pgbench: https://github.com/magicstack/pgbench
[6] Подробнее.: https://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/report.html#bench1
[7] Подробнее.: https://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/report.html#bench2
[8] Подробнее.: https://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/report.html#bench3
[9] Подробнее.: https://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/report.html#bench4
[10] 1M rows/s from Postgres to Python: https://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/
[11] Источник: https://habrahabr.ru/post/317394/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.