博学的汤圆 · Python/C++混合编程利器Pybind ...· 1 年前 · |
一直单身的小刀 · java - Spring ...· 1 年前 · |
睿智的跑步鞋 · .net - Why is ...· 1 年前 · |
酒量小的小虾米 · Redis 哈希(Hash) | 菜鸟教程· 1 年前 · |
完美的地瓜 · 创建TLS客户端凭据时发生严重错误,内部错误 ...· 1 年前 · |
我有一个Java应用程序,通过TCP套接字连接到一个用C/C++开发的“服务器”。
两个应用程序和服务器都运行在同一台机器上,一台Solaris机器上(但我们正在考虑最终迁移到Linux )。交换的数据类型是简单的消息(登录,登录确认,然后客户端请求一些东西,服务器回复)。每条消息大约300字节长。
目前我们正在使用Sockets,一切正常,但是我正在寻找一种更快的方式来交换数据(更低的延迟),使用IPC方法。
我一直在研究网络,并提出了以下技术的参考:
直接内存访问共享内存
)
但我找不到对它们各自性能的适当分析,也找不到如何在JAVA和C/C++中实现它们(以便它们可以相互通信),除了我可以想象如何做的管道。
在这种情况下,任何人都能对每种方法的性能和可行性发表评论吗?有没有指向有用实现信息的指针/链接?
编辑/更新
根据我在这里得到的评论和答案,我找到了关于Unix Domain Sockets的信息,它似乎就建立在管道之上,可以节省我整个TCP堆栈。它是特定于平台的,所以我计划使用JNI或者 juds 或 junixsocket 来测试它。
下一步可能是直接实现管道,然后共享内存,尽管我已经被警告过额外的复杂性级别……
谢谢你的帮忙
在我以前的公司,我们曾经使用过这个项目, http://remotetea.sourceforge.net/ ,非常容易理解和集成。
我不太了解本机进程间通信,但我猜您需要使用本机代码进行通信,您可以使用JNI机制访问本机代码。因此,在Java中,您将调用一个与另一个进程对话的本机函数。
如果您曾经考虑过使用本机访问(因为您的应用程序和“服务器”都在同一台机器上),那么考虑一下 JNA ,它需要处理的样板代码更少。
DMA是一种硬件设备可以在不中断CPU的情况下访问物理RAM的方法。一个常见的例子是硬盘控制器,它可以直接将字节从磁盘复制到RAM。因此,它不适用于IPC。
现代OSes直接支持共享内存和管道。因此,它们是相当快的。队列通常是抽象的,例如在套接字、管道和/或共享存储器之上实现。这可能看起来像是一种较慢的机制,但另一种选择是创建这样的抽象。
下面是一个包含各种IPC传输性能测试的项目:
您是否考虑过保持套接字打开,以便可以重用这些连接?
甲骨文关于JNI性能的错误报告: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4096069
JNI是一个很慢的接口,因此Java TCP套接字是在应用程序之间进行通知的最快方法,但是这并不意味着您必须通过套接字发送有效负载。使用LDMA传输有效负载,但正如 previous questions 所指出的那样,Java对内存映射的支持并不理想,因此您需要实现一个JNI库来运行mmap。
刚刚在我的Corei5 2.8 CPU上测试了Java的延迟,只有单字节发送/接收,2个Java进程刚刚产生,没有分配特定的CPU核心和任务集:
TCP - 25 microseconds
Named pipes - 15 microseconds
现在显式指定核心掩码,如 taskset 1 java Srv 或 taskset 2 java Cli 。
TCP, same cores: 30 microseconds
TCP, explicit different cores: 22 microseconds
Named pipes, same core: 4-5 microseconds !!!!
Named pipes, taskset different cores: 7-8 microseconds !!!!
所以
TCP overhead is visible
scheduling overhead (or core caches?) is also the culprit
同时,Thread.sleep(0) (如strace所示,它会导致执行一次sched_yield() Linux内核调用)花费0.3微秒-因此调度到单个内核的命名管道仍然有很多开销
一些共享内存测量:2009年9月14日- Solace Systems今天宣布,使用共享内存传输,其统一消息平台API可以实现低于700纳秒的平均延迟。 http://solacesystems.com/news/fastest-ipc-messaging/
附言-第二天以内存映射文件的形式尝试共享内存,如果繁忙等待是可以接受的,我们可以将传递单个字节的延迟减少到0.3微秒,代码如下:
MappedByteBuffer mem =
new RandomAccessFile("/tmp/mapped.txt", "rw").getChannel()
.map(FileChannel.MapMode.READ_WRITE, 0, 1);
while(true){
while(mem.get(0)!=5) Thread.sleep(0); // waiting for client request
mem.put(0, (byte)10); // sending the reply
}
注意: Thread.sleep(0)是必需的,这样两个进程就可以看到彼此的变化(我还不知道有其他方法)。如果2个进程与taskset被强制分配到同一个内核,则延迟将变为1.5微秒-这是上下文切换延迟
附言: 0.3微秒是个不错的数字!下面的代码恰好只用了0.1微秒,而只做了一个基本字符串连接:
int j=123456789;
String ret = "my-record-key-" + j + "-in-db";
P.S-希望这不是太离题,但最后我尝试了用递增静态的易失性整数变量来代替Thread.sleep(0) (JVM在这样做的时候碰巧刷新了CPU缓存),并获得了-记录!- 72纳秒java- to -java进程通信 !
然而,当被迫使用相同的CPU核心时,易失性递增的JVM永远不会相互控制,因此恰好会产生10毫秒的延迟- Linux时间段似乎是5ms……因此,只有在有备用内核的情况下才应该使用它-否则,sleep(0)会更安全。
这个问题是在一段时间前提出的,但您可能会对 https://github.com/peter-lawrey/Java-Chronicle 感兴趣,它支持200 ns的典型延迟和20M消息/秒的吞吐量。它使用在进程之间共享的内存映射文件(它还持久化数据,这使得持久化数据的速度最快)
一直单身的小刀 · java - Spring WebSocket ConvertAndSendToUser not working but convertAndSend working - Stack Overflow 1 年前 |
酒量小的小虾米 · Redis 哈希(Hash) | 菜鸟教程 1 年前 |