ELK Stack 완벽 가이드: Elasticsearch, Logstash, Kibana로 구축하는 대용량 로그 통합 관리 시스템

ELK Stack 완벽 가이드: Elasticsearch, Logstash, Kibana로 구축하는 대용량 로그 통합 관리 시스템

1. 서론

지난 포스팅에서 Logback을 이용해 단일 서버 환경에서 로그를 파일로 남기고, 치명적인 에러가 발생했을 때 슬랙(Slack)으로 알림을 받는 방법까지 알아보았습니다. 서비스 초기 단계나 트래픽이 많지 않은 단일 서버 아키텍처(Monolithic Architecture)에서는 이 정도 설정만으로도 충분히 운영이 가능합니다. 개발자가 필요할 때 서버에 접속해서 vim이나 catgrep 명령어로 로그 파일을 열어보면 되기 때문입니다.

하지만 서비스가 성장하여 서버가 10대, 100대로 늘어나거나, 마이크로서비스 아키텍처(MSA)를 도입하여 수십 개의 서비스가 서로 통신하는 환경이 되면 상황은 완전히 달라집니다. 어떤 요청에서 에러가 발생했을 때, 그 요청이 지나간 모든 서버의 로그 파일을 일일이 열어보는 것은 물리적으로 불가능에 가깝습니다. 또한, “지난 일주일간 발생한 500 에러의 추이를 그래프로 보고 싶다”거나 “특정 사용자가 발생시킨 모든 트랜잭션을 추적하고 싶다”는 요구사항은 리눅스 명령어만으로는 해결할 수 없습니다.

이러한 한계를 극복하기 위해 등장한 것이 바로 로그 통합 관리 시스템이며, 그중 전 세계적으로 가장 널리 사용되는 사실상의 표준(De Facto Standard) 기술이 바로 ELK Stack입니다. 오늘은 흩어져 있는 수많은 로그 데이터를 한곳으로 모으고, 검색하고, 시각화하여 데이터에 생명력을 불어넣는 ELK Stack의 아키텍처와 구축 방법에 대해 심도 있게 다뤄보겠습니다.


2. 본론

1: ELK Stack이란 무엇인가? (E, L, K 그리고 B)

ELK Stack은 로그 데이터를 수집, 저장, 분석, 시각화하기 위해 엘라스틱(Elastic) 사에서 제공하는 오픈소스 프로젝트들의 묶음을 말합니다. 각 앞 글자를 따서 Elasticsearch, Logstash, Kibana라고 부르며, 최근에는 경량 수집기인 Beats가 추가되어 Elastic Stack이라는 명칭으로 불리기도 합니다. 각 컴포넌트가 담당하는 역할과 원리를 상세히 이해해야 효율적인 시스템을 구축할 수 있습니다.

1. Elasticsearch (저장 및 검색 엔진)

ELK 스택의 심장이라고 할 수 있는 Elasticsearch는 아파치 루씬(Apache Lucene)을 기반으로 구축된 분산 검색 엔진입니다. 단순히 데이터를 저장하는 데이터베이스 역할을 넘어, 방대한 양의 데이터를 거의 실시간(Near Real-time)에 가깝게 저장하고 검색할 수 있는 강력한 성능을 자랑합니다.

RDBMS(관계형 데이터베이스)가 행(Row) 기반으로 데이터를 저장하고 SQL문으로 LIKE 검색을 수행한다면, Elasticsearch는 역색인(Inverted Index) 구조를 사용하여 텍스트를 분석하고 저장합니다. 마치 책 뒤편의 ‘색인(Index)’처럼, 문장 속에 포함된 단어들을 쪼개어 어떤 문서에 포함되어 있는지를 기록해 두기 때문에, 수십억 건의 로그 중에서도 특정 에러 메시지를 순식간에 찾아낼 수 있습니다. 또한, 데이터를 ‘샤드(Shard)’ 단위로 분산하여 여러 노드에 저장하므로 고가용성과 수평적 확장성(Scale-out)이 매우 뛰어납니다.

2. Logstash (데이터 수집 및 가공 파이프라인)

Logstash는 다양한 소스(애플리케이션 로그, DB 데이터, 센서 데이터 등)로부터 데이터를 수집하여 변환 과정을 거친 뒤, Elasticsearch와 같은 저장소로 전송하는 ETL(Extract, Transform, Load) 도구입니다.

Logstash의 핵심은 ‘필터(Filter)’ 기능입니다. 비정형 데이터인 로그 문자열을 받아서, 이를 분석하기 쉬운 JSON 형태의 정형 데이터로 변환합니다. 예를 들어, 2024-01-01 ERROR [User-123] Payment Failed라는 텍스트 로그가 들어오면, Logstash는 이를 타임스탬프, 로그 레벨, 사용자 ID, 메시지 필드로 쪼개어 구조화합니다. 이 과정에서 Grok 패턴이라는 정규표현식 기반의 문법을 사용하여 데이터를 정교하게 파싱 할 수 있습니다.

3. Kibana (시각화 및 관리 대시보드)

Elasticsearch에 저장된 데이터는 그 자체로는 JSON 덩어리에 불과합니다. Kibana는 이 데이터를 시각적으로 표현해 주는 UI 도구입니다. 개발자나 운영자는 복잡한 쿼리문을 작성하지 않고도 Kibana의 ‘Discover’ 탭을 통해 로그를 검색할 수 있으며, 파이 차트, 라인 차트, 히트맵 등 다양한 그래프를 활용하여 대시보드를 구성할 수 있습니다. 이를 통해 “시간대별 트래픽 추이”, “가장 많이 발생한 에러 TOP 5” 등을 한눈에 모니터링할 수 있어, 장애 발생 시 원인 분석 시간을 획기적으로 단축시켜 줍니다.

4. Beats (경량 데이터 수집기)

Logstash는 강력한 기능을 가지고 있지만, 자바 런타임 위에서 동작하기 때문에 리소스를 꽤 많이 소모합니다. 모든 웹 서버마다 Logstash를 설치하는 것은 부담스러운 일입니다. 이를 해결하기 위해 등장한 것이 Beats입니다. Go 언어로 작성되어 매우 가볍고, 서버에 설치되어 로그 파일이나 메트릭 정보를 수집하여 Logstash나 Elasticsearch로 전송하는 역할만 전담합니다. 로그 파일 수집을 위한 Filebeat, 시스템 리소스 모니터링을 위한 Metricbeat 등이 있습니다.

2: 대용량 로그 처리를 위한 아키텍처 설계

단순히 ELK를 설치한다고 끝나는 것이 아닙니다. 트래픽 규모에 따라 아키텍처를 적절하게 설계해야 데이터 유실을 막고 성능을 유지할 수 있습니다.

1. 기본 아키텍처 (Small Scale)

  • 구성: App Server (Filebeat) -> Logstash -> Elasticsearch -> Kibana
  • 특징: 가장 일반적인 구성입니다. 애플리케이션 서버에는 가벼운 Filebeat만 설치하여 로그를 수집하고, 이를 별도의 Logstash 서버로 보냅니다. Logstash에서 데이터를 가공(필터링)하여 Elasticsearch에 저장합니다. 트래픽이 크지 않은 중소규모 서비스에 적합합니다.

2. 고가용성 아키텍처 (Large Scale with Buffering)

  • 구성: App Server (Filebeat) -> Kafka (Message Queue) -> Logstash -> Elasticsearch -> Kibana
  • 특징: 대규모 이벤트가 발생하는 블랙 프라이데이 같은 상황에서는 로그 발생량이 폭증하여 Logstash나 Elasticsearch가 이를 감당하지 못하고 다운될 수 있습니다. 이를 방지하기 위해 중간에 Kafka나 Redis 같은 메시지 큐를 버퍼(Buffer)로 둡니다. 로그 데이터는 먼저 안정적인 큐에 저장되고, Logstash는 자신이 처리할 수 있는 속도에 맞춰 큐에서 데이터를 가져가 처리합니다. 이를 통해 시스템의 안정성을 극대화할 수 있습니다.

3: Docker Compose를 활용한 ELK 구축 실습

이론을 넘어 실제 구축을 해보겠습니다. 로컬 환경에서 가장 쉽고 빠르게 테스트해 볼 수 있는 Docker Compose 방식을 소개합니다. 아래 설정 파일은 가장 기본적인 형태의 ELK 스택을 구성합니다.

먼저, 프로젝트 루트에 docker-compose.yml 파일을 생성합니다.

YAML

version: '3.7'
services:
  # 1. Elasticsearch: 데이터 저장소
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
    container_name: elasticsearch
    environment:
      - node.name=elasticsearch
      - discovery.type=single-node # 단일 노드 모드
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # 힙 메모리 설정
    ports:
      - "9200:9200"
    volumes:
      - ./es-data:/usr/share/elasticsearch/data # 데이터 영구 저장

  # 2. Logstash: 데이터 처리 파이프라인
  logstash:
    image: docker.elastic.co/logstash/logstash:7.17.0
    container_name: logstash
    volumes:
      - ./logstash/config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    ports:
      - "5000:5000/tcp"
      - "5000:5000/udp"
      - "9600:9600"
    depends_on:
      - elasticsearch

  # 3. Kibana: 시각화 도구
  kibana:
    image: docker.elastic.co/kibana/kibana:7.17.0
    container_name: kibana
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200
      ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]'
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

다음으로 Logstash가 데이터를 어떻게 처리할지 정의하는 logstash/config/logstash.conf 파일을 작성합니다. 여기서는 TCP 포트 5000번으로 들어오는 데이터를 받아서 Elasticsearch로 넘기는 설정을 해보겠습니다.

코드 스니펫

# [Input]: 데이터가 들어오는 곳
input {
  tcp {
    port => 5000
    codec => json_lines # JSON 형태로 들어오는 로그 처리
  }
}

# [Filter]: 데이터 가공 (필요 시 Grok 패턴 등 사용)
filter {
  # 예시: 특정 필드 추가
  mutate {
    add_field => { "service_name" => "my-backend-server" }
  }
}

# [Output]: 가공된 데이터를 저장할 곳
output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    index => "app-logs-%{+YYYY.MM.dd}" # 날짜별로 인덱스 생성
  }
  # 디버깅을 위해 콘솔에도 출력
  stdout { codec => rubydebug }
}

이제 docker-compose up -d 명령어를 실행하면 컨테이너 3개가 구동됩니다. 애플리케이션에서 Logstash 서버(localhost:5000)로 로그를 쏘면(SocketAppender 등을 이용), Kibana(localhost:5601)에 접속하여 인덱스 패턴을 등록하고 로그를 실시간으로 확인할 수 있습니다.

4: 실무 운영 시 반드시 고려해야 할 사항들

ELK 스택은 매우 강력하지만, 자원을 많이 소모하고 관리가 까다로운 시스템이기도 합니다. 실무 운영 시 다음 포인트들을 반드시 챙겨야 합니다.

  1. 인덱스 수명 주기 관리 (ILM, Index Lifecycle Management):로그 데이터는 시간이 지날수록 가치가 떨어집니다. 하지만 계속 쌓아두면 디스크 용량이 부족해집니다. 따라서 ‘핫(Hot) – 웜(Warm) – 콜드(Cold) – 삭제(Delete)’ 단계를 정의하여, 최근 데이터는 고성능 SSD에 저장하고, 오래된 데이터는 저렴한 HDD로 옮기거나 자동으로 삭제되도록 정책을 설정해야 합니다.
  2. 매핑(Mapping) 설정의 중요성:Elasticsearch는 데이터가 들어올 때 자동으로 타입을 추론하여 매핑을 생성합니다. 하지만 이 과정에서 문자열 필드가 불필요하게 분석(Analyze)되어 검색 성능을 저하시키거나 저장 공간을 낭비할 수 있습니다. 가능한 한 명시적으로 인덱스 템플릿을 정의하여 필드 타입을 지정하는 것이 좋습니다. 특히 정확히 일치하는 검색을 위해서는 keyword 타입으로, 전문 검색이 필요하다면 text 타입으로 설정하는 것을 구분해야 합니다.
  3. 보안 설정 (X-Pack Security):기본 설치 시 Elasticsearch는 인증 없이 누구나 접근 가능합니다. 이는 보안상 매우 치명적입니다. X-Pack Security 기능을 활성화하여 ID/PW 인증을 설정하고, HTTPS 통신을 적용하여 데이터를 암호화해야 합니다. 특히 Kibana가 외부에 노출되어 있다면 반드시 로그인을 거치도록 해야 합니다.

3. 결론

지금까지 대용량 로그 처리를 위한 ELK Stack의 개념부터 아키텍처, 그리고 Docker Compose를 활용한 구축 방법까지 상세히 알아보았습니다.

과거에는 로그 관리가 단순히 “파일을 저장한다”는 개념이었다면, ELK 스택을 도입한 이후에는 로그가 **”비즈니스 인사이트를 제공하는 데이터 자산”**으로 변모하게 됩니다. 개발자는 에러 로그를 통해 코드의 잠재적인 버그를 빠르게 찾아내고, 기획자는 사용자의 행동 패턴 로그를 분석하여 서비스 개선의 단서를 얻을 수 있습니다. 이것이 바로 우리가 ‘관측 가능성(Observability)’ 확보에 힘써야 하는 이유입니다.

처음에는 설치하고 설정하는 과정이 다소 복잡하게 느껴질 수 있습니다. 하지만 한 번 구축해 놓으면 수백 대의 서버를 운영하더라도 두려움 없이 전체 시스템을 조망할 수 있는 강력한 눈을 갖게 될 것입니다. 오늘 소개한 내용을 바탕으로 여러분의 로컬 환경에서부터 작은 로그 파이프라인을 만들어보시기를 권장합니다.


로그 모니터링 시스템을 구축했다면, 이제는 시스템의 리소스(CPU, Memory)와 성능 지표를 수집할 차례입니다. ELK Stack으로도 가능하지만, 메트릭 수집에 특화된 “Prometheus와 Grafana를 활용한 서버 성능 모니터링 시스템 구축” 방안도 검토해보는 것은 어떨까요

“ELK Stack 완벽 가이드: Elasticsearch, Logstash, Kibana로 구축하는 대용량 로그 통합 관리 시스템”에 대한 1개의 생각

댓글 남기기