엔지니어링

공간 절약: Elasticsearch의 인덱스 정렬이 지닌 잘 알려지지 않은 장점

Elasticsearch 6.0에 인덱스 정렬이라고 부르는 새로운 기능이 출시되었습니다. 링크로 연결된 블로그에서 이 기능에 대해 자세히 살펴보시기 바랍니다. 한 마디로 요약하자면 이는 인덱스 시점에 문서를 가져와 고객이 정한 순서에 따라 하나의 키 또는 여러 키로 정렬하는 기능입니다. 이 방식에는 몇 가지 장점이 있습니다.

  • Elasticsearch에서 색인을 정렬한 것과 동일한 키로 정렬된 결과 집합을 반환하도록 요청하면 Elasticsearch는 쿼리 시점에 결과를 정렬할 필요가 없습니다. 이미 정렬되어 있습니다!
  • 전체 조회수를 필요로 하지 않으며 정렬 키를 기준으로 정렬하는 경우 Elasticsearch는 고객의 요청에 부응하는 충분한 조회수가 나타나면 쿼리를 실제로 중단시킬 수 있습니다. 이렇게 하면 쿼리 성능이 제한 없이 개선될 수 있습니다.
  • 다른 필드 간에 AND를 사용하는 쿼리일 경우, 이러한 필드에 대한 인덱스 정렬은 필드를 그룹화함으로써 일치하지 않는 대규모 문서 블록을 Elasticsearch에서 건너뛸 수 있는 방식으로 이뤄지고, 따라서 검색 또한 빨리 진행됩니다.

간단히 말해, 인덱스 정렬은 일부 경우에 검색을 빨리 수행할 수 있게 해 줍니다. 특히 문서 검색과 분류를 수행하는 방법이 몇 가지 없을 때 그렇습니다. 자주 언급되지 않는 점 한 가지는, 인덱스 정렬이 인덱스가 활용하는 디스크의 용량을 절감해 준다는 것입니다. 그 이유와 방식을 설명하겠습니다.

주의: 인덱스 정렬이 모든 경우에 알맞지는 않습니다

보다 자세한 점을 알려드리기 전에, 인덱스 정렬이 모든 경우에 적합한 것은 아니라는 점을 다시 한 번 알려드리고자 합니다. 인덱스 정렬은 인덱스 시점에 정렬 작업이 이뤄집니다. 정렬은 많은 대가를 치뤄야 하는 작업으로, 인덱싱 속도가 주된 문제인 경우 기능을 작동시키기 전에 주의하시기 바랍니다. 기록 성능을 40~50%가량 저하시킬 수 있습니다. 인덱싱 처리율이 주된 문제라면, 인덱스 정렬은 높은 용량의 로깅, 메트릭스, 보안 분석 사용 사례에 나타나듯이 인덱스 정렬을 사용하는 것이 적합하지 않을 수 있습니다. 인덱스 속도가 낮은 경우, 쿼리 속도가 가장 중요한 상황인 경우 또는 피크 인덱싱 시점이 아닌 때에 작동하는 일반 재인덱스 절차를 진행하는 경우 유용합니다.

가능한 정렬 순서 검사: 사례

제품 검색에 사용되는 Elasticsearch 인스턴스를 실행한다고 해보겠습니다. 여러 문서가 있고 인덱스 시점에 다음과 같은 데이터가 보인다고 가정해 보겠습니다. (보기 쉽도록 간단하게 표를 만들었습니다.)

제품 ID제품 카테고리제품 색상가격
206f467b-8cfe신발빨간색$97.00
4f89fbec-acc3재킷검정색$120.50
47771396-dfe3재킷회색$170.10
c6c8fbdf-651b모자노란색$15.00
dc18c426-0eb3신발빨간색$107.20
ee304259-df57재킷검정색$88.00
9332c0ac-e55e신발검정색$49.00
30e96765-52a1모자파란색$11.00
811cc8ca-d6bb재킷파란색$92.99

이제 인덱스 정렬을 활성화하기를 원한다고 해 봅시다. 어떤 기준으로 정렬할 수 있습니까? 몇 가지 옵션이 있습니다. 제품 카테고리, 제품 색상, 가격 정도가 있겠네요. 만약 사용자 검색이 거의 언제나 가격을 기준으로 정렬되고 카테고리나 색상에 대한 필터가 없는 경우 가격에 의한 정렬이 대부분의 경우 정렬 기준이 될 것입니다. 하지만, 사용자는 가장 저렴한 상품을 선택하기 전에 카테고리를 하나 정도는 선택할 것이며, 색상에 대한 취향도 있을 것입니다. 카테고리 오름차순, 색상 오름차순, 가격 오름차순으로 정렬해 봅시다.

"sort.field" : ["product_category", "product_color", "price"], "sort.order" : ["asc", "asc", "asc"]

인덱스가 정렬되면 다음과 같이 나타날 것입니다.

제품 ID제품 카테고리제품 색상가격
30e96765-52a1모자파란색$11.00
c6c8fbdf-651b모자노란색$15.00
ee304259-df57재킷검정색$88.00
4f89fbec-acc3재킷검정색$120.50
811cc8ca-d6bb재킷파란색$92.99
47771396-dfe3재킷회색$170.10
9332c0ac-e55e신발검정색$49.00
206f467b-8cfe신발빨간색$97.00
dc18c426-0eb3신발빨간색$107.20

이제 몇 가지 흥미로운 일들이 일어납니다. 예를 통해 설명해 드리겠습니다.

  • 만약 Elasticsearch를 통해 가격을 기준으로 정렬된 가장 저렴한 순으로 2개의 신발을 검색하려고 하며 모든 신발의 전체 조회수를 필요로 하지는 않는 경우, 효율을 위해 다른 모든 카테고리를 건너뛰고 신발 블록을 검색해야 합니다. 그리고 2개의 결과를 찾아내면 나머지 인덱스의 처리를 중단하고 결과값을 반환합니다. 이러한 과정이 제대로 작동하려면, 일치하는 필터가 있는 경우라도 인덱스의 정렬 순서의 모든 요소를 포함시켜야 합니다.
  • 만약 Elasticsearch를 통해 product_category:Jackets AND product_color:Black을 검색하는 경우 Elasticsearch는 모자, 신발은 전부 건너뛰고 재킷 가운데서 ‘검정색’을 검색합니다. 그리고 검색을 마치면 효율을 위해 다른 모든 색상은 건너뜁니다.
  • Elasticsearch는 드러나지 않는 방식으로 압축을 상당히 많이 사용합니다. 압축은 반복된 값이 있는 경우 활용할 수 있으며, 인덱스상에서 반복된 값이 가까운 위치에 있을 때 가장 효과적입니다. “재킷” 또는 “색상”이 모두 한데 있는 경우 디스크상에서 효율적으로 압축될 수 있는 것입니다. 이렇게 하면 디스크 공간이 덜 필요하면서도 운영체제가 더 많은 파일시스템 캐시를 활용할 수 있고 따라서 속도가 더 빨라집니다.

일반적으로, 카디널리티를 증가시키는 정렬 순서를 적용하여 동일한 열에 반복된 값이 가능한 많이 있어 이점을 누릴 수 있게 하는 것이 좋습니다.

얼마나 되는 디스크 공간을 절약할 수 있습니까?

그러면 인덱스 정렬을 사용해 얼마나 되는 디스크 공간을 절약할 수 있습니까? 인생과 마찬가지로, 그 답은 “상황마다 다르다”라는 것입니다. 한 가지 주요 요소는 정렬하려는 필드의 카디널리티입니다. 하지만 디스크 절약은 중대한 영향을 미칠 수 있습니다. 지난 주말에, 저는 개인 프로젝트에 사용하던 IoT/가정 자동화 데이터 일부를 기존 기기에서 새로운 기기로 옮기기로 했습니다. 이러한 데이터 이전을 수행하려면 스냅샷/복구와 같은 보다 빠른 방법이 있지만 재인덱스를 해 볼 시간이 났고 인덱스 정렬이 얼마나 되는 공간을 절약해 주는지 확인하고 싶었습니다. 먼저 원격 재인덱스를 정렬되지 않은 인덱스로 수행했습니다.

status    index           pri    docs.count    docs.deleted    pri.store.size 
open      devices-2017    1      33310674      0               4.2gb

기기의 수는 30개가 약간 넘었고, 각각의 기기가 매 30초마다 그 상태를 전송해 왔기 때문에 전체 인덱스 속도는 초당 1개의 문서 정도가 되었습니다. 인덱싱과 관련한 사항을 인위적으로 조절하지 않았으며, 그러한 변화를 하려면 인덱스 속도 또는 기기의 수를 크게 증가시켜야 했을 것입니다. 인덱스 정렬에 알맞은 후보로 보이네요. 데이터는 하드웨어 ID, 하드웨어 이름, 시간, 온도, 해당 시점의 기기 전원이 켜졌는지의 여부 또는 다른 센서 레벨 등과 같은 여러 센서 판독값으로 구성됩니다. 저는 인덱스를 기기 ID, 그 다음에는 시간으로 정렬했으며, 대상이 되는 기기의 경우 동일한 시점에 비슷하거나 같은 값일 확률이 상식적으로 매우 높으므로 이는 더 많은 압축을 가져올 것으로 판단되었습니다. 예를 들어, 스위치가 7:00:00에 "켜짐" 상태인 경우, 7:00:30, 7:01:00에도 "켜짐" 상태일 확률이 더 높으며, 적어도 몇 분 뒤까지는 압축이 원활하게 이뤄집니다. 정렬된 인덱스 통계에 따르면…

status    index           pri    docs.count     docs.deleted    pri.store.size
open      devices-2017    1      3310674        0               2.5gb

디스크가 약 40%나 절약되었네요!

재차 드리는 주의사항

이 시점에, 모두에게 다시 한 번 이 주의사항을 알려드려야 한다는 기분이 드네요. 왜냐하면 거의 모든 분들이 동일한 데이터에 대해 40%의 디스크 절약을 기대하실 수 있으니 말이죠. 간단한 두 가지 문장으로 요약하겠습니다.

  • 수치는 상황마다 달라집니다. 제가 인덱스 정렬을 다른 데이터 세트에 적용했을 때에는 20%의 절약이 나타났습니다. 어느 필드를 정렬할 지 심사숙고하시기 바랍니다.
  • 고객의 인덱스 속도가 느려질 수 있습니다. 높은 용량의 로깅 또는 메트릭스를 사용하는 등 인덱싱 속도가 가장 중요한 경우라면, 짧은 시간 내에 인덱싱하려는 문서의 수에 민감할 가능성이 높으며 따라서 인덱스 정렬을 활성화하는 것이 좋은 선택이 아닐 수 있습니다.

인덱스 속도보다는 디스크 공간에 민감하거나 인덱스 용량이 충분히 낮아 인덱스 속도에 구애받지 않는 경우라면 인덱스 정렬을 활용해 볼 수 있을 것입니다.