ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Elasticsearch의 개념 살펴보기..(1)위에서 아래로
    개발하면서/타인글보면서 2021. 8. 21. 13:41
    반응형

    내 기준으로 Elasticsearch을 간단하게 운영하고 사용은 할 수 있지만
    조금 복잡한 쿼리 작성이 필요할 때 바로 작성을 못하거나 예상치 못한 오류(Circuit breaker!!)를 보는 경우가
    있어 필요한 부분을 하나하나 알아보려고 한다.

    사실 가장 큰 이유는 그냥 궁금해서다. ㅎㅎ
    Elasticsearch에는 어떠한 기능들이 있고 역할이 무엇이며 왜 필요한지 알아가는 과정이
    재밌을 것 같다. 알아가는 과정 중간중간 나의 업무나 삶에 적용하는 것도 재밌다.

     

    먼저 Elasticsearch 사용자 입장에서 색인과 검색이 어떻게 이루어지는지 살펴본다. 위에서 아래로
    https://www.elastic.co/blog/found-elasticsearch-top-down
    2014년 글이지만 개념에 대한 설명이라 지금 봐도 큰 문제없다.

     


     

    위 그림은 Elasticsearch cluster를 간단하게 그린 것이다.
    A cluster내에 Master node 1개, Data node 3개가 있고 Data node에는 3개 shard, 1개 replica로 설정된 index가
    존재한 상황이다. 요청은 모든 노드에게 갈 수 있다.
    요청을 받아 적절한 노드에 전달하고 응답하는 역할을 coordinator라고 하는데 모든 노드는 coordinator가 default다.

    노드 설정에 cluster.name으로 클러스터 세팅을 할 수 있고 node.roles로 노드의 역할을 지정할 수 있다. [1]
    cluster.name 이 같아야 동일한 클러스터로 묶인다.
    노드의 역할은 다양하게 있는데 3개만 알아보자

    master: 클러스터 상태를 관리하는 역할, ※ coordinator가 되기 위해서는 클러스터 상태가 필요한데 마스터에서 가져가는 듯?

    data: 문서를 색인하고 검색을 담당하는 역할

    ingest: 문서 색인 전에 전처리를 담당하는 역할

     

    node.roles: [], node.roles: [master]. , node.roles: [master, data]

    노드에 역할을 부여하는 방법인데 역할을 안 줄 수도 있고 한 개, 혹은 여러 개 줄 수도 있다.
    모든 노드는 coordinator 역할을 한다. "node.roles: []"은 coordinator 역할만 한다고 볼 수 있다.
    master는 data처럼 요청이 분산되지 않고 한 노드가 모든 요청을 처리하고 그 외는 대기 상태로 있으니
    서버 비용이 부담되는 게 아니라면 master 역할만 하는 노드 세팅을 추천한다.

    Coordinator

    cluster에 요청이 오면 요청을 받은 노드가 coordinator가 되어 어디로 요청을 보내야 할지 결정하고
    요청이 처리되어 받은 응답들을 합쳐 보내주는 역할을 한다.

    노드가 coordinator가 되기 위해선, 즉 요청을 받기 위해선 모든 cluster의 상태를 알아야 한다.

    cluster 상태란 모든 노드의 routing table(노드에 저장된 index, shard 정보), 노드의 속성이나
    index mapping정보 등을 말한다.
    coordinator는 모든 노드 가능

       -> cluster 상태는 모든 노드로 복제
       -> 모든 노드는 클러스터 상태와 응답을 합치는 연산을 무난하게 처리할 만한 memory와 cpu도 여유분 고려

     

    검색 요청은 random으로 shard를 선택하거나 preference에 알맞은 노드의 샤드를 선택해서 처리한다.
    색인 요청은 primary shard에만 요청이 간다. 각 shard는 primary가 딱 하나씩 있다.  replica는 0개 이상.

    Index

    "색인(index)"이라는 단어는 다양한 문맥에서 다른 뜻으로 쓰여 혼란을 준다.
    예를 들어 문서를 Elasticsearch index색인을 하고 Elasticsearch index는 한 개 이상의 shard를
    갖는데 이는 Lucene index다.

    두 개 shard인 Elasticsearch index는 한 개 shard Elasticsearch index 두 개와 동일하다.
    즉 Lucene Index = Elasticsearch shard라고 생각하면 된다.
    Elasticsearch index와 Lucene index의 가장 큰 차이점은 routing이다.
    Elasticsearch routing 기능이 있어 쉽게 확장이 가능하다.

    색인 시 문서 ID는 coordinator가 routing 할 때 사용되는데 문서 ID가 없으면 coordinator가 임의로 할당해준다.
    ※ 색인할 때 문서에 ID가 있으면 routing 되는 shard에 문서 ID가 존재하는지 확인하는데
    ID가 없으면 확인하는 연산을 하지 않아 문서 색인 속도가 빨라진다고 하네요. [2]
    운영하는데 어느 정도 문서 중복도 괜찮다면 coordinator에서 ID 할당하는 것도 좋은 방법 같다.

     

    또한  schema를 정하지 않아도 색인이 가능한데 운영해보면 알겠지만 schema를 정의하는 게 좋다.

    ※ 많이 예를 드는 게 색인 생성 시 첫 문서의 A라는 필드 값이 숫자여서 숫자 필드로 스키마가 정의됐는데,
    나중에 A필드 값이 문자인 경우 해당 문서는 색인에 실패한다.

    segment에 기록이 되지 않으면 검색되지 않는다. 즉 위 그림에서 Memory Buffer에 있는 문서는 검색이 되지 않는다. [3]
    일반적으로 refresh_interval 간격으로 refresh가 실행되면 새로운 Segment(mem)이 생성되면서 Memory Buffer에 있는 내용이
    기록되고 검색이 된다.
    segment도 memory와 disk로 나뉘는데 만약 memory에만 기록된 상태에서 노드가 재시작되면 유실 된다.
    memory에서 disk로 저장하는 연산인 Elasticsearch flush(Lucene commit)를 빈번하게 실행하자니
    비싼 연산이어서 자주 실행하기도 어렵다.

    그래서 나온 개념이 translog(transaction log)다. translog에는 색인 요청을 기록해서 나중에 복구할 때 사용한다.
    물론 translog도 한 건 한 건 파일에 쓰는 게 아니라 유실이 있을 수 있지만 Elasticsearch flush보다 가벼워서
    파일에 빈번하게 쓸 수 있어 유실되는 양을 줄일 수 있다.

    아래 그림은 flush 했을 때 translog와 segment를 나타낸 그림이다.
    segment(memory)를 합쳐 segment(disk)에 기록하는데
    Disk에 써져서 기존 Translog는 불필요해져서 기존 Translog는 지우고 새로운 Translog를 만든다.

     

    Search

    검색 요청도 색인과 비슷한 흐름인데 다른 점이 두 개 있다.
    첫째, 색인은 routing 할 때 꼭 primary shard 가야 하는데 검색은 primary, replica 구분 없이 요청할 수 있다.

    둘째, coordinator가 각 shard에 검색 요청을 하고 취합해서 검색 요청에 결과를 보내준다. [4]
    이때 query_then_fetch라는 개념이 나오는데 coordinator가 쿼리를 각 shard에 보내주면
    shard들은 문서 ID와 정렬에 사용되는 값을 리턴한다. 그럼 coordinator는 이를 정렬 및 검색 요청의 개수를 고려해서
    문서 ID를 뽑아내고 문서 ID에 해당하는 shard에만 실제 문서 조회를 한다.
    재밌는 건 만약 shard가 3개인 index에 검색 개수 9개 요청이 오면 coordinator가 각 shard에 3개 결과를 요청하고
    합치는 게 아니라 각 shard당 9개 결과를 요청한다는 점이다.
    다음과 같은 이유로 3개가 아닌 9개를 요청한다.
    1. 어떤 shard에는 쿼리에 적합한 문서가 없을 수 있다. (2개 이하인 경우)
    2. 쿼리에 적합한 문서가 있다고 해도 score 계산할 때 특정 shard에 연관도 높은 문서가 몰려있을 수 있다.

    위에 설명한 검색 방식은 query_then_fetch인데 정말 정확한 검색 결과를 원한다면
    search_type parameter 값을 dfs_query_then_fetch 주면 된다고 한다.  자세한 동작은 나중에 알아보자. ㅎ
    ※ 미래의 나야 파이팅!!

     

    ref url:
    cluster topology
    https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html ... [1]

    index
    https://www.elastic.co/guide/en/elasticsearch/reference/master/tune-for-indexing-speed.html#_use_auto_generated_ids  ... [2]
    https://www.elastic.co/guide/en/elasticsearch/guide/current/translog.html#img-xlog-pre-refresh ... [3]

    https://qbox.io/blog/refresh-flush-operations-elasticsearch-guide/

    https://medium.com/@pooja.narula/watch-your-elasticsearch-cluster-6e9c2f80578c
    https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-refresh.html#refresh-api-desc
    search
    https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
    https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-search-type.html ... [4]


    지금까지 사용자의 색인/검색 요청이 Elasticsearch내에서 어떻게 흐르는지 알아보았다.
    다음 포스트는 검색의 역색인 구조부터 시작하여 shard 구성에 대해 알아보기로 한다.

    반응형

    댓글

Designed by Tistory.