2个JVM之间的低CPU使用率轮询体系结构

时间:2015-02-05 16:54:53

标签: java multithreading performance low-latency hft

服务器环境

  • 的Linux / RedHat的
  • 6核
  • Java 7/8

关于申请:

  • 我们正在努力开发一个使用Java的低延迟(7-8毫秒)高速交易平台
  • 有两个模块A& B各自运行在自己的JVM上
  • B从A
  • 获取数据

架构:

  • 我们使用了MemoryMaps&不安全。在这种情况下,模块A写入存储器映射文件&模块B从文件中读取(两者都将地址位置保存到文件中)
  • 我们继续前进使用无限的while循环继续读取,直到从内存映射文件中获取所需的值

问题

  • CPU利用率高达100%&在其生命周期之前保持不变

问题:

是否有更复杂的方法来保持对内存映射文件中的值的轮询,这涉及最小的开销,最小延迟和最小值。最低CPU利用率?请注意,每微秒延迟都会降低性能

代码段

模块B的代码片段(无限循环,轮询和读取内存映射文件)位于

之下
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

1 个答案:

答案 0 :(得分:4)

  1. 高负载CPU是可能的最低延迟的实际成本。在一个使用无锁信令的实际架构中,每个CPU插槽只运行几个Consumer-Producer线程对。一对吃一两个(每个线程一个核心,如果没有固定到启用了超线程的单个Intel CPU核心)核心几乎完全(这就是为什么在大多数情况下,当你构建超低延迟服务器系统时你必须考虑水平可扩展性对于许多客户)。顺便说一句,在性能测试和禁用电源管理之前,不要忘记使用“任务集”将每个进程固定到特定的核心。

  2. 在长时间旋转后锁定消费者并且没有结果时,有一个众所周知的技巧。但你必须花一些时间停车,然后取消停放线程。当然,这是一个零星的延迟增加的时刻,但是当线程停放时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(替代等待策略)

  3. 如果您谈论的是毫秒(ms),而不是微秒(μs),您可以尝试通过环回进行TCP套接字通信。它增加了大约10μs来将生产者的少量数据传递给消费者,这就是阻塞技术。命名管道具有比套接字更好的延迟特性,但它们实际上是非阻塞的,你必须再次构建像spinloop这样的东西。内存映射文件+内在的Unsafe.getXXX(单个x86 MOV)在延迟和吞吐量方面仍然是最好的IPC技术,因为它在读写时不需要系统调用。

  4. 如果您仍然要使用无锁和内存映射文件并使用Unsafe直接访问,请不要忘记生产者和消费者的适当内存障碍。例如,“unsafe.getIntVolatile”而不是第一个“unsafe.getInt”,如果您不确定您的代码是否总是在以后的x86上运行。

  5. 如果您看到每对Producer-Consumer的CPU利用率不应超过30-40%(2个核心用于6核CPU),则必须使用标准工具检查其他运行的内容核心和整体系统性能。如果您看到与映射文件关联的密集IO,请确保将其映射到tmpfs文件系统以防止实际磁盘IO。检查内存总线加载和L3缓存未命中的“最胖”进程,因为,正如我们所知,CPU时间=(CPU执行时钟周期+ _memory_stall_cycles_)*时钟周期时间

  6. 最后,一个非常相似和有趣的开源项目,提供了一个如何使用内存映射文件的好例子:http://openhft.net/products/chronicle-queue/