🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Elasticsearch 인덱스 최적화 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 29. · 21 Views

Elasticsearch 인덱스 최적화 완벽 가이드

Elasticsearch를 운영하면서 반드시 알아야 할 인덱스 최적화 기법을 다룹니다. 샤드 설계부터 ILM, Rollover까지 실무에서 바로 적용할 수 있는 핵심 전략을 초급자도 이해할 수 있게 설명합니다.


목차

  1. 샤드_개수_설계
  2. 인덱스_템플릿
  3. 인덱스_별칭
  4. ILM_인덱스_수명_관리
  5. Rollover_전략
  6. 인덱스_최적화_force_merge

1. 샤드 개수 설계

김개발 씨는 최근 회사에서 Elasticsearch를 도입하는 프로젝트에 투입되었습니다. 처음 인덱스를 생성하려는데, 설정 화면에서 "샤드 개수"라는 항목을 발견했습니다.

기본값이 1로 되어 있는데, 이대로 두어도 되는 걸까요? 아니면 데이터가 많으니까 100개쯤 넣어야 하는 걸까요?

**샤드(Shard)**는 Elasticsearch에서 데이터를 나누어 저장하는 기본 단위입니다. 마치 도서관에서 책을 여러 서가에 분산해서 보관하는 것과 같습니다.

샤드 개수를 적절히 설계하면 검색 성능을 극대화하고, 클러스터 자원을 효율적으로 활용할 수 있습니다.

다음 코드를 살펴봅시다.

PUT /logs-2024
{
  "settings": {
    // 프라이머리 샤드 개수 - 한번 설정하면 변경 불가
    "number_of_shards": 3,
    // 레플리카 샤드 개수 - 운영 중 변경 가능
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "timestamp": { "type": "date" },
      "message": { "type": "text" },
      "level": { "type": "keyword" }
    }
  }
}

김개발 씨는 입사 6개월 차 백엔드 개발자입니다. 이번에 처음으로 Elasticsearch 클러스터를 구축하는 업무를 맡게 되었습니다.

공식 문서를 읽어보니 "샤드"라는 개념이 계속 등장하는데, 도대체 이게 뭔지 감이 오지 않았습니다. 옆자리 선배 박시니어 씨에게 조심스럽게 물어봤습니다.

"선배, 샤드가 정확히 뭔가요? 그리고 몇 개로 설정해야 하나요?" 박시니어 씨가 웃으며 설명을 시작했습니다.

"샤드를 이해하려면 먼저 도서관을 떠올려봐. 만약 도서관에 책이 100만 권이 있다고 해봐.

이걸 한 곳에 다 모아두면 어떻게 될까?" 김개발 씨가 잠시 생각했습니다. "음...

찾기도 어렵고, 한 사람이 책을 찾는 동안 다른 사람들은 기다려야 할 것 같아요." "바로 그거야. 그래서 도서관은 책을 여러 서가에 나눠서 보관하지.

Elasticsearch도 마찬가지야. 대용량 데이터를 하나의 덩어리로 저장하면 검색도 느리고, 장애에도 취약해져.

그래서 데이터를 여러 조각으로 나누는데, 이 조각 하나하나를 샤드라고 불러." 샤드에는 두 종류가 있습니다. **프라이머리 샤드(Primary Shard)**는 원본 데이터를 저장하는 샤드입니다.

**레플리카 샤드(Replica Shard)**는 프라이머리 샤드의 복제본으로, 장애 상황에서 데이터를 보호하고 검색 성능을 높이는 역할을 합니다. 여기서 중요한 점이 있습니다.

프라이머리 샤드 개수는 인덱스를 생성할 때 결정되면 나중에 변경할 수 없습니다. 마치 건물의 기둥 개수를 건축 후에 바꿀 수 없는 것과 같습니다.

반면 레플리카 샤드 개수는 언제든지 조정할 수 있습니다. 그렇다면 샤드 개수는 어떻게 정해야 할까요?

박시니어 씨가 화이트보드에 공식을 적었습니다. "일반적으로 샤드 하나당 10GB에서 50GB 정도의 데이터를 담는 게 좋아.

너무 작으면 오버헤드가 커지고, 너무 크면 복구 시간이 길어지거든." 예를 들어 100GB의 로그 데이터를 저장한다면, 샤드를 2개에서 10개 사이로 설정하는 것이 적당합니다. 또한 노드당 샤드 수는 20개 이하로 유지하는 것이 권장됩니다.

샤드가 너무 많으면 클러스터 상태 관리에 부담이 되기 때문입니다. 실무에서 흔히 하는 실수 중 하나는 "데이터가 많아질 것 같으니까 미리 샤드를 100개로 설정해두자"라는 생각입니다.

하지만 이렇게 하면 각 샤드에 담기는 데이터가 너무 적어져서 오히려 성능이 저하됩니다. 작은 샤드가 수백 개 있으면 검색 시 모든 샤드를 조회해야 하므로 오버헤드가 급격히 증가합니다.

김개발 씨가 고개를 끄덕였습니다. "그러면 저희 프로젝트는 일일 로그가 약 30GB 정도 예상되니까, 샤드를 3개 정도로 시작하면 되겠네요?" 박시니어 씨가 엄지를 치켜세웠습니다.

"정확해. 그리고 레플리카는 1개로 설정해서 데이터 안정성도 확보하면 돼.

나중에 클러스터 규모가 커지면 그때 새 인덱스를 만들면서 조정하면 되니까 너무 걱정하지 마."

실전 팁

💡 - 샤드당 10-50GB를 목표로 설계하고, 노드당 샤드 수는 20개 이하로 유지하세요

  • 프라이머리 샤드 개수는 변경 불가하므로 신중하게 결정하되, 처음부터 완벽할 필요는 없습니다

2. 인덱스 템플릿

김개발 씨는 매일 생성되는 로그 인덱스를 관리하게 되었습니다. logs-2024-01-01, logs-2024-01-02...

매일 새 인덱스를 만들어야 하는데, 매번 똑같은 설정을 반복해서 입력하자니 여간 번거로운 게 아닙니다. 실수로 샤드 개수를 잘못 입력한 날에는 처음부터 다시 만들어야 했습니다.

**인덱스 템플릿(Index Template)**은 새로운 인덱스가 생성될 때 자동으로 적용되는 설정과 매핑의 청사진입니다. 마치 문서 작성 시 미리 만들어둔 양식을 사용하는 것과 같습니다.

템플릿을 한 번 정의해두면 일관된 설정으로 인덱스를 자동 생성할 수 있습니다.

다음 코드를 살펴봅시다.

PUT _index_template/logs-template
{
  // 이 패턴과 일치하는 인덱스에 템플릿 적용
  "index_patterns": ["logs-*"],
  // 우선순위 - 높을수록 먼저 적용
  "priority": 100,
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "refresh_interval": "5s"
    },
    "mappings": {
      "properties": {
        "timestamp": { "type": "date" },
        "message": { "type": "text" },
        "level": { "type": "keyword" },
        "service": { "type": "keyword" }
      }
    }
  }
}

매일 아침 김개발 씨의 일과 중 하나는 새로운 로그 인덱스를 생성하는 것이었습니다. 오늘도 어김없이 인덱스 생성 명령어를 작성하려는데, 문득 이런 생각이 들었습니다.

"이걸 매일 수동으로 해야 하나? 분명 더 좋은 방법이 있을 텐데..." 마침 옆을 지나가던 박시니어 씨가 김개발 씨의 화면을 보더니 웃음을 터뜨렸습니다.

"아직도 그렇게 하고 있었어? 인덱스 템플릿을 쓰면 자동으로 되는데." 인덱스 템플릿이란 무엇일까요?

쉽게 말해 "인덱스 생성 양식"입니다. 회사에서 보고서를 작성할 때 매번 처음부터 양식을 만들지 않고, 미리 만들어둔 템플릿을 사용하는 것처럼요.

Elasticsearch도 마찬가지입니다. 템플릿을 한 번 정의해두면, 특정 패턴의 인덱스가 생성될 때 자동으로 해당 설정이 적용됩니다.

위의 코드를 살펴보겠습니다. index_patterns 부분에서 "logs-*"라고 지정했습니다.

이는 "logs-"로 시작하는 모든 인덱스에 이 템플릿을 적용하겠다는 의미입니다. 따라서 logs-2024-01-01, logs-2024-01-02, logs-production 등 어떤 이름이든 "logs-"로 시작하기만 하면 템플릿이 자동 적용됩니다.

priority는 템플릿의 우선순위입니다. 만약 하나의 인덱스가 여러 템플릿의 패턴과 일치할 경우, priority가 높은 템플릿이 적용됩니다.

예를 들어 "logs-" 템플릿과 "logs-error-" 템플릿이 둘 다 있을 때, logs-error-2024 인덱스는 priority가 더 높은 템플릿의 설정을 따릅니다. template 블록 안에는 실제로 적용될 settings와 mappings가 들어갑니다.

여기서 설정한 샤드 개수, 레플리카 개수, 필드 매핑 등이 새 인덱스에 자동으로 적용됩니다. 특히 refresh_interval은 데이터가 검색 가능해지는 주기를 의미하는데, 로그처럼 실시간성이 덜 중요한 데이터는 5초나 10초로 설정해서 성능을 높일 수 있습니다.

김개발 씨가 눈을 반짝였습니다. "그러면 이제 그냥 인덱스 이름만 지정해서 생성하면 되는 건가요?" 박시니어 씨가 고개를 끄덕였습니다.

"맞아. 심지어 데이터를 색인하면서 존재하지 않는 인덱스에 넣으면, Elasticsearch가 자동으로 인덱스를 생성하면서 템플릿을 적용해줘.

수동 작업이 완전히 사라지는 거지." 실무에서는 보통 환경별로 템플릿을 나누어 관리합니다. logs-prod-, logs-dev-, logs-staging-* 같은 식으로요.

각 환경에 맞는 샤드 개수와 레플리카 설정을 다르게 할 수 있어서 자원을 효율적으로 사용할 수 있습니다. 주의할 점도 있습니다.

템플릿을 수정해도 이미 생성된 인덱스에는 적용되지 않습니다. 템플릿은 오직 "새로 생성되는" 인덱스에만 영향을 미칩니다.

따라서 기존 인덱스의 설정을 바꾸려면 새 인덱스를 만들고 데이터를 마이그레이션해야 합니다. 김개발 씨는 바로 템플릿을 생성하고, 테스트로 새 인덱스를 만들어봤습니다.

설정이 자동으로 적용되는 것을 확인하고 환하게 웃었습니다. "이제 매일 아침 인덱스 만드느라 고생 안 해도 되겠네요!"

실전 팁

💡 - 템플릿 변경은 기존 인덱스에 영향을 주지 않으니, 변경 후 새 인덱스부터 적용됨을 기억하세요

  • priority를 활용해 범용 템플릿과 특화 템플릿을 계층적으로 구성할 수 있습니다

3. 인덱스 별칭

김개발 씨는 애플리케이션에서 logs-2024-01 인덱스를 직접 참조하도록 코드를 작성했습니다. 그런데 월이 바뀌어 logs-2024-02 인덱스를 사용해야 할 때, 애플리케이션 코드를 수정하고 재배포해야 했습니다.

"인덱스 이름이 바뀔 때마다 코드를 고쳐야 하다니... 이건 뭔가 잘못된 것 같아요."

**인덱스 별칭(Alias)**은 하나 이상의 인덱스를 가리키는 가상의 이름입니다. 마치 사람의 별명처럼, 실제 인덱스 이름과 별개로 불변하는 이름을 제공합니다.

애플리케이션은 별칭만 참조하면 되므로, 실제 인덱스가 바뀌어도 코드 변경 없이 유연하게 대응할 수 있습니다.

다음 코드를 살펴봅시다.

// 별칭 생성 - logs-current가 logs-2024-01을 가리킴
POST _aliases
{
  "actions": [
    {
      "add": {
        "index": "logs-2024-01",
        "alias": "logs-current"
      }
    }
  ]
}

// 별칭 전환 - 원자적으로 새 인덱스로 변경
POST _aliases
{
  "actions": [
    { "remove": { "index": "logs-2024-01", "alias": "logs-current" }},
    { "add": { "index": "logs-2024-02", "alias": "logs-current" }}
  ]
}

박시니어 씨가 김개발 씨의 코드를 보더니 한숨을 쉬었습니다. "인덱스 이름을 코드에 하드코딩하면 안 돼.

나중에 유지보수가 지옥이 될 거야." 김개발 씨가 고개를 갸웃했습니다. "그러면 어떻게 해야 하나요?

인덱스 이름은 날짜별로 계속 바뀌는데..." "그래서 **별칭(Alias)**이라는 게 있어." 박시니어 씨가 화이트보드에 그림을 그리기 시작했습니다. "쉽게 말해, 인덱스에 별명을 붙여주는 거야." 별칭의 개념은 정말 단순합니다.

실제 인덱스 이름이 logs-2024-01이더라도, 이것에 "logs-current"라는 별칭을 붙여줄 수 있습니다. 애플리케이션은 항상 logs-current만 참조합니다.

내부적으로 어떤 인덱스가 연결되어 있든 상관없이요. 마치 회사에서 "마케팅팀 담당자"라고 부르는 것과 같습니다.

담당자가 김철수 씨에서 이영희 씨로 바뀌더라도, 우리는 여전히 "마케팅팀 담당자"라고 부르면 됩니다. 실제 담당자가 누구인지 매번 확인할 필요가 없는 것이죠.

위 코드에서 첫 번째 명령은 logs-2024-01 인덱스에 logs-current라는 별칭을 추가합니다. 이제 애플리케이션에서 logs-current로 검색하면 실제로는 logs-2024-01에서 데이터를 가져옵니다.

두 번째 명령이 더 중요합니다. actions 배열 안에 remove와 add를 함께 넣으면, 이 두 작업이 원자적(atomic)으로 실행됩니다. 즉, 둘 중 하나만 실행되는 상황이 발생하지 않습니다.

기존 인덱스에서 별칭을 제거하고 새 인덱스에 별칭을 추가하는 작업이 동시에 이루어지므로, 전환 중에 검색이 실패하는 일이 없습니다. 별칭의 또 다른 강력한 기능은 여러 인덱스를 하나의 별칭으로 묶을 수 있다는 것입니다.

예를 들어 logs-2024-01, logs-2024-02, logs-2024-03 세 개의 인덱스를 logs-all이라는 별칭으로 묶으면, logs-all로 검색할 때 세 인덱스를 모두 검색합니다. 지난 분기 전체 로그를 분석할 때 유용합니다.

또한 별칭에 필터를 적용할 수도 있습니다. logs-errors라는 별칭을 만들면서 level이 "error"인 문서만 보이도록 필터를 설정할 수 있습니다.

이렇게 하면 에러 로그만 따로 조회하는 뷰를 만들 수 있습니다. 김개발 씨가 감탄했습니다.

"와, 그러면 애플리케이션 코드는 그대로 두고, Elasticsearch 쪽에서만 별칭을 관리하면 되겠네요?" 박시니어 씨가 고개를 끄덕였습니다. "정확해.

배포 없이 인덱스를 전환할 수 있으니까, 운영이 훨씬 유연해져. 특히 무중단 배포나 블루-그린 배포 전략에서 별칭은 필수야." 주의할 점이 하나 있습니다.

별칭이 여러 인덱스를 가리킬 때는 검색은 가능하지만, 쓰기 작업은 제한됩니다. 데이터를 색인할 때는 is_write_index 옵션을 사용해서 어느 인덱스에 쓸지 명시해야 합니다.

그렇지 않으면 Elasticsearch가 어디에 데이터를 넣어야 할지 몰라서 에러가 발생합니다.

실전 팁

💡 - 애플리케이션에서는 항상 별칭을 사용하고, 실제 인덱스 이름을 직접 참조하지 마세요

  • 별칭 전환 시 remove와 add를 하나의 actions 배열에 넣어 원자적으로 실행하세요

4. ILM 인덱스 수명 관리

어느 날 김개발 씨가 출근해보니 모니터링 알람이 빨간불이었습니다. 디스크 용량이 95%를 넘어섰다는 경고였습니다.

확인해보니 지난 2년간의 로그 인덱스가 모두 그대로 남아 있었습니다. "오래된 데이터는 어떻게 관리해야 하지?"

**ILM(Index Lifecycle Management)**은 인덱스의 생성부터 삭제까지 전체 수명 주기를 자동으로 관리하는 기능입니다. 마치 문서 보관 정책처럼, 데이터의 나이에 따라 저장 방식을 바꾸고 최종적으로 삭제할 수 있습니다.

운영자가 수동으로 관리하지 않아도 디스크 공간을 효율적으로 유지할 수 있습니다.

다음 코드를 살펴봅시다.

PUT _ilm/policy/logs-lifecycle
{
  "policy": {
    "phases": {
      // Hot: 활발하게 읽고 쓰는 단계
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50gb",
            "max_age": "7d"
          }
        }
      },
      // Warm: 읽기 전용, 검색은 가끔
      "warm": {
        "min_age": "30d",
        "actions": {
          "shrink": { "number_of_shards": 1 },
          "forcemerge": { "max_num_segments": 1 }
        }
      },
      // Delete: 완전 삭제
      "delete": {
        "min_age": "90d",
        "actions": { "delete": {} }
      }
    }
  }
}

디스크 용량 경고를 받은 김개발 씨는 당장 오래된 인덱스를 삭제하려고 했습니다. 하지만 박시니어 씨가 말렸습니다.

"잠깐, 그렇게 수동으로 하면 언젠가 또 같은 문제가 생겨. ILM을 설정해서 자동화하자." **ILM(Index Lifecycle Management)**은 인덱스의 일생을 관리하는 정책입니다.

사람도 유아기, 청소년기, 성인기, 노년기를 거치듯이, 데이터도 비슷한 생애 주기를 거칩니다. Elasticsearch는 이를 Hot, Warm, Cold, Delete 네 단계로 구분합니다.

Hot 단계는 데이터가 가장 활발하게 사용되는 시기입니다. 방금 생성된 로그, 실시간 검색이 필요한 데이터가 여기에 속합니다.

빠른 SSD 디스크에 저장하고, 여러 샤드로 분산해서 쓰기 성능을 극대화합니다. Warm 단계는 데이터가 어느 정도 지나서 쓰기는 없고 가끔 읽기만 하는 시기입니다.

일주일이 지난 로그를 분석할 때가 이런 경우입니다. 이 단계에서는 샤드 개수를 줄이고(shrink), 세그먼트를 병합해서(forcemerge) 저장 공간을 절약합니다.

Cold 단계는 거의 검색하지 않지만 보관은 해야 하는 데이터입니다. 법적 요구사항 때문에 1년간 로그를 보관해야 하는 경우가 이에 해당합니다.

저렴한 HDD 디스크로 이동하거나, 더 적은 자원을 할당합니다. Delete 단계는 보관 기간이 끝나서 삭제해도 되는 데이터입니다.

설정된 기간이 지나면 자동으로 인덱스가 삭제됩니다. 위의 코드를 자세히 살펴보겠습니다.

Hot 단계에서 rollover 액션은 인덱스가 50GB에 도달하거나 7일이 지나면 새 인덱스로 전환하라는 의미입니다. 이렇게 하면 인덱스 크기를 적절하게 유지할 수 있습니다.

Warm 단계의 **min_age: "30d"**는 인덱스 생성 후 30일이 지나면 이 단계로 진입한다는 뜻입니다. shrink 액션은 샤드 개수를 1개로 줄이고, forcemerge는 세그먼트를 1개로 병합합니다.

더 이상 데이터가 추가되지 않으므로 이렇게 최적화해도 문제가 없습니다. Delete 단계에서는 90일이 지난 인덱스를 자동으로 삭제합니다.

김개발 씨가 걱정하던 디스크 용량 문제가 근본적으로 해결되는 것입니다. 박시니어 씨가 덧붙였습니다.

"ILM 정책을 만들었으면, 인덱스 템플릿에 이 정책을 연결해야 해. 그래야 새로 생성되는 인덱스에 자동으로 적용되거든." 김개발 씨가 ILM 정책을 설정하고 나니, 더 이상 디스크 용량을 수동으로 관리할 필요가 없어졌습니다.

시스템이 알아서 오래된 데이터를 정리하니, 운영 부담이 크게 줄었습니다.

실전 팁

💡 - ILM 정책은 인덱스 템플릿과 연결해야 새 인덱스에 자동 적용됩니다

  • 처음에는 보수적으로 설정하고, 모니터링하면서 단계별 기간을 조정하세요

5. Rollover 전략

김개발 씨는 ILM 설정에서 본 "rollover"라는 단어가 계속 마음에 걸렸습니다. "인덱스를 굴린다(roll over)는 게 무슨 뜻이지?" 검색해봐도 명확하게 와닿지 않아서, 결국 박시니어 씨에게 물어보기로 했습니다.

Rollover는 특정 조건(크기, 문서 수, 나이)을 충족하면 자동으로 새 인덱스를 생성하고 별칭을 전환하는 기능입니다. 마치 일기장이 다 차면 새 일기장을 꺼내 쓰는 것과 같습니다.

이를 통해 인덱스 크기를 적절하게 유지하고, 관리 효율성을 높일 수 있습니다.

다음 코드를 살펴봅시다.

// 1. Rollover용 인덱스 생성 (숫자 패턴 필수)
PUT logs-000001
{
  "aliases": {
    "logs-write": { "is_write_index": true },
    "logs-read": {}
  }
}

// 2. 수동 Rollover 실행
POST logs-write/_rollover
{
  "conditions": {
    "max_age": "7d",
    "max_docs": 10000000,
    "max_size": "50gb"
  }
}

// 결과: logs-000002가 생성되고 logs-write 별칭이 이동됨

박시니어 씨가 설명을 시작했습니다. "Rollover를 이해하려면 먼저 문제 상황을 알아야 해.

로그 데이터를 하나의 인덱스에 계속 쌓으면 어떻게 될까?" 김개발 씨가 생각해봤습니다. "음...

인덱스가 점점 커지겠죠? 수백 GB가 될 수도 있을 것 같아요." "맞아.

그러면 검색 성능이 떨어지고, 장애 복구 시간도 길어지고, 샤드 재배치도 오래 걸려. 그래서 인덱스 크기를 적절하게 유지해야 하는데, 이걸 자동으로 해주는 게 바로 Rollover야." Rollover의 핵심 개념은 간단합니다.

"조건을 충족하면 새 인덱스로 넘어간다." 마치 공책이 다 차면 새 공책을 펼치는 것과 같습니다. 조건은 세 가지가 있습니다.

max_age(최대 나이), max_docs(최대 문서 수), max_size(최대 크기). 이 중 하나라도 충족하면 rollover가 실행됩니다.

위의 코드에서 중요한 점을 짚어보겠습니다. 첫째, 인덱스 이름이 logs-000001처럼 숫자로 끝나야 합니다.

Rollover가 실행되면 Elasticsearch가 자동으로 숫자를 증가시켜 logs-000002를 생성하기 때문입니다. 둘째, is_write_index: true 설정이 핵심입니다.

이 설정이 있는 인덱스에만 새 데이터가 쓰입니다. Rollover가 실행되면 이 플래그가 새 인덱스로 이동합니다.

기존 인덱스는 읽기 전용이 됩니다. 셋째, logs-writelogs-read 두 개의 별칭을 사용하는 패턴이 일반적입니다.

애플리케이션에서 데이터를 쓸 때는 logs-write를, 검색할 때는 logs-read를 사용합니다. logs-read는 여러 인덱스를 묶어서 전체 데이터를 검색할 수 있게 합니다.

실무에서 Rollover는 보통 ILM과 함께 사용합니다. ILM의 Hot 단계에서 rollover 액션을 설정하면, 조건 충족 시 자동으로 새 인덱스가 생성됩니다.

수동으로 POST _rollover를 호출할 필요가 없습니다. 김개발 씨가 질문했습니다.

"그러면 인덱스가 logs-000001, logs-000002, logs-000003... 이렇게 계속 늘어나는 건가요?" 박시니어 씨가 고개를 끄덕였습니다.

"맞아. 하지만 걱정하지 마.

ILM의 delete 단계에서 오래된 인덱스는 자동으로 삭제되니까. Rollover와 ILM을 함께 쓰면 인덱스 수가 일정하게 유지돼." 또 하나 주의할 점이 있습니다.

Rollover 조건 체크는 주기적으로 일어나는데, 기본값이 10분입니다. 따라서 조건을 충족해도 최대 10분까지는 기존 인덱스에 데이터가 쌓일 수 있습니다.

이 주기는 indices.lifecycle.poll_interval 설정으로 조정할 수 있습니다.

실전 팁

💡 - Rollover용 인덱스는 반드시 숫자로 끝나야 합니다 (예: logs-000001)

  • ILM과 함께 사용하면 완전 자동화된 인덱스 관리가 가능합니다

6. 인덱스 최적화 force merge

김개발 씨는 Warm 단계로 넘어간 인덱스의 상태를 확인하다가 이상한 점을 발견했습니다. "세그먼트가 87개나 있네요?

이게 정상인가요?" 디스크 공간도 예상보다 많이 차지하고 있었습니다. 분명히 데이터 양은 같은데, 왜 이렇게 공간을 많이 쓰는 걸까요?

Force Merge는 여러 개의 세그먼트를 하나로 병합하여 저장 공간을 절약하고 검색 성능을 향상시키는 작업입니다. 마치 여러 개의 작은 파일을 하나의 압축 파일로 합치는 것과 같습니다.

더 이상 쓰기가 발생하지 않는 인덱스에서만 사용해야 합니다.

다음 코드를 살펴봅시다.

// 세그먼트 상태 확인
GET logs-2024-01/_segments

// Force Merge 실행 - 세그먼트를 1개로 병합
POST logs-2024-01/_forcemerge?max_num_segments=1

// 삭제된 문서 완전 제거 옵션
POST logs-2024-01/_forcemerge?max_num_segments=1&only_expunge_deletes=true

// 여러 인덱스 동시 최적화
POST logs-2024-*/_forcemerge?max_num_segments=1

박시니어 씨가 김개발 씨의 화면을 보더니 말했습니다. "아, 세그먼트 얘기구나.

이건 Elasticsearch의 내부 구조를 알아야 이해할 수 있어." Elasticsearch는 내부적으로 Lucene이라는 검색 엔진을 사용합니다. Lucene은 데이터를 **세그먼트(Segment)**라는 단위로 저장합니다.

새로운 데이터가 들어오면 작은 세그먼트가 생성되고, 이것들이 점점 쌓입니다. 비유하자면, 메모를 할 때 포스트잇에 하나씩 적어서 붙이는 것과 같습니다.

처음에는 포스트잇이 몇 장 안 되지만, 시간이 지나면 벽면 가득 포스트잇이 붙어 있게 됩니다. 뭔가를 찾으려면 모든 포스트잇을 다 뒤져야 하니 비효율적입니다.

Force Merge는 이 많은 포스트잇을 하나의 노트에 깔끔하게 정리하는 작업입니다. 여러 세그먼트를 하나로 합치면 검색 시 확인해야 할 세그먼트 수가 줄어들어 성능이 향상됩니다.

또한 Elasticsearch에서 문서를 삭제하면 실제로 바로 지워지지 않습니다. 세그먼트 내에서 "삭제됨" 표시만 됩니다.

이 표시된 문서들은 검색에서 제외되지만, 디스크 공간은 여전히 차지합니다. Force Merge를 실행하면 이렇게 "삭제됨" 표시된 문서들이 완전히 제거되어 디스크 공간이 확보됩니다.

코드를 살펴보겠습니다. max_num_segments=1은 모든 세그먼트를 1개로 병합하라는 의미입니다.

가장 효율적인 상태입니다. only_expunge_deletes=true 옵션을 사용하면 전체 병합 대신 삭제된 문서만 제거하는 가벼운 작업을 수행합니다.

그러나 Force Merge는 신중하게 사용해야 합니다. 절대로 쓰기가 진행 중인 인덱스에서 실행하면 안 됩니다. Force Merge 중에 새 데이터가 들어오면 다시 세그먼트가 생성되고, 최악의 경우 디스크 공간이 두 배로 필요할 수 있습니다.

박시니어 씨가 강조했습니다. "Force Merge는 ILM의 Warm이나 Cold 단계에서 자동으로 실행되도록 설정하는 게 가장 안전해.

Hot 단계에서는 절대 하면 안 돼." 또한 Force Merge는 리소스를 많이 사용하는 작업입니다. 실행 중에 CPU와 디스크 I/O가 급증할 수 있습니다.

따라서 트래픽이 적은 시간대에 실행하거나, 한 번에 너무 많은 인덱스를 병합하지 않는 것이 좋습니다. 김개발 씨가 물었습니다.

"그러면 Force Merge 후에 얼마나 공간이 절약되나요?" 박시니어 씨가 대답했습니다. "케이스마다 다르지만, 삭제된 문서가 많았던 인덱스라면 20-30% 이상 줄어들기도 해.

특히 업데이트가 빈번했던 인덱스에서 효과가 커. 업데이트는 내부적으로 삭제 후 삽입이거든." 김개발 씨는 Force Merge를 ILM의 Warm 단계에 설정해두고, 더 이상 수동으로 최적화 작업을 할 필요가 없어졌습니다.

실전 팁

💡 - Force Merge는 반드시 쓰기가 완료된 인덱스에서만 실행하세요

  • ILM Warm/Cold 단계에 자동으로 설정해두면 안전하고 효율적입니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Elasticsearch#IndexOptimization#Sharding#ILM#Alias#Elasticsearch,Search,Backend

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스