Index Template은 인덱스를 생성할 때 사용되는 설정 템플릿입니다. 새로운 인덱스가 생성될 때 매번 정의하는 번거러움을 인덱스 템플릿 설정을 통하여 해결할 수 있습니다. 인덱스 템플릿을 선언을 통해 자동적으로 새롭게 생성되는 인덱스에 설정을 적용하여 일관된 인덱스 구조와 매핑을 유지하고 반복적인 작업을 줄이는 데 사용됩니다.

 

Index Template 생성

실습으로 my-log라는 Index Template을 생성하여 데이터 필드가 잘 적용되는지 확인하도록 하겠습니다.

 

인덱스 생성 시 설정 파라미터에 대한 정보

https://opensearch.org/docs/1.2/opensearch/rest-api/index-apis/create-index/

 

Create index

Create index Introduced 1.0

opensearch.org

PUT _index_template/my-log
{
    "index_patterns": [
        "my-log-*"
    ],
    "template": {
        "settings": {
            "number_of_shards": 4,
            "number_of_replicas": 1,
            "refresh_interval": "5s",
            "opendistro.index_state_management.policy_id": "my-ism"
        },
        "mappings": {
            "properties": {
                "cluster": {
                    "type": "keyword"
                },
                "node": {
                    "type": "keyword"
                },
                "level": {
                    "type": "keyword"
                },
                "message": {
                    "type": "text"
                },
                "timestamp": {
                    "type": "long"
                }
            },
            "dynamic_templates": [
                {
                    "default_string": {
                        "match": "default*",
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "keyword"
                        }
                    }
                },
                {
                    "default_number": {
                        "match": "default*",
                        "match_mapping_type": "long",
                        "mapping": {
                            "type": "integer"
                        }
                    }
                }
            ]
        }
    }
}

index_patterns을 통해 "my-log-"로 시작하는 새롭게 생성된 인덱스에 해당 Template을 적용하도록 지정합니다.

 

number_of_shards 해당 인덱스의 샤드 개수를 설정합니다. Opensearch의 경우 Cluster가 여러 Data Node로 구성되는데 하나의 Data Node에 데이터가 집중되지 않도록 number_of_shards를 설정하여 여러 Data Node에 샤드를 골고루 배치할 수 있습니다.

 

number_of_replicas는 primary shard를 복제한 replica shard의 개수를 설정합니다. 위 설정에서는 1로 설정하여 각각의 primary shard가 복제한 샤드를 한 개씩 구성할 수 있도록 설정하여 HA 구성이 되도록 설정하였습니다.

 

refresh_interval은 간단하게 설명하면 검색할 수 있는 document를 refresh 하는 것을 의미합니다. Opensearch는 데이터가 들어왔다고 바로 검색이 가능한 것이 아니고 데이터가 들어오고 해당 인덱스가 refresh가 되었을 경우 검색이 가능하게 됩니다. refresh_interval을 1s로 설정하였다면 1초마다 refresh 되어 실시간처럼 검색이 가능하게 되지만 indexing 성능에 영향을 미칠 수 있습니다. 만약 본인의 환경이 실시간을 중요하게 여기지 않고 indexing 성능을 우선으로 한다면 refresh_interval값을 크게 가져가는 것을 추천합니다. 보다 자세한 정보를 원하신다면 "Lucene"에 대해 알아보는 것을 추천합니다.

 

opendistro.index_state_management.policy_id 설정은 ISM Policy 정책을 지정하는 것입니다. ISM은 Index state Management로 인덱스의 Lifecycle을 관리해 주는 역할을 수행합니다. 아래 링크에 정리해 두었으니 자세한 내용을 링크에서 확인해 주세요

https://stdhsw.tistory.com/entry/Opensearch-ISMIndex-State-Management

 

mappings.properties 설정은 데이터의 field의 타입을 지정합니다. string 타입에는 대표적으로 keyword, text 타입이 있는데 keyword는 Aggregation과 같이 통계를 내거나 반듯이 같은 값을 검색하는 데 사용되며 text의 경우 Analyzer를 통해 데이터를 분석하는 데 사용됩니다. 그 밖에 많은 field type이 존재하는데 자세한 내용은 Opensearch document를 확인해 주세요

https://opensearch.org/docs/latest/field-types/supported-field-types/index/

 

Supported field types

Supported field types

opensearch.org

mappings.dynamic_templates 설정은 properties로 지정하지 않은 field의 데이터가 들어올 경우 해당 데이터의 필드 타입을 지정합니다. dynamic_templates 은 어떠한 데이터 필드가 들어올지 명확하지 않거나 동일한 이름 형식의 필드가 너무 많을 경우 사용합니다. 위에서 설정된 default_string의 경우 필드의 이름이 default로 시작되며 데이터 형식이 string일 경우 필드의 타입을 keyword로 지정하는 설정이며 default_number의 경우 default로 시작하여 데이터 형식이 number일 경우 필드의 타입을 integer로 설정합니다.

 

Index Template 확인하기

방금 생성한 my-log Template을 확인합니다.

GET _index_template/my-log

 

테스트 해보기

지정된 Template이 잘 적용되는지 bulk를 이용하여 실제 데이터를 넣어 확인합니다. (참고로 bulk는 HTTP Body의 가장 마지막 라인에 enter를 한번 더 넣어줘야지 Error가 발생하지 않습니다.)

POST _bulk
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992028}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992038}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992048}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-2", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992029}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-2", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992030}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-2", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992031}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-2", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992033}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "err", "message": "[err] failed data send", "timestamp": 1688992048}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "warn", "message": "[warn] json format is not valid", "timestamp": 1688992041}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "err", "message": "[err] failed data send", "timestamp": 1688992042}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-2", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992031, "default-text": "APP Test"}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-2", "level": "debug", "message": "[debug] data send successful", "timestamp": 1688992033, "default-text": "APP Test"}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "err", "message": "[err] failed data send", "timestamp": 1688992048, "default-text": "APP Test"}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "warn", "message": "[warn] json format is not valid", "timestamp": 1688992041, "default-number": 111111}
{ "index": { "_index": "my-log-2023-07-10"} }
{ "cluster": "my-test-cluster", "node": "worker-1", "level": "err", "message": "[err] failed data send", "timestamp": 1688992042, "default-number": 222222}

 

정상적으로 데이터가 들어갔는지 확인해 봅니다.

POST my-log-2023-07-10/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_all": {}
        }
      ]
    }
  },
  "from": 0,
  "size": 20
}

 

마지막으로 저장된 데이터와 해당 데이터의 필드 타입이 어떻게 설정되었는지 확인합니다.

GET my-log-2023-07-10/

결과는 다음과 같습니다.

{
    "my-log-2023-07-10": {
        "aliases": {},
        "mappings": {
            "dynamic_templates": [
                {
                    "default_string": {
                        "match": "default*",
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "keyword"
                        }
                    }
                },
                {
                    "default_number": {
                        "match": "default*",
                        "match_mapping_type": "long",
                        "mapping": {
                            "type": "integer"
                        }
                    }
                }
            ],
            "properties": {
                "cluster": {
                    "type": "keyword"
                },
                "default-number": {
                    "type": "integer"
                },
                "default-text": {
                    "type": "keyword"
                },
                "level": {
                    "type": "keyword"
                },
                "message": {
                    "type": "text"
                },
                "node": {
                    "type": "keyword"
                },
                "timestamp": {
                    "type": "long"
                }
            }
        },
        "settings": {
            "index": {
                "opendistro": {
                    "index_state_management": {
                        "policy_id": "my-ism"
                    }
                },
                "refresh_interval": "5s",
                "number_of_shards": "4",
                "provided_name": "my-log-2023-07-10",
                "creation_date": "1688992258343",
                "number_of_replicas": "1",
                "uuid": "n24SvkagRl2OI0NcHb5SXw",
                "version": {
                    "created": "136297827"
                }
            }
        }
    }
}

template으로 지정한 필드의 경우 정상적으로 필드의 타입이 적용된 것을 확인할 수 있습니다. 그리고 default-number와 default-text의 경우 직접적으로 지정하지는 않았지만 dynamic_templates 설정을 통하여 자동적으로 문자열 타입은 keyword로 지정되고 숫자 타입은 integer로 설정된 것을 확인할 수 있습니다.

 

Opensearch에서 ISM은 Index State Management의 약자로 인덱스의 상태를 관리하는 Management 플러그인입니다. 인덱스의 상태란 인덱스의 생명주기를 관리하고 관리 작업을 자동화하는 기능을 제공합니다. 이를 통해 데이터 유지 정책을 정의하여 자주 사용하는 데이터를 Hot, 자주 사용되지는 않지만 종종 사용되는 데이터를 Cold, 그리고 사용되지 않는 데이터를 Delete를 하여 Opensearch의 자원을 보다 효율적으로 사용할 수 있게 할 수 있습니다.

 

ISM Policy 생성

# ISM 생성
PUT _plugins/_ism/policies/my-ism
{
    "policy": {
        "description": "my-index ism policy",
        "default_state": "hot",
        "states": [
          {
            "name" : "hot",
            "actions" : [],
            "transitions" : [
              {
                "state_name" : "cold",
                "conditions" : {
                  "min_index_age" : "3d"
                }
              }
              ]
          },
          {
            "name" : "cold",
            "actions" : [],
            "transitions" : [
              {
                "state_name" : "delete",
                "conditions" : {
                  "min_index_age" : "7d"
                }
              }
              ]
          },
          {
            "name" : "delete",
            "actions" : [
              {
                "delete" : {}
              }
            ],
            "transitions" : []
          }
        ]
    }
}

# 결과
{
    "_id": "my-ism",
    "_version": 1,
    "_primary_term": 409,
    "_seq_no": 936,
    "policy": {
        "policy": {
            "policy_id": "my-ism",
            "description": "my-index ism policy",
            "last_updated_time": 1688990475484,
            "schema_version": 1,
            "error_notification": null,
            "default_state": "hot",
            "states": [
                {
                    "name": "hot",
                    "actions": [],
                    "transitions": [
                        {
                            "state_name": "cold",
                            "conditions": {
                                "min_index_age": "3d"
                            }
                        }
                    ]
                },
                {
                    "name": "cold",
                    "actions": [],
                    "transitions": [
                        {
                            "state_name": "delete",
                            "conditions": {
                                "min_index_age": "7d"
                            }
                        }
                    ]
                },
                {
                    "name": "delete",
                    "actions": [
                        {
                            "retry": {
                                "count": 3,
                                "backoff": "exponential",
                                "delay": "1m"
                            },
                            "delete": {}
                        }
                    ],
                    "transitions": []
                }
            ],
            "ism_template": null
        }
    }
}

인덱스 policy 동작 순서

  1. default_state의 값을 hot으로 정의하여 인덱스가 생성될 때 hot 상태로 생성됩니다. 
  2. transitions.min_index_age를 통해 3일 동안 hot 데이터 형식으로 유지됩니다.
  3. 3일이 지나면 transitions.state_name으로 명시한 cold 상태로 전달됩니다.
  4. cold 상태에서 명시한 7일 동안 데이터를 유지하고 delete 상태로 전달됩니다.
  5. delete 상태에서는 action으로 정의된 delete를 통해 인덱스를  삭제합니다.

간단히 정리하면 명시한 ISM은 3일 동안 Hot 데이터로 유지하고 3일 뒤에는 Delete 되는 Policy입니다. 

 

ISM Policy 확인

ISM을 잘 생성하였다면 GET을 통해 확인합니다.

GET _plugins/_ism/policies

 

ISM 삭제

더 이상 사용되지 않는 ISM을 삭제합니다.

DELETE _plugins/_ism/policies/my-ism

 

Hot에서 바로 Delete로

개발자의 환경에 따라 Cold 데이터를 사용하지 않는 경우가 많습니다. 이런 경우 굳이 Cold 상태까지 선언하는 것보다는 Hot 다음에 바로 Delete로 보내면 됩니다. 아래 예시는 3일 동안 Hot 데이터로 유지하고 3일 뒤에 인덱스가 삭제되는 예시입니다.

PUT _plugins/_ism/policies/my-ism
{
    "policy": {
        "description": "my-index ism policy",
        "default_state": "hot",
        "states": [
          {
            "name" : "hot",
            "actions" : [],
            "transitions" : [
              {
                "state_name" : "delete",
                "conditions" : {
                  "min_index_age" : "3d"
                }
              }
              ]
          },
          {
            "name" : "delete",
            "actions" : [
              {
                "delete" : {}
              }
            ],
            "transitions" : []
          }
        ]
    }
}

 

 

자세한 내용은 아래 링크(Opensearch Document)를 확인해 주세요.

 

https://opensearch.org/docs/latest/im-plugin/ism/index/

 

Index State Management

Index State Management

opensearch.org

 

인덱스의 구조는 이전 template 설정과 같습니다.
https://stdhsw.tistory.com/entry/Elasticsearch%EC%9D%98-Index-template-%EC%84%A4%EC%A0%95

현재 인덱스 구조

필드 타입
user_id long
level keyword
timestamp long
action keyword
message text

 

도큐먼트 생성하기

Elasticsearch index에 document를 생성하여 각각의 필드에 값을 설정하고 index에 데이터를 넣습니다.
user 1 추가하기

api PUT http://localhost:9200/my-log-index-2021-08-24/_doc/1
header Content-type: application/json
body {
    "user_id": 1,
    "level": "info",
    "timestamp": 1629792520,
    "action": "open_file",
    "message": "user file open"
}


user 2 추가하기

api PUT http://localhost:9200/my-log-index-2021-08-24/_doc/2
header Content-type: application/json
body {
    "user_id": 2,
    "level": "info",
    "timestamp": 1629792525,
    "action": "open_socket",
    "message": "user socket open"
}


덮어쓰기를 방지하기 위한 데이터 생성방법
기존처럼 PUT http://localhost:9200/my-log-index-2021-08-24/_doc/2 을 사용하여 데이터를 생성한다면 기존에 도큐먼트 아이디 2가 존재한다면 기존의 데이터는 지워지고 현재 데이터가 덮어써지는 문제가 발생합니다. 이러한 문제를 해결하기 위해 _create를 통하여 데이터를 생성할 수 있습니다.
만약 같은 도큐먼트 아이디가 존재 할 경우 status 409 version_conflict_engine_exception 에러를 반환합니다.

api POST http://localhost:9200/my-log-index-2021-08-24/_create/2
header Content-type: application/json
body {
    "user_id": 3,
    "level": "info",
    "timestamp": 1629792540,
    "action": "close_file",
    "message": "user close open"
}

 

도큐먼트 조회하기

지금까지 입력한 데이터를 조회하도록 하겠습니다.

인덱스에 모든 도큐먼트 조회하기

api GET http://localhost:9200/my-log-index-2021-08-24/_search

출력 결과


특정 도큐먼트 아이디를 이용하여 조회하기
이번에는 인덱스의 모든 데이터가 아닌 도큐먼트 아이디를 이용하여 해당 도큐먼트의 값을 가져오도록 하겠습니다.

api GET http://localhost:9200/my-log-index-2021-08-24/_doc/1

출력 결과


조건을 이용하여 데이터 조회하기
이번에는 특정 조건에 만족하는 데이터를 찾아 조회하도록 하겠습니다.
action 필드의 값이 "open_socket"인 것을 조회하도록 하겠습니다.

api GET http://localhost:9200/my-log-index-2021-08-24/_search?q=action:open_socket

출력 결과

 

도큐먼트 수정하기

데이터를 수정하기 전에 먼저 version의 값을 확인하면 좋습니다.

api GET http://localhost:9200/my-log-index-2021-08-24/_doc/2

출력 결과
출력 결과를 보면 알 수 있듯이 현재 수정을 하지 않은 상태에서는 version이 1입니다.


도큐먼트 아이디를 이용하여 수정하기
도큐먼트 수정하는 것도 조회와 마찬가지로 도큐먼트 아이디를 이용하여 level 필드의 값을 "debug"로 수정하도록 하겠습니다.
_update를 사용하면 기존에 도큐먼트 아이디가 존재하지 않는 다면 에러가 발생합니다.

api POST http://localhost:9200/my-log-index-2021-08-24/_update/2
header Content-type: application/json
body {
    "doc": {
        "level": "debug"
    }
}


버전 확인하기

api GET http://localhost:9200/my-log-index-2021-08-24/_doc/2

출력 결과
버전이 2로 증가하였습니다. 버전은 해당 도큐먼트 아이디의 변경된 횟수를 의미합니다. 버전을 통하여 해당 도큐먼트의 아이디가 수정된 적이 있는지 확인할 수 있습니다.

 

도큐먼트 개수 측정하기

인덱스의 모든 도큐먼트 개수 측정하기

api GET http://localhost:9200/my-log-index-2021-08-24/_count


특정 조건을 이용하여 개수 측정하기
level 필드에 값이 "debug"인 도큐먼트 개수 측정

api GET http://localhost:9200/my-log-index-2021-08-24/_count?q=level:debug

 

도큐먼트 삭제하기

특정 도큐먼트 삭제하기

api DELETE http://localhost:9200/my-log-index-2021-08-24/_doc/2


인덱스 삭제하기
인덱스를 삭제하여 인덱스의 모든 값을 삭제합니다.

api DELETE http://localhost:9200/my-log-index-2021-08-24



Index ilm policy이란

ILM (Index Lifecycle Management)은 데이터 인덱스의 수명 주기를 관리하기 위한 기능입니다. ILM를 사용하면 데이터의 보존, 압축, 백업 및 삭제와 같은 다양한 관리 작업을 자동화하고 데이터 스토리지를 효율적으로 관리할 수 있는 기능을 제공하지만 이번 문서에서는 아주 간단하게 인덱스가 생성되고 일정 기간이 지나면 인덱스가 삭제되도록 하는 방법에 대하여 정리하였습니다.

보다 자세한 ILM 설명은 링크를 확인해주세요 (https://stdhsw.tistory.com/entry/Elasticsearch-%EC%B5%9C%EC%A0%81%ED%99%94-3-ilm-policy%EB%A1%9C-data-tiering-%ED%95%98%EA%B8%B0)

 

Index ilm policy 설정하기

PUT localhost:9200/_ilm/policy/my-policy
Content-Type: application/json

{
  "policy": {
    "phases": {
      "delete": {
        "min_age": "3d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

ilm policy 파라미터

  • delete.min_age : 인덱스가 생성되고 얼마만큼의 기간이 흐르면 지울지 설정합니다.

 

Index ilm policy 설정 확인 하기

GET localhost:9200/_ilm/policy/my-policy

### 결과
{
  "my-policy": {
    "version": 1,
    "modified_date": "2023-10-25T09:43:53.527Z",
    "policy": {
      "phases": {
        "delete": {
          "min_age": "3d",
          "actions": {
            "delete": {
              "delete_searchable_snapshot": true
            }
          }
        }
      }
    },
    "in_use_by": {
      "indices": [],
      "data_streams": [],
      "composable_templates": []
    }
  }
}

 

ILM Policy를 Index template에 적용하기

인덱스 template에 ILM 설정을 적용합니다. 인덱스 template에 대한 자세한 설명은 링크를 확인해 주세요 (https://stdhsw.tistory.com/entry/Elasticsearch%EC%9D%98-Index-template-%EC%84%A4%EC%A0%95)

PUT http://localhost:9200/_template/my-index-template
Content-Type: application/json

{
  "index_patterns": ["my-index*"],
  "settings": {
    "index": {
      "number_of_shards": "2",
      "number_of_replicas": "1",
      "refresh_interval": "5s",
      "lifecycle": {
        "name": "my-policy"
      }
    }
  },
  "mappings": {
    "properties": {
      "app": {
        "type": "keyword"
      },
      "level": {
        "type": "keyword"
      },
      "message": {
        "type": "text"
      }
    }
  }
}

Index template 파라미터

  • settings.index.lifecycle.name : 위에서 지정한 ILM의 명칭을 기입합니다.

위 설정을 적용하면 이제 "my-index"로 시작하는 모든 인덱스는 앞으로 생성되고 3일 뒤에 자동적으로 삭제가 되어 보다 효율적으로 디스크 사용량을 관리할 수 있습니다.

 

Index ilm policy 삭제하기

### delete
DELETE localhost:9200/_ilm/policy/my-policy

 

Index template 사용 이유

Elsticsearch에서 index의 template을 지정하지 않을 경우 인덱스를 생성할 때마다 shard 및 field type을 계속해서 지정을 해줘야 하는 귀찮은 문제가 발생합니다. 저 같은 경우 인덱스를 날짜 별로 생성하는 Rolling 방식을 이용하고 있는데 만약 template이 존재하지 않았다면 매일 00시마다 인덱스를 생성하는 노가다를 하게 될 겁니다.

template를 사용하게 되면 특정 패턴의 인덱스가 생성될때 template으로 지정된 설정이 자동으로 적용되어 인덱스가 생성되기 때문에 shard, refresh, field 타입이 자동으로 적용됩니다. 

Field data type 종류

default 타입으로 설정되어 생성됩니다. 문자열인 경우 keyword, text 둘 다 지정되며, 숫자인 경우 long 타입으로 설정됩니다. 기본 값으로 사용하는데 문제가 없다면 그냥 사용해도 되지만 최적화를 하거나 리소스의 자원을 아끼며, 상황에 맞게 Analyzer의 기능을 사용할 때는 반듯이 template을 생성하고 해당 template를 기반으로 인덱스가 생성되어 사용하는 것을 권장합니다.

각각의 필드의 타입에 대해서는 아래 elasticsearch 공식 document를 통하여 확인하여 주시기 바랍니다.

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html

 

Field data types | Elasticsearch Guide [8.10] | Elastic

Each field has a field data type, or field type. This type indicates the kind of data the field contains, such as strings or boolean values, and its intended use. For example, you can index strings to both text and keyword fields. However, text field value

www.elastic.co

Index ilm policy 설정하기

curl -X PUT http://localhost:9200/_ilm/policy/my-log-policy -H 'Content-Type: application/json' -d '
{
  "policy": {
    "phases": {
      "delete": {
        "min_age": "3d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}
'

먼저 인덱스 Template를 설정하기 전에 ilm에 대해서 간단하게 알아보겠습니다. ilm이란 Index Lifecycle Management로 인덱스의 생명 주기 및 인덱스 크기를 관리해 주는 기능입니다.  위 설정은 "my-log-policy"라는 ilm을 생성하는 API이며 파라미터의 대한 설명은 다음과 같습니다.

  • policy.phases.delete.min_age : 인덱스의 생명 주기입니다. 저는 3일로 설정하였습니다.
  • policy.phases.delete.action : 3일 뒤 수행하는 action입니다. 저는 인덱스가 생성된 지 3일이 지나면 해당 인덱스를 삭제하도록 설정하였습니다.

이번 문서는 인덱스 Template에 대한 설명이기 때문에 ilm policy의 삭제에 대해서만 간단하게 설정하였습니다. ilm의 기능으로는 삭제뿐만 아니라 hot, warm, cold, rollover등과 같은 여러 가지의 기능을 제공하고 있습니다.

Index template 설정하기

"my-log-template"이라는 template를 shard 개수를 4개, 각 샤드의 복제본 1개 그리고 5초마다 한 번씩 refresh를 수행하여 데이터가 검색될 수 있도록 설정을 하며 필드의 타입은 다음과 같이 설정하도록 하였습니다.

Field명 Type
level keyword
timestamp date
logger keyword
message text
msg로 시작하는 Field text
그밖에 문자열 keyword
그밖에 숫자 integer

 

curl -X PUT http://localhost:9200/_template/my-log-template -H 'Content-Type: application/json' -d '
{
  "index_patterns": [
    "my-log-*"
  ],
  "settings": {
    "index": {
      "number_of_shards": "4",
      "number_of_replicas": "1",
      "refresh_interval": "5s",
      "lifecycle": {
        "name": "my-log-policy"
      }
    }
  },
  "mappings": {
    "properties": {
      "level": {
        "type": "keyword"
      },
      "timestamp": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss"
      },
      "logger": {
        "type": "keyword"
      },
      "message": {
        "type": "text"
      },
      "action": {
        "type": "keyword"
      }
    },
    "dynamic_templates": [
      {
        "message": {
          "match_mapping_type": "string",
          "match": "msg*",
          "mapping": {
            "type": "text"
          }
        }
      },
      {
        "default_strings": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "keyword"
          }
        }
      },
      {
        "default_number": {
          "match_mapping_type": "long",
          "mapping": {
            "type": "integer"
          }
        }
      }
    ]
  }
}
'

인덱스의 template은 인덱스 필드의 데이터 타입을 설정하는 것뿐만 아니라 인덱스의 전체적인 설정을 지정하는 기능을 합니다. 인덱스는 하나 이상의 샤드로 구성되어 있습니다. 샤드는 인덱스의 데이터를 분할되어 여러 노드에 나눠 저장되어 한 노드에 부하가 집중되는 것을 방지하며 replica 샤드를 통하여 고가용성(HA)을 보장하는 기능을 수행합니다. 이러한 설정을 인덱스의 template 설정을 통하여 지정할 수 있습니다. 위 request를 통하여 "my-log-template"라는 template을 설정하고 "my-log-"로 시작되는 모든 인덱스에 해당 설정이 적용됩니다. 파라미터에 대한 설명은 다음과 같습니다.

  • index_patterns : 해당 templat이 적용되는 인덱스명의 패턴을 입력합니다. 저는 "my-log-"로 시작되는 새롭게 생성되는 인덱스에 template이 적용되도록 설정하였습니다.
  • settings.index.number_of_shards : 인덱스는 하나 이상의 샤드로 구성되어 있는데 샤드의 개수를 늘려 여러 노드에 분할 저장될 수 있도록 설정할 수 있습니다. 해당 설정은 샤드의 개수를 지정하는 것인데 너무 많은 설정으로 구성하면 Elasticsearch의 Cluster 전체에 악영향을 미칠 수 있기 때문에 적당한 양의 샤드로 구성하는 것을 권장합니다. 저는 웬만하면 Data Node 개수의 배수로 설정하여 여러 Data Node에 골고루 분할할 수 있도록 설정합니다. 한 인덱스에 최대로 설정할 수 있는 샤드의 개수는 1024개입니다.
  • settings.index.number_of_replicas : 고가용성을 보장하기 위해 복제본 샤드의 개수를 설정합니다. 너무 많은 복제 샤드를 설정하면 데이터 보존의 안정성은 보장되지만 클러스터에 많은 부하가 발생할 수 있습니다. 저는 복제본 샤드를 1개로 구성하여 HA를 보장하지만 클러스터에 부하를 최소한으로 하도록 설정하여 사용합니다.
  • settings.index.refresh_interval : Elasticsearch는 데이터가 저장되면 바로 검색이 되지 않습니다. 인덱스에 refresh가 되어야지 검색이 가능해집니다. refresh가 1초마다 되면 실시간에 가깝게 검색을 수행할 수 있지만 데이터에 삽입되는 Indexing의 성능이 저하될 수 있습니다. 만약 실시간 검색이 중요하면 1초로 설정하지만 그렇지 않다면 어느 정도 긴 시간을 설정하는 것을 추천합니다. 저 같은 경우 로그 데이터 엄청 많은 양의 데이터가 발생할 수 있기 때문에 데이터가 안정적으로 들어오는 것이 중요하다고 판단하여 5초로 설정하였습니다. ML분야에 개발자 분들은 하루동안 데이터를 모으고 다음날 데이터를 분석할 때는 refresh가 하루에 한 번 또는 한 시간에 한번 수행하는 경우도 있다고 합니다.
  • settings.index.lifecycle.name : 인덱스의 lifecycle을 지정합니다. 위에서 설정한 ilm을 지정하여 인덱스가 생성되고 3일 뒤에 삭제 하도록 하였습니다.

다음은 데이터 필드 타입을 설정하는 부분입니다. https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 해당 페이지에서 데이터 필드 타입에 대하여 알아보는 것을 권장합니다.

  • mappings.properties : 데이터 필드의 타입을 지정합니다. level필드는 keyword타입, timestamp는 date타입, logger는 keyword타입, message는 text타입, action은 keyword타입으로 설정하였습니다. 이 것 이외에 여러 데이터 타입이 있습니다.
  • mappings.dynamic_templates : dynamic_template은 데이터의 필드 명칭이 명확하지 않을때 사용하는 기능입니다.
  • mappings.dynamic_templates.message : message dynamic_template은 문자열로 입력된 msg로 시작되는 명칭의 필드가 들어오면 해당 필드의 타입은 text로 지정합니다. 
  • mappings.dynamic_templates.default_strings : 모든 문자열로 들어온 지정되지 않은 필드는 무조건 keyword 타입으로 설정합니다.
  • mappings.dynamic_templates.default_number : 모든 숫자형식으로 들어온 지정되지 않은 필드는 무조건 integer 타입으로 설정합니다.

Index template 확인

위 request를 통하여 생성된 인덱스 template을 확인합니다.

curl -XGET http://localhost:9200/_template/my-log-template

모든 Index template 가져오기

Elasticsearch에 설정된 모든 Index의 template를 가져옵니다.

curl -XGET http://localhost:9200/_template

Index template 삭제하기

더 이상 해당 Index의 template을 사용하지 않을 경우 Index template을 삭제합니다.

curl -XDELETE http://localhost:9200/_template/my-log-template

마지막으로

Elasticsearch의 template설정은 데이터 삽입 및 검색의 성능에 많은 영향을 미칠 수 있습니다. 자신의 환경 및 상황에 맞게 인덱스를 설정한다면 보다 더 효율적인 클러스터 운영이 가능해지기 때문에 데이터의 형식 및 검색할 때 어떻게 검색할 것인지를 파악하고 template를 반듯이 설정하는 것을 권장합니다.

 

+ Recent posts