Nuestro setup de ClickHouse para reducir costes
ObsessionDB baja el coste de ClickHouse recortando cuánto usas, no lo que pagas por unidad. Guardamos una sola copia de los datos en object storage en lugar de una por réplica, dimensionamos el compute según la carga en vez de duplicarlo por disponibilidad, movemos unas cuatro veces menos datos entre nodos durante los merges y no cobramos por transferencia de datos. El almacenamiento se factura por terabyte comprimido, así que tu orden de claves y tus tipos de columna deciden esa línea.
25.600 $ al mes frente a bastante más de 150.000 $. Esas son las dos facturas de infraestructura detrás de nuestro benchmark de 10.000 millones de filas, con veinte nodos en cada lado. La migración desde BigQuery que publicamos en junio fue por el mismo camino: unos 8.000 $ al mes en cargos por escaneo pasaron a ser un cluster de tres nodos por unos 2.000 $. Ya hemos hablado de latencia y de escala. Este post va de coste: de qué está hecha una factura de ClickHouse, qué parte de nuestro setup recorta cada línea y qué puedes cambiar en cualquier cluster.
De qué está hecha una factura de ClickHouse
Una factura de ClickHouse puede tener cuatro líneas. Compute, porque los nodos necesitan RAM y cores para las queries y para los merges que corren entre medias. Almacenamiento comprimido, porque MergeTree comprime cada columna al escribir, y esos bytes son los que se miden. Transferencia de datos, porque los clusters mueven parts entre nodos y resultados hacia los clientes, y los proveedores cloud cobran por los bytes que salen de una región. Los cargos por query solo aparecen en warehouses como BigQuery y Snowflake. ClickHouse factura la capacidad que provisionas, y las queries sobre ella no cuestan nada extra.
Las líneas que ves dependen de quién opera el cluster. Self-hosted, pagas a tu proveedor cloud por las instancias, por el almacenamiento multiplicado por el número de réplicas y por el egress, más los ingenieros de guardia. ClickHouse Cloud mide el compute por minuto, el almacenamiento comprimido por terabyte y el egress por gigabyte. Los servicios bring-your-own-cloud añaden una cuota de gestión por vCPU encima de la factura de tu proveedor. ObsessionDB cobra un precio mensual fijo por nodo y un precio por terabyte comprimido, sin cargos por transferencia ni por query. Nuestros precios:
| Concepto | ObsessionDB |
|---|---|
| Compute, un nodo de 64 GB durante un mes | 1.280 $ (8 unidades de 2 vCPU y 8 GB a 160 $) |
| Almacenamiento, por TB comprimido al mes | 25 $ |
| Transferencia de datos de salida | Gratis, en ambos sentidos |
| Por query | Nada |
El gráfico de arriba aplica estos precios a tres nodos de 64 GB con compresión 7x, desde 10 TB hasta un petabyte. La misma carga necesita menos de esos nodos y menos de esos terabytes en nuestro setup, por las razones que vienen a continuación.
El setup, capa por capa
Cada parte del setup reduce la cantidad de algo que pagas: copias de los datos, nodos, ancho de banda, terabytes comprimidos o datos que salen de la región. Los precios no se mueven.
Una sola copia de los datos
Tres réplicas son tres copias. Con ReplicatedMergeTree, un servidor escribe una part y cada una de las demás réplicas la descarga a su propio disco, así que tres réplicas de una tabla de 54 GiB ocupan unos 162 GiB. A los 23,60 $ por terabyte de S3 Standard, 10 TB en tres réplicas son 30 TB y 708 $ al mes. Los mismos 10 TB en ObsessionDB cuestan 250 $. Poner MergeTree sobre un disco S3 no lo arregla, porque cada réplica sigue guardando sus propios objetos y metadatos. La replicación zero-copy permitiría compartirlos, pero lleva desactivada por defecto desde la 22.8 y no se recomienda en producción.
Alloy, nuestro motor desarrollado sobre la API de SharedMergeTree, guarda una sola copia de los datos en object storage y nada permanente en los nodos. Añadir un nodo no mueve datos, y quitar uno tampoco los toca. Pagas el almacenamiento una vez, tengas los nodos que tengas.
Compute a la medida del trabajo
En un cluster replicado, cada réplica es un seguro que pagas a precio completo, todo el tiempo. Tiene que ser tan grande como la primaria por si le toca sustituirla, y mientras espera repite los mismos merges sobre su propia copia. Con almacenamiento compartido, un nodo caído se sustituye por otro que se engancha a los mismos datos, así que no hay nada en reserva.
Los nodos que sirven a un cliente los tenemos en un grupo, y sus backfills y benchmarks en otro, los dos leyendo los mismos datos. Los nodos de servicio se dimensionan para servir, no para el trabajo más pesado del trimestre. Mover un nodo entre grupos no copia datos, y cuando un trabajo termina el nodo extra desaparece, y su coste con él. Nuestra regla de tamaño del post de escala: menos nodos y más grandes, y como mínimo tres. Los merges y joins grandes necesitan la memoria de un solo nodo, y un cluster de dos nodos pierde la mitad de su capacidad durante un rolling update.
Ancho de banda, el coste oculto
Las instancias de AWS optimizadas para red cuestan alrededor de un tercio más por la misma CPU y memoria. Una c6in.xlarge cuesta 0,2268 $ la hora frente a 0,17 $ de una c6i.xlarge, las dos con 4 vCPU y 8 GiB, y la m6in.xlarge cuesta un 45 % más que la m6i.xlarge (us-east-1, 22 de septiembre de 2026). Ninguna lista de precios de ClickHouse tiene una línea de ancho de banda. Lo pagas en el tamaño de los nodos que necesitas.
Un cluster distribuido de ClickHouse pasa la mayor parte del tiempo moviendo datos, así que el ancho de banda limita la latencia y la concurrencia antes que la CPU. Uno de nuestros clusters de seis nodos movió unos 400 TB entre nodos en una sola semana de ingesta intensa. Cuando seis nodos reparten los merges al azar, solo el 17 % de los datos que lee un merge está en local. Los nuestros están en torno al 70 % en local, más o menos cuatro veces menos tráfico de merges, y las lecturas con parallel replicas usan la misma colocación para quedarse al menos a la mitad en local.
La cache distribuida hace el resto. El NVMe de cada nodo forma parte de una única cache compartida, las parts se cachean en cuanto se escriben, y traer datos de otro nodo tarda menos de un milisegundo, mientras que el object storage tarda decenas de milisegundos. Con peticiones más rápidas cada nodo sirve más con el mismo ancho de banda y manda menos peticiones GET al object storage, que las cobra por millar. La cache va sobre discos que ya pagas como parte del nodo. Conseguir la misma velocidad desde el almacenamiento supondría S3 Express One Zone a 0,11 $ por GB al mes, 4,8 veces el precio de S3 Standard incluso después de la bajada de 2025. El resultado son nodos más pequeños para la misma carga, o más carga sobre los mismos nodos, y de ahí sale la diferencia del benchmark del principio.
Compresión
El almacenamiento se factura por terabyte comprimido, así que tu ratio de compresión fija la factura de almacenamiento. La documentación de ClickHouse habla de unas 10x para datos analíticos típicos, y nuestros clusters andan por ahí: 7,94x en una partición de transferencias de blockchain, unas 6,5x en un cluster entero (130 TB de datos en bruto guardados en 20 TB), 16x en nuestros logs y 13x en nuestras métricas, y 3,05x en la tabla de 56 TB llena de claves aleatorias de 64 bytes. Nuestra página de precios asume 7x, y la query del kit de más abajo mide la tuya. El esquema puede sumar otro multiplicador encima: solo el orden de claves ya es casi 2x sobre las mismas filas, como muestra el gráfico de abajo. Los codecs aportan unos pocos puntos como mucho.
Los merges también ayudan. El dataset del benchmark de 10.000 millones de filas ocupaba 92 GB en seis parts y 54 GB una vez fusionado en una, porque las parts grandes comprimen mejor. Los merges con localidad nos dejan llegar a parts de 150 GB sin saturar la red. Un cluster que limita el tamaño de las parts para ahorrar ancho de banda lo paga en almacenamiento.
Transferencia
El egress es lo que pagas por leer tus propios datos desde fuera de su región. En ClickHouse Cloud, los datos hacia internet cuestan 0,1152 $ por GB en AWS us-east-1 y los datos entre regiones 0,0312 $ por GB. Un dashboard que saca 1 TB al mes cuesta 118 $, y replicar 10 TB al mes a otra región cuesta 319 $. Nuestros precios no tienen cargo por transferencia, y desplegamos en la misma región que tu aplicación.
Sin cargos por query
Pagar por escaneo funciona si lanzas una query al mes. BigQuery cobra 6,25 $ por TiB escaneado y Snowflake cobra créditos por segundo de warehouse, multiplicados por el número de clusters encendidos. La migración desde BigQuery que publicamos en junio escaneaba unos 1.600 TB al mes, y con ese volumen el cargo por escaneo era la factura. ObsessionDB no cobra por query. El post de agentes explica por qué importa cuando tu cliente es un programa que lanza cien queries por cada una que lanza un usuario de dashboard.
El kit: qué mueve el coste de ClickHouse en cualquier cluster
Todo lo anterior viene de serie en nuestra plataforma. Los cambios de abajo funcionan en cualquier cluster de ClickHouse, agrupados por la línea de la factura que reducen.
Almacenamiento
Empieza por los cambios que más bytes por fila recortan. Primero la clave de ordenación: las columnas de baja cardinalidad delante y las de alta entropía detrás, para que los valores repetidos queden juntos. Después los tipos: usa el tipo más pequeño en el que quepan los datos. Las dos cosas pesan más que cualquier codec.
LowCardinality ayuda por debajo de unos 10.000 valores distintos y puede empeorar las cosas por encima de 100.000, así que mira uniqExact sobre una muestra antes. Nullable añade un segundo fichero con una máscara UInt8, y la documentación de ClickHouse dice que casi siempre perjudica el rendimiento, así que usa un valor DEFAULT donde puedas.
Los codecs van al final. ClickHouse self-managed usa LZ4 por defecto y ClickHouse Cloud, ZSTD(1). ZSTD comprime alrededor de un 30 % mejor pero descomprime más despacio. Delta y DoubleDelta van bien con enteros crecientes, T64 con enteros en un rango estrecho y Gorilla con floats que cambian despacio, pero las propias pruebas de ClickHouse vieron que rara vez mejoran a ZSTD. Revisa cada columna antes de cambiar nada:
SELECT name,
formatReadableSize(sum(data_compressed_bytes)) AS compressed,
formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed,
round(sum(data_uncompressed_bytes) / sum(data_compressed_bytes), 2) AS ratio
FROM system.columns
WHERE table = 'transfers'
GROUP BY name
ORDER BY sum(data_compressed_bytes) DESC;
| Palanca | Qué te da | Qué te cuesta |
|---|---|---|
| Clave de ordenación: baja cardinalidad primero, entropía al final | Bytes por fila, en múltiplos | Una proyección o un índice para el otro patrón de acceso |
| Tipos más estrechos | Unas 2x en el dataset de ejemplo de la documentación de ClickHouse | Nada |
LowCardinality por debajo de 10.000 valores distintos | Codificación por diccionario, filtros más rápidos | Inserts más lentos; peor por encima de 100.000 |
Int8 DEFAULT 0 en lugar de Nullable(Int8) | Sin fichero de máscara, escaneos más rápidos | Un valor centinela que la aplicación tiene que conocer |
FixedString y CODEC(NONE) en bytes aleatorios | Nada de CPU gastada en bytes que no comprimen | Decodificar al leer |
| Una clave sustituta para un valor incompresible que se repite | De 20 a 14 TiB en una tabla | Un lookup en los caminos que necesitan el original |
| De ZSTD(1) a ZSTD(3), codecs por tipo en columnas monótonas | Los últimos puntos porcentuales | Velocidad de descompresión por encima del nivel 3 |
| Una proyección | Latencia sobre una segunda clave | Unas 2x el almacenamiento de la tabla |
Compute
Usa menos nodos y más grandes, y nunca menos de tres. Dimensiona la cache según tu working set: todos los datos calientes para una API en tiempo real, porque la cache se llena al escribir y expulsa primero lo más antiguo, y bastante menos para cargas de observabilidad o de warehouse. Activa parallel replicas por query, con un mínimo de filas como guarda. Deja que los merges lleguen a parts de 150 GB, porque la bajada de 92 GB a 54 GB de antes es almacenamiento gratis. Quita los nodos extra cuando terminen los trabajos; con almacenamiento compartido eso solo toca metadatos.
Movimiento de datos
Un merge descarga datos, los descomprime, los vuelve a comprimir y los sube, y los deletes repiten parte de ese trabajo. En object storage, cada paso cuesta peticiones y ancho de banda. Una query cuesta como mínimo sus peticiones GET, como explica el post de latencia, y la ingesta cuesta como mínimo los PUT de cada part. El almacenamiento empaquetado escribe todas las columnas de una part en un solo objeto, unas 15 veces menos escrituras en parts anchas. Para mover menos datos, usa los settings de colocación: cache_locality_aware_merges con min_bytes_for_locality_aware_merges a 100 MB, y parallel_replicas_cache_locality_strategy = 'auto'. Cada materialized view añade otra escritura por insert. En cuanto al egress, el tráfico dentro de una región es gratis en cualquier servicio de ClickHouse, así que pon el compute en la misma región que tu aplicación y usa un private link para lo demás.
Qué línea está creciendo y cómo arreglarlo
Localiza la línea de la factura que crece y usa la tabla.
| Qué ha crecido | Qué mirar primero | Qué hacer |
|---|---|---|
| Almacenamiento, más rápido que el número de filas | Bytes por fila y columna en system.columns | Orden de la clave, tipos más estrechos, DEFAULT en lugar de Nullable, LowCardinality por debajo de 10.000, una clave sustituta para la columna incompresible |
| Almacenamiento, duplicado tras un cambio de esquema | Tamaño de la proyección frente a la tabla | Presupuestar 2x, o servir la segunda clave con un skip index |
| Compute, con el número de nodos | Bytes entre nodos durante las ventanas de merges | Merges con localidad, o menos nodos y más grandes |
| Compute, con la concurrencia | Tasa de aciertos de la cache y GET por query | Cache a la medida del working set; una cache distribuida en lugar de caches por nodo |
| Una línea de transferencia | Quién lee desde qué región | Poner el compute en la misma región; private links para lo demás |
| Una línea por escaneo | Queries al mes frente al precio de compute fijo | Esa carga tiene que ir sobre compute provisionado |
Es la misma idea que en los posts de latencia y de escala: menos hardware para el mismo rendimiento, o más rendimiento con el mismo hardware. La factura sigue al hardware. Si la tuya no para de crecer y la tabla no explica por qué, nuestra auditoría de costes revisa tu query log y el tamaño de tus columnas y te cuenta lo que encontremos, estés en ObsessionDB o no.
FAQ
Porque el volumen de datos es solo una de las cuatro líneas de la factura. El compute crece con la concurrencia y con los nodos más grandes a los que te empuja el ancho de banda. El almacenamiento crece con el orden de claves y los tipos de columna tanto como con el número de filas. La transferencia crece según dónde estén quienes leen. Revisa cada línea por separado.
Depende de los datos. La documentación de ClickHouse habla de unas 10x para datos analíticos típicos. Nosotros hemos medido 16x en logs, 13x en métricas, 7,94x en una partición de transferencias, unas 6,5x en un cluster entero y 3,05x en una tabla llena de firmas aleatorias de 64 bytes. Lanza la query de `system.columns` del kit sobre tus tablas.
Sí. Una columna Nullable guarda un fichero extra con una máscara UInt8 junto a los valores, y la documentación de ClickHouse dice que casi siempre perjudica el rendimiento. Una prueba independiente sobre mil millones de filas encontró una máscara de 187 MB, un 9 % más de almacenamiento y escaneos un tercio más lentos. Usa un valor DEFAULT donde puedas.
Ahorra espacio por debajo de unos 10.000 valores distintos, donde el diccionario ocupa menos que la columna en bruto. Por encima de 100.000 el diccionario cuesta más de lo que ahorra, y ClickHouse lo rechaza en tipos de 8 bytes o menos salvo que desactives la comprobación. Los inserts también se vuelven más lentos, un 60 % en una prueba publicada.
En ReplicatedMergeTree, sí. Cada réplica copia todas las parts a su propio disco u objetos de S3, así que tres réplicas guardan tres copias. La replicación zero-copy permitiría compartirlas, pero ClickHouse dice que no está lista para producción. Los motores sobre almacenamiento compartido, SharedMergeTree y Alloy de ObsessionDB, guardan una sola copia tengas los nodos que tengas.
Cobran por cosas distintas. BigQuery on-demand cobra 6,25 $ por TiB escaneado, y Snowflake cobra créditos por segundo de warehouse, multiplicados por los clusters encendidos. Los servicios de ClickHouse cobran por compute y almacenamiento comprimido, sin nada por query. Así es como una carga que escaneaba 1.600 TB al mes pasó a costar un 75 % menos al migrar.
Seguir Leyendo
Publicado originalmente en obsessionDB. Lee el artículo original aquí.
ClickHouse is a registered trademark of ClickHouse, Inc. https://clickhouse.com