Асинхронные веб-фреймворки
Oct. 28th, 2015 11:21 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Народ, а кто может подсказать фреймворки для построения веб-страниц, в которых порядок генерации отдельных фрагментов не принципиален?
Вернее, требуется фреймворк, который выдает запрос в БД, а потом не дожидаясь его результата выдает следующий и т.д., а по мере получения результатов эти результаты обрабатывает. Причем с более-менее приличным синтаксическим сахаром.
Ну то есть что-то подобное есть в питоновских вариантах на базе Twisted и Tornado, но у twisted просто ужасный синтаксис в этом месте. Опять же Twisted и Tornado не самые популярные инструменты у веб-разработчков.
Дело в том, что выяснилось, что если не соблюдать четкую последовательность запрос-ответ-запрос-ответ, а вывалить в бэкенд сразу сотню запросов, а потом читать ответы, у постгреса даже на той же машине, получается ускорение примерно вдвое (на простых запросах, сводящихся к одному index range scan или index lookup).
Соответственно, хочется попытаться оторвать от libpq существующую там проверку на "если результат предыдущего запроса не прочитан, со следующим посылаем", и попытаться это применить на каких-то реальных задачах.
Подобные паттерны с сотнями легких запросов в рамках одного коннекта характерны как раз для динамических веб-фреймворков.
У меня возникло подозрение, что подобный стиль работы естественным образом вписывается во всякие решения на базе haskell или ocaml. Но я web-фреймворков на базе этих языков (да и самих-то языков) толком не знаю.
Вернее, требуется фреймворк, который выдает запрос в БД, а потом не дожидаясь его результата выдает следующий и т.д., а по мере получения результатов эти результаты обрабатывает. Причем с более-менее приличным синтаксическим сахаром.
Ну то есть что-то подобное есть в питоновских вариантах на базе Twisted и Tornado, но у twisted просто ужасный синтаксис в этом месте. Опять же Twisted и Tornado не самые популярные инструменты у веб-разработчков.
Дело в том, что выяснилось, что если не соблюдать четкую последовательность запрос-ответ-запрос-ответ, а вывалить в бэкенд сразу сотню запросов, а потом читать ответы, у постгреса даже на той же машине, получается ускорение примерно вдвое (на простых запросах, сводящихся к одному index range scan или index lookup).
Соответственно, хочется попытаться оторвать от libpq существующую там проверку на "если результат предыдущего запроса не прочитан, со следующим посылаем", и попытаться это применить на каких-то реальных задачах.
Подобные паттерны с сотнями легких запросов в рамках одного коннекта характерны как раз для динамических веб-фреймворков.
У меня возникло подозрение, что подобный стиль работы естественным образом вписывается во всякие решения на базе haskell или ocaml. Но я web-фреймворков на базе этих языков (да и самих-то языков) толком не знаю.
Go подойдёт
Date: 2015-10-28 06:27 pm (UTC)Вот простецкий код с демонстрацией: numWorkers "запросов" осуществляются параллельно, их "результаты" по мере поступления рендерятся в HTML.
После того, как все отработали, рендерер, который тоже работал параллельно, отдаёт результат в основной код.
Вот код на плэйграунде (http://play.golang.org/p/GxwDWPnFFb)
Как можно заметить, в коде нет ни одного события и ни одного колбэка.
В реальном коде были бы изменения:
* Горутины, которые делают запросы, получали бы инстанс sql.DB (который на самом деле инкапсулирует пул запросов) и выполняли запросы.
* Рендерер мог бы рендерить не в буфер, а напрямую в тело HTTP-ответа клиенту.
Если требуется упорядочить обработку запросов, то каждой горутине, которая делает запрос, нужно передать её номер, и она должна отдать его вместе с результатом. Дальше рендерер пытается частично упорядочить результаты, буферизуя их и отрисовывая то, что уже подобралось с подходящими номерами по возрастанию.
Нативный драйвер (чистый Go) хорошего качества под Постгрес есть (https://github.com/lib/pq).
К сожалению, локального инстанса Постгреса у меня нет, и в плейграунде с ним, понятно, тоже не поиграться.
Если что, готов ответить на вопросы (XMPP, e-mail kostix at 007spb.ru).
no subject
Date: 2015-10-28 08:42 am (UTC)Популярные асинхронные фремворки врядли существуют, асинхронность не самая простая для восприятия штука.
no subject
Date: 2015-10-28 08:49 am (UTC)По-моему, вообще генерация веб-страниц это самая ниша для функционального программирования - получаешь на вход некоторый набор параметров - URL заголовки запроса, состояние БД, возвращаешь строку.
no subject
Date: 2015-10-28 09:54 am (UTC)А так, для Эрланга есть асихнронный клиент к Постгресу, можно пользоваться
(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2015-10-28 09:20 am (UTC)no subject
Date: 2015-10-28 09:24 am (UTC)Хотя я уже не в курсе какие сейчас там новые фреймворки понаписали, может что прорывное и появилось.
no subject
Date: 2015-10-28 08:56 am (UTC)no subject
Date: 2015-10-28 09:03 am (UTC)no subject
Date: 2015-10-28 09:18 am (UTC)aiohttp, возможно, имеет перспективы, но судя по всему - еще не выросло.
no subject
Date: 2015-10-28 09:36 am (UTC)no subject
Date: 2015-10-28 09:42 am (UTC)no subject
Date: 2015-10-28 09:49 am (UTC)Потому что вообще идея пайплайнинга запросов возникла из соображений "ну многие noSQL-базы так делают, и это там дает выигрыш".
(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2015-10-28 11:40 am (UTC)Да и как это реализовать? Я могу представить асинхронный database backend для Django только так, что функции ORM работают c нативными SQL views вместо отложенных результатов. Но боюсь, тогда испортятся и переносимость, и производительность в тех случаях, когда это вообще будет возможно. Создание SQL view − довольно ресурсоёмкая штука afaik.
(no subject)
From:(no subject)
From:no subject
Date: 2015-10-28 11:14 am (UTC)Сохранять в шаблоне для вывода жёсткую привязку к БД для того, что бы шаблонизатор мог асинхронно разбить множество N полей шаблона на количество M (M<=N) запросов к БД и потом собрать полученные данные в страницу; либо в контролере по хитрой логике делать тоже самое - очень неслабое нарушение идеалогии MVC, с соотвествующими накладными расходами на написание/поддержание этого не-MVC`шного кода.
А так - в большинстве крупных проектов, по-моему, так или иначе используются мультиплексоры обращений к RDBMS (где K коннектов к RDBMS используются всеми частями системы через синхронные tcp запросы к серверу-мультиплексору либо через какой-то сервер очередей/протокол сообщений). Учитывая большое количество одновременно выполняющихся программ, получается почти такая же "упаковка" запросов, только без применения, собственно, асинхронных техник.
Возможно, где-то в области высокочастотного трейдинга именно асинхронное выполнение запросов востребовано (но, боюсь, им нужно больше детерминированности в скорости и порядке выполнения отдельных запросов - что немного противоречит асинхронности).
no subject
Date: 2015-10-28 11:46 am (UTC)И тут как раз ситуация, когда не нужно разбивать множество полезй шаблона на M<=N запросов в БД, а можно, не мудрствуя лукаво посылать для каждого поля отдельный запрос.
(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2015-10-28 11:19 am (UTC)no subject
Date: 2015-10-28 11:29 am (UTC)no subject
Date: 2015-10-28 12:07 pm (UTC)Попытайтесь собрать их в несколько более крупных запросов, производительносить вырастет не в 2 раза, а на порядки.
no subject
Date: 2015-10-28 12:19 pm (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:ZeroMQ from Python?
Date: 2015-10-28 04:29 pm (UTC)Вам придется разобраться, какую из patterns
использовать (например, Publish-Subscribe etc)
Тогда программки на обоих концах соединения
смогут издавать асинхронные запросы или публиковать
результаты - и их собирать в осмысленное.
В целом вы как бы хотите что-то вроде парадигмы
Эрланга, воплощенной в каком-то из Web Frameworks?
Присобачьте ZeroMQ (или её потомков по нисходящей),
и пользуйтесь существующим framework'ом.
.. если я понял вашу задачу правильно..
Re: ZeroMQ from Python?
Date: 2015-10-28 06:46 pm (UTC)У меня есть клиент-серверная база данных, и есть возможность выполнять в секунду вдвое больше запросов к этой базе ценой некоторого переупорядочения отправки запросов и разбора ответов к ней на клиенте. Соответственно вопрос заключается в том, какое приложение можно найти, которое сумеет это ускорение использовать.
Так что всякое middleware вроде MQ тут вообще ни при чем. Сокет соединяющий клиента и сервер - он сам по себе очередь, вернее даже две, поскольку данные по нему передаются в обе стороны.
no subject
Date: 2015-10-28 05:15 pm (UTC)node.js, которая вдоль и поперек должна быть асинхронной, по идее (надеюсь клиенты к СУБД для нее тоже асинхронные и используют тот же libuv для сокетов).
no subject
Date: 2015-10-28 06:55 pm (UTC)Там что ли ORM отображающий реляционную базу в набор REST-объектов?
Ну так к это совершенно незрелищно в плане демонстрации.
(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2015-10-29 07:03 am (UTC)no subject
Date: 2015-10-29 07:32 am (UTC)Асинхронные-то циклы обработки событий есть сейчас на всех платформах, как и сопрограммы (yield), синтаксические сахары вроде Promise и т.п. Т.е. при желании везде можно в две строчки навертеть, была бы только необходимость...