服务器环境
- Linux/ReHat
- 6芯
- Java 7/8
关于应用程序:
- 我们正在使用Java开发一个低延迟(7-8毫秒)的高速交易平台
- 有两个模块A&B每个都在自己的JVM上运行
- B从A获取数据
体系结构:
- 我们使用了MemoryMaps&不安全的在这种情况下,模块A写入存储器映射文件&模块B从文件中读取(两者都持有文件的地址位置)
- 我们继续前进&使用无休止的while循环继续读取,直到从内存映射文件中获得所需值
问题
- CPU利用率飙升至100%&在其生命周期之前保持不变
问题:
是否有一种更复杂的方法来保持对内存映射文件中的值的轮询,该方法涉及最小开销、最小延迟&最低CPU利用率?请注意,每微秒的延迟都会降低的性能
代码段
模块B的代码片段(从内存映射文件中轮询和读取的无休止while循环)位于下方
FileChannel fc_pointer = new RandomAccessFile(file, "rw").getChannel();
MappedByteBuffer mem_file_pointer =fc_pointer.map(FileChannel.MapMode.READ_ONLY, 0, bufferSize);
long address_file_pointer = ((DirectBuffer) mem_file_pointer).address();
while(true)
{
int value_from_memory_mapped_file = unsafe.getInt(address_file_pointer);
if (value_from_memory_mapped_file .. is different from the last read value)
{
//do some operation....
//exit the routine;
}
else
{
continue;
}
}//end of while
-
高负载CPU是最低延迟的实际成本。在使用无锁信令的实用体系结构中,每个CPU套接字运行的线程不应超过Consumer-Productor对。一对几乎完全吃掉一个或两个核心(如果不是在启用超线程的情况下固定到单个Intel CPU核心,则每个线程一个核心)(这就是为什么在大多数情况下,当您为许多客户端构建超低延迟服务器系统时,您必须考虑水平可扩展性)。顺便说一句,在性能测试和禁用电源管理之前,不要忘记使用"任务集"将每个进程固定到特定的核心。
-
有一个众所周知的技巧,当你在长时间旋转后锁定消费者,但没有结果。但你必须花一些时间停车,然后打开线。当然,这是一个偶尔延迟增加的时刻,但当线程停止时,CPU核心是空闲的。例如,请参见:http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf(8.4.4较长周期的同步)此外,可以在这里找到java不同等待策略的一个很好的例子:https://github.com/LMAX-Exchange/disruptor/wiki/Getting-Started(替代等待策略)
-
如果您谈论的是毫秒(ms),而不是微秒(µs),您可以尝试通过环回进行TCP套接字通信。它增加了大约10µs,将少量数据从生产者传递给消费者,这是一种阻塞技术。命名管道比套接字具有更好的延迟特性,但它们实际上是非阻塞的,您必须再次构建类似spinloop的东西。内存映射文件+内部Unsafe.getXXX(它是一个单独的x86 MOV)在延迟和吞吐量方面仍然是最好的IPC技术,因为它在读写时不需要系统调用。
-
如果您仍然要使用无锁和内存映射文件,并使用不安全直接访问,请不要忘记为生产者和消费者设置适当的内存障碍。例如,如果您不确定代码总是在以后的x86上运行,请使用"unsafe.getIntVolatile"而不是第一个"unsafet.getInt"。
-
如果您发现每对Producer Consumer的意外CPU利用率不应超过30-40%(2个已利用的内核对应6个内核的CPU),则必须使用标准工具来检查其他内核上运行的内容和整体系统性能。如果您看到与映射文件相关联的密集型IO,请确保将其映射到tmpfs文件系统,以防止实际的磁盘IO。检查内存总线加载和三级缓存未命中的"最胖"进程,因为正如我们所知,CPU时间=(CPU exec时钟周期+_memory_sstall_cycles_)*时钟周期时间
最后,还有一个非常相似和有趣的开源项目,其中有一个如何使用内存映射文件的好例子:http://openhft.net/products/chronicle-queue/