3.1 설계 방향

AI 서버 영역은 대량의 로그를 안정적으로 처리하고, AI 기반 분석 인프라를 제공하는 것을 목표로 설계했습니다.

3.1.1. 핵심 설계 원칙

1) 확장 가능한 파이프라인 구조 고객 수와 로그량이 증가해도 처리 성능이 저하되지 않도록 확장성을 우선했습니다.

  • Kafka: 로그를 버퍼링하여 트래픽 급증에도 안정적
  • Logstash: Worker 수평 확장으로 처리량 증가
  • OpenSearch: 클러스터링으로 스토리지 및 검색 성능 확장

2) 고객 서버와의 역할 분리 고객 서버에서는 최소한의 처리만 수행하고, 복잡한 작업은 AI 서버에서 담당합니다.

  • 고객 서버: 로그 생성 → 기본 파싱 → Kafka 전송
  • AI 서버: 2차 정규화 → 인덱싱 → AI 분석 → 대시보드 제공

3) 실시간 분석과 안정성의 균형 실시간 검색을 제공하면서도, 장애 시 데이터 유실이 없도록 설계했습니다.

  • Kafka 보관 기간: 7일 → 장애 발생 시 재처리 가능
  • OpenSearch refresh interval: 5초 → 준실시간 검색 제공
  • 백업 설계 → 필요 시 인덱스를 장기 보관 스토리지로 이관 가능

3.2 구성 요소

3.2.1 Kafka

고객 서버와 AI 서버 사이에서 로그를 안정적으로 전달하는 메시지 큐입니다.

Kafka를 선택한 이유

비교 항목KafkaRabbitMQRedis Streams
처리량매우 높음 (수백만 msg/s)보통높음
메시지 보관설정 가능 (7일)소비 후 삭제제한적
확장성파티션 기반 수평 확장제한적제한적
재처리오프셋 기반 재소비불가가능하지만 복잡

Kafka는 대량의 로그를 고속으로 처리하면서도, 장애 시 재처리가 가능하므로 로그 수집 파이프라인에 적합합니다.

역할

Fluent Bit (고객 서버)
  → Kafka Producer
  → application-logs 토픽
  → 최대 7일간 보관
  → Logstash Consumer

KRaft 모드 도입 Zookeeper 없는 KRaft 모드를 사용해 구성 요소를 단순화했습니다.

  • 관리 포인트 감소
  • 장애 복구 속도 향상
  • 운영 비용 절감

실제 운영 설정 예시

KAFKA_LOG_RETENTION_HOURS: 168              # 7일간 보관
KAFKA_ADVERTISED_LISTENERS:
  - PLAINTEXT://kafka:19092                 # 내부 통신
  - PLAINTEXT_HOST://ai.loglens.store:9092  # 외부 통신 (고객 서버)
  • 내부 통신: AI 서버 내부에서는 kafka:19092 사용 (Logstash ↔ Kafka)
  • 외부 통신: 고객 서버에서는 ai.loglens.store:9092 사용 (Fluent Bit → Kafka)

3.2.2 Logstash

Kafka에서 전달된 로그를 읽어 2차 정규화 후 OpenSearch로 저장합니다.

2차 정규화가 필요한 이유:

고객 서버의 Fluent Bit에서 기본 정규화를 수행하지만,
더 복잡한 구조 변환은 AI 서버에서 처리하는 것이 효율적입니다.

Logstash에서 수행하는 주요 작업

1) 복잡한 필드 변환

  • 중첩 JSON(log_details) 파싱
  • Java Map → JSON 변환
  • Response 로그에서 HTTP 정보 추출

2) 고유 log_id 생성
중복 인덱싱을 방지하기 위해 고유 식별자를 생성합니다.

hash_input = "#{project_uuid}-#{timestamp}-#{message}" log_id = Digest::SHA256.hexdigest(hash_input).to_i(16) % (2**63)

3) 고객별 인덱스 라우팅
고객 프로젝트를 구분하기 위해 인덱스를 분리합니다.

index => "%{safe_project_uuid}_%{+YYYY_MM}"

Pipeline 구조

Kafka Consumer
  → 필드 정리 및 변환
  → log_id 생성
  → 인덱스 결정
  → OpenSearch Bulk Insert

리소스 설정

LS_JAVA_OPTS: -Xmx4g -Xms4g 
PIPELINE_WORKERS: 4

메모리가 많이 필요한 특성을 고려해 적절한 힙 메모리를 확보했습니다.

3.2.3 OpenSearch

정규화된 로그를 저장·검색·집계하는 검색 엔진입니다.

OpenSearch를 선택한 이유

비교 항목OpenSearchElasticsearchMongoDB
검색 성능매우 빠름매우 빠름보통
전문 검색강력강력제한적
집계 쿼리강력강력보통
KNN Vector지원 (AI 분석)지원미지원
라이선스Apache 2.0 (오픈소스)SSPL (제한적)SSPL

OpenSearch는 오픈소스 기반이면서, AI 분석에 필요한 KNN 벡터 검색을 지원한다는 점이 강점입니다.

인덱싱 전략

1) 프로젝트별 + 월별 인덱스 생성

${projectA_UUID}_2025_01
${projectA_UUID}_2025_02
${projectB_UUID}_2025_01
  • 고객 데이터 격리
  • 특정 기간만 검색해 성능 향상
  • 삭제/백업이 월 단위로 쉬움

2) Refresh Interval

refresh_interval: 5s

검색 속도와 인덱싱 부하 사이에서 적절한 균형을 맞췄습니다.

KNN Vector 지원

AI 기반 로그 분석을 위해 OpenSearch의 KNN(K-Nearest Neighbors) Vector 기능을 활용합니다.

"log_vector": {
  "type": "knn_vector",
  "dimension": 1536,
  "method": {
    "name": "hnsw",
    "space_type": "innerproduct",
    "engine": "faiss"
  }
}

LLM 기반 분석을 위해 벡터 검색을 활용합니다.
(유사 로그 검색, 패턴 분석 등)


3.3 AI 서버 관점의 이점

3.3.1 고객 서버와의 완전한 분리

  • AI 서버 장애가 고객 서버 동작에 영향을 주지 않음
  • Kafka 버퍼링으로 장시간 장애에도 데이터 유실 없음
  • 중앙 집중적 운영으로 관리 효율성 향상

Fluent Bit이 파일 기반 offset을 관리하므로,
AI 서버가 다운되더라도 고객 서버는 그대로 로그를 저장·전송할 준비를 유지합니다.

3.3.2 수평 확장 가능한 구조

필요에 따라 각 컴포넌트를 독립적으로 확장할 수 있습니다.

Kafka: 파티션 증설 
Logstash: Worker/인스턴스 수평 확장 
OpenSearch: 노드 & 샤드 증가

또한 Kafka UI, OpenSearch Dashboards를 통해 병목 구간을 쉽게 파악할 수 있습니다.

3.3.3 AI 분석 인프라 제공

OpenSearch + FastAPI 기반으로 AI 분석 기능을 제공합니다.

  • 벡터 검색 기반 유사 로그 추천
  • LLM 기반 에러 원인 분석
  • 패턴 기반 이상 탐지

FastAPI 덕분에 Python 생태계(OpenAI, LangChain 등)를 유연하게 연결할 수 있으며,
AI 분석 로직을 독립적으로 발전시킬 수 있습니다.


3.4 설계 트레이드오프

3.4.1 Kafka 보관 기간

선택: 7일

장점

  • 최대 7일간 재처리 가능
  • Logstash 장애에도 데이터 유실 없음

단점

  • 저장 공간 증가
  • 오래된 데이터 read 시 성능 저하

보완책

  • 디스크 사용량 모니터링
  • 지연 시 알림

3.4.2 OpenSearch 인덱스 전략

선택: 고객별 + 월별 인덱스

장점

  • 고객 데이터 분리
  • 검색 성능 향상
  • 삭제·백업 쉬움

단점

  • 인덱스 수 증가
  • 관리 복잡성 증가

보완책

  • ILM 정책 적용
  • 오래된 인덱스 Cold Storage로 이동 가능

3.4.3 Logstash vs Kafka Streams

선택: Logstash

항목LogstashKafka Streams
러닝커브낮음높음
개발 속도빠름느림
OpenSearch 연동공식 지원직접 구현
디버깅쉬움복잡

LogLens의 로그 처리량은 Logstash로 충분히 감당할 수 있으며,
빠른 개발·유지보수 관점에서 Logstash가 적합했습니다.

단점

  • Ruby 기반이라 메모리 사용량이 많음
  • 초고성능 환경에서는 Kafka Streams보다 느릴 수 있음

보완책

  • 충분한 메모리 할당
  • 필요 시 수평 확장