Time-to-Live (TTL) es una función fundamental de ClickStack para la retención y gestión eficiente de datos, especialmente porque se generan continuamente grandes volúmenes de información. TTL permite la expiración y eliminación automáticas de los datos más antiguos, lo que garantiza un uso óptimo del almacenamiento y mantiene el rendimiento sin necesidad de intervención manual. Esta capacidad es esencial para mantener la base de datos ligera, reducir los costos de almacenamiento y garantizar que las consultas sigan siendo rápidas y eficientes al centrarse en los datos más relevantes y recientes. Además, facilita el cumplimiento de las políticas de retención de datos al gestionar de forma sistemática los ciclos de vida de los datos, lo que mejora la sostenibilidad y la escalabilidad generales de la solución de observabilidad.
De forma predeterminada, ClickStack conserva los datos durante 3 días. Para modificarlo, consulta “Modificar TTL”.
TTL se controla a nivel de tabla en ClickHouse. Por ejemplo, a continuación se muestra el esquema de los logs:
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
El particionado en ClickHouse permite separar lógicamente los datos en disco según una columna o una expresión SQL. Al separar los datos de forma lógica, cada partición puede gestionarse de manera independiente; por ejemplo, eliminarse cuando caduque según una política de TTL.
Como se muestra en el ejemplo anterior, el particionado se especifica en una tabla cuando se define inicialmente mediante la cláusula PARTITION BY. Esta cláusula puede contener una expresión SQL sobre cualquier columna, cuyos resultados determinarán a qué partición se envía una fila. Esto hace que los datos queden asociados lógicamente (mediante un prefijo común en el nombre de la carpeta) a cada partición del disco, que luego puede consultarse de forma aislada. En el ejemplo anterior, el esquema predeterminado de otel_logs particiona por día mediante la expresión toDate(Timestamp). A medida que las filas se insertan en ClickHouse, esta expresión se evalúa para cada fila y se enruta a la partición correspondiente si existe (si la fila es la primera de un día, se creará la partición). Para obtener más información sobre el particionado y otras aplicaciones, consulta “Particiones de tablas”.
El esquema de la tabla también incluye un TTL TimestampTime + toIntervalDay(3) y la configuración ttl_only_drop_parts = 1. La primera cláusula garantiza que los datos se eliminen una vez superados los 3 días de antigüedad. La configuración ttl_only_drop_parts = 1 hace que solo caduquen las partes de datos en las que todos los datos han expirado (en lugar de intentar eliminar filas de forma parcial). Como el particionado garantiza que los datos de días distintos nunca se fusionen, los datos pueden eliminarse de forma eficiente.
ttl_only_drop_partsRecomendamos usar siempre la configuración ttl_only_drop_parts=1. Cuando esta configuración está habilitada, ClickHouse elimina una parte completa cuando todas las filas que contiene han expirado. Eliminar partes completas en lugar de limpiar parcialmente filas afectadas por TTL (algo que se logra mediante mutaciones con un alto consumo de recursos cuando ttl_only_drop_parts=0) permite usar tiempos de merge_with_ttl_timeout más cortos y reducir el impacto en el rendimiento del sistema. Si los datos están particionados por la misma unidad con la que se aplica la expiración de TTL, por ejemplo, por día, las partes contendrán de forma natural únicamente datos del intervalo definido. Esto garantizará que ttl_only_drop_parts=1 pueda aplicarse de forma eficiente.
De forma predeterminada, los datos con TTL expirado se eliminan cuando ClickHouse fusiona partes de datos. Cuando ClickHouse detecta que los datos han expirado, realiza una fusión fuera de programación.
Programación de TTLLos TTL no se aplican de inmediato, sino según una programación, como se indicó antes. La configuración de tabla de MergeTree merge_with_ttl_timeout establece el retraso mínimo, en segundos, antes de repetir una fusión con TTL de eliminación. El valor predeterminado es 14400 segundos (4 horas). Pero ese es solo el retraso mínimo; puede pasar más tiempo hasta que se active una fusión de TTL. Si el valor es demasiado bajo, se realizarán muchas fusiones fuera de programación que pueden consumir muchos recursos. La expiración de TTL puede forzarse con el comando ALTER TABLE my_table MATERIALIZE TTL.
Para modificar TTL, puede optar por una de estas opciones:
- Modificar los esquemas de la tabla (recomendado). Para ello, es necesario conectarse a la instancia de ClickHouse, por ejemplo, mediante clickhouse-client o Cloud SQL Console. Por ejemplo, podemos modificar el TTL de la tabla
otel_logs mediante el siguiente DDL:
ALTER TABLE default.otel_logs
MODIFY TTL TimestampTime + toIntervalDay(7);
- Modifique el OTel collector. El ClickStack OpenTelemetry collector crea tablas en ClickHouse si no existen. Esto se logra mediante el ClickHouse exporter, que a su vez expone un parámetro
ttl para controlar la expresión TTL predeterminada, por ejemplo.
exporters:
clickhouse:
endpoint: tcp://localhost:9000?dial_timeout=10s&compress=lz4&async_insert=1
ttl: 72h
Los ejemplos anteriores hacen que los datos caduquen a nivel de tabla. También puede hacer que los datos caduquen a nivel de columna. A medida que los datos envejecen, esto puede usarse para eliminar columnas cuyo valor en las investigaciones no justifica el consumo de recursos que supone conservarlas. Por ejemplo, recomendamos conservar la columna Body por si se añaden nuevos metadatos dinámicos que no se hayan extraído en el momento de la inserción, p. ej., una nueva etiqueta de Kubernetes. Tras un período de, p. ej., 1 mes, puede resultar evidente que estos metadatos adicionales no son útiles, lo que reduce el valor de conservar la columna Body.
A continuación, mostramos cómo puede eliminarse la columna Body después de 30 días.
CREATE TABLE otel_logs_v2
(
`Body` String TTL Timestamp + INTERVAL 30 DAY,
`Timestamp` DateTime,
...
)
ENGINE = MergeTree
ORDER BY (ServiceName, Timestamp)
Para especificar un TTL a nivel de columna, los usuarios deben definir su propio esquema. Esto no se puede especificar en el OTel collector.