Time-to-Live (TTL) é um recurso essencial do ClickStack para retenção e gerenciamento eficientes de dados, especialmente considerando que grandes volumes de dados são gerados continuamente. O TTL permite a expiração e a exclusão automáticas de dados mais antigos, garantindo o uso otimizado do armazenamento e a manutenção do desempenho sem intervenção manual. Essa capacidade é fundamental para manter o banco de dados enxuto, reduzir os custos de armazenamento e garantir que as consultas continuem rápidas e eficientes ao se concentrarem nos dados mais relevantes e recentes. Além disso, ajuda na conformidade com políticas de retenção de dados ao gerenciar sistematicamente os ciclos de vida dos dados, aumentando a sustentabilidade e a escalabilidade geral da solução de observabilidade.
Por padrão, o ClickStack retém os dados por 3 dias. Para alterar isso, consulte “Modificando o TTL”.
No ClickHouse, o TTL é controlado no nível da tabela. Por exemplo, o schema dos logs é mostrado abaixo:
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
O particionamento no ClickHouse permite separar logicamente os dados em disco de acordo com uma coluna ou expressão SQL. Ao separar os dados logicamente, cada partição pode ser operada de forma independente, por exemplo, sendo excluída quando expirar de acordo com uma política de TTL.
Como mostrado no exemplo acima, o particionamento é especificado em uma tabela quando ela é definida inicialmente por meio da cláusula PARTITION BY. Essa cláusula pode conter uma expressão SQL sobre qualquer coluna, e o resultado dela definirá para qual partição uma linha será enviada. Isso faz com que os dados fiquem logicamente associados (por meio de um prefixo comum no nome da pasta) a cada partição no disco, que então pode ser consultada isoladamente. No exemplo acima, o schema padrão otel_logs particiona por dia usando a expressão toDate(Timestamp). À medida que as linhas são inseridas no ClickHouse, essa expressão é avaliada para cada linha e a encaminha para a partição resultante, se ela já existir (se a linha for a primeira de um dia, a partição será criada). Para mais detalhes sobre particionamento e suas outras aplicações, consulte “Partições de tabelas”.
O schema da tabela também inclui um TTL TimestampTime + toIntervalDay(3) e a configuração ttl_only_drop_parts = 1. A primeira cláusula garante que os dados serão removidos quando tiverem mais de 3 dias. A configuração ttl_only_drop_parts = 1 faz com que apenas partes de dados em que todos os dados expiraram sejam removidas (em vez de tentar excluir linhas parcialmente). Como o particionamento garante que dados de dias diferentes nunca sejam “mesclados”, os dados podem, assim, ser removidos com eficiência.
ttl_only_drop_partsRecomendamos sempre usar a configuração ttl_only_drop_parts=1. Quando essa configuração está habilitada, o ClickHouse remove uma parte inteira quando todas as linhas nela expiraram. Remover partes inteiras, em vez de limpar parcialmente linhas expiradas por TTL (o que é feito por meio de mutações que consomem muitos recursos quando ttl_only_drop_parts=0), permite usar tempos menores de merge_with_ttl_timeout e reduzir o impacto no desempenho do sistema. Se os dados forem particionados pela mesma unidade usada para a expiração por TTL, por exemplo, dia, as partes naturalmente conterão apenas dados do intervalo definido. Isso garantirá que ttl_only_drop_parts=1 possa ser aplicado com eficiência.
Por padrão, dados com TTL expirado são removidos quando o ClickHouse mescla partes de dados. Quando o ClickHouse detecta que os dados expiraram, ele executa uma mesclagem fora do cronograma.
Agendamento de TTLTTLs não são aplicados imediatamente, mas sim de acordo com um agendamento, como observado acima. A configuração de tabela MergeTree merge_with_ttl_timeout define o atraso mínimo, em segundos, antes de repetir uma mesclagem com TTL de exclusão. O valor padrão é 14400 segundos (4 horas). Mas esse é apenas o atraso mínimo; a mesclagem de TTL pode demorar mais para ser acionada. Se o valor for muito baixo, muitas mesclagens fora do cronograma serão executadas, o que pode consumir muitos recursos. A expiração de TTL pode ser forçada com o comando ALTER TABLE my_table MATERIALIZE TTL.
Para modificar o TTL, você pode:
- Modificar os schemas da tabela (recomendado). Para isso, é necessário se conectar à instância do ClickHouse, por exemplo, usando o clickhouse-client ou o Cloud SQL Console. Por exemplo, podemos modificar o TTL da tabela
otel_logs usando o seguinte DDL:
ALTER TABLE default.otel_logs
MODIFY TTL TimestampTime + toIntervalDay(7);
- Modifique o OTel collector. O ClickStack OpenTelemetry collector cria tabelas no ClickHouse caso elas ainda não existam. Isso é feito por meio do ClickHouse exporter, que expõe um parâmetro
ttl usado para controlar a expressão TTL padrão, por exemplo.
exporters:
clickhouse:
endpoint: tcp://localhost:9000?dial_timeout=10s&compress=lz4&async_insert=1
ttl: 72h
Os exemplos acima fazem os dados expirarem no nível da tabela. Você também pode fazer os dados expirarem no nível da coluna. À medida que os dados envelhecem, isso pode ser usado para remover colunas cujo valor nas investigações não justifica o custo adicional de recursos para mantê-las. Por exemplo, recomendamos manter a coluna Body caso novos metadados dinâmicos sejam adicionados e ainda não tenham sido extraídos no momento da inserção, por exemplo, um novo label do Kubernetes. Após um período, por exemplo, de 1 mês, pode ficar evidente que esses metadados adicionais não são úteis, reduzindo assim o valor de manter a coluna Body.
Abaixo, mostramos como a coluna Body pode ser removida após 30 dias.
CREATE TABLE otel_logs_v2
(
`Body` String TTL Timestamp + INTERVAL 30 DAY,
`Timestamp` DateTime,
...
)
ENGINE = MergeTree
ORDER BY (ServiceName, Timestamp)
Para especificar um TTL no nível da coluna, os usuários precisam definir seu próprio schema. Isso não pode ser especificado no OTel collector.