Как я могу избежать узких мест производительности при использовании jni в веб-приложении / службе Java - PullRequest
1 голос
/ 17 октября 2010

Привет, я не смог предоставить все детали в вопросе, поэтому вот ключевые детали.

У меня есть нативный dll (и соответствующий .so), обертывающий статическую библиотеку, созданную языком программирования Eiffel.Я написал оболочку C ++ вокруг статической библиотеки и успешно открыл ее для Java.Однако, если я буду использовать эту DLL в веб-приложении, все станет немного сложнее.Проблема в том, что несколько потоков Java будут обращаться к одному и тому же коду C ++, где собственный контекст (?) Сохраняется между вызовами разных классов и экземпляров.Чтобы использовать функциональность из кода Eiffel, нужно инициализировать среду выполнения Eiffel из C ++, а затем использовать библиотеки Eiffel для использования классов Eiffel из C ++.К сожалению, это означает, что все входящие запросы на стороне Java-сервера оказываются в одном месте в C ++ (внутри нативной dll), где есть только одна среда выполнения Eiffel.Эта ситуация заставляет меня сделать весь поток времени выполнения Eiffel безопасным, и только одна операция одного потока Java может использовать код Eiffel, проходя через JNI.У меня есть ощущение, что это может быстро стать проблемой масштабируемости.

Мне кажется, что мне может понадобиться пул процессов, каждый из которых загружает копию одной и той же dll (или .so в * nix), которая будет обслуживаться входящим потокам из Java.Таким образом, после загрузки разделяемой библиотеки будет создан код C ++, скажем, 10 процессов, и входящие потоки со стороны Java будут распределены этим процессам через код C ++.Поток событий будет выглядеть следующим образом:

Поток Java обращается к собственному коду (c ++) в разделяемой библиотеке.Нативный код проверяет, какие процессы доступны из пула процессов, использует один из процессов через ipc, помечая его как занятый (возможно, с использованием потока?)

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

Это все из-за того, что среда выполнения Eiffel является дорогим и глобальным компонентом, который я должен раскрыть через JNI.

Или я должен просто пойти с потокобезопасными операциями, где только один поток обслуживается из JNI в любое время?Есть ли какой-нибудь трюк, который я могу сделать с Java для создания облегченных изолированных jvm-подобных контейнеров, каждый из которых использует только одну среду выполнения Eiffel?

Ваши отзывы будут высоко оценены.

С наилучшими пожеланиями Seref

1 Ответ

1 голос
/ 17 октября 2010

Первый вопрос: если бы у вас было несколько копий DLL, загруженных в отдельных процессах, они бы работали правильно? Если предположить «да», то ваша идея иметь несколько копий работающих звуков, чтобы иметь потенциал. (На самом деле, сначала нужно задать еще один вопрос: я предполагаю, что повторная реализация Eiffel в Java уже была исследована и доказала, что она слишком сложна?)

Вначале я хотел бы проверить, может ли ваш простой, однопоточный подход обеспечить достаточную производительность. Если это не так, и вам нужна масштабируемость, то другой возможностью является рассмотреть возможность использования нескольких дешевых машин (или виртуальных машин) - это имеет большое преимущество простоты. Разработка не требует больших усилий, чтобы стоить больше, чем несколько машин.

В противном случае ваше представление о пуле «сервисных» процессов звучит как разумная идея. Существует множество различных возможностей межпроцессного взаимодействия (IPC). Почти по определению вы тратите много времени на обслуживание в каждом вызове (в противном случае у вас возникнут проблемы?), Поэтому в этом случае фактический механизм IPC не нуждается в высокой оптимизации - предпочтение простоте и легкости администрирования. Сначала я хотел бы взглянуть на подход, основанный на очереди, с использованием JMS - да, есть много других вариантов, включая RMI или низкоуровневые сокеты, - но у JMS есть два преимущества: он очень прост и масштабируемость выпадает, запрашивающий просто высылает сообщения очереди, никогда не нужно знать, сколько там может быть сервисных процессов. Также интересно, что на платформах некоторых поставщиков есть реализации JMS на C ++ (я использую XMS), и, следовательно, вы даже не используете Java в процессе обслуживания.

Для уточнения: начальная позиция

  WS-Client ---WS Call ---> WS in Web App ---JNI--->C++/Eiffel

Я предлагаю использовать

  WS-Client ---WS Call ---> WS in Web App --JMS enq--> Q --JMS deq--> Java---JNI--->C++/Eiffel

или

  WS-Client ---WS Call ---> WS in Web App --JMS enq--> Q --XMS deq--->C++/Eiffel

Ответы могут быть возвращены во временных очередях ответов, при этом сообщение запроса содержит имя ответа Q и информацию о корреляции.

Как оказалось, этот последний шаблон в значительной степени является тем, что делает мое текущее приложение, с хорошей производительностью. Я думаю, что отсутствие Java в движке C ++ / Eiffel может быть победой. Если это псевдосинхронное использование JMS кажется непривлекательным, тогда я мог бы использовать EJB с удаленными интерфейсами. Идея снова заключается в том, чтобы перенести всю работу по масштабируемости в инфраструктуру.

...