IT TIP

NoRouteToHostException을 피하는 방법?

itqueen 2020. 12. 8. 20:34
반응형

NoRouteToHostException을 피하는 방법?


공개 : 제가 작업중인 코드는 대학 수업 용입니다.

배경 : 내가 완료하려는 작업은 다양한 스레딩 기술의 효과에 대해보고하는 것입니다. 이를 위해 Java 소켓을 사용하는 클라이언트의 요청에 응답하는 여러 클래스를 작성했습니다. 아이디어는 요청으로 서버를 넘치고 다양한 스레딩 전략이 이에 대처하는 방법을보고하는 것입니다. 각 클라이언트는 100 개의 요청을 만들고 각 반복에서 무언가 중단 될 때까지 클라이언트 수를 50 개씩 늘립니다.

문제 : 반복적이고 일관되게 예외가 발생합니다.

원인 : java.net.NoRouteToHostException : 요청 된 주소를 할당 할 수 없습니다.
    java.net.PlainSocketImpl.socketConnect (Native Method)에서
    java.net.PlainSocketImpl.doConnect (PlainSocketImpl.java:333)

이는 클라이언트와 서버가 모두 localhost에서 실행중인 경우를 포함하여 여러 시나리오에서 발생합니다. 잠시 동안 성공적으로 연결할 수 있지만 150 개의 클라이언트를 연결하려고 시도한 직후 예외가 발생합니다.

내 첫 번째 생각은 열린 파일 설명자 (1024)에 대한 Linux의 한계 일 수 있지만 그렇게 생각하지 않습니다. 또한 소켓 사이의 모든 연결이 제대로 닫혀 있는지 (즉, 올바른 finally블록 내에서 ) 확인했습니다.

나는 어떤 부분이 가장 관련성이 있는지 확실하지 않고 질문에 엄청난 양의 코드 목록을 갖고 싶지 않기 때문에 코드를 게시하는 것을 주저합니다.

전에 이것을 본 사람이 있습니까? NoRouteToHostException을 어떻게 피할 수 있습니까?


편집 (추가 질문은 기울임 꼴로 표시됨)

지금까지 The Ephemeral Port Range 또는 RFC 2780을 가리키는 몇 가지 좋은 답변입니다. 둘 다 내가 너무 많은 연결이 열려 있음을 시사합니다. 두 경우 모두이 제한에 도달하기 위해 만들어야하는 연결 수는 어느 시점에서 연결을 닫지 않을 것임을 시사합니다.

클라이언트와 서버를 모두 디버깅 한 후 둘 다 메서드 호출에 도달하는 것으로 관찰되었습니다 myJava-Net-SocketInstance.close(). 이것은 연결이 닫히고 있음을 시사합니다 (적어도 예외적이지 않은 경우). 이것이 올바른 제안입니까?

또한 포트를 다시 사용할 수있을 때까지 OS 레벨 대기가 필요합니까? 다음 시도를 실행하기 전에 짧은 기간 (또는 낙관적으로 명령 실행)이 필요한 경우 50 개 이상의 클라이언트마다 별도의 시간에 프로그램을 실행할 수 있습니다.


v2.0 수정

제공된 좋은 답변을 얻은 후 클라이언트에서 이루어진 모든 소켓 연결에 setReuseAddress (true) 메서드를 사용하도록 코드를 수정했습니다. 이것은 원하는 효과가 없었으며 여전히 250-300 명의 클라이언트로 제한되어 있습니다. 프로그램이 종료 된 후 명령을 실행 netstat -a하면 TIME_WAIT 상태에 많은 소켓 연결이 있음을 알 수 있습니다.

내 가정은 소켓이 TIME-WAIT상태에 있고 SO-REUSEADDR옵션 으로 설정되어 있으면 해당 포트를 사용하려는 모든 새 소켓이 가능하지만 여전히 NoRouteToHostException을 수신하고 있습니다.

이 올바른지? 이 문제를 해결하기 위해 할 수있는 다른 조치가 있습니까?


설정을 시도해 보셨습니까?

echo "1" >/proc/sys/net/ipv4/tcp_tw_reuse

및 / 또는

echo "1" >/proc/sys/net/ipv4/tcp_tw_recycle

이러한 설정은 Linux가 TIME_WAIT 소켓을 재사용하도록 할 수 있습니다. 불행히도 확실한 문서를 찾을 수 없습니다.


도움이 될 수 있습니다.

임시 포트 범위

임시 포트 범위의 또 다른 중요한 결과는 한 시스템에서 원격 시스템의 특정 서비스로의 최대 연결 수를 제한한다는 것입니다! TCP / IP 프로토콜은 연결의 4 개 튜플을 사용하여 연결을 구분하므로 임시 포트 범위가 포트 폭이 4000 개에 불과하면 클라이언트 컴퓨터에서 원격 서비스로 한 번에 4000 개의 고유 연결 만있을 수 있습니다.

따라서 사용 가능한 포트가 부족할 수 있습니다. 사용 가능한 포트 수를 확인하려면

$ cat /proc/sys/net/ipv4/ip_local_port_range 
32768   61000

출력은 클라이언트 연결을위한 28,232 개의 포트가있는 Ubuntu 시스템에서 가져온 것입니다. 따라서 280 개 이상의 클라이언트가있는 즉시 테스트가 실패합니다.


요청 된 주소를 할당 할 수 없음은 EADDRNOTAVAIL 오류에 대한 오류 문자열입니다.

소스 포트가 부족한 것 같습니다. 소스 포트로 사용할 수있는 동적 범위에는 16,383 개의 소켓이 있습니다 ( RFC 2780 참조 ). 클라이언트 150 개 * 연결 100 개 = 포트 15,000 개-따라서이 제한에 도달 한 것입니다.


소스 포트가 부족하지만 실제로 그렇게 많은 열린 연결을 유지하지 않는 경우 SO_REUSEADDR소켓 옵션을 설정하십시오 . 이렇게하면 여전히 TIME_WAIT상태 에있는 로컬 포트를 재사용 할 수 있습니다 .


초당 500 개의 연결을 닫으면 소켓이 부족해집니다. Keepalive를 사용하는 동일한 위치 (웹 서버)에 연결하는 경우 연결 풀을 구현할 수 있으므로 소켓을 닫고 다시 열지 않아도됩니다.

이것은 CPU도 절약 할 것입니다.

tcp_tw_recycle 및 tcp_tw_reuse를 사용하면 이전 연결에서 들어오는 패킷이 발생할 수 있으므로 패킷이 지워질 때까지 1 분 동안 기다려야합니다.


이 질문을 우연히 발견하는 다른 Java 사용자의 경우 연결 풀링을 사용하여 연결을 올바르게 재사용하는 것이 좋습니다.

참고 URL : https://stackoverflow.com/questions/1572215/how-to-avoid-a-noroutetohostexception

반응형