programing

Java와 C/C++ 간의 프로세스 간 통신을 위한 가장 빠른(저레이텐시) 방식

kingscode 2022. 12. 28. 22:16
반응형

Java와 C/C++ 간의 프로세스 간 통신을 위한 가장 빠른(저레이텐시) 방식

나는 TCP 소켓을 통해 C/C++로 개발된 "서버"에 접속하는 Java 앱을 가지고 있다.

어플리케이션과 서버는 모두 같은 머신, Solaris 박스 상에서 동작하고 있습니다(단, 최종적으로 Linux로의 이행을 검토하고 있습니다).교환되는 데이터의 타입은 단순한 메시지(로그인, 로그인 ACK, 클라이언트의 요구, 서버의 응답)입니다.각 메시지의 길이는 약 300바이트입니다.

현재는 소켓을 사용하고 있습니다만, 모두 문제 없습니다만, IPC 방식으로 데이터를 교환할 수 있는(레이텐시 단축) 방법을 찾고 있습니다.

저는 인터넷을 조사하여 다음 기술에 대한 참조를 생각해 냈습니다.

  • 공유 메모리
  • 파이프
  • DMA(Direct Memory Access)라고 불리는 것도 있습니다.

그러나 각각의 퍼포먼스에 대한 적절한 분석을 찾을 수 없었습니다.또한 JAVA와 C/C++(서로 대화할 수 있도록)에 실장하는 방법도 생각할 수 없었습니다.

이 맥락에서 각 방법의 성과와 실현 가능성에 대해 누구나 의견을 말할 수 있습니까? 유용한 구현 정보에 대한 포인터/링크는 무엇입니까?


편집/갱신

여기서 받은 의견과 답변에 따라 파이프 바로 위에 구축되어 있는 것으로 보이는 Unix Domain Sockets에 대한 정보가 발견되어 TCP 스택 전체를 절약할 수 있었습니다.플랫폼에 따라 다르므로 JNI 또는 Jud 또는 junixsocket으로 테스트할 예정입니다.

다음 단계는 파이프의 직접 구현과 공유 메모리가 될 수 있습니다. 비록 더 복잡하다는 경고를 받았지만...


도와주셔서 고마워요.

Java에서 Corei5 2.8로 레이텐시 테스트 완료GHz, 1바이트 송수신만 가능, 태스크셋에 특정 CPU 코어를 할당하지 않고 2개의 Java 프로세스가 생성되었습니다.

TCP         - 25 microseconds
Named pipes - 15 microseconds

여기서 태스크 세트1 Java Srv 또는 태스크 세트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

동시에 스레드.sleep (0) (스트레이스에서 알 수 있듯이 단일 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
}

주의: 스레드.sleep(0)은 두 프로세스가 서로의 변화를 볼 수 있도록 필요합니다(다른 방법은 아직 모릅니다).2개의 프로세스가 태스크셋과 같은 코어로 강제된 경우 지연은 1.5마이크로초가 됩니다.이것은 컨텍스트 스위치 지연입니다.

P.P.S - 0.3마이크로초 정도면 좋은 수치입니다.다음 코드에는 0.1마이크로초가 소요되며 기본 문자열 연결만 수행됩니다.

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

P.P.P.S. 너무 주제에서 벗어난 일이 아니길 바라지만, 마지막으로 스레드를 교체해 보았습니다.static volatile int 변수 증분을 수반하는 sleep(0) 및 record!-72나노초의 지연 java-to-java 프로세스 통신을 취득했습니다.

다만, 같은 CPU Core에 강제적으로 접속하면, 휘발성이 증가하는 JVM은 서로 제어를 양보하지 않기 때문에, 정확하게 10 밀리초의 레이텐시가 발생합니다.Linux 의 시간 퀀텀은 5 밀리초인 것 같습니다.따라서 예비 코어가 있는 경우에만 사용해야 합니다. 그렇지 않으면 sleep(0)이 더 안전합니다.

이 질문은 조금 전에 제기되었지만 200ns의 일반적인 지연과 초당 20M 메시지의 throughput을 지원하는 https://github.com/peter-lawrey/Java-Chronicle에 관심이 있을 수 있습니다.프로세스 간에 공유되는 메모리 매핑 파일을 사용합니다(데이터도 유지되므로 데이터를 가장 빠르게 유지할 수 있습니다).

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

공유 메모리와 파이프는 모두 최신 OS에서 직접 지원됩니다.그만큼 꽤 빠르죠.큐는 일반적으로 소켓, 파이프 및/또는 공유 메모리 상단에 구현되는 추상화입니다.이것은 느린 메커니즘처럼 보일 수 있지만, 다른 방법은 이러한 추상화를 만드는 것입니다.

다양한 IPC 트랜스포트의 퍼포먼스 테스트를 포함한 프로젝트를 다음에 나타냅니다.

http://github.com/rigtorp/ipc-bench

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

상세한 것에 대하여는, 이 블로그 투고를 참조해 주세요.결과는 다음과 같습니다(나노 단위의 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의 경우 실제 결과는 더 낮을 수 있습니다.즐거운 시간 되세요.

(어플리케이션과 「서버」가 모두 같은 머신상에 있기 때문에) 네이티브 액세스를 고려하고 있는 경우는, 취급할 수 있는 보일러 플레이트 코드가 적은 을 고려해 주세요.

원어민 프로세스 간 통신은 잘 모르지만, JNI 메커니즘을 사용하여 접근할 수 있는 원어민 코드를 사용하여 통신할 필요가 있다고 생각합니다.Java에서는 다른 프로세스와 통신하는 네이티브 함수를 호출합니다.

이전 회사에서는 http://remotetea.sourceforge.net/,이라는 프로젝트를 매우 쉽게 이해하고 통합할 수 있었습니다.

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

JNI 퍼포먼스에 관한 Oracle 버그 리포트:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4096069

JNI는 느린 인터페이스이므로 Java TCP 소켓이 애플리케이션 간에 가장 빠른 알림 방법이지만, 그렇다고 해서 소켓을 통해 페이로드를 전송할 필요는 없습니다.LDMA를 사용하여 payload를 전송합니다., 이전 질문에서 지적한 바와 같이 메모리 매핑에 대한 Java 지원은 이상적이지 않으므로 mmap을 실행하기 위해 JNI 라이브러리를 구현해야 합니다.

언급URL : https://stackoverflow.com/questions/2635272/fastest-low-latency-method-for-inter-process-communication-between-java-and-c

반응형