CoralRing 是堆外共享内存中的超低延迟、无锁、无垃圾、批处理和并发循环队列(环),用于使用内存映射文件在不同的 JVM 之间进行 Java 进程间通信 (IPC)。
它通过易失性操作使用内存屏障而不是锁,以允许尽快发送消息。
内存映射文件的一个有趣特点是,它们通过依赖操作系统的虚拟内存机制,允许共享内存超过机器物理内存(RAM)的大小。 因此,共享内存的大小不受 RAM 限制,而是受硬盘(HDD/SSD)大小限制。 大内存映射文件会影响性能,因为操作系统需要在硬盘和内存之间来回交换页面,这个过程称为分页。
为了获得最高性能(尽可能低的延迟),你应该将内存映射文件放在 Linux /dev/shm/ 文件夹中,这样文件内容就会完全保存在 RAM 内存中。
当然,这样做你又会回到可用 RAM 内存的限制。 CoralRing 在共享内存中使用循环队列(环),因此即使只有一小块内存,你也可以向其他进程传送无限量的信息。
CoralRing
于环是一个有界循环队列,因此第一种方法是使用阻塞生产者和消费者。换句话说,当环已满时,环生产者将阻塞(等待),而当环为空时,环消费者将阻塞(等待)。基本上,缓慢的消费者会导致生产者阻塞,等待环中有可用空间。消费者按照生产者发送的顺序读取消息(所有消息)。
Blocking Broadcast Ring
您还可以让单个生产者向多个消费者广播消息,这样每个消费者按生产者发送信息的顺序接收所有信息。任何缓慢的消费者都可能导致环变满,生产者被阻塞。随着缓慢的消费者取得进展,生产者也会取得进展。
无阻塞环
当我们允许环生产者尽可能快地写入而不会在环已满时阻塞时,事情会变得更加有趣。由于环是一个循环队列,因此生产者可以一直写入,用最新的消息覆盖队列头部最旧的消息。在这种新情况下,落后并丢失消息的滞后消费者将直接断开连接(放弃),而不会导致生产者阻塞。它必须断开连接,因为它绝不能跳过来自生产者的消息。
long avail = ringConsumer.availableToPoll(); |
可以通过创建一个大型内存映射文件来缓解这种滞后消费者问题,这样您的共享内存环就足够大,为消费者提供落后和赶上的空间。然而,我们需要使用非阻塞环来解决一个更重要的问题,即当消费者落后太多以至于触及环形环的边缘时。当这种情况发生时,消费者很可能会同时读取环中最旧的消息,而生产者则用最新消息覆盖它。换句话说,消费者可能会绊倒生产者。
总之:
- CoralRing 非常适合在不同 JVM 中运行的线程。
- 但是,如果线程在同一个 JVM中运行,情况又如何呢?为此,您可以查看我们的CoralQueue项目,它是 Java 中用于线程间通信的循环数据结构的集合。