Skip to main content
Las implementaciones de ClickHouse para la observabilidad implican invariablemente grandes volúmenes de datos, que deben gestionarse. ClickHouse ofrece varias funciones para facilitar la gestión de los datos.
ClickStack incluye un esquema predeterminado optimizadoClickStack proporciona esquemas listos para usar para logs, trazas y métricas que incorporan las funciones más recientes de ClickHouse (índices de texto para búsqueda de texto completo y por claves de Map, columnas materializadas y arrays ALIAS para filtrado de lectura directa, búsquedas de filas por número de bloque) y se han sometido a benchmark para ofrecer un sólido rendimiento desde el primer momento en cargas de trabajo de logging y trazas. Úselos como punto de referencia para su propio diseño.

Particiones

El particionamiento de datos en ClickHouse permite separar lógicamente los datos en disco según una columna o una expresión SQL. Al separar los datos de esta forma, cada partición puede gestionarse de manera independiente; por ejemplo, eliminarse. Esto permite mover particiones y, por tanto, subconjuntos de datos, entre niveles de almacenamiento de forma eficiente según el tiempo o hacer caducar datos/eliminarlos eficientemente de un clúster. El particionamiento 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 una o varias columnas, cuyo resultado determinará a qué partición se envía una fila. Las partes de datos se asocian lógicamente (mediante un prefijo común en el nombre de la carpeta) con cada partición en disco y pueden consultarse de forma aislada. En el ejemplo siguiente, el esquema predeterminado otel_logs particiona por día mediante la expresión toDate(Timestamp). A medida que se insertan filas en ClickHouse, esta expresión se evaluará para cada fila y se dirigirá a la partición correspondiente si existe (si la fila es la primera de un día, se creará la partición).
Se pueden realizar varias operaciones sobre las particiones, incluidas copias de seguridad, manipulaciones de columnas, mutaciones para modificar/eliminar datos por fila) y limpieza de índices (p. ej., índices secundarios). Como ejemplo, supongamos que nuestra tabla otel_logs está particionada por día. Si se llena con el conjunto de datos estructurados de logs, contendrá datos de varios días:
Las particiones actuales pueden consultarse con una sencilla consulta a una tabla del sistema:
Podemos tener otra tabla, otel_logs_archive, que usamos para almacenar los datos más antiguos. Los datos pueden moverse a esta tabla de forma eficiente por partición (esto es solo un cambio de metadatos).
Esto contrasta con otras técnicas, que requerirían usar INSERT INTO SELECT y reescribir los datos en la nueva tabla de destino.
Mover particionesMover particiones entre tablas requiere que se cumplan varias condiciones; entre ellas, que las tablas tengan la misma estructura, clave de partición, clave primaria e índices/proyecciones. Puedes encontrar notas detalladas sobre cómo especificar particiones en ALTER DDL aquí.
Además, los datos pueden eliminarse eficientemente por partición. Esto es mucho más eficiente en términos de recursos que las técnicas alternativas (mutaciones o eliminaciones ligeras), por lo que debe ser la opción preferente.
TTL aprovecha esta funcionalidad cuando se usa la configuración ttl_only_drop_parts=1. Consulta Gestión de datos con TTL para más detalles.

Aplicaciones

Lo anterior ilustra cómo los datos pueden moverse y manipularse de forma eficiente por particiones. En la práctica, lo más habitual es aprovechar las operaciones sobre particiones en casos de uso de observabilidad en dos escenarios:
  • Arquitecturas por niveles - mover datos entre niveles de almacenamiento (consulte Niveles de almacenamiento), lo que permite construir arquitecturas hot-cold.
  • Eliminación eficiente - cuando los datos han alcanzado un TTL especificado (consulte Gestión de datos con TTL)
A continuación, examinamos ambos en detalle.

Rendimiento de las consultas

Aunque las particiones pueden ayudar al rendimiento de las consultas, esto depende en gran medida de los patrones de acceso. Si las consultas se dirigen solo a unas pocas particiones (idealmente una), el rendimiento puede mejorar. Por lo general, esto solo es útil si la clave de particionamiento no forma parte de la clave primaria y se filtra por ella. Sin embargo, las consultas que necesitan abarcar muchas particiones pueden tener peor rendimiento que si no se usara particionamiento (ya que podría haber más partes). La ventaja de dirigirse a una sola partición será aún menor, o incluso nula, si la clave de particionamiento ya aparece al principio de la clave primaria. El particionamiento también puede usarse para optimizar las consultas GROUP BY si los valores de cada partición son únicos. Sin embargo, en general, debe asegurarse de que la clave primaria esté optimizada y considerar el particionamiento como una técnica de optimización de consultas solo en casos excepcionales en los que los patrones de acceso se centren en un subconjunto específico y predecible de los datos; por ejemplo, particionar por día cuando la mayoría de las consultas se realizan sobre el último día. Consulte aquí para ver un ejemplo de este comportamiento.

Gestión de datos con TTL (Time-to-live)

Time-to-Live (TTL) es una funcionalidad clave en las soluciones de observabilidad basadas en ClickHouse para la retención y gestión eficientes de datos, especialmente dado que se generan continuamente grandes volúmenes de información. Implementar TTL en ClickHouse 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 intervención manual. Esta capacidad es esencial para mantener una base de datos ágil, reducir los costes 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 mediante la gestión sistemática del ciclo de vida de los datos, lo que mejora la sostenibilidad y la escalabilidad generales de la solución de observabilidad. TTL puede especificarse a nivel de tabla o de columna en ClickHouse.

TTL a nivel de tabla

El esquema predeterminado tanto de los logs como de las trazas incluye un TTL para que los datos caduquen tras un período determinado. Esto se especifica en el exportador de ClickHouse mediante una clave ttl, por ejemplo.
Esta sintaxis admite actualmente la sintaxis de Duration de Golang. Recomendamos que los usuarios utilicen h y se aseguren de que esto coincida con el período de particionado. Por ejemplo, si se particiona por día, asegúrese de que sea un múltiplo de días, p. ej., 24h, 48h, 72h. Esto garantizará automáticamente que se añada una cláusula TTL a la tabla, por ejemplo, si ttl: 96h.
De forma predeterminada, los datos con un TTL vencido se eliminan cuando ClickHouse fusiona partes de datos. Cuando ClickHouse detecta que los datos han caducado, realiza una fusión fuera de programación.
TTLs programadosLos TTL no se aplican inmediatamente, 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 de 14400 segundos (4 horas). Pero ese es solo el retraso mínimo; puede pasar más tiempo hasta que se active una fusión TTL. Si el valor es demasiado bajo, se realizarán muchas fusiones fuera de programación que pueden consumir muchos recursos. El vencimiento de un TTL se puede forzar con el comando ALTER TABLE my_table MATERIALIZE TTL.
**Importante: Recomendamos usar la configuración ttl_only_drop_parts=1 ** (aplicada por el esquema predeterminado). Cuando esta configuración está habilitada, ClickHouse elimina una parte completa cuando todas sus filas han caducado. Eliminar partes completas en lugar de limpiar parcialmente las filas con TTL vencido (algo que se logra mediante mutaciones con un alto consumo de recursos cuando ttl_only_drop_parts=0) permite usar valores más cortos de merge_with_ttl_timeout y reducir el impacto en el rendimiento del sistema. Si los datos están particionados por la misma unidad con la que se aplica el vencimiento del TTL, por ejemplo, día, las partes contendrán de forma natural solo datos del intervalo definido. Esto garantizará que ttl_only_drop_parts=1 pueda aplicarse de forma eficiente.

TTL a nivel de columna

El ejemplo anterior hace que los datos expiren a nivel de tabla. También puede hacer que expiren a nivel de columna. A medida que los datos envejecen, esto puede usarse para eliminar columnas cuyo valor en las investigaciones no justifica el coste de recursos de conservarlas. Por ejemplo, recomendamos conservar la columna Body por si se añade algún metadato dinámico nuevo que no se haya extraído en el momento de la inserción, p. ej., una nueva etiqueta de Kubernetes. Después de un tiempo, p. ej., 1 mes, puede resultar evidente que estos metadatos adicionales no son útiles, lo que limita el valor de conservar la columna Body. A continuación, mostramos cómo se puede eliminar la columna Body al cabo de 30 días.
Para especificar un TTL a nivel de columna, los usuarios deben definir su propio esquema. Esto no se puede especificar en el OTel collector.

Recompresión de datos

Aunque normalmente recomendamos ZSTD(1) para los conjuntos de datos de observabilidad, puede probar distintos algoritmos de compresión o niveles de compresión más altos, como ZSTD(3). Además de poder especificarlo al crear el esquema, la compresión puede configurarse para que cambie después de un período determinado. Esto puede resultar adecuado si un codec o algoritmo de compresión mejora la compresión, pero empeora el rendimiento de las consultas. Esta contrapartida puede ser aceptable para datos más antiguos, que se consultan con menos frecuencia, pero no para datos recientes, que se usan con más frecuencia en las investigaciones. A continuación se muestra un ejemplo, en el que comprimimos los datos con ZSTD(3) después de 4 días en lugar de eliminarlos.
Evaluar el rendimientoRecomendamos a los usuarios evaluar siempre el impacto en el rendimiento de la inserción y las consultas de los distintos niveles y algoritmos de compresión. Por ejemplo, los códecs delta pueden ser útiles para comprimir marcas de tiempo. Sin embargo, si forman parte de la clave primaria, el rendimiento del filtrado puede verse afectado.
Encontrará más detalles y ejemplos sobre cómo configurar TTL aquí. Puede encontrar aquí ejemplos de cómo añadir y modificar TTL en tablas y columnas. Para ver cómo TTL permite jerarquías de almacenamiento, como las arquitecturas hot-warm, consulte Niveles de almacenamiento.

Niveles de almacenamiento

En ClickHouse, puede crear niveles de almacenamiento en distintos discos; por ejemplo, datos calientes o recientes en SSD y datos más antiguos respaldados por S3. Esta arquitectura permite usar almacenamiento menos costoso para los datos antiguos, que pueden tolerar SLA de consulta más laxos debido a su uso poco frecuente en las investigaciones.
No es relevante para ClickHouse CloudClickHouse Cloud usa una sola copia de los datos respaldada por S3, con cachés de nodo sobre SSD. Por lo tanto, los niveles de almacenamiento no son necesarios en ClickHouse Cloud.
La creación de niveles de almacenamiento requiere que los usuarios creen discos, que luego se usan para definir políticas de almacenamiento, con volúmenes que pueden especificarse durante la creación de la tabla. Los datos pueden moverse automáticamente entre discos según los niveles de ocupación, los tamaños de las partes y las prioridades de los volúmenes. Puede encontrar más detalles aquí. Aunque los datos pueden moverse manualmente entre discos mediante el comando ALTER TABLE MOVE PARTITION, el movimiento de datos entre volúmenes también puede controlarse mediante TTL. Puede encontrar un ejemplo completo aquí.

Gestión de cambios de esquema

Los esquemas de logs y trazas cambiarán inevitablemente a lo largo de la vida útil de un sistema, por ejemplo, a medida que los usuarios supervisan nuevos sistemas con metadatos o etiquetas de pod de Kubernetes diferentes. Al generar datos con el esquema de OTel y capturar los datos originales de los eventos en un formato estructurado, los esquemas de ClickHouse serán robustos frente a estos cambios. Sin embargo, a medida que haya nuevos metadatos disponibles y cambien los patrones de acceso de las consultas, le convendrá actualizar los esquemas para reflejar estos cambios. Para evitar tiempo de inactividad durante los cambios de esquema, los usuarios disponen de varias opciones, que presentamos a continuación.

Usar valores predeterminados

Se pueden añadir columnas al esquema mediante valores DEFAULT“. El valor predeterminado especificado se usará si no se indica durante el INSERT. Los cambios en el esquema pueden realizarse antes de modificar la lógica de transformación de cualquier vista materializada o la configuración del OTel collector, lo que permite que se envíen estas nuevas columnas. Una vez modificado el esquema, puede reconfigurar los OTel collectors. Suponiendo que los usuarios sigan el proceso recomendado descrito en “Extracción de estructura con SQL”, en el que los OTel collectors envían sus datos a un motor de tabla Null con una vista materializada encargada de extraer el esquema de destino y enviar los resultados a una tabla de destino para su almacenamiento, la vista puede modificarse mediante la sintaxis ALTER TABLE ... MODIFY QUERY. Supongamos que tenemos la siguiente tabla de destino con su vista materializada correspondiente (similar a la utilizada en “Extracción de estructura con SQL”) para extraer el esquema de destino de los logs estructurados de OTel:
Supongamos que queremos extraer una nueva columna Size de LogAttributes. Podemos añadirla a nuestro esquema con un ALTER TABLE, especificando el valor por defecto:
En el ejemplo anterior, especificamos como valor predeterminado la clave size en LogAttributes (será 0 si no existe). Esto significa que las consultas que acceden a esta columna en filas donde no se ha insertado el valor deben acceder al Map y, por lo tanto, serán más lentas. También podríamos especificarlo fácilmente como una constante, p. ej., 0, lo que reduce el coste de las consultas posteriores sobre las filas que no tienen ese valor. Al consultar esta tabla, se observa que el valor se rellena como se espera a partir del Map:
Para garantizar que este valor se inserte en todos los datos que se incorporen en el futuro, podemos modificar nuestra vista materializada mediante la sintaxis de ALTER TABLE, como se muestra a continuación:
Las filas posteriores tendrán la columna Size rellenada en el momento de la inserción.

Crear tablas nuevas

Como alternativa al proceso anterior, puedes simplemente crear una nueva tabla de destino con el nuevo esquema. Luego, cualquier vista materializada puede modificarse para que use la nueva tabla mediante el ALTER TABLE MODIFY QUERY mencionado anteriormente. Con este enfoque, puedes versionar tus tablas, por ejemplo, otel_logs_v3. Este enfoque deja a los usuarios con varias tablas para consultar. Para consultar datos en varias tablas, puedes usar la función merge, que acepta patrones comodín para el nombre de la tabla. A continuación, mostramos esto consultando una v2 y una v3 de la tabla otel_logs:
Si se desea evitar el uso de la función merge y exponer a los usuarios finales una tabla que combine varias tablas, se puede utilizar el motor de tabla Merge. Lo mostramos a continuación:
Esto se puede actualizar cada vez que se añade una nueva tabla mediante la sintaxis EXCHANGE para tablas. Por ejemplo, para añadir una tabla v4, podemos crear una nueva tabla e intercambiarla de forma atómica con la versión anterior.
Última modificación el 23 de julio de 2026