каков хороший способ интеграции сторонних асинхронных API с Cap'n Proto RPC?

У меня есть сервер Linux, который обрабатывает запросы Cap'n Proto RPC. Некоторые из этих запросов должны пересылать данные в запросе на другой сервер, на котором запущен брокер Kafka. Библиотеки librdkafka и Cap'n Proto KJ могут использовать poll(), поэтому я думаю, что ОС обеспечит их асинхронную работу, но я не уверен, что дальнейшая интеграция требуется или полезна. У кого-нибудь есть опыт в этом?

Вопрос немного шире, чем те особенности, которые я перечислил. Есть и другие API, которые я могу вызвать в будущем из Cap'n Proto RPC, поэтому любые общие рекомендации будут оценены.


person James Fremen    schedule 14.10.2015    source источник


Ответы (1)


К сожалению, это не так просто. Да, они обе используют poll(), но проблема в том, что только одна библиотека будет вызывать poll() в каждый момент времени, и только эта библиотека фактически будет получать какие-либо события, а другая застревает. Это классическая проблема с библиотеками циклов событий — по умолчанию их нельзя использовать вместе.

Один из вариантов — попытаться использовать библиотеки в отдельных потоках. Но часто библиотеки, управляемые событиями, разрабатываются исходя из предположения, что вы делаете все в одном потоке, потому что иначе зачем вам нужен цикл обработки событий?

Но «Правильно» — интегрировать циклы событий. Цикл событий KJ можно интегрировать с другими библиотеками событий. Например, я интегрировал его с libuv для node-capnp; см. первую часть этого файла:

https://github.com/kentonv/node-capnp/blob/master/src/node-capnp/capnp.cc

(В какой-то момент я планирую выделить код, связанный с libuv, в отдельную библиотеку, поставляемую с Cap'n Proto.)

В качестве другого примера, вот запрос на вытягивание от Натана Хурта, чтобы добавить интеграцию с циклом событий Qt, но обратите внимание, что этот запрос не включает интеграцию ввода-вывода, я думаю, потому что Натан использует реализацию AsyncIoStream, в которую он вручную помещает данные когда это доступно:

https://github.com/sandstorm-io/capnproto/pull/253

В любом случае вам нужно будет сделать что-то подобное с тем, что использует Kafka. Надеюсь, вы вернете свой код обратно в Cap'n Proto! :)

person Kenton Varda    schedule 15.10.2015
comment
спасибо Кентон. Я посмотрел на реализацию узла, но был немного осторожен, потому что он добавляет libuv в смесь, и это считалось медленным и немного неуклюжим. У меня возникает соблазн переместить биты Kafka в новую библиотеку, которая связана с интерфейсами KJ. Было бы неплохо, если бы конвейер RPC также мог получить доступ к новым функциям с нулевым копированием, но я не уверен, насколько это сложно. Это звучит жизнеспособно для вас? Я нахожусь на ранней стадии стартапа, поэтому мы не сможем открыть исходный код, пока не найдем инвесторов :). - person James Fremen; 15.10.2015
comment
librdkafka предоставляет неблокирующий асинхронный интерфейс, все операции ввода-вывода выполняются в фоновых потоках, поэтому вы можете просто полагаться на диспетчер событий Cap'n в качестве основного цикла. - person Edenhill; 15.10.2015
comment
@JamesFremen Я указал на реализацию libuv в качестве примера того, как интегрировать KJ с внешним циклом событий. Я не знаю о каких-либо проблемах с производительностью или других серьезных проблемах в связующем коде KJ-UV. Это полностью нулевая копия. Если низкоуровневый интерфейс событий Kafka не очень плох, вы должны иметь возможность интегрироваться с ним таким образом. - person Kenton Varda; 16.10.2015
comment
@Edenhill Даже если есть фоновый поток, выполняющий ввод-вывод (что звучит удивительно), ему, вероятно, потребуется какой-то способ доставки событий в основной поток, что требует какой-то интеграции цикла событий. - person Kenton Varda; 16.10.2015
comment
@Edenhill спасибо за ответ. Я ищу однопоточную реализацию, так как думаю, что она может обеспечить более детальное распределение ресурсов с достаточной производительностью для моей рабочей нагрузки. - person James Fremen; 16.10.2015
comment
@KentVarda да, я оценил это на основе моего первоначального прохождения комментариев к проекту верхнего уровня, в которых говорится, что это медленный и краткосрочный взлом, слова, которые я обычно никогда не использую :). У меня, вероятно, будет больше вопросов, когда я поднимусь по кривой обучения, но пока все хорошо. - person James Fremen; 16.10.2015
comment
@JamesFremen - Да, эти комментарии касаются привязок node capnp в целом, а не не клея libuv в частности. (И они могут быть слишком жесткими; исполнение не было проблемой для Sandstorm.) - person Kenton Varda; 16.10.2015
comment
@KentonVarda Создание сообщений Kafka — это асинхронная операция, которая немедленно возвращается (rd_kafka_produce*()). Потребление сообщений использует механизм на основе извлечения (msg = rd_kafka_consume*(.., timeout_ms)), который вам нужно вызывать из кода вашего приложения. Кроме того, есть отчеты об ошибках и отчеты о доставке, предоставляемые rd_kafka_poll(), которые обычно идут в вашем основном цикле. - person Edenhill; 16.10.2015
comment
@KentonVarda Внутренние потоки ввода-вывода используются по соображениям производительности и для обеспечения неблокирующего интерфейса для приложения. - person Edenhill; 16.10.2015