본문 바로가기
카테고리 없음

AWS OpenSearch Deep Dive

by yeon_zoo 2024. 2. 6.

 

[오픈서치 딥다이브]

  • 샤드를 고르게 배포하려면 샤드 수를 데이터 노드 수의 배수로 구성
  • 가용성을 높이려면 AZ의 배수를 고려해서 레플리카 수를 구성
  • 인덱스 생성 패턴
    • Rolling index : 데이터에 시간이 있어서 오래된 인덱스는 주기적으로 마이그레이션하거나 삭제 가능.
      • ex) search-logs-2022, iot-sensor-logs-2022-07
    • Long-Term Retention Index : 같은 인덱스에 소스 데이터를 저장
      • 문서의 업데이트나 삭제가 필요한 경우가 많음
      • ex) movies, website-contents, internal-docs
  • 인덱스 사이즈 관리
    • 사이즈 기반 로테이션 : 특정 크기를 넘어서면 인덱스를 새로 생성하여 데이터를 분배하여 넣음
      • 데이터가 늘어나도 샤드 하나의 크기가 예측값보다 커지지 않음
      • 인덱스가 나뉘더라도 샤드의 크기가 동일하기 때문에 성능 예측이 쉬움
  • 기간(시계열) 기반 로테이션 : 일정 시간 단위동안 들어오는 데이터 양이 비슷하다면 시간 단위로 인덱스를 생성
    • 크기 추정 가능
    • 삭제 쉬움. 기간 기준 검색 요구사항 필요
    • 요청할 때도 특정 인덱스를 찾아서 요청하기 때문에 성능 더 빨라짐
  • 로테이션 빈도에 따른 주의사항
    • 매일 들어오는 데이터 양이 일정하더라도 빈도(인덱스 생성 주기)에 따라서 샤드 구성이 달라짐
    • 예를 들어 아래 식을 본다 (프라이머리 샤드만 고려한다고 하며 일일 데이터 양은 30GB / 샤드 사이즈는 50GB)
      • Daily rotate : 30GB * 1.1 (인덱싱하면 10% 정도 저장소가 더 든다고 가정) / 50GB = 0.66 샤드 (이지만 0.66 샤드는 없으므로 하루에 1 샤드씩 증가됨)
      • Weekly rotate : 30GB * 1.1 * 7 /50GB = 4.62 = 5개의 샤드
      • Monthly rotate : 21개의 샤드 vs Daily rotate * 30일 = 30개의 샤드
      • 샤드의 개수는 성능에 영향을 미치므로 이런 지점도 고려 필요
  • 적합한 opensearch cluster (=도메인)구성하기
    • 스토리지 - 티어
      • ultra warm과 cold storage를 고려해야 할까
      • hot : instance + Data volume
      • ultra warm : instance + cache volume + S3 bucket
      • Cold storage : S3 bucket
    • 샤드 - 개수와 사이즈
      • 일반적인 사이즈는 아래와 같이 설정해서 시작하곤 함.
        • Long-Term Retention Index : 10 ~ 30 GB 사이 
        • Rolling Index : 10 ~ 50GB
      • 샤드는 50GB 이하로 시작해라 + 인덱스 생성 후에는 샤드 수 수정 불가하니 long-term은 데이터 증가를 좀 고려해라
    • 샤드 - 예측
      • 인덱스 지정 시 프라이머리 샤드 수 / 레플리카 샤드의 수를 지정해줘야 함.
      • 프라이머리 샤드 수 = (source data + room for growth) * (1 + indexing overhead) / size per shard  (indexing overhead는 보통.. 10% 로 생각)
  • vCPU 예측 & Memory 예측
    • 클러스터에 할당할 vCPU 수는 활성화된 샤드 수를 기반으로 한다.
  • API 요청 핸들링
    • es에 요청 시 큐에 쌓임. 이 큐에 쌓인 요청을 Thread Pool 에서 각각의 쓰레드가 가져와서 해결하는 식
    • 큐는 검색 큐와 데이터 CRUD 큐가 따로 있음 (Thread Pool도 따로 있음)
    • 큐에 요청 너무 많으면 429 (Too Many Requests) 에러를 반환함
      • 특히 쓰레드가 샤드별로 할당되기 때문에 하나의 요청 당 여러 개의 쓰레드 (= 여러 개의 vCPU)가 할당 될 수 있다.
    • 따라서 인스턴스 유형을 변경하여 vCPU 추가하면 API 처리 동시성이 증가한다.

[검색 성능 최적화]

  • File system cache 에 메모리 할당 늘리기
  • Node Query Cache 활용
    • filter 쿼리를 사용했을 때의 응답속도 개선
    • LRU 정책을 토대로 가장 오랫동안 사용되지 않은 것을 삭제
    • 힙 영역의 10% 정도 사용
  • 필요한 경우 인스턴스 스토어 사용
    • 많은 양의 데이터를 검색하거나 집계할 때 높은 io 성능이 필요
    • 인스턴스 스토어는 EBS보다 지연시간이 낮음
    • 높은 I/O 성능이 필요한 경우, 인스턴스 스토어가 있는 인스턴스 유형 사용
  • 복잡한 도큐먼트 구조 피하기
    • 중첩 필드 유형은 가능한 사용하지 않기
      • 일반 필드 유형보다 검색 요청을 처리하는데 몇 배 더 오래 걸릴 수 있음
      • 중첩 유형 아래에 여러 필드가 있고 해당 필드의 조합으로 검색해야 하는 경우
      • copy_to를 사용하려 여러 필드를 결합하고 단일 필드로 복사
  • 조인 필드 유형으로 부모-자식 관계를 최대한 사용하지 말기
    • 일반 필드 유형보다 검색 요청 처리 시 수백배 더 오래 걸릴 수 있음
    • 1:N 부모-자식 관계 외에는 사용하지 않는 것을 권장
  • Term을 이용해서 범위 만들기
    • e.g.) price_krw 라는 필드의 값이 4980 이라면 “price_krw_range” 라는 필드에 “1000-5000" 값을 추가
    • 이 경우 검색 시 ranges 대신 terms 쿼리로 field : “price_krw_range” 를 검색하면 됨. (훨씬 빠르고 쿼리도 덜 복잡)
  • 검색 시점을 고려하여 필드 유형을 지정하기 (= 목적에 따라 수치 데이터의 종류 선택)
    • e.g) product_id 값 keyword로 설정하고 목적을 알 수 없는 필드의 경우에는 서브 필드의 형태로 integer 필드로 등록
  • 가능한 script 피하기
    • script 대신 데이터 전처리를 이용하는 편이 더 성능이 좋음.
    • 데이터 전처리에 사용하는 것은.. kinesis data firehose 나 Lambda 등
  • 인덱스 소팅
    • “size” 같은 조건이 있을 때, 인덱스 소팅 조건도 넣어주면 n개만 찾고 나머지는 스킵하게 된다. (아예 탐색하지 않음)
    • 소팅은 쓰기 성능을 저하시킬 수 있으므로 상황에 맞춰서 사용
  • 큰 결과 값에는 페이징과 비동기 검색 활용
    • 기본 반환되는 문서는 10000개
    • 10000개 이상으로 많은 문서를 가져오려면 큰 힙 메모리가 필요하고 vCPU 사용률 증가
    • search_After, size & from 을 이용하여 API 실행 당 검색되는 문서 수 줄이기
    • 비동기 검색 사용 고려 : 배치 프로세싱과 같이 오랫동안 실행되는 쿼리 등
  • 인덱스 롤업
    • 집계 비용을 절약하는 기능
    • 모든 데이터를 검색하지 않고 집계된 데이터를 활용하는 데에 쓸 수 있음

 

[인덱스 최적화]

  • _bulk API
    • 다중 문서 생성 및 수정
      • tcp /https 연결 통신 비용 감소
    • 데이터 크기는 운영 환경에 따라 적절한 크기가 달라짐
      • 단일 샤드 환경 ) 페이로드 3~5 MB 정도로 설정하고 모니터링하여 수정
  • 새로 고침 간격 조절
    • API -> JVM Heap -refresh-> File System Cache (Page Cache) -flush-> Disk
    • 위의 과정에서 flush 주기를 조절하는 것
    • 간격을 넓게 하면 세그먼트 (디스크에 작성되는 단위) 생성 빈도가 줄어든다. -> 성능이 좋아짐.
    • 새로고침 간격이 멀면 인덱싱 시점과 검색 가능 시점이 차이가 나게 됨 -> 실시간 성 줄어듬
    • 실시간성에 대한 요구가 크지 않은 경우, 간격 조절하는 것이 좋음
  • Replica 비활성화
    • 인덱싱 성능 향상
  • 도큐먼트 id 자동 생성
    • 개발자가 등록하려는 도큐먼트의 Id가 이미 존재하는지 확인 필요 없음
  • 인덱싱과 검색 워크로드 분리
    • 두 요청 사이의 경쟁 x
    • 검색 도메인을 read replica로 생성하여 도메인1 (인덱싱 요청을 받는 도메인) 에서 도메인2 (검색 요청을 받는 도메인)으로 복사

 

[AWS Opensearch 내의 꿀팁]

  • 자동 튜닝 사용
    • 유지 관리 기간 중 블루 / 그린 배포로 운영
    • 온라인으로 즉시 반영
  • 워크로드 특성에 따른 클러스터 분리
    • 로그 수집 도메인인 경우, IO 요청이 많음.
    • 풀텍스트 검색용 도메인인 경우, 데이터 양은 많지 않고 시간당 요청 수가 많음 -> vCPU 성능이 좋아야 함
    • 각 특성에 따라 최적의 클러스터를 선택
  • 운영환경에서는 T2, T3 사용하지 말기
    • 메모리 관련 이슈가 발생하기 쉬움.
  • Data Stream 활용
    • 하나의 인덱스 내의 데이터가 너무 많은 경우, Data Stream이 일정 크기를 넘어갔을 때 인덱스 뒤에 일련 번호를 붙여 서로 다른 인덱스를 생성한다.
    • 같은 인덱스에 인덱싱 요청이 들어오는 경우는 마지막 일련 번호 인덱스에 요청을, 검색 요청을 하는 경우는 모든 일련번호에 요청을 하게 된다.
  • 스케일링 전략
    • 일반적으로 스케일 아웃보다 스케일 업이 더 효율적이다. (스케일 아웃은 노드가 분리되어 노드 간의 통신에 병목 현상이 발생할 수 있음)
    • 노드 사용량 제한이나 힙사이즈 제한 등은 스케일 아웃이 효율적일 있다.

댓글