메인 콘텐츠로 건너뛰기

병렬 운영 전략

관측성 사용 사례에서 Elastic에서 ClickStack으로 이전할 때는 과거 데이터를 마이그레이션하는 대신 병렬 운영 방식을 권장합니다. 이 전략에는 다음과 같은 장점이 있습니다.
  1. 위험 최소화: 두 시스템을 동시에 운영하면 ClickStack을 검증하고 사용자가 새 시스템에 익숙해지는 동안에도 기존 데이터와 대시보드에 계속 접근할 수 있습니다.
  2. 자연스러운 데이터 만료: 대부분의 관측성 데이터는 보존 기간이 제한적이며(일반적으로 30일 이하), Elastic의 데이터가 만료되면서 자연스럽게 전환할 수 있습니다.
  3. 간소화된 마이그레이션: 시스템 간 과거 데이터를 옮기기 위한 복잡한 데이터 전송 도구나 프로세스가 필요하지 않습니다.

데이터 마이그레이션Elasticsearch에서 ClickHouse로 필수 데이터를 마이그레이션하는 방법은 “데이터 마이그레이션” 섹션에서 설명합니다. 다만 이 방식은 대규모 데이터셋에는 권장하지 않습니다. Elasticsearch의 내보내기 성능에 제약이 있고 JSON 포맷만 지원되므로, 충분한 성능을 내는 경우가 드물기 때문입니다.

구현 단계

1

이중 수집 구성

데이터 수집 파이프라인을 설정하여 데이터를 Elastic과 ClickStack으로 동시에 전송합니다.구성 방법은 현재 사용 중인 수집 에이전트에 따라 달라집니다. “Migrating Agents”를 참조하십시오.
2

보존 기간 조정

Elastic의 TTL 설정을 원하는 보존 기간에 맞게 구성합니다. ClickStack TTL도 동일한 기간 동안 데이터를 유지하도록 설정합니다.
3

검증 및 비교

  • 두 시스템에서 모두 쿼리를 실행하여 데이터 일관성을 확인합니다
  • 쿼리 성능과 결과를 비교합니다
  • 대시보드와 알림을 ClickStack으로 마이그레이션합니다. 이 작업은 현재 수동으로 수행해야 합니다.
  • 모든 핵심 대시보드와 알림이 ClickStack에서 예상대로 작동하는지 확인합니다
4

점진적 전환

  • 데이터가 Elastic에서 자연스럽게 만료되면서 점차 ClickStack에 더 많이 의존하게 됩니다
  • ClickStack에 대한 신뢰가 확보되면 쿼리와 대시보드를 점진적으로 전환할 수 있습니다

장기 보존

더 긴 보존 기간이 필요한 조직의 경우:
  • Elastic에서 모든 데이터가 만료될 때까지 두 시스템을 계속 병렬로 운영합니다.
  • ClickStack의 계층형 스토리지 기능을 활용하면 장기 데이터를 효율적으로 관리할 수 있습니다.
  • 원시 데이터는 만료되도록 두면서 집계되거나 필터링된 이력 데이터를 유지하려면 구체화된 뷰(Materialized View) 사용을 고려하십시오.

마이그레이션 일정

마이그레이션 일정은 데이터 보존 요구 사항에 따라 달라집니다:
  • 30일 보존: 마이그레이션은 한 달 이내에 완료할 수 있습니다.
  • 더 긴 보존 기간: 데이터가 Elastic에서 만료될 때까지 병렬 운영을 계속하십시오.
  • 과거 데이터: 꼭 필요한 경우에만 데이터 마이그레이션을 사용해 특정 과거 데이터를 가져오는 방안을 고려하십시오.

설정 마이그레이션

Elastic에서 ClickStack으로 마이그레이션할 때는 인덱싱 및 스토리지 설정을 ClickHouse 아키텍처에 맞게 조정해야 합니다. Elasticsearch는 성능과 장애 허용을 위해 수평 스케일링과 세그먼트 분할에 의존하므로 기본적으로 여러 개의 세그먼트를 사용하지만, ClickHouse는 수직 스케일링에 최적화되어 있어 일반적으로 세그먼트 수가 적을수록 더 나은 성능을 제공합니다. 단일 세그먼트로 시작한 다음 수직으로 스케일링하는 것을 권장합니다. 이 구성은 대부분의 관측성 워크로드에 적합하며, 관리와 쿼리 성능 튜닝을 모두 단순화합니다.
  • ClickHouse Cloud: 기본적으로 단일 세그먼트, 다중 레플리카 아키텍처를 사용합니다. 스토리지와 컴퓨트가 독립적으로 스케일링되므로, 수집 패턴을 예측하기 어렵고 읽기 중심의 워크로드가 많은 관측성 사용 사례에 적합합니다.
  • ClickHouse OSS: 자가 관리형 배포에서는 다음을 권장합니다.
    • 단일 세그먼트로 시작
    • CPU와 RAM을 추가하여 수직으로 스케일링
    • 계층형 스토리지를 사용하여 S3 호환 객체 스토리지로 로컬 디스크를 확장
    • 고가용성이 필요한 경우 ReplicatedMergeTree 사용
    • 장애 허용을 위해서는 관측성 워크로드에서 일반적으로 세그먼트당 레플리카 1개면 충분합니다.

세그먼트 분할이 필요한 경우

다음과 같은 경우에는 세그먼트 분할이 필요할 수 있습니다.
  • 수집 속도가 단일 노드의 처리 용량을 초과하는 경우(일반적으로 초당 500K행 초과)
  • 테넌트 격리 또는 리전별 데이터 분리가 필요한 경우
  • 객체 스토리지를 사용하더라도 전체 데이터셋이 단일 서버에 저장하기에는 너무 큰 경우
세그먼트 분할이 필요한 경우, 세그먼트 키와 분산 테이블 설정에 대한 지침은 수평 스케일링을 참조하십시오.

보존 및 TTL

ClickHouse는 데이터 만료를 관리하기 위해 MergeTree 테이블에서 TTL 절을 사용합니다. TTL 정책으로 다음 작업을 수행할 수 있습니다:
  • 만료된 데이터를 자동으로 삭제
  • 오래된 데이터를 콜드 객체 스토리지로 이동
  • 최근 데이터 중 자주 조회되는 로그만 고속 디스크에 유지
마이그레이션 중에도 일관된 데이터 수명 주기를 유지할 수 있도록, 기존 Elastic 보존 정책에 맞춰 ClickHouse TTL 구성을 조정하는 것을 권장합니다. 예시는 ClickStack 프로덕션 TTL 설정에서 확인하십시오.

데이터 마이그레이션

대부분의 관측성 데이터는 병렬 운영을 권장하지만, 경우에 따라 Elasticsearch에서 ClickHouse로 데이터를 직접 마이그레이션해야 할 수도 있습니다.
  • 데이터 보강에 사용하는 소규모 조회 테이블(예: 사용자 매핑, 서비스 카탈로그)
  • 관측성 데이터와 연관시켜야 하는 Elasticsearch의 비즈니스 데이터. ClickHouse는 SQL 기능과 비즈니스 인텔리전스 통합을 제공하므로, Elasticsearch의 제한적인 쿼리 옵션에 비해 데이터를 유지 관리하고 쿼리하기가 더 쉽습니다.
  • 마이그레이션 과정 전반에서 보존해야 하는 구성 데이터
이 접근 방식은 Elasticsearch의 내보내기 기능이 HTTP를 통한 JSON으로 제한되고 대규모 데이터셋에는 잘 확장되지 않으므로, 1천만 행 미만의 데이터셋에만 적합합니다. 다음 단계에 따라 ClickHouse에서 단일 Elasticsearch 인덱스를 마이그레이션할 수 있습니다.
1

스키마 마이그레이션

Elasticsearch에서 마이그레이션할 인덱스에 대한 테이블을 ClickHouse에 생성하십시오. Elasticsearch 타입을 ClickHouse 동등 타입으로 매핑할 수 있습니다. 또는 ClickHouse의 JSON 데이터 타입을 활용하면, 데이터가 삽입될 때 적절한 타입의 컬럼이 동적으로 생성됩니다.syslog 데이터를 포함하는 인덱스에 대한 다음 Elasticsearch 매핑을 확인하십시오.
GET .ds-logs-system.syslog-default-2025.06.03-000001/_mapping
{
  ".ds-logs-system.syslog-default-2025.06.03-000001": {
    "mappings": {
      "_meta": {
        "managed_by": "fleet",
        "managed": true,
        "package": {
          "name": "system"
        }
      },
      "_data_stream_timestamp": {
        "enabled": true
      },
      "dynamic_templates": [],
      "date_detection": false,
      "properties": {
        "@timestamp": {
          "type": "date",
          "ignore_malformed": false
        },
        "agent": {
          "properties": {
            "ephemeral_id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "name": {
              "type": "keyword",
              "fields": {
                "text": {
                  "type": "match_only_text"
                }
              }
            },
            "type": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "version": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "cloud": {
          "properties": {
            "account": {
              "properties": {
                "id": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "availability_zone": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "image": {
              "properties": {
                "id": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "instance": {
              "properties": {
                "id": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "machine": {
              "properties": {
                "type": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            },
            "provider": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "region": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "service": {
              "properties": {
                "name": {
                  "type": "keyword",
                  "fields": {
                    "text": {
                      "type": "match_only_text"
                    }
                  }
                }
              }
            }
          }
        },
        "data_stream": {
          "properties": {
            "dataset": {
              "type": "constant_keyword",
              "value": "system.syslog"
            },
            "namespace": {
              "type": "constant_keyword",
              "value": "default"
            },
            "type": {
              "type": "constant_keyword",
              "value": "logs"
            }
          }
        },
        "ecs": {
          "properties": {
            "version": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "elastic_agent": {
          "properties": {
            "id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "snapshot": {
              "type": "boolean"
            },
            "version": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "event": {
          "properties": {
            "agent_id_status": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "dataset": {
              "type": "constant_keyword",
              "value": "system.syslog"
            },
            "ingested": {
              "type": "date",
              "format": "strict_date_time_no_millis||strict_date_optional_time||epoch_millis",
              "ignore_malformed": false
            },
            "module": {
              "type": "constant_keyword",
              "value": "system"
            },
            "timezone": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "host": {
          "properties": {
            "architecture": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "containerized": {
              "type": "boolean"
            },
            "hostname": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "id": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "ip": {
              "type": "ip"
            },
            "mac": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "name": {
              "type": "keyword",
              "ignore_above": 1024
            },
            "os": {
              "properties": {
                "build": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "codename": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "family": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "kernel": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "name": {
                  "type": "keyword",
                  "fields": {
                    "text": {
                      "type": "match_only_text"
                    }
                  }
                },
                "platform": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "type": {
                  "type": "keyword",
                  "ignore_above": 1024
                },
                "version": {
                  "type": "keyword",
                  "ignore_above": 1024
                }
              }
            }
          }
        },
        "input": {
          "properties": {
            "type": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "log": {
          "properties": {
            "file": {
              "properties": {
                "path": {
                  "type": "keyword",
                  "fields": {
                    "text": {
                      "type": "match_only_text"
                    }
                  }
                }
              }
            },
            "offset": {
              "type": "long"
            }
          }
        },
        "message": {
          "type": "match_only_text"
        },
        "process": {
          "properties": {
            "name": {
              "type": "keyword",
              "fields": {
                "text": {
                  "type": "match_only_text"
                }
              }
            },
            "pid": {
              "type": "long"
            }
          }
        },
        "system": {
          "properties": {
            "syslog": {
              "type": "object"
            }
          }
        }
      }
    }
  }
}
동일한 ClickHouse 테이블 스키마:
SET enable_json_type = 1;

CREATE TABLE logs_system_syslog
(
    `@timestamp` DateTime,
    `agent` Tuple(
        ephemeral_id String,
        id String,
        name String,
        type String,
        version String),
    `cloud` Tuple(
        account Tuple(
            id String),
        availability_zone String,
        image Tuple(
            id String),
        instance Tuple(
            id String),
        machine Tuple(
            type String),
        provider String,
        region String,
        service Tuple(
            name String)),
    `data_stream` Tuple(
        dataset String,
        namespace String,
        type String),
    `ecs` Tuple(
        version String),
    `elastic_agent` Tuple(
        id String,
        snapshot UInt8,
        version String),
    `event` Tuple(
        agent_id_status String,
        dataset String,
        ingested DateTime,
        module String,
        timezone String),
    `host` Tuple(
        architecture String,
        containerized UInt8,
        hostname String,
        id String,
        ip Array(Variant(IPv4, IPv6)),
        mac Array(String),
        name String,
        os Tuple(
            build String,
            codename String,
            family String,
            kernel String,
            name String,
            platform String,
            type String,
            version String)),
    `input` Tuple(
        type String),
    `log` Tuple(
        file Tuple(
            path String),
        offset Int64),
    `message` String,
    `process` Tuple(
        name String,
        pid Int64),
    `system` Tuple(
        syslog JSON)
)
ENGINE = MergeTree
ORDER BY (`host.name`, `@timestamp`)
참고 사항:
  • 중첩 구조는 점 표기법 대신 튜플로 표현합니다
  • 매핑에 따라 적절한 ClickHouse 타입을 사용했습니다:
    • keywordString
    • dateDateTime
    • booleanUInt8
    • longInt64
    • ipArray(Variant(IPv4, IPv6)). 이 필드에는 IPv4IPv6가 혼재되어 있으므로 여기서는 Variant(IPv4, IPv6)를 사용합니다.
    • object → 구조를 예측할 수 없는 syslog 객체에는 JSON을 사용합니다.
  • host.iphost.mac 컬럼은 Elasticsearch에서 모든 타입이 배열로 취급되는 것과 달리, 명시적인 Array 타입입니다.
  • 시간 기반 쿼리를 효율적으로 처리할 수 있도록 timestamp와 호스트명을 사용한 ORDER BY 절이 추가됩니다
  • 로그 데이터에 최적화된 MergeTree를 엔진 유형으로 사용합니다
스키마를 정적으로 정의하고 필요한 경우에만 선택적으로 JSON 타입을 사용하는 이 방식을 권장합니다.이 엄격한 스키마(schema)는 다음과 같은 여러 가지 이점을 제공합니다:
  • 데이터 검증 – 특정 구조를 제외하면 엄격한 스키마를 적용해 컬럼 폭증 위험을 방지할 수 있습니다.
  • 컬럼 폭증 위험 방지: JSON 타입은 서브컬럼이 전용 컬럼으로 저장되는 방식으로 잠재적으로 수천 개의 컬럼까지 확장될 수 있지만, 이 경우 지나치게 많은 컬럼 파일이 생성되는 컬럼 파일 폭증으로 이어져 성능에 영향을 줄 수 있습니다. 이를 완화하기 위해 JSON의 기반이 되는 Dynamic 타입max_dynamic_paths 매개변수를 제공하며, 이 매개변수는 별도의 컬럼 파일로 저장되는 고유 경로 수를 제한합니다. 임계값에 도달하면 추가 경로는 compact 인코딩 포맷을 사용하는 공유 컬럼 파일에 저장되므로, 유연한 데이터 수집을 지원하면서도 성능과 스토리지 효율성을 유지할 수 있습니다. 다만 이 공유 컬럼 파일에 접근할 때는 성능이 전용 컬럼만큼 좋지 않습니다. 하지만 JSON 컬럼은 타입 힌트와 함께 사용할 수도 있습니다. “힌트가 지정된” 컬럼은 전용 컬럼과 동일한 성능을 제공합니다.
  • 경로와 타입을 더 간단히 내부 검사: JSON 타입은 추론된 타입과 경로를 확인하기 위한 인트로스펙션 함수를 지원하지만, 정적 구조는 예를 들어 DESCRIBE로 더 쉽게 살펴볼 수 있습니다.

또는 JSON 컬럼 하나로 테이블을 간단히 생성할 수도 있습니다.
SET enable_json_type = 1;

CREATE TABLE syslog_json
(
 `json` JSON(`host.name` String, `@timestamp` DateTime)
)
ENGINE = MergeTree
ORDER BY (`json.host.name`, `json.@timestamp`)
정렬/프라이머리 키(primary key)에서 이를 사용하므로 JSON 정의에서 host.nametimestamp 컬럼에 유형 힌트를 제공합니다. 이렇게 하면 ClickHouse가 이 컬럼이 NULL이 될 수 없음을 파악할 수 있고, 어떤 서브컬럼(sub-columns)을 사용해야 하는지도 알 수 있습니다(유형마다 여러 개가 있을 수 있으므로, 그렇지 않으면 모호해집니다).
후자의 방식은 더 단순하지만 프로토타이핑 및 데이터 엔지니어링 작업에 가장 적합합니다. 프로덕션 환경에서는 동적 하위 구조가 반드시 필요한 경우에만 JSON을 사용하십시오.스키마에서 JSON 타입을 사용하는 방법과 이를 효율적으로 적용하는 방법에 대한 자세한 내용은 “스키마 설계” 가이드를 참조하십시오.
2

elasticdump 설치

Elasticsearch에서 데이터를 내보낼 때는 elasticdump를 권장합니다. 이 도구를 사용하려면 node가 필요하며, Elasticsearch와 ClickHouse 모두에 네트워크 지연이 낮은 머신에 설치해야 합니다. 대부분의 내보내기 작업에는 최소 4코어와 16GB RAM을 갖춘 전용 서버를 권장합니다.
npm install elasticdump -g
elasticdump는 데이터 마이그레이션에 몇 가지 장점이 있습니다:
  • Elasticsearch REST API와 직접 통신하므로 데이터를 정확하게 내보낼 수 있습니다.
  • Point-in-Time (PIT) API를 사용해 내보내기 과정에서 데이터 일관성을 유지합니다. 즉, 특정 시점의 일관된 데이터 스냅샷을 생성합니다.
  • 데이터를 JSON 포맷으로 직접 내보내므로, 이를 ClickHouse client로 스트리밍해 삽입할 수 있습니다.
가능하다면 네트워크 이그레스를 최소화하고 처리량을 극대화할 수 있도록 ClickHouse, Elasticsearch, elastic dump를 모두 동일한 가용 영역 또는 데이터 센터에서 실행하는 것이 좋습니다.
3

ClickHouse client 설치

elasticdump가 있는 서버에 ClickHouse를 설치했는지 확인하십시오. ClickHouse 서버는 시작하지 마십시오. 이 단계에는 클라이언트만 필요합니다.
4

데이터 스트리밍

Elasticsearch와 ClickHouse 간에 데이터를 스트리밍하려면 elasticdump 명령을 사용해 출력을 clickhouse client로 직접 파이프하세요. 다음 예제에서는 데이터를 잘 구조화된 테이블 logs_system_syslog에 삽입합니다.
# URL 및 자격 증명 내보내기
export ELASTICSEARCH_INDEX=.ds-logs-system.syslog-default-2025.06.03-000001
export ELASTICSEARCH_URL=
export ELASTICDUMP_INPUT_USERNAME=
export ELASTICDUMP_INPUT_PASSWORD=
export CLICKHOUSE_HOST=
export CLICKHOUSE_PASSWORD=
export CLICKHOUSE_USER=default

# 실행할 명령 - 필요에 따라 수정하세요
elasticdump --input=${ELASTICSEARCH_URL} --type=data --input-index ${ELASTICSEARCH_INDEX} --output=$ --sourceOnly --searchAfter --pit=true | 
clickhouse-client --host ${CLICKHOUSE_HOST} --secure --password ${CLICKHOUSE_PASSWORD} --user ${CLICKHOUSE_USER} --max_insert_block_size=1000 \
--min_insert_block_size_bytes=0 --min_insert_block_size_rows=1000 --query="INSERT INTO test.logs_system_syslog FORMAT JSONEachRow"
elasticdump에서 다음 플래그를 사용한다는 점에 유의하십시오:
  • type=data - 응답을 Elasticsearch의 문서 내용으로만 제한합니다.
  • input-index - Elasticsearch 입력 인덱스입니다.
  • output=$ - 모든 결과를 stdout으로 리디렉션합니다.
  • sourceOnly 플래그 - 응답에서 메타데이터 필드를 제외합니다.
  • searchAfter 플래그 - 결과를 효율적으로 페이지네이션하기 위해 searchAfter API를 사용합니다.
  • pit=true - point in time API를 사용해 쿼리 간 일관된 결과를 보장합니다.

여기서 사용하는 ClickHouse client 매개변수는 다음과 같습니다(자격 증명 제외):
  • max_insert_block_size=1000 - 이 행 수에 도달하면 ClickHouse client가 데이터를 전송합니다. 값을 늘리면 처리량은 향상되지만 block을 구성하는 시간이 길어지므로, ClickHouse에 데이터가 나타나기까지 걸리는 시간도 늘어납니다.
  • min_insert_block_size_bytes=0 - 바이트 기준 server block squashing을 비활성화합니다.
  • min_insert_block_size_rows=1000 - server 측에서 client가 보낸 block을 squashing합니다. 여기서는 행이 즉시 나타나도록 이 값을 max_insert_block_size와 동일하게 설정합니다. 처리량을 높이려면 값을 늘리십시오.
  • query="INSERT INTO logs_system_syslog FORMAT JSONAsRow" - 데이터를 JSONEachRow 포맷으로 삽입합니다. 이는 logs_system_syslog처럼 스키마가 명확하게 정의된 경우에 적합합니다.

초당 수천 행 수준의 처리량을 기대할 수 있습니다.
단일 JSON 행으로 삽입단일 JSON 컬럼에 삽입하는 경우(위의 syslog_json 스키마 참조)에도 동일한 삽입 명령을 사용할 수 있습니다. 다만 포맷으로 JSONEachRow 대신 JSONAsObject를 지정해야 합니다. 예:
elasticdump --input=${ELASTICSEARCH_URL} --type=data --input-index ${ELASTICSEARCH_INDEX} --output=$ --sourceOnly --searchAfter --pit=true | 
clickhouse-client --host ${CLICKHOUSE_HOST} --secure --password ${CLICKHOUSE_PASSWORD} --user ${CLICKHOUSE_USER} --max_insert_block_size=1000 \
--min_insert_block_size_bytes=0 --min_insert_block_size_rows=1000 --query="INSERT INTO test.logs_system_syslog FORMAT JSONAsObject"
자세한 내용은 “JSON을 객체로 읽기”를 참조하십시오.
5

데이터 변환(선택 사항)

위 명령은 Elasticsearch 필드와 ClickHouse 컬럼이 1:1로 매핑된다고 가정합니다. 실제로는 ClickHouse에 삽입하기 전에 Elasticsearch 데이터를 필터링하고 변환해야 하는 경우가 많습니다.이 작업은 input 테이블 함수를 사용해 수행할 수 있습니다. 이 함수로 stdout에 대해 임의의 SELECT 쿼리를 실행할 수 있습니다.앞서 사용한 데이터에서 timestamphostname 필드만 저장한다고 가정해 보겠습니다. ClickHouse 스키마는 다음과 같습니다.
CREATE TABLE logs_system_syslog_v2
(
    `timestamp` DateTime,
    `hostname` String
)
ENGINE = MergeTree
ORDER BY (hostname, timestamp)
elasticdump에서 이 테이블로 삽입하려면 input 테이블 함수를 바로 사용할 수 있습니다. 이때 JSON 타입을 사용해 필요한 컬럼을 동적으로 감지하고 선택할 수 있습니다. 참고로 이 SELECT 쿼리에는 필터를 쉽게 추가할 수 있습니다.
elasticdump --input=${ELASTICSEARCH_URL} --type=data --input-index ${ELASTICSEARCH_INDEX} --output=$ --sourceOnly --searchAfter --pit=true |
clickhouse-client --host ${CLICKHOUSE_HOST} --secure --password ${CLICKHOUSE_PASSWORD} --user ${CLICKHOUSE_USER} --max_insert_block_size=1000 \
--min_insert_block_size_bytes=0 --min_insert_block_size_rows=1000 --query="INSERT INTO test.logs_system_syslog_v2 SELECT json.\`@timestamp\` as timestamp, json.host.hostname as hostname FROM input('json JSON') FORMAT JSONAsObject"
@timestamp 필드 이름은 이스케이프 처리해야 하며, JSONAsObject 입력 형식을 사용해야 합니다.
마지막 수정일 2026년 6월 10일