오늘 인텔리제이로 작업하다가 

Caused by: java.net.SocketTimeoutException: connect timed out

라는 에러가 떠서, 관련 CS 지식 타임아웃에 대해 정리해보려고 한다.

 

스프링부트 API 제작 후 빌드해서 테스트하려고 하는데 직전까지만 해도 잘 돌아가던 빌드가 왜 안되었을까?

.

.

인줄 알았으나 그냥 경고 표시였다.

 

이번 기회에 타임아웃에 대해 제대로 알고 가보자.

 

서버 간 통신이 많아지는 MSA 구조가 주목받으면서 내부 시스템 안에서도 서로 클라이언트와 서버가 되어 데이터를 주고 받는 비중이 점점 커지고 있다. 이런 상황에서 통신을 요청하는 클라이언트는 다양한 Timeout 오류를 만날 수 있는데, 이런 Timeout에 대한 종류를 잘 구별한다면 각각의 상황에 따라 구분해서 처리할 수 있다. 

 

 

타임아웃

  • 프로그램이 특정한 시간 내 성공적으로 수행되지 않아 진행이 자동적으로 중단되는 것
  • 응답을 무한정 기다릴 수 없기 때문에 기다릴 시간을 정해야 함

 

타임아웃 사례

  • Socket(양방향 통신), Http(단방향 통신)에서 다양하게 활용
  • JDBC
    • JDBC Driver Type4는 소켓을 사용하여 DBMS에 연결하는 방식
    • Connection Timeout : DB 커넥션 요청을 했으나, 특정 시간 내 연결이 안될 때
  • 채팅 프로그램
    • Socket Timeout : 채팅 프로그램에서 서버로부터 특정 시간 응답이 없을 때
  • WEB
    • Connection Timeout : 클라이언트에서 서버로 request를 날렸을 때 연결되지 않은 상태로 특정시간 이상 대기

 

관련 패키지

  • java.net
  • HttpClient

 

1) java.net 패키지


  • 네트워킹 응용 프로그램을 구현하기 위한 클래스를 제공하는 패키지
  • java.net 패키지는 크게 두 섹션으로 나뉨
    • 저수준 API
      • Addresses : 네트워크 식별자 ex) IP 주소
      • Sockets : 기본 양방향 데이터 통신 메카니즘
      • Interfaces : 네트워크 인터페이스
    • 고수준 API
      • URIs : Universal Resource Identifiers
      • URLs : Universal Resource Locators
      • Connections : URL이 가리키는 리소스에 대한 연결

 

java.net 패키지에서 제공하는 4개의 socket

  • Socket : TCP 클라이언트 API, 일반적으로 원격 호스트에 연결하는 데 사용됨
  • ServerSocket : TCP 서버 API, 일반적으로 클라이언트 소켓의 연결 허용
  • DatagramSocket : UDP 엔드포인트 API, datagram 패킷을 주고 받는데 사용
  • MulticastSocket : multicast 그룹을 처리하는 DatagramSocket의 하위클래스
  • TCP 소켓을 통한 송수신 -> Socket.getInputStream() 메소드 및 Socket.getOutputStream()메소드를 통해 얻을 수 있는 InputStreams 및 OutputStreams를 통해 수행됨

 

* Socket 관련 Timeout

  1. Connection Timeout
  2. Socket Timeout / Read Timeout

 

1. Connection Timeout

  • 클라이언트가 서버측으로 Connection을 맺길 원하지만 서버의 장애 상황으로 맺어지지 못할 때 발생하는 timeout
  • 이 경우에는 서버에 접근이 안되는 경우라서 클라이언트는 서버의 장애 상황으로 간주할 수 있음. 보통 이 경우에 클라이언트는 일시적인 오류 상황으로 구분하여 처리를 하거나 미리 정의된 dafault 데이터나 cache 데이터로 fallback 처리하기도 함.
  • Connection 과정
    • TCP 소켓 통신에서 클라이언트와 서버가 연결될 때 정확한 전송을 보장하기 위해 상대방 컴퓨터와 사전에 세션을 수립함. (3-way handshake)
    • 3-way handshake가 정상적으로 끝나야 Connection이 됐다고 표현할 수 있음. 즉, Connection Timeout이란 3-way HandShake가 정상적으로 수행되어 서버에 연결되기까지 소요된 시간임.
  • TCP 3-way HandShake 절차
    • 1) 클라이언트 A 는 B 서버에 접속을 요청하는 SYN 패킷을 보냄. 이때 A는 SYN을 보내고 SYN/ACK 응답을 기다리는 SYN_SENT 상태가 됨
    • 2) B 서버는 SYN 요청을 받고 A에게 요청을 수락한다는 ACK와 SYN flag가 설정된 패킷을 발송하고 A가 다시 ACK으로 응답하길 기다린다. 이때 B 서버는 SYN_RECEIVED 상태가 됨
    • 3) A는 B에게 ACK을 보내고 이후부터는 연결이 이뤄지고 데이터가 오가게 되는 것이다. 이때 B 서버 상태는 ESTABILSHED이다.
      • SYN : synchronize sequence numbers
      • ACK : acknowledgement
      • 4-way handshake : 3-way handshake는 TCP의 연결을 초기화할 때 사용한다면, 4-way handshake는 세션을 종료하기 위해 수행되는 절차임

2. Socket Timeout

  • 클라이언트와 서버가 connection을 맺은 후 서버는 데이터를 클라이언트에게 전송하게 됨. 이때 실제 데이터를 주고 받는 과정은 하나의 데이터 덩어리가 아닌 여러개의 패킷으로 나눠서 전송되는데 각 패킷이 전송될 때 시간 차(Gap)가 있음. 이 차이 시간의 제한(임계치)을 SocketTimeout이라고 함.
  • read timeout과의 관계
    • 클라이언트와 서버가 connection은 맺어졌지만 I/O (Input/Out) 작업이 길어지거나 락이 걸려 요청이 처리되지 못하고 있을 때 클라이언트는 더 이상 기다리지 못하고 커넥션을 끊음. 이런 상황을 Read Timeout이라고 함.
  • java.net에서는 socket timeout과 read timeout을 혼용하며, setSoTimeout() 메소드를 사용함

2-1. Read Timeout

  • 클라이언트와 서버가 connection에는 성공했지만 실제 데이터를 전송하는 I/O 과정이 길어지는 경우 일정 시간이 경과되면 클라이언트는 connection을 끊게 됨.
  • 보통 주고 받는 데이터의 양이나 네트워크 속도에 따라서 대응을 다르게 함. 만약 데이터의 양이 크다면 이를 분할해서 받을 수 있도록 API 자체 Spec을 변경하거나 Retry 전략을 사용할 수 있고, 속도가 느려서 발생하는 상황이라면 전반적으로 네트워크 대역폭 증가를 위한 인프라 작업을 고려할 수 있음

 

* Connection, Socket/Read Timeout과 관련된 예외

  • java.net.Socket.Exception : Thrown to indicate that there is an error creating or accessing a Socket. -> connection timeout
  • java.net.SocketTimeoutException : Signals that a timeout has occurred on a socket read or accept. -> socket timeout, read timeout

 

2) HttpClient 라이브러리


Apache HttpClient

  • HTTP 프로토콜을 손쉽게 사용할 수 있게 해주는 클라이언트측 HTTP 전송 라이브러리
  • Apache HttpComponents 제품군의 HttpClient는 http 통신을 위한 표준이 되어옴
  • httpURLConnection의 단점(connection pooling)을 채우는 다양한 API를 가진 성숙한 프로젝트
  • Apache HttpClient를 이용하면 간편하게 HTTP request를 보낼 수 있음. 간혹 웹 서버를 만들면서 다른 서버로부터 request를 보내 response받아 데이터를 처리해야할 때가 있음. 이때 HttpClient를 이용하면 간단하게 구현 가능
  •  java.net 패키지와의 차이점
    • java.net 패키지는 HTTP를 통해 리소스에 액세스하기 위한 기본 기능을 제공하지만, 많은 애플리케이션에 필요한 완전한 유연성이나 기능을 제공하지 않음
    • HttpClient 패키지는 최신 HTTP 표준 및 권장 사항의 클라이언트 측을 구현하는 효율적이고 최신이며 기능이 풍부한 패키지를 제공해 이 공백을 채우려고 함
    • 확장을 위해 설계된 HttpClient는 기본 HTTP 프로토콜에 대한 강력한 지원을 제공하는 동시에 웹 브라우저, 웹 서비스 클라이언트 또는 분산 통신을 위해 HTTP 프로토콜을 활용하거나 확장하는 시스템과 같은 HTTP 인식 클라이언트 응용 프로그램을 구축하는 모든 사람에게 유용할 수 있음

HttpClient에서 제공하는 timeout 관련 메소드

  • setConnectTimeout : 서버와 연결을 맺을 때의 타임아웃
  • setConnectionRequestTimeout : ConnectionManager(커넥션풀)로부터 꺼내올 때의 타임아웃
  • setSocketTimeout : 요청/응답간의 타임아웃
  • Connection Pooling
    • HttpClient로 빈번히 connection을 맺었다가 사용이 끝나고 끊고 하다 보면 더 이상 Connection을 열 수 없는 경우가 발생할 수 있음
    • connection을 닫는다고 호출을 해도 실제로는 어느정도 TIME_WAIT 상태에 있다가 끊어지는데 이런 것들이 많이 쌓여 있으면 File Descriptor가 꽉 찼다는 에러(Too Many Open Files)가 나면서 connection을 맺지 못하게 된다.
    • 이런 현상을 방지하기 위해서 Connection을 재사용할 수 있도록 HttpClient에서 제공하는 Connection Pool을 사용함 (getHttpClient를 호출할 때 Connection Pool이 지정된 사이즈로 생성되고 Connection을 하나 만들어 리턴함)
    • Pool을 사용할 때마다 항상 주의해야할 것은 반환을 꼭 해 줘야한다!

Timeout 예시

# HttpClient 4.3 (Configure Timeouts Using the New 4.3 Builde)
int timeout = 5;
RequestConfig config = RequestConfig.custom()
	.setConnectTimeout(timeout * 1000)
    .setConnectionRequestTimeout(timeout * 1000)
    .setSocketTimeout(timeout * 1000).build();
   CloseableHttpClient client = 
   	HttpClientBuilder.create().setDefaultRequestConfig(config).build();

+ Recent posts