Java와 C / C ++ 간의 프로세스 간 통신을위한 가장 빠른 (낮은 지연) 방법


100

TCP 소켓을 통해 C / C ++로 개발 된 "서버"에 연결하는 Java 앱이 있습니다.

앱과 서버는 모두 동일한 시스템 인 Solaris 상자에서 실행됩니다 (하지만 결국 Linux로 마이그레이션하는 것을 고려 중입니다). 교환되는 데이터 유형은 간단한 메시지입니다 (로그인, 로그인 ACK, 클라이언트 요청, 서버 응답). 각 메시지의 길이는 약 300 바이트입니다.

현재 우리는 소켓을 사용하고 있으며 모든 것이 괜찮지 만 IPC 방법을 사용하여 데이터를 교환하는 더 빠른 방법 (낮은 대기 시간)을 찾고 있습니다.

나는 인터넷을 조사해 왔고 다음 기술에 대한 언급을 찾았습니다.

  • 공유 메모리
  • 파이프
  • 대기열
  • DMA (Direct Memory Access)라고하는 것

하지만 각각의 성능에 대한 적절한 분석을 찾을 수 없었습니다. JAVA와 C / C ++ 모두에서 구현하는 방법 (서로 대화 할 수 있도록)도 찾을 수 없었습니다. 제가 상상할 수있는 파이프를 제외하고는 말입니다.

누구든지이 맥락에서 각 방법의 성능 및 타당성에 대해 언급 할 수 있습니까? 유용한 구현 정보에 대한 포인터 / 링크가 있습니까?


편집 / 업데이트

내가 여기에 얻은 의견 및 답변에 따라 파이프 위에 구축 된 것처럼 보이는 Unix 도메인 소켓에 대한 정보를 발견했으며 전체 TCP 스택을 저장합니다. 플랫폼에 따라 다르므로 JNI 또는 juds 또는 junixsocket 으로 테스트 할 계획입니다 .

다음으로 가능한 단계는 파이프를 직접 구현 한 다음 메모리를 공유하는 것입니다. 비록 추가 수준의 복잡성에 대해 경고를 받았지만 ...


당신의 도움을 주셔서 감사합니다


7
귀하의 경우에는 과잉 일 수 있지만 zeromq.org를
jfs

흥미롭지 만 아이디어는 먼저 "일반"(OS 제공 또는 언어 제공) 메소드를 사용하는 것이므로 큐 및 공유 메모리에 대해 언급했습니다.
Bastien 2010-04-14


매핑 된 파일이나 UDP 만 잊지 마십시오.

10
TCP보다 느린 UDP ??? 흠 ... 증명하십시오
Boppity Bop 2013 년

답변:


103

Corei5 2.8GHz에서 Java의 지연 시간을 테스트했습니다. 단일 바이트 전송 / 수신, 2 개의 Java 프로세스가 방금 생성되었으며 작업 세트와 함께 특정 CPU 코어를 할당하지 않았습니다.

TCP         - 25 microseconds
Named pipes - 15 microseconds

이제 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 !!!!

그래서

TCP overhead is visible
scheduling overhead (or core caches?) is also the culprit

동시에 Thread.sleep (0) (strace가 보여 주듯이 단일 sched_yield () Linux 커널 호출이 실행 됨)은 0.3 마이크로 초가 걸립니다. 따라서 단일 코어로 예약 된 명명 된 파이프에는 여전히 많은 오버 헤드가 있습니다.

일부 공유 메모리 측정 : 2009 년 9 월 14 일 – Solace Systems는 오늘 자사의 통합 메시징 플랫폼 API가 공유 메모리 전송을 사용하여 700 나노초 미만의 평균 대기 시간을 달성 할 수 있다고 발표했습니다. http://solacesystems.com/news/fastest-ipc-messaging/

추신-다음날 메모리 매핑 파일의 형태로 공유 메모리를 시도했습니다. 바쁜 대기가 허용되는 경우 다음과 같은 코드로 단일 바이트를 전달하는 대기 시간을 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
}

참고 : Thread.sleep (0)이 필요하므로 두 프로세스가 서로의 변경 사항을 볼 수 있습니다 (아직 다른 방법은 모릅니다). 2 개의 프로세스가 작업 세트와 동일한 코어로 강제되면 지연 시간이 1.5 마이크로 초가됩니다. 이는 컨텍스트 전환 지연입니다.

PPS-0.3 마이크로 초는 좋은 수치입니다! 다음 코드는 기본 문자열 연결 만 수행하는 동안 정확히 0.1 마이크로 초가 걸립니다.

int j=123456789;
String ret = "my-record-key-" + j  + "-in-db";

PPPS-이것이 너무 주제에서 벗어난 것이 아니기를 바라지 만, 마침내 Thread.sleep (0)을 정적 휘발성 int 변수 (이렇게 할 때 JVM이 CPU 캐시를 플러시하는 일이 발생 함)를 증가시켜 바꾸려고 시도하고 획득했습니다-기록! - 72 나노초 지연 자바 대 자바 프로세스 통신 !

그러나 동일한 CPU 코어로 강제 될 때 휘발성 증가 JVM은 서로 제어를 양보하지 않으므로 정확히 10 밀리 초의 지연 시간이 발생합니다. Linux 시간 퀀텀은 5ms 인 것 같습니다. 따라서 예비 코어가있는 경우에만 사용해야합니다. 그렇지 않으면 sleep (0)이 더 안전합니다.


감사합니다 Andriy, 매우 정보 연구입니다. TCP에 대한 내 측정치와 거의 일치하므로 좋은 참조입니다. 명명 된 파이프를 살펴 보겠습니다.
Bastien 2011-06-21

따라서 Thread (Sleep)를 휘발성 static int 증가로 대체하는 것은 프로세스를 다른 코어에 고정 할 수있는 경우에만 수행되어야합니까? 또한 당신이 이걸 할 수 있는지 몰랐어요? OS가 결정한다고 생각 했나요?
mezamorphic apr

3
LockSupport.parkNanos (1)를 사용해보십시오. 동일한 작업을 수행해야합니다.
reccles

아주 좋아. 그래도 TCP 핑에 대해 더 잘할 수 있습니다 (5-7us RTT 지연 시간). 여기를보십시오 : psy-lob-saw.blogspot.com/2012/12/…
Nitsan Wakart

1
Java에서 IPC 대기열을 지원하기 위해 메모리 매핑 파일을 공유 메모리로 사용하는 추가 탐색 : psy-lob-saw.blogspot.com/2013/04/lock-free-ipc-queue.html 은 초당 1 억 3 천 5 백만 메시지를 달성합니다. 또한 방법 별 대기 시간 비교 연구는 아래 내 대답을 참조하십시오.
Nitsan Wakart 2014 년

10

DMA는 하드웨어 장치가 CPU를 중단하지 않고 물리적 RAM에 액세스 할 수있는 방법입니다. 예를 들어 일반적인 예는 디스크에서 RAM으로 바이트를 직접 복사 할 수있는 하드 디스크 컨트롤러입니다. 따라서 IPC에는 적용되지 않습니다.

공유 메모리와 파이프는 모두 최신 OS에서 직접 지원됩니다. 따라서 매우 빠릅니다. 큐는 일반적으로 추상화입니다. 예를 들어 소켓, 파이프 및 / 또는 공유 메모리 위에 구현됩니다. 이것은 느린 메커니즘처럼 보일 수 있지만 대안은 그러한 추상화 만드는 것입니다.


DMA의 경우 네트워크 전반에 걸쳐 (특히 InfiniBand를 사용하여) 적용되는 RDMA (원격 직접 메모리 액세스)와 관련된 많은 것을 읽을 수있는 이유는 무엇입니까? 나는 실제로 네트워크없이 동등한 것을 달성하려고 노력하고 있습니다 (모두 같은 상자에 있기 때문에).
Bastien 2010-04-14

RDMA는 동일한 개념입니다. 양쪽에서 CPU를 중단하지 않고 네트워크를 통해 바이트를 복사합니다. 여전히 프로세스 수준에서 작동하지 않습니다.
MSalters

10

이 질문은 얼마 전에 질문되었지만 일반적인 지연 시간 200ns와 처리량 20M / 초를 지원하는 https://github.com/peter-lawrey/Java-Chronicle에 관심이있을 수 있습니다 . 프로세스간에 공유되는 메모리 매핑 파일을 사용합니다 (데이터를 유지하는 가장 빠른 방법으로 데이터를 유지함).



6

네이티브 액세스 사용을 고려한 적이 있다면 (애플리케이션과 "서버"가 모두 동일한 시스템 에 있기 때문에) JNA를 고려하십시오 . 처리 할 표준 코드가 적습니다.


6

늦게 도착했지만 Java NIO를 사용하여 핑 대기 시간을 측정하는 데 전념 하는 오픈 소스 프로젝트 를 지적하고 싶었습니다 .

블로그 게시물 에서 더 자세히 알아보고 설명했습니다 . 결과는 다음과 같습니다 (나노 단위의 RTT) :

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

이것은 받아 들여지는 대답의 선을 따른 것입니다. System.nanotime () 오류 (아무것도 측정하지 않음으로 추정 됨)는 약 40 나노에서 측정되므로 IPC의 경우 실제 결과가 더 낮을 수 있습니다. 즐겨.


2

네이티브 프로세스 간 통신에 대해서는 잘 모르지만 JNI 메커니즘을 사용하여 액세스 할 수있는 네이티브 코드를 사용하여 통신해야한다고 생각합니다. 따라서 Java에서 다른 프로세스와 통신하는 기본 함수를 호출합니다.



0

연결을 재사용 할 수 있도록 소켓을 열어 두는 것을 고려해 보셨습니까?


소켓은 열려 있습니다. 연결은 응용 프로그램이 실행되는 내내 (약 7 시간) 살아 있습니다. 메시지는 어느 정도 지속적으로 교환됩니다 (초당 약 5 ~ 10 개). 현재 지연 시간은 약 200 마이크로 초이며 목표는 1 배 또는 2 배 정도를 줄이는 것입니다.
Bastien 2010-04-15

2ms 지연? 거창한. JNI를 사용하여 인터페이스 할 수있는 공유 라이브러리에 C-stuff를 다시 작성할 수 있습니까?
Thorbjørn Ravn Andersen

2ms는 200이 아니라 2000 마이크로 초입니다. 이것은 2ms를 훨씬 덜 야심 차게 만듭니다.
thewhiteambit

-1

JNI 성능에 대한 Oracle 버그 보고서 : http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4096069

JNI는 느린 인터페이스이므로 Java TCP 소켓은 애플리케이션 간 알림을위한 가장 빠른 방법이지만 소켓을 통해 페이로드를 보내야한다는 의미는 아닙니다. LDMA를 사용하여 페이로드를 전송하지만 이전 질문에서 지적했듯이 메모리 매핑에 대한 Java 지원은 이상적이지 않으므로 mmap을 실행하기 위해 JNI 라이브러리를 구현하는 것이 좋습니다.


3
JNI가 느린 이유는 무엇입니까? Java의 저수준 TCP 계층이 작동하는 방식을 고려하십시오. Java 바이트 코드로 작성되지 않았습니다! (예를 들어 이것은 네이티브 호스트를 통과해야합니다.) 따라서 저는 Java TCP 소켓이 JNI보다 빠르다는 주장을 거부합니다. (그러나 JNI는 IPC가 아닙니다.)

4
기본 요소 만 사용하는 경우 단일 JNI 호출 비용은 Intel i5에서 9ns입니다. 그래서 그렇게 느리지 않습니다.
Martin Kersten 2015
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.