Bas*_*ien 99 c++ java performance latency ipc
我有一个Java应用程序,通过TCP套接字连接到用C/C++开发的"服务器".
app和server都运行在同一台机器上,一个Solaris机箱(但我们最终考虑迁移到Linux).交换的数据类型是简单的消息(登录,登录ACK,然后客户端要求的东西,服务器回复).每条消息长约300字节.
目前我们正在使用套接字,一切正常,但我正在寻找一种更快的方式来交换数据(更低的延迟),使用IPC方法.
我一直在研究网络,并提出了以下技术的参考:
但我无法找到他们各自的性能适当的分析,无论是如何实现它们在Java和C/C++(这样他们可以互相交谈),也许除了管我能想象该怎么办.
在这种情况下,任何人都可以评论每种方法的表现和可行性吗?任何有用的实现信息的指针/链接?
编辑/更新
按照我在这里的评论和答案,我发现了有关Unix域套接字的信息,它似乎是通过管道构建的,并且可以节省整个TCP堆栈.它是特定于平台的,因此我计划使用JNI或者juds或junixsocket进行测试.
接下来可能的步骤是直接实现管道,然后共享内存,虽然我已被警告过额外的复杂程度......
谢谢你的帮助
And*_*riy 102
刚刚测试了我的Corei5 2.8GHz上的Java延迟,只发送/接收了单字节,2个Java进程刚刚生成,没有为任务集分配特定的CPU内核:
TCP - 25 microseconds
Named pipes - 15 microseconds
Run Code Online (Sandbox Code Playgroud)
现在显式指定核心掩码,如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 !!!!
Run Code Online (Sandbox Code Playgroud)
所以
TCP overhead is visible
scheduling overhead (or core caches?) is also the culprit
Run Code Online (Sandbox Code Playgroud)
同时Thread.sleep(0)(作为strace显示导致执行单个sched_yield()Linux内核调用)需要0.3微秒 - 因此命名为单核的命名管道仍然有很多开销
一些共享内存测量: 2009年9月14日 - Solace Systems今天宣布其统一消息平台API使用共享内存传输可以实现小于700纳秒的平均延迟. http://solacesystems.com/news/fastest-ipc-messaging/
PS - 第二天以内存映射文件的形式尝试共享内存,如果繁忙等待是可以接受的,我们可以通过以下代码传递单个字节,将延迟减少到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
}
Run Code Online (Sandbox Code Playgroud)
注意:需要Thread.sleep(0),因此2个进程可以看到彼此的更改(我还不知道另一种方式).如果2个进程与taskset强制使用相同的核心,则延迟变为1.5微秒 - 这是一个上下文切换延迟
PPS - 和0.3微秒是一个很好的数字!以下代码仅需0.1微秒,而仅执行原始字符串连接:
int j=123456789;
String ret = "my-record-key-" + j + "-in-db";
Run Code Online (Sandbox Code Playgroud)
PPPS - 希望这不是太偏离主题,但最后我尝试用增量静态volatile int变量替换Thread.sleep(0)(JVM碰巧在执行此操作时刷新CPU缓存)并获得 - 记录!- 72纳秒延迟java-to-java进程通信!
然而,当被强制使用相同的CPU核心时,易失性递增的JVM永远不会相互控制,从而产生恰好10毫秒的延迟 - Linux时间量似乎是5毫秒......所以只有在有备用核心时才应该使用它 - 否则睡觉(0)更安全.
MSa*_*ers 10
DMA是一种硬件设备可以在不中断CPU的情况下访问物理RAM的方法.例如,一个常见的例子是硬盘控制器,它可以直接从磁盘复制字节到RAM.因此,它不适用于IPC.
现代操作系统直接支持共享内存和管道.因此,它们非常快.队列通常是抽象,例如在套接字,管道和/或共享存储器之上实现.这可能看起来像一个较慢的机制,但另一种方法是你创建这样的抽象.
Pet*_*rey 10
问题是前一段时间被问到的,但您可能对https://github.com/peter-lawrey/Java-Chronicle感兴趣,它支持200 ns的典型延迟和20 M消息/秒的吞吐量.它使用进程之间共享的内存映射文件(它还会持久保存数据,这使得它成为持久化数据的最快方式)
迟到,但想指出一个致力于使用Java NIO测量ping延迟的开源项目.
在这篇博文中进一步探讨/解释.结果是(RTT in nanos):
Implementation, Min, 50%, 90%, 99%, 99.9%, 99.99%,Max
IPC busy-spin, 89, 127, 168, 3326, 6501, 11555, 25131
UDP busy-spin, 4597, 5224, 5391, 5958, 8466, 10918, 18396
TCP busy-spin, 6244, 6784, 7475, 8697, 11070, 16791, 27265
TCP select-now, 8858, 9617, 9845, 12173, 13845, 19417, 26171
TCP block, 10696, 13103, 13299, 14428, 15629, 20373, 32149
TCP select, 13425, 15426, 15743, 18035, 20719, 24793, 37877
Run Code Online (Sandbox Code Playgroud)
这与接受的答案一致.System.nanotime()误差(通过无测量估计)测量为大约40纳米,因此对于IPC,实际结果可能更低.请享用.