Elasticsearch를 사용하다 보면 가장 흔하게 마주치게 되는 에러 중 하나가 바로 NoNodeAvailableException입니다. 이 에러는 클라이언트가 Elasticsearch 클러스터의 어떤 노드에도 연결할 수 없을 때 발생하는데, 생각보다 다양한 원인이 있어서 개발자들을 당황스럽게 만들기도 합니다. 실제로 운영 환경에서 이 에러를 만났을 때의 답답함을 저도 잘 알고 있습니다. 분명히 어제까지는 잘 작동했는데 갑자기 연결이 안 된다면? 이런 상황에서 체계적으로 문제를 해결할 수 있는 방법을 정리해보겠습니다.

 

1. 가장 흔한 원인: 포트 설정 오류

많은 개발자들이 놓치는 가장 기본적인 문제는 포트 번호 혼동입니다.

HTTP API vs Transport API 포트 차이점

Elasticsearch는 두 가지 다른 포트를 사용합니다:

  • 9200번 포트: HTTP REST API용 (브라우저에서 접근 가능)
  • 9300번 포트: Transport API용 (노드 간 통신 및 Java 클라이언트)
// ❌ 잘못된 예시 - HTTP 포트로 Transport 클라이언트 연결 시도
TransportClient client = new TransportClient()
    .addTransportAddress(new InetSocketTransportAddress("localhost", 9200)); // 틀림!

// ✅ 올바른 예시 - Transport 포트 사용
TransportClient client = new TransportClient()
    .addTransportAddress(new InetSocketTransportAddress("localhost", 9300)); // 맞음!

포트 확인 방법

현재 Elasticsearch가 어떤 포트를 사용하고 있는지 확인하려면:

# HTTP API로 확인
curl -X GET "localhost:9200/_nodes/_local/http?pretty"

# Transport 포트 확인
curl -X GET "localhost:9200/_nodes/_local/transport?pretty"

 

 

2. 클러스터 이름 불일치 문제

두 번째로 흔한 원인은 클러스터 이름이 맞지 않는 경우입니다.

클러스터 이름 확인하기

# 현재 클러스터 정보 확인
curl -X GET "localhost:9200/"

응답 예시:

{
  "name" : "my-node-1",
  "cluster_name" : "elasticsearch",  // 이 값이 중요!
  "cluster_uuid" : "abc123...",
  "version" : {...}
}

Java 클라이언트에서 올바른 설정

// 클러스터 이름을 정확히 맞춰야 함
Settings settings = Settings.builder()
    .put("cluster.name", "elasticsearch")  // 위에서 확인한 이름과 일치해야 함
    .build();

TransportClient client = TransportClient.builder()
    .settings(settings)
    .build()
    .addTransportAddress(new InetSocketTransportAddress(
        InetAddress.getByName("localhost"), 9300));

 

 

3. 버전 호환성 문제 해결

Elasticsearch 서버와 Java 클라이언트의 버전 불일치도 자주 발생하는 문제입니다.

버전 확인 방법

서버 버전 확인:

curl -X GET "localhost:9200/"
# 또는
./bin/elasticsearch --version

Java 클라이언트 버전 확인:

<!-- Maven pom.xml에서 확인 -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.17.9</version> <!-- 이 버전이 서버와 일치해야 함 -->
</dependency>

호환성 규칙

Elasticsearch 서버 버전 권장 Java 클라이언트
7.x 7.x (동일 마이너 버전 권장)
8.x 8.x (동일 마이너 버전 권장)
6.x 6.x

 

 

4. TransportClient에서 REST Client로 마이그레이션

중요한 업데이트: Elasticsearch 7.0부터 TransportClient가 deprecated되었고, 8.0에서는 완전히 제거되었습니다. 현재는 Java High Level REST Client 또는 Java API Client를 사용해야 합니다.

REST Client 사용 예시

// Elasticsearch 7.x용 High Level REST Client
RestHighLevelClient client = new RestHighLevelClient(
    RestClient.builder(
        new HttpHost("localhost", 9200, "http")));

// Elasticsearch 8.x용 Java API Client
ElasticsearchTransport transport = new RestClientTransport(
    RestClient.builder(new HttpHost("localhost", 9200)).build(),
    new JacksonJsonpMapper());

ElasticsearchClient client = new ElasticsearchClient(transport);

마이그레이션의 장점

  1. 더 안정적인 연결: HTTP 기반으로 네트워크 문제에 더 강함
  2. 버전 호환성: 서버와 클라이언트 버전 불일치 문제 감소
  3. 보안: HTTPS 지원이 더 쉬움

 

 

5. 네트워크 및 방화벽 설정

네트워크 환경에서 발생하는 문제들도 살펴보겠습니다.

방화벽 설정 확인

# Linux에서 포트 확인
sudo netstat -tlnp | grep :9300
sudo netstat -tlnp | grep :9200

# 방화벽 상태 확인 (Ubuntu/Debian)
sudo ufw status

# 포트 열기
sudo ufw allow 9200
sudo ufw allow 9300

Docker 환경에서의 주의사항

Docker로 Elasticsearch를 실행할 때:

# docker-compose.yml
version: '3'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9
    ports:
      - "9200:9200"
      - "9300:9300"  # Transport 포트도 열어야 함
    environment:
      - discovery.type=single-node
      - network.host=0.0.0.0  # 외부 접근 허용

 

 

6. Sniffing 설정 문제

클라이언트의 sniffing 기능이 문제를 일으키는 경우가 있습니다.

Sniffing 비활성화

Settings settings = Settings.builder()
    .put("cluster.name", "elasticsearch")
    .put("client.transport.sniff", false)  // sniffing 비활성화
    .build();

Sniffing이 문제가 되는 상황

  • NAT 환경에서 실행 중일 때
  • 여러 네트워크 인터페이스가 있는 서버
  • 클라우드 환경 (AWS, GCP 등)

 

 

7. ‘NoNodeAvailableException’ Error 발생시 단계별 확인 방법을 정리하자면…

문제가 발생했을 때 다음 순서로 확인해보세요:

1단계: 기본 연결 확인

# Elasticsearch가 실행 중인지 확인
curl -X GET "localhost:9200/"

# 응답이 없다면 Elasticsearch 재시작
sudo systemctl restart elasticsearch

2단계: 포트 및 클러스터 정보 확인

# 클러스터 이름과 포트 정보 확인
curl -X GET "localhost:9200/_nodes/_local?pretty"

3단계: Java 코드 검증

// 최소한의 연결 테스트 코드
public void testConnection() {
    try {
        Settings settings = Settings.builder()
            .put("cluster.name", "your-cluster-name")  // 실제 클러스터 이름
            .put("client.transport.sniff", false)
            .build();
            
        TransportClient client = TransportClient.builder()
            .settings(settings)
            .build()
            .addTransportAddress(new InetSocketTransportAddress(
                InetAddress.getByName("localhost"), 9300));
                
        // 간단한 클러스터 상태 확인
        ClusterHealthResponse health = client.admin().cluster()
            .prepareHealth().get();
            
        System.out.println("연결 성공! 클러스터 상태: " + health.getStatus());
        client.close();
        
    } catch (Exception e) {
        System.err.println("연결 실패: " + e.getMessage());
        e.printStackTrace();
    }
}

 

 

8. 추가적인 해결 방법 – 로그확인, 타임아웃 조정

로그 분석을 통한 진단

Elasticsearch 로그에서 연결 관련 정보 확인:

# 로그 파일 위치 확인
tail -f /var/log/elasticsearch/elasticsearch.log

# 또는 journalctl 사용
sudo journalctl -u elasticsearch -f

주목해야 할 로그 패턴:

  • "received message from unsupported version": 버전 불일치
  • "failed to connect": 네트워크 연결 문제
  • "cluster.name": 클러스터 이름 불일치

타임아웃 설정 조정

Settings settings = Settings.builder()
    .put("cluster.name", "elasticsearch")
    .put("client.transport.ping_timeout", "60s")
    .put("client.transport.nodes_sampler_interval", "30s")
    .build();

 

 

NoNodeAvailableException은 처음에는 복잡해 보일 수 있지만, 체계적으로 접근하면 대부분 해결할 수 있습니다. 가장 중요한 것은 포트 설정과 클러스터 이름을 정확히 맞추는 것이고, 가능하다면 최신 REST Client로 마이그레이션하는 것을 권장합니다. 실제 운영 환경에서는 이런 문제들을 미리 예방할 수 있도록 모니터링 시스템을 구축하고, 정기적인 연결 상태 확인을 하는 것이 좋습니다. 혹시 위의 방법들로도 해결이 안 된다면, Elasticsearch 버전과 환경 정보를 상세히 확인해보시기 바랍니다.

 

댓글 남기기