java-2个JVM之间的低CPU使用率轮询架构

服务器环境

> Linux / RedHat
> 6核
> Java 7/8

关于申请:

>我们正在使用Java开发低延迟(7-8 ms)的高速交易平台
>有2个模块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-Producer对线程.一对几乎吃掉一两个内核(如果不固定到启用了超线程的单个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”而不是第一个“ unsafe.getInt”.
>如果您看到意外的CPU利用率应该不超过每对Producer-Consumer对30-40%(2个已使用的核心,每个6个核心的CPU),则必须使用标准工具来检查其他核心和整个系统上正在运行的资源性能.如果看到与映射文件关联的密集型IO,请确保将其映射到tmpfs文件系统以防止出现实际磁盘IO.检查内存总线加载和“ fattest”进程的L3缓存未命中,因为众所周知,CPU时间=(CPU执行时钟周期_memory_stall_cycles _)*时钟周期时间

最后,是一个非常相似且有趣的开源项目,其中有一个很好的示例如何使用内存映射文件:http://openhft.net/products/chronicle-queue/

上一篇:python学习笔记22 面向服务的方法


下一篇:Find Minimum in Rotated Sorted Array II leetcode