TSDS (Time Series Data Stream)

TSDS란?

TSDS(Time Series Data Stream)는 Timestamp가 지정된 메트릭 데이터를 하나 혹은 그 이상의 시계열 데이터로 모델링하는 방식의 Data Stream입니다. 

TSDS를 통해 메트릭 데이터를 더 효율적으로 보관할 수 있습니다.
Elastic 공식 벤치마킹 결과, TSDS에 저장되는 메트릭 데이터는 기본 Data Stream 대비 70% 적은 디스크 공간을 사용했습니다.


기본 Data Stream과 TSDS 모두 Timestamp가 지정된 메트릭 데이터를 저장할 수 있으나,
TSDS는 거의 실시간에 가까운 Timestamp 순서로 Elasticsearch에 메트릭 데이터를 저장하는 경우에만 사용하는 것을 권장합니다.

TSDS는 메트릭 데이터 전용으로, 로그나 트레이스 등의 데이터는 일반 Data Stream을 사용합니다.

Data Stream과의 차이

TSDS는 기본적으로는 Data Stream과 동일한 역할을 하지만 다음과 같은 차이점들이 있습니다.

Time Series란?

Time Series는 특정 개체에 대한 일련의 관측값입니다. 그 관측값들을 종합하면 시간의 경과에 따른 개체의 변화를 추적할 수 있습니다.

TSDS에서 각 Document는 특정 Time Series의 관측 또는 데이터 포인트를 의미합니다. TSDS에는 여러 Time Series가 있을 수 있지만, document는 하나의 Time Series에만 속할 수 있습니다. 

Time Series는 여러 Data Stream에 걸쳐 있을 수 없습니다.

Dimensions

Dimension은 필드의 이름과 값을 조합하여 document의 time series를 식별하는 것입니다. 대부분의 경우 dimension은 현재 측정하고 있는 개체의 일부 측면을 설명합니다. 예시로, 동일한 날씨 감지 센서에 대한 document는 항상 동일한 sensor_idlocation 값을 가지고 있습니다.

TSDS의 document는 Time Series와 timestamp로 고유하게 식별되며, 그 두 가지 값을 _id를 생성하는데 사용합니다. 따라서, 동일한 dimension과 timestamp를 가지고 있는 두 document는 중복인 것으로 판별됩니다. _bulk를 통해 앞서 말한 두 document를 추가한다면 두 번째 document가 첫 번째를 덮어쓰게 됩니다. 

Dimension은 Mapping 단계에서 Boolean 파라미터인 time_series_dimension을 사용하여 지정합니다.
다음 타입들이 time_series_dimension 파라미터를 지원합니다.

Metrics

Metric은 숫자 측정 값과 해당 측정 값을 기반으로 한 집계, 다운샘플링 값을 포함하는 필드입니다. 필수는 아니지만, 대체로 TSDS의 document에는 하나 이상의 Metric 필드가 존재합니다.

일반적으로 Dimension은 일정하게 유지되지만 Metric은 드물거나 느리게라도 시간이 지남에 따라서 변경될 것으로 예상된다는 점에서 Dimension과 차이가 있습니다. 

Metric은 Mapping 단계에서 time_series_metric 파라미터를 사용하여 지정합니다.
다음 타입들이 time_series_metric 파라미터를 지원합니다.

time_series_metrics 파라미터의 설정값들은 다음과 같습니다.

Time Series 기능

TSDS의 인덱스 템플릿에는 index.mode: time_series 옵션이 있는 data_stream 오브젝트가 포함되어야 합니다.
해당 옵션은 Backing 인덱스들의 TSDS 관련 기능을 활성화 합니다. 

기존의 Data Stream을 TSDS로 변환하는 경우, 변환 후에 생성되는 인덱스만 index.mode가 되고, 기존 Backing 인덱스는 변경할 수 없습니다.

_tsid 메타데이터 필드

TSDS에 document를 넣을 때, Elasticsearch는 자동으로 _tsid 메타데이터 필드를 생성합니다.
_tsid는 document의 dimension을 포함하고 있는 오브젝트 입니다. 한 TSDS에 동일한 _tsid가 있는 document는 동일한 time series의 일부입니다.

_tsid는 검색, 업데이트가 불가능합니다. GET 명령을 통해서 문서를 불러오는 것도 불가능합니다. 하지만 집계, fields 파라미터를 이용해 검색 결과값을 가지고 오는 것은 가능합니다.

Time-Bound Indices

TSDS의 각 Backing Index에는 @timestamp 값의 범위가 있습니다.
범위는 인덱스 세팅의 index.time_series.start_time, index.time_series.end_time에서 정의됩니다. 

TSDS에 document를 추가할 때, Elasticsearch는 해당 document의 @timestamp 값에 따라서 적절한 Backing 인덱스에 문서를 추가합니다. 따라서 TSDS는 쓰기 가능한 모든 Backing 인덱스에 문서를 추가할 수 있습니다. 이는 해당 Backing 인덱스가 가장 최근의 인덱스가 아니더라도 가능합니다.

만약 document의 @timestamp 값을 받을 수 있는 Backup 인덱스가 없는 경우, Elasticsearch는 해당 document를 추가하지 않습니다.

Elasticsearch는 인덱스 생성과 Rollover 프로세스의 과정에서 index.time_series.start_time, index.time_series.end_time 세팅을 자동으로 구성합니다.

Dimension-based routing

TSDS의 각 Backing 인덱스 내에서 Elasticsearch는 index.routing_path 인덱스 설정을 통해 동일한 dimension의 document를 동일한 샤드로 라우팅합니다.

TSDS의 인덱스 템플릿을 만들 때 index.routing_path 설정에서 하나 이상의 dimension을 지정해야 합니다. TSDS의 각 document는 index.routing_path 설정에 있는 dimension을 하나 이상 포함하고 있어야 합니다.

index.routing_path 에서 설정한 dimension은 keyword 타입의 필드여야 합니다. index.routing_path 설정은 와일드카드 패턴을 지원하여 새로운 필드와 동적으로 일치시킬 수 있습니다. 하지만 Elasticsearch는 index.routing_path 값과 일치하는 scripted, runtime, non-dimension, non-keyword 인 필드들은 Reject 됩니다.

TSDS의 document, mapping은 커스텀 _routing 값을 지원하지 않습니다. 

인덱스 정렬

Elasticsearch는 압축 알고리즘을 사용해 반복되는 값을 압축합니다. 압축 알고리즘은 반복되는 값이 동일한 인덱스, 동일한 샤드, 동일한 샤드 세그먼트에 나란히 저장되어 있을 때 가장 효율적으로 작동합니다. 

대부분의 Time Series 데이터는 반복되는 값을 가지고 있습니다. Dimension은 동일한 Time Series의 document에서 반복됩니다. Metric 값은 시간에 따라서 변화할 수 있습니다.

내부적으로 각 TSDS Backing 인덱스는 인덱스 정렬을 사용해 _tsid@timestamp를 기준으로 샤드 세그먼트의 순서를 지정합니다. 이렇게 하면 더 효율적인 압축을 위해 반복되는 값이 가까이 저장될 수 있게 됩니다. 

효율적인 인덱스 정렬 후 압축을 위해서 TSDS는 index.sort.* 설정을 지원하지 않습니다.

TSDS 생성 설정

TSDS 설정은 다음과 같은 단계로 이루어집니다.

조건 확인

Index Lifecycle Policy 생성

선택 사항이지만, ILM을 사용하여 TSDS의 Backing 인덱스 관리를 하는 것을 권장합니다.
ILM을 사용하기 위해 Index Lifecycle Policy를 생성해야 합니다.

Policy에서 Rollover 액션에 대한 max_age 기준을 설정하는 것이 좋습니다. 설정하게 되면 TSDS Backing Index의 @timestamp 범위가 일관되게 유지됩니다. 예를 들어, max_age를 1d로 설정하면 Backing Index에 하루 분량의 데이터가 일관적으로 보관됩니다. 

예시

PUT _ilm/policy/my-weather-sensor-lifecycle-policy

{

  "policy": {

    "phases": {

      "hot": {

        "actions": {

          "rollover": {

            "max_age": "1d",

            "max_primary_shard_size": "50gb"

          }

        }

      },

      "warm": {

        "min_age": "30d",

        "actions": {

          "shrink": {

            "number_of_shards": 1

          },

          "forcemerge": {

            "max_num_segments": 1

          }

        }

      },

      "cold": {

        "min_age": "60d",

        "actions": {

          "searchable_snapshot": {

            "snapshot_repository": "found-snapshots"

          }

        }

      },

      "frozen": {

        "min_age": "90d",

        "actions": {

          "searchable_snapshot": {

            "snapshot_repository": "found-snapshots"

          }

        }

      },

      "delete": {

        "min_age": "735d",

        "actions": {

          "delete": {}

        }

      }

    }

  }

}

매핑 컴포넌트 템플릿 생성

TSDS는 인덱스 템플릿이 필요합니다. 대부분의 경우, 하나 이상의 컴포넌트 템플릿을 사용하여 인덱스 템플릿을 작성합니다. 일반적으로 매핑, 세팅을 각각의 컴포넌트 템플릿으로 생성합니다. 그 방식으로 설정하면 한번 생성한 컴포넌트 템플릿을 다른 인덱스 템플릿들을 만들 때에 재사용이 가능합니다.

TSDS를 위한 매핑에 반드시 필요한 설정:

TSDS를 위한 매핑에 선택적으로 포함하는 설정:

예시

PUT _component_template/my-weather-sensor-mappings

{

  "template": {

    "mappings": {

      "properties": {

        "sensor_id": {

          "type": "keyword",

          "time_series_dimension": true

        },

        "location": {

          "type": "keyword",

          "time_series_dimension": true

        },

        "temperature": {

          "type": "half_float",

          "time_series_metric": "gauge"

        },

        "humidity": {

          "type": "half_float",

          "time_series_metric": "gauge"

        },

        "@timestamp": {

          "type": "date",

          "format": "strict_date_optional_time"

        }

      }

    }

  },

  "_meta": {

    "description": "Mappings for weather sensor data"

  }

}

인덱스 세팅 컴포넌트 템플릿 생성

TSDS를 위한 세팅에 선택적으로 포함하는 설정:

예시

PUT _component_template/my-weather-sensor-settings

{

  "template": {

    "settings": {

      "index.lifecycle.name": "my-lifecycle-policy"

    }

  },

  "_meta": {

    "description": "Index settings for weather sensor data"

  }

}

인덱스 템플릿 생성

생성한 컴포넌트 템플릿들을 사용해서 인덱스 템플릿을 설정합니다.

예시

PUT _component_template/my-weather-sensor-settings

{

  "template": {

    "settings": {

      "index.lifecycle.name": "my-lifecycle-policy"

    }

  },

  "_meta": {

    "description": "Index settings for weather sensor data"

  }

}

TSDS 생성

인덱싱 Request를 통해 TSDS에 document를 추가합니다. 

TSDS document에 들어가야 하는 것:

TSDS를 자동으로 만드려면 TSDS의 이름을 대상으로 하는 인덱싱 Request를 입력하여 document를 추가합니다. 

예시

PUT metrics-weather_sensors-dev/_bulk

{ "create":{ } }

{ "@timestamp": "2099-05-06T16:21:15.000Z", "sensor_id": "HAL-000001", "location": "plains", "temperature": 26.7,"humidity": 49.9 }

{ "create":{ } }

{ "@timestamp": "2099-05-06T16:25:42.000Z", "sensor_id": "SYKENET-000001", "location": "swamp", "temperature": 32.4, "humidity": 88.9 }


POST metrics-weather_sensors-dev/_doc

{

  "@timestamp": "2099-05-06T16:21:15.000Z",

  "sensor_id": "SYKENET-000001",

  "location": "swamp",

  "temperature": 32.4,

  "humidity": 88.9

}

create data stream API를 통해서도 TSDS를 생성할 수 있습니다.

두 가지 방법 모두 TSDS의 이름이 인덱스 템플릿에서 설정한 인덱스 패턴에 일치해야 합니다.

TSDS 보안

인덱스 Privileges를 사용해 TSDS의 권한을 관리할 수 있습니다. TSDS에 권한을 부여하면 Backing 인덱스들에도 동일한 권한이 부여됩니다.

Data stream privileges를 참고해 Data Stream과 동일한 방법으로 설정할 수 있습니다.

Data Stream을 TSDS로 변환

위의 방법들을 따라 이미 존재하는 일반 Data Stream을 TSDS로 변환할 수 있습니다. 

출처, 참고 문서

LinkedIn

ⓒ 이동훈 (Lee Donghoon)