elasticsearch sockettimeout

a worker on the blue dot·2025년 2월 10일
0

엘라스틱서치

목록 보기
6/6

sockettimetout 30초짜리 나고,
node개수만큼 돌면서 계속 timeout 나는 현상

rest-cleint내에 node개수만큼 돌면서 쿼리를 날리고, 계속 sockettimeout발생하여 cpu증가하는 현상

=> 결론은 sockettimeout과 search.timeout을 적절히 설정해야 함.
socketimeout > search.timeout이고, search.timeout이 끝났다고 바로 응답을 받는것은 아님.
바로 응답을 보내려면 strict하게 적용해서 탐색할 문서 개수를 설정해야함.

-----------아래는 chat cpt 대화-----------

elasticsearch-rest-client에서 exception발생시 node를 순회하면서 조회하잖아
ChatGPT의 말:
맞습니다! Elasticsearch Low-Level REST Client (RestClient) 는 기본적으로 요청 실패 시 등록된 노드들을 순회하며 재시도합니다.

🔹 어떤 경우에 다른 노드로 재시도하나?

네트워크 장애 (IOException) 발생 시
노드 다운 (ConnectionRefusedException) 발생 시
소켓 타임아웃 (SocketTimeoutException) 발생 시
하지만 쿼리 타임아웃(예: search.timeout)이 발생하면 재시도하지 않습니다.

1️⃣ 노드 순회 방식 (Round Robin)
Elasticsearch Low-Level Client는 여러 노드를 등록하면, 요청이 실패할 경우 자동으로 다음 노드로 요청을 시도합니다.
즉, 라운드 로빈 방식으로 노드를 순회하면서 요청을 수행합니다.

RestClient restClient = RestClient.builder(
    new HttpHost("node1.example.com", 9200, "http"),
    new HttpHost("node2.example.com", 9200, "http"),
    new HttpHost("node3.example.com", 9200, "http")
).build();

위와 같이 여러 개의 노드를 등록하면, 한 노드에서 요청이 실패할 경우 다음 노드로 자동 재시도됩니다.

2️⃣ 재시도 동작을 커스텀하려면?
기본적으로 쿼리 타임아웃(서버가 응답을 안 주는 경우)에는 재시도하지 않으므로, 이를 변경하려면 수동으로 재시도를 구현해야 합니다.

✅ setFailureListener를 사용한 노드 실패 감지

RestClient restClient = RestClient.builder(
    new HttpHost("node1.example.com", 9200, "http"),
    new HttpHost("node2.example.com", 9200, "http")
).setFailureListener(new RestClient.FailureListener() {
    @Override
    public void onFailure(Node node) {
        System.err.println("노드 실패: " + node.getName());
    }
}).build();

✔ 특정 노드에서 실패할 경우 로깅할 수 있습니다.

3️⃣ High-Level REST Client에서도 동일한 동작을 하는가?
아니요!

RestHighLevelClient 자체는 노드 자동 순회를 지원하지 않습니다.
하지만 내부적으로 RestClient를 사용하므로, Low-Level REST Client의 재시도 전략을 활용할 수 있습니다.

RestHighLevelClient client = new RestHighLevelClient(
    RestClient.builder(
        new HttpHost("node1.example.com", 9200, "http"),
        new HttpHost("node2.example.com", 9200, "http")
    )
);

✔ Low-Level REST Client의 노드 순환 로직이 적용되므로, 네트워크 장애 발생 시 다른 노드로 재시도합니다.

4️⃣ 완전한 재시도 로직 구현 (쿼리 타임아웃 포함)
쿼리 타임아웃을 포함하여, 노드를 순회하며 재시도하려면 수동 재시도 로직을 추가해야 합니다.

public static SearchResponse executeWithRetry(RestHighLevelClient client, SearchRequest request, int maxRetries) {
    int attempt = 0;
    while (attempt < maxRetries) {
        try {
            return client.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            System.err.println("요청 실패 (시도 " + (attempt + 1) + "): " + e.getMessage());
            attempt++;
            if (attempt >= maxRetries) {
                throw new RuntimeException("모든 재시도 실패", e);
            }
        }
    }
    throw new RuntimeException("예기치 않은 오류");
}

✔ IOException 발생 시 최대 maxRetries번 노드를 순회하며 재시도합니다.
✔ 쿼리 타임아웃(search.timeout)이 발생한 경우에도 재시도하도록 설정할 수 있습니다.

✅ 정리
Elasticsearch Low-Level REST Client는 기본적으로 노드들을 순회하며 재시도합니다.
네트워크 장애(IOException)나 노드 다운 시에는 자동 재시도하지만, 쿼리 타임아웃 시에는 재시도하지 않습니다.
노드 장애 감지를 위해 setFailureListener를 사용할 수 있습니다.
쿼리 타임아웃도 포함한 완전한 재시도 로직이 필요하면, 수동으로 재시도를 구현해야 합니다. 🚀

나의 말:
elasticsaerch에서 sockettimeout의 설정은 기본 몇이야?
ChatGPT의 말:
Elasticsearch Low-Level REST Client (RestClient) 의 기본 socketTimeout 값은 30초(30,000ms) 입니다.

🔹 기본 설정 값
설정 옵션 기본값 설명
connectTimeout 1000ms (1초) 서버에 연결을 시도할 때의 최대 대기 시간
socketTimeout 30000ms (30초) 요청을 보낸 후 응답을 기다리는 최대 시간
🔹 socketTimeout을 변경하는 방법

RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200, "http"))
    .setRequestConfigCallback(requestConfigBuilder -> 
        requestConfigBuilder
            .setSocketTimeout(60000)  // 60초로 설정
            .setConnectTimeout(5000)   // 연결 타임아웃 5초로 설정
    )
    .build();
    ```
✔ setSocketTimeout(60000)60초 동안 응답을 기다림
✔ setConnectTimeout(5000)5초 내에 연결이 안 되면 실패

즉, 기본적으로 socketTimeout 값은 30초이며, 필요에 따라 조정할 수 있습니다. 🚀






나의 말:
sockettimeout과 쿼리타임아웃은 어떻게 달라?
ChatGPT의 말:
🔹 socketTimeout vs 쿼리 타임아웃(search timeout) 차이점
설정 옵션	의미
socketTimeout	네트워크 레벨의 타임아웃. 요청을 보낸 후 서버 응답을 기다리는 최대 시간.
쿼리 타임아웃 (search.timeout)	Elasticsearch 내부에서 실행되는 쿼리의 제한 시간. 지정된 시간 내에 완료되지 않으면 부분 결과를 반환하거나 실패.
🔹 1. socketTimeout (네트워크 레벨 타임아웃)
요청을 보낸 후 Elasticsearch 서버의 응답을 기다리는 최대 시간
네트워크 지연이나 서버 응답이 늦어질 경우 적용됨
기본값: 30(30,000ms)
설정 방법:
```java
RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200, "http"))
    .setRequestConfigCallback(requestConfigBuilder -> 
        requestConfigBuilder
            .setSocketTimeout(60000)  // 60초로 설정
            .setConnectTimeout(5000)  // 연결 타임아웃 5초로 설정
    )
    .build();
    ```
✅ 만약 socketTimeout을 초과하면 SocketTimeoutException이 발생하며, 클라이언트는 응답을 받지 못함.

🔹 2. search.timeout (쿼리 실행 타임아웃)
Elasticsearch 내부에서 실행되는 쿼리의 제한 시간
지정된 시간 내에 실행되지 않으면 쿼리가 중단될 수 있음
기본적으로 설정되지 않음 (무한정 실행 가능)
설정 방법:
```java
SearchRequest searchRequest = new SearchRequest("index_name");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
    .query(QueryBuilders.matchAllQuery())
    .timeout(TimeValue.timeValueSeconds(5)); // 5초 제한
searchRequest.source(searchSourceBuilder);

✅ 쿼리가 search.timeout을 초과하면 실패하거나 부분 결과를 반환할 수도 있음.
✅ 하지만 search.timeout이 초과되더라도 클라이언트는 여전히 socketTimeout 내에서 응답을 기다릴 수 있음.

🔹 차이점 요약
구분 socketTimeout search.timeout
설정 대상 클라이언트 ↔ 서버 간 네트워크 통신 Elasticsearch 내부에서 실행되는 쿼리
기본값 30초 설정하지 않으면 무제한
적용 시점 클라이언트가 응답을 기다리는 동안 쿼리가 실행될 때 내부적으로 적용
초과 시 결과 SocketTimeoutException 발생 (응답 없음) 부분 결과 반환 또는 실패
✔ 결론:

socketTimeout은 클라이언트가 서버 응답을 기다리는 시간을 의미하고,
search.timeout은 Elasticsearch가 쿼리를 실행하는 최대 시간을 의미함.
🚀 둘을 함께 조정하면 더 안정적인 Elasticsearch 쿼리 타임아웃 관리가 가능!

나의 말:
search.timeout이 초과되었는데 왜 client는 여전히 응답을 기다려? socketTimeout시간 내에 search.timeout이 초과되면 에러 메세지를 받는거 아냐?
ChatGPT의 말:
좋은 질문이에요! search.timeout이 초과되었는데도 클라이언트가 여전히 응답을 기다리는 이유는 Elasticsearch의 동작 방식 때문입니다.

🔹 search.timeout과 socketTimeout의 관계
search.timeout은 Elasticsearch 내부에서 실행되는 쿼리의 제한 시간입니다.
초과되면 쿼리를 중단할 수도 있고, 부분 결과를 반환할 수도 있으며, 경우에 따라 에러를 반환할 수도 있음
socketTimeout은 클라이언트가 서버 응답을 기다리는 최대 시간입니다.
socketTimeout이 초과되면 클라이언트는 SocketTimeoutException을 발생시킴
즉, search.timeout이 초과되었다고 해서 바로 클라이언트가 응답을 받는 게 아니라, Elasticsearch가 응답을 어떻게 처리하느냐에 따라 달라집니다.

🔹 search.timeout 초과 시 클라이언트가 기다리는 이유
Elasticsearch는 search.timeout을 "강제 중단"이 아니라 "최대한 제한하는 옵션"으로 사용함

만약 검색이 search.timeout을 초과하면, Elasticsearch는 요청을 완전히 중단하지 않을 수도 있음
대신, 부분적인 결과를 반환하거나, 내부적으로 추가 연산을 수행한 후 에러를 반환할 수 있음
이 과정에서 클라이언트는 응답을 기다릴 수 있음
Elasticsearch가 search.timeout 이후에도 연산을 계속 수행하는 경우

일부 복잡한 쿼리(예: aggregations, scroll 쿼리)는 search.timeout이 초과되어도 부분 데이터를 수집하려고 할 수 있음
이때 응답이 늦어지면 클라이언트는 여전히 socketTimeout 내에서 기다리게 됨
Elasticsearch가 search.timeout 초과 시 에러 응답을 반환하는 경우

만약 search.timeout이 초과되었고, Elasticsearch가 바로 에러를 반환하면 클라이언트는 즉시 응답을 받음
이 경우, 클라이언트가 socketTimeout 내에 응답을 받으므로 문제 없음
응답 예시:

{
  "error": {
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "caused_by": {
      "type": "timeout_exception",
      "reason": "timed out after 5s"
    }
  },
  "status": 504
}

위처럼 에러가 반환되면 클라이언트는 socketTimeout 내에 응답을 받고 처리 가능
Elasticsearch가 search.timeout 초과 후에도 내부적으로 작업을 마무리하는 경우

일부 경우, 노드 간 데이터 이동이나 리덕션 작업이 남아 있으면, search.timeout이 초과되었더라도 서버가 최종 응답을 완전히 정리한 후 반환할 수 있음
이 과정에서 클라이언트는 socketTimeout 내에서 계속 기다리게 됨
🔹 search.timeout 초과 시 즉시 응답을 받으려면?
타임아웃을 단호하게 적용하려면 terminate_after 옵션 추가

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
    .query(QueryBuilders.matchAllQuery())
    .timeout(TimeValue.timeValueSeconds(5))  // 5초 검색 타임아웃
    .terminateAfter(100); // 최대 100개 문서까지만 처리 후 종료

terminate_after는 설정된 문서 개수만큼 처리한 후 강제로 쿼리를 중단하도록 강제하는 옵션
search.timeout과 함께 사용하면 훨씬 강력한 타임아웃 제어 가능
socketTimeout을 search.timeout보다 짧게 설정하지 않도록 주의

예를 들어, search.timeout = 10초인데 socketTimeout = 5초면 클라이언트가 먼저 타임아웃 남
일반적으로 socketTimeout은 search.timeout보다 길게 설정하는 것이 좋음
🔹 결론
search.timeout이 초과되었더라도 Elasticsearch가 즉시 응답을 반환하는 것은 아님
socketTimeout이 초과되지 않으면 클라이언트는 응답을 계속 기다릴 수 있음
search.timeout 초과 시 즉시 응답을 받으려면 terminate_after 같은 강제 중단 옵션을 추가하는 것이 좋음 🚀

나의 말:
복잡한 시스템에서 socketTimeout을 몇초정도로 하려나?
ChatGPT의 말:
복잡한 시스템에서 socketTimeout을 설정할 때 고려할 요소는 많지만, 일반적인 기준을 정리하면 다음과 같습니다.

🔹 1. 일반적인 socketTimeout 설정 기준
시스템 유형 socketTimeout 추천값 설명
일반적인 검색 요청 30~60초 기본적인 쿼리 수행에 적절
대량 데이터 조회 (scroll, aggregation) 60~120초 데이터가 많아 응답이 오래 걸릴 경우
ML 기반 분석, 복잡한 통계 쿼리 120~300초 복잡한 연산 수행 시 안정적
백오피스 배치 시스템 (야간 배치 작업) 300~600초 배치성 작업으로 여유롭게 설정
실시간 API (모바일, 웹 등) 1~5초 사용자 경험을 위해 빠른 응답 필요
🔹 2. socketTimeout 설정 시 고려해야 할 요소
✅ (1) 평균 쿼리 응답 시간 측정
Elasticsearch의 slow log를 활용해서 쿼리 응답 시간이 얼마나 걸리는지 분석
예제 (log4j2.properties에서 설정):

index.search.slowlog.threshold.query.warn: 5s
index.search.slowlog.threshold.query.info: 3s
index.search.slowlog.threshold.query.debug: 1s

실제 평균 응답 시간이 2초 정도라면 socketTimeout을 5초 정도로 설정하는 것이 합리적
✅ (2) 네트워크 상태 및 부하 고려
시스템이 다중 노드 환경이라면, 네트워크 레이턴시를 포함하여 설정
네트워크 상태가 좋지 않다면 여유 있게 설정하는 게 안전
✅ (3) 쿼리 특성 분석
단순 검색 (match, term) → socketTimeout 5~30초
복잡한 Aggregation → socketTimeout 60~120초
Deep Pagination (scroll 사용) → socketTimeout 120~300초
✅ (4) search.timeout과 조합하여 설정
search.timeout(쿼리 실행 제한 시간)과 socketTimeout(클라이언트가 기다리는 시간)은 맞춰야 함
예를 들어, search.timeout = 10초이면 socketTimeout = 15초 정도로 설정

// search.timeout = 10초
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
    .query(QueryBuilders.matchAllQuery())
    .timeout(TimeValue.timeValueSeconds(10));

// socketTimeout = 15초
RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200, "http"))
    .setRequestConfigCallback(requestConfigBuilder -> 
        requestConfigBuilder.setSocketTimeout(15000) // 15초 설정
    )
    .build();
    ```
🔹 3. 현실적인 socketTimeout 설정 예시
🔹 A. 실시간 API (사용자 검색)
요청이 1~2초 내에 끝나야 함
search.timeout = 2, socketTimeout = 3~5초
```java
searchSourceBuilder.timeout(TimeValue.timeValueSeconds(2));
requestConfigBuilder.setSocketTimeout(5000);

🔹 B. 대량 데이터 조회 (대시보드, 분석)
Aggregation이나 scroll을 사용할 때
search.timeout = 60초, socketTimeout = 90~120초

searchSourceBuilder.timeout(TimeValue.timeValueSeconds(60));
requestConfigBuilder.setSocketTimeout(120000);

🔹 C. 배치 작업 (야간 분석, 백오피스)
대량 처리, 시간 여유 있음
search.timeout = 300초, socketTimeout = 600초

searchSourceBuilder.timeout(TimeValue.timeValueMinutes(5));
requestConfigBuilder.setSocketTimeout(600000);

🔹 4. 결론: 적절한 socketTimeout 설정
실시간 API → 1~5초 (빠른 응답 필요)
일반적인 검색 요청 → 30~60초 (기본값 유지)
대시보드 및 Aggregation → 60~120초
배치성 분석 작업 → 300~600초 (충분한 처리 시간 확보)
🚀 즉, 평균 응답 시간을 측정하고, search.timeout과 조합하여 최적의 socketTimeout을 설정하는 것이 중요!

profile
일하며 하는 기록

0개의 댓글

관련 채용 정보