> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-86180b7b.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# TTL 관리

> ClickStack의 TTL 관리

export const Image = ({img, alt, size}) => {
  return <Frame>
      <img src={img} alt={alt} />
    </Frame>;
};

<div id="ttl-clickstack">
  ## ClickStack의 TTL
</div>

TTL(Time-to-Live)은 ClickStack에서 효율적인 데이터 보존 및 관리를 위한 핵심 기능이며, 특히 방대한 양의 데이터가 지속적으로 생성되는 환경에서 더욱 중요합니다. TTL을 사용하면 오래된 데이터가 자동으로 만료되어 삭제되므로, 수동 개입 없이도 스토리지를 효율적으로 활용하고 성능을 유지할 수 있습니다. 이 기능은 데이터베이스를 경량으로 유지하고 스토리지 비용을 절감하며, 가장 관련성 높고 최신의 데이터에 집중함으로써 쿼리 성능을 빠르고 효율적으로 유지하는 데 필수적입니다. 또한 데이터 수명 주기를 체계적으로 관리해 데이터 보존 정책 관련 컴플라이언스를 지원하므로, 관측성 솔루션 전반의 지속 가능성과 확장성도 향상됩니다.

**기본적으로 ClickStack은 데이터를 3일간 보존합니다. 이를 변경하려면 ["TTL 수정"](#modifying-ttl)을 참조하십시오.**

ClickHouse에서는 TTL을 테이블 수준에서 제어합니다. 예를 들어, logs의 스키마(schema)는 아래와 같습니다.

```sql theme={null}
CREATE TABLE default.otel_logs
(
    `Timestamp` DateTime64(9) CODEC(Delta(8), ZSTD(1)),
    `TimestampTime` DateTime DEFAULT toDateTime(Timestamp),
    `TraceId` String CODEC(ZSTD(1)),
    `SpanId` String CODEC(ZSTD(1)),
    `TraceFlags` UInt8,
    `SeverityText` LowCardinality(String) CODEC(ZSTD(1)),
    `SeverityNumber` UInt8,
    `ServiceName` LowCardinality(String) CODEC(ZSTD(1)),
    `Body` String CODEC(ZSTD(1)),
    `ResourceSchemaUrl` LowCardinality(String) CODEC(ZSTD(1)),
    `ResourceAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
    `ScopeSchemaUrl` LowCardinality(String) CODEC(ZSTD(1)),
    `ScopeName` String CODEC(ZSTD(1)),
    `ScopeVersion` LowCardinality(String) CODEC(ZSTD(1)),
    `ScopeAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
    `LogAttributes` Map(LowCardinality(String), String) CODEC(ZSTD(1)),
    INDEX idx_trace_id TraceId TYPE bloom_filter(0.001) GRANULARITY 1,
    INDEX idx_res_attr_key mapKeys(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_res_attr_value mapValues(ResourceAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_scope_attr_key mapKeys(ScopeAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_scope_attr_value mapValues(ScopeAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_log_attr_key mapKeys(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_log_attr_value mapValues(LogAttributes) TYPE bloom_filter(0.01) GRANULARITY 1,
    INDEX idx_body Body TYPE tokenbf_v1(32768, 3, 0) GRANULARITY 8
)
ENGINE = MergeTree
PARTITION BY toDate(TimestampTime)
PRIMARY KEY (ServiceName, TimestampTime)
ORDER BY (ServiceName, TimestampTime, Timestamp)
TTL TimestampTime + toIntervalDay(3)
SETTINGS ttl_only_drop_parts = 1
```

ClickHouse의 파티셔닝은 컬럼 또는 SQL 표현식에 따라 디스크상에서 데이터를 논리적으로 분리할 수 있게 해줍니다. 데이터를 논리적으로 분리하면 각 파티션을 독립적으로 처리할 수 있으므로, 예를 들어 TTL 정책에 따라 만료된 데이터를 삭제할 수 있습니다.

위 예시에서 보듯이 파티셔닝은 테이블(table)을 처음 정의할 때 `PARTITION BY` 절로 지정합니다. 이 절에는 하나 이상의 컬럼에 대한 SQL 표현식이 들어갈 수 있으며, 그 결과에 따라 각 행이 어느 파티션으로 보내질지가 결정됩니다. 그 결과 데이터는 디스크의 각 파티션과 논리적으로 연결되며(공통 폴더 이름 접두사를 통해), 이후 특정 파티션만 분리해서 조회할 수 있습니다. 위 예시에서 기본 `otel_logs` 스키마(schema)는 `toDate(Timestamp).` 표현식을 사용해 일 단위로 파티셔닝합니다. 행이 ClickHouse에 삽입되면 이 표현식이 각 행에 대해 평가되며, 해당 결과의 파티션이 이미 있으면 그 파티션으로 라우팅됩니다(해당 날짜의 첫 번째 행이면 파티션이 생성됩니다). 파티셔닝과 그 밖의 활용 방식에 대한 자세한 내용은 ["테이블 파티션"](/ko/concepts/core-concepts/partitions)을 참조하십시오.

<Image img="https://mintcdn.com/private-7c7dfe99-mintlify-86180b7b/2H6FswmM7cixHRYm/images/use-cases/observability/observability-14.png?fit=max&auto=format&n=2H6FswmM7cixHRYm&q=85&s=836628e50ecbad6a8df5272a5a29879f" alt="파티션" size="lg" width="1600" height="1077" data-path="images/use-cases/observability/observability-14.png" />

테이블 스키마에는 `TTL TimestampTime + toIntervalDay(3)`와 설정 `ttl_only_drop_parts = 1`도 포함됩니다. 앞의 절은 데이터가 3일이 지나면 삭제되도록 보장합니다. 설정 `ttl_only_drop_parts = 1`은 모든 데이터가 만료된 데이터 파트만 만료 대상으로 처리하도록 합니다(행을 부분적으로 삭제하려고 시도하는 대신). 또한 파티셔닝을 통해 서로 다른 날짜의 데이터가 절대 머지되지 않으므로 데이터를 효율적으로 삭제할 수 있습니다.

<Warning>
  **`ttl_only_drop_parts`**

  항상 [`ttl_only_drop_parts=1`](/ko/reference/settings/merge-tree-settings#ttl_only_drop_parts) 설정을 사용할 것을 권장합니다. 이 설정을 활성화하면 ClickHouse는 해당 파트의 모든 행이 만료되었을 때 파트 전체를 삭제합니다. `ttl_only_drop_parts=0`일 때 리소스를 많이 소비하는 뮤테이션으로 TTL이 적용된 행을 부분적으로 정리하는 대신, 파트 전체를 삭제하면 `merge_with_ttl_timeout` 시간을 더 짧게 설정할 수 있고 시스템 성능에 미치는 영향도 줄일 수 있습니다. TTL 만료를 수행하는 것과 동일한 단위(예: 일)로 데이터를 파티셔닝하면 파트에는 자연스럽게 정의된 인터벌의 데이터만 포함됩니다. 그러면 `ttl_only_drop_parts=1`을 효율적으로 적용할 수 있습니다.
</Warning>

기본적으로 TTL이 만료된 데이터는 ClickHouse가 [데이터 파트를 머지할 때](/ko/reference/engines/table-engines/mergetree-family/mergetree#mergetree-data-storage) 제거됩니다. ClickHouse가 데이터가 만료되었음을 감지하면 예정되지 않은 머지를 수행합니다.

<Info>
  **TTL 일정**

  위에서 설명했듯이 TTL은 즉시 적용되지 않고 일정에 따라 적용됩니다. MergeTree 테이블 설정 `merge_with_ttl_timeout`은 delete TTL이 적용된 머지를 다시 수행하기 전까지의 최소 지연 시간을 초 단위로 설정합니다. 기본값은 14400초(4시간)입니다. 하지만 이는 최소 지연 시간일 뿐이며 TTL 머지가 실제로 트리거되기까지는 더 오래 걸릴 수 있습니다. 값이 너무 낮으면 예정되지 않은 머지가 많이 수행되어 많은 리소스를 소비할 수 있습니다. TTL 만료는 `ALTER TABLE my_table MATERIALIZE TTL` 명령으로 강제로 수행할 수 있습니다.
</Info>

<div id="modifying-ttl">
  ## TTL 수정
</div>

TTL은 다음 두 가지 방법으로 수정할 수 있습니다:

1. **테이블 스키마를 수정합니다(권장)**. 이 방법을 사용하려면 [clickhouse-client](/ko/concepts/features/interfaces/cli) 또는 [Cloud SQL Console](/ko/products/cloud/features/sql-console-features/sql-console)을 사용해 ClickHouse 인스턴스에 연결해야 합니다. 예를 들어, 다음 DDL을 사용하면 `otel_logs` 테이블의 TTL을 수정할 수 있습니다:

```sql theme={null}
ALTER TABLE default.otel_logs
MODIFY TTL TimestampTime + toIntervalDay(7);
```

2. **OTel collector를 수정합니다**. ClickStack OpenTelemetry collector는 ClickHouse에 테이블이 없으면 생성합니다. 이는 ClickHouse exporter를 통해 수행되며, 이 exporter에는 기본 TTL 표현식을 제어하는 데 사용하는 `ttl` 매개변수가 있습니다. 예:

```yaml theme={null}
exporters:
 clickhouse:
   endpoint: tcp://localhost:9000?dial_timeout=10s&compress=lz4&async_insert=1
   ttl: 72h
```

<div id="column-level-ttl">
  ### 컬럼 수준 TTL
</div>

위의 예시에서는 데이터를 테이블 수준에서 만료합니다. 데이터는 컬럼 수준에서도 만료할 수 있습니다. 데이터가 오래될수록 조사에 활용했을 때의 가치가 보관에 따른 리소스 오버헤드를 정당화하지 못하는 컬럼을 삭제하는 데 이를 사용할 수 있습니다. 예를 들어, 삽입 시점에 아직 추출되지 않은 새로운 동적 메타데이터(예: 새로운 Kubernetes 레이블)가 추가될 가능성에 대비해 `Body` 컬럼을 유지할 것을 권장합니다. 예를 들어 1개월 정도 지난 후에는 이러한 추가 메타데이터가 유용하지 않다는 점이 분명해질 수 있으므로 `Body` 컬럼을 계속 유지할 가치도 낮아집니다.

아래에서는 `Body` 컬럼을 30일 후 삭제하는 방법을 보여드립니다.

```sql theme={null}
CREATE TABLE otel_logs_v2
(
        `Body` String TTL Timestamp + INTERVAL 30 DAY,
        `Timestamp` DateTime,
 ...
)
ENGINE = MergeTree
ORDER BY (ServiceName, Timestamp)
```

<Note>
  컬럼 수준 TTL을 지정하려면 스키마(schema)를 직접 정의해야 합니다. 이 설정은 OTel collector에서 지정할 수 없습니다.
</Note>
