在 java web 应用程序/服务中使用 jni 时如何避免性能瓶颈

发布于 2024-09-28 04:37:02 字数 966 浏览 1 评论 0原文

问候, 我无法提供问题中的所有细节,因此以下是关键细节。

我有一个本机 dll(以及相应的 .so),包装了一个由 Eiffel 编程语言创建的静态库。 我已经围绕静态库编写了一个 C++ 包装器,并且已成功将其公开给 Java。但是,如果我在 Web 应用程序中使用这个 dll,事情就会变得有点复杂。问题是多个 java 线程将访问相同的 C++ 代码,其中本机上下文(?)在不同类和类的调用之间保留。实例。 为了使用 Eiffel 代码中的功能,必须从 C++ 初始化 Eiffel 运行时,然后使用 Eiffel 库来利用 C++ 中的 Eiffel 类。 不幸的是,这意味着对 Java 服务器端的所有传入请求最终都会到达 C++ 中的单个位置(在本机 dll 内),其中只有一个 Eiffel 运行时。 这种情况迫使我使整个 Eiffel 运行时线程安全,并且只有一个 Java 线程的一个操作可以通过 JNI 传递来使用 Eiffel 代码。 我有一种感觉,这可能很快就会成为一个可扩展性问题。

我觉得我可能需要一个进程池,每个进程加载相同 dll(或 *nix 下的 .so)的副本,该副本将服务于来自 Java 的传入线程。因此,一旦加载共享库,C++ 代码将创建(例如 10 个)进程,并且来自 Java 端的传入线程将通过 C++ 代码分配给这些进程。 事件流程如下:

Java 线程访问共享库中的本机代码(C++)。 本机代码检查进程池中哪些进程可用 通过 ipc 使用其中一个进程,将其标记为繁忙(可能使用线程?)

这是我能想到的唯一跨平台方法,可以安全地加载同一段代码(Eiffel 运行时和 eiffel 类),而不会出现任何线程安全问题。

这都是因为 Eiffel 运行时是一个昂贵的全局组件,我必须通过 JNI 公开它。

或者我应该简单地进行线程安全操作,即任何时候 JNI 只提供一个线程? 我可以使用 Java 来创建类似容器的轻量级隔离 jvm,每个容器仅使用单个 Eiffel 运行时吗?

我们将非常感谢您的反馈。

此致 塞雷夫

Greetings,
I could not provide all the details in the question, so here are the key details.

I have a native dll (and a corresponding .so) wrapping a static library, which is created by Eiffel programming language.
I've written a C++ wrapper around the static lib, and I've successfully exposed this to Java. However, if I use this dll in a web application, things will become kinda complicated. The problem is multiple java threads will access the same C++ code, where native context(?) is kept between calls by different classes & instances.
In order to use functionality from the Eiffel code, one has to initialize Eiffel runtime from C++ and then use Eiffel libraries to make use of Eiffel classes from C++.
Unfortunately, this means that all incoming requests to Java server side end up in a single location in C++ (within native dll), where there is only one Eiffel runtime.
This situation forces me to make the whole Eiffel runtime thread safe, and only one operation by one Java thread can use Eiffel code, by passing through JNI.
I have a feeling that this may quickly become a scalability issue.

I feel that I may need a pool of processes, each loading a copy of the same dll(or .so under *nix) which will be served to incoming threads from Java. So once the shared library is loaded, C++ code will create, say 10 processes, and incoming threads from Java side will be allocated to these processes via C++ code.
The flow of events would be like this:

Java thread accesses native code (c++) in shared library.
Native code checks which processes are available from the process pool
makes use of one of the processes via ipc, marking it busy (probably using a thread?)

This is the only cross platform way I could think of to safely load the same piece of code (Eiffel runtime and eiffel classes) without any thread safety issues.

This is all due to Eiffel runtime being an expensive, and global component, which I must expose via JNI.

Or should I simply go with thread safe operations, where only one thread is served from JNI at any time?
Is there any trick I can do with Java to create lightweight isolated jvm like containers each using only a single Eiffel runtime?

Your feedback would be much appreciated.

Best Regards
Seref

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

随遇而安 2024-10-05 04:37:02

第一个问题:如果您在不同的进程中加载​​了 DLL 的多个副本,它们能否正常运行?假设“是”,那么让多个副本运行的想法听起来有潜力。 (实际上,还有一个问题首先要问:我假设用 Java 重新实现 Eiffel 已经被检查过并被证明太困难了?)

我倾向于首先检查您的简单、单线程是否是这样的?安全的方法可能会提供足够好的性能。如果没有,并且您需要可扩展性,那么另一种可能性是考虑使用多个廉价机器(或虚拟机) - 这具有简单性的巨大优点。花费多于几台机器并不需要太多的开发工作。

否则,您关于“服务”流程池的想法听起来像是一个合理的想法。有很多不同的进程间通信 (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 名称和相关信息。

碰巧,后一种模式几乎就是我当前的应用程序正在做的事情,并且具有良好的性能。我认为 C++/Eiffel 引擎中没有 Java 可能是一个胜利。如果 JMS 的伪同步使用看起来没有吸引力,那么我的替代方案是使用带有远程接口的 EJB。这个想法再次是将所有可扩展性工作推入基础设施中。

First question: if you had multiple copies of the DLL loaded in separate processes would they operate correctly? Assuming "yes" then your idea of having multiple copies running sounds to have potential. (Actually, there is another question to ask first: I'm assuming that re-implementing the Eiffel in Java has already been examined and proven to be too difificult?)

My inclination would first be to check whether your simple, single, thread-safe approach might give good enough performance. If it doesn't and you need scalability then another possibility is to consider using several cheap meachine (or virtual machines) - this has the great merit of simplicity. It doesn't take much development effort to cost more than a few machines.

Otherwise your idea of a pool of "service" processes sounds like a reasonable idea. There's plenty of different Inter-process communication (IPC) possibilities. Almost by definition you're spending a long time in the service in each call (otherwise would you have a problem?) so in which case the actual IPC mechanism need not be highly optimised - favour simplicity and ease of administration. I would look first at a queue-based approach using JMS - yes there are plenty of other options including RMI or low-level sockets - but JMS has two advantages: it's very easy and scalability kind of falls out, the requester just pops messages on a queue, never needs to know how many service processes there may be. Also interestingly on some vendors platforms there are C++ implementations of JMS (XMS is the one I use) and hence you don't even meed Java in the service process.

To elaborate: the starting position is

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

I suggest using

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

or

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

Responses can be returned on temparary response queues with the request message contains a Reply To Q name and correlation information.

As it happens this latter pattern is pretty much what my current app is doing, with nice performance. I think having no Java in the C++/Eiffel engine may be a win. If that pseudo synchronous use of JMS seems unappealing then my alternative would be to use EJBs with remote interfaces. The idea again is to push all the scalability work into the infrastructure.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文