Saltar al contenido principal

Introducción

ClickHouse procesa las consultas con gran rapidez, pero ¿cómo se distribuyen y paralelizan estas consultas entre varios servidores?
En esta guía, primero veremos cómo ClickHouse distribuye una consulta entre varios segmentos mediante tablas distribuidas, y luego cómo una consulta puede aprovechar varias réplicas durante su ejecución.

Arquitectura segmentada

En una arquitectura shared-nothing, los clústeres suelen dividirse en múltiples segmentos, y cada segmento contiene un subconjunto del total de datos. Una tabla distribuida se sitúa por encima de estos segmentos y proporciona una vista unificada de todos los datos. Las lecturas pueden enviarse a la tabla local. La ejecución de la consulta ocurrirá solo en el segmento especificado, o bien puede enviarse a la tabla distribuida, y en ese caso, cada segmento ejecutará las consultas indicadas. El servidor en el que se consultó la tabla distribuida agregará los datos y responderá al cliente: La figura anterior muestra lo que sucede cuando un cliente consulta una tabla distribuida:
  1. La consulta SELECT se envía arbitrariamente a una tabla distribuida en un nodo (mediante una estrategia round-robin o después de ser enrutada a un servidor específico por un balanceador de carga). Este nodo pasará a actuar como coordinador.
  2. El nodo localizará cada segmento que deba ejecutar la consulta mediante la información especificada por la tabla distribuida, y la consulta se enviará a cada segmento.
  3. Cada segmento lee, filtra y agrega los datos localmente, y luego devuelve un estado fusionable al coordinador.
  4. El nodo coordinador fusiona los datos y luego envía la respuesta al cliente.
Cuando añadimos réplicas a la ecuación, el proceso es bastante similar, con la única diferencia de que solo una réplica de cada segmento ejecutará la consulta. Esto significa que luego pueden procesarse más consultas en paralelo.

Arquitectura sin segmentos

ClickHouse Cloud tiene una arquitectura muy distinta de la presentada anteriormente. (Consulta “Arquitectura de ClickHouse Cloud” para obtener más detalles). Con la separación entre cómputo y almacenamiento, y con una capacidad de almacenamiento prácticamente infinita, la necesidad de usar segmentos pasa a ser menos importante. La siguiente figura muestra la arquitectura de ClickHouse Cloud: Esta arquitectura nos permite añadir y eliminar réplicas casi instantáneamente, lo que garantiza una escalabilidad muy alta del clúster. El clúster de ClickHouse Keeper (mostrado a la derecha) garantiza que haya una única fuente de verdad para los metadatos. Las réplicas pueden obtener los metadatos del clúster de ClickHouse Keeper y mantener así los mismos datos. Los datos en sí se almacenan en almacenamiento de objetos, y la caché SSD nos permite acelerar las consultas. Pero ¿cómo podemos distribuir ahora la ejecución de consultas entre varios servidores? En una arquitectura con segmentos, era bastante obvio, ya que cada segmento podía ejecutar una consulta sobre un subconjunto de los datos. ¿Cómo funciona cuando no hay segmentación?

Introducción a las réplicas paralelas

Para paralelizar la ejecución de consultas a través de varios servidores, primero necesitamos poder asignar uno de nuestros servidores como coordinador. El coordinador es quien crea la lista de tareas que deben ejecutarse, garantiza que todas se ejecuten, se agreguen y que el resultado se devuelva al cliente. Como en la mayoría de los sistemas distribuidos, este será el papel del nodo que recibe la consulta inicial. También necesitamos definir la unidad de trabajo. En una arquitectura con segmentos, la unidad de trabajo es el segmento, un subconjunto de los datos. Con las réplicas paralelas usaremos una pequeña porción de la tabla, llamada gránulos, como unidad de trabajo. Ahora, veamos cómo funciona en la práctica con ayuda de la siguiente figura: Con réplicas paralelas:
  1. La consulta del cliente se envía a un nodo después de pasar por un balanceador de carga. Este nodo se convierte en el coordinador de esta consulta.
  2. El nodo analiza el índice de cada parte y selecciona las partes y los gránulos adecuados para procesar.
  3. El coordinador divide la carga de trabajo en un conjunto de gránulos que pueden asignarse a diferentes réplicas.
  4. Cada conjunto de gránulos es procesado por las réplicas correspondientes y se envía un estado fusionable al coordinador cuando terminan.
  5. Por último, el coordinador fusiona todos los resultados de las réplicas y luego devuelve la respuesta al cliente.
Los pasos anteriores describen cómo funcionan las réplicas paralelas en teoría. Sin embargo, en la práctica, hay muchos factores que pueden impedir que esta lógica funcione a la perfección:
  1. Algunas réplicas pueden no estar disponibles.
  2. La replicación en ClickHouse es asíncrona; es posible que algunas réplicas no tengan las mismas partes en un momento dado.
  3. La latencia de cola entre réplicas debe gestionarse de algún modo.
  4. La caché del sistema de archivos varía de una réplica a otra según la actividad en cada réplica, lo que significa que una asignación aleatoria de tareas podría dar lugar a un rendimiento subóptimo debido a la localidad de la caché.
En las siguientes secciones veremos cómo se superan estos factores.

Anuncios

Para abordar (1) y (2) de la lista anterior, introdujimos el concepto de anuncio. Veamos cómo funciona en la siguiente figura:
  1. La consulta del cliente se envía a un nodo tras pasar por un balanceador de carga. Ese nodo se convierte en el coordinador de la consulta.
  2. El nodo coordinador envía una solicitud para obtener anuncios de todas las réplicas del clúster. Las réplicas pueden tener vistas ligeramente diferentes del conjunto actual de partes de una tabla. Por ello, necesitamos recopilar esta información para evitar decisiones de planificación incorrectas.
  3. A continuación, el nodo coordinador usa los anuncios para definir un conjunto de gránulos que pueden asignarse a las distintas réplicas. Aquí, por ejemplo, podemos ver que no se asignó ningún gránulo de la parte 3 a la réplica 2 porque esta réplica no incluyó esa parte en su anuncio. Observe también que no se asignaron tareas a la réplica 3 porque la réplica no proporcionó ningún anuncio.
  4. Después de que cada réplica haya procesado la consulta sobre su subconjunto de gránulos y el estado fusionable se haya enviado de vuelta al coordinador, el coordinador fusiona los resultados y la respuesta se envía al cliente.

Coordinación dinámica

Para abordar el problema de la latencia de cola, añadimos coordinación dinámica. Esto significa que no todos los gránulos se envían a una réplica en una sola solicitud, sino que cada réplica podrá solicitar una nueva tarea (un conjunto de gránulos que se van a procesar) al coordinador. El coordinador proporcionará a la réplica el conjunto de gránulos según el anuncio recibido. Supongamos que estamos en la fase del proceso en la que todas las réplicas han enviado un anuncio con todas las partes. La figura siguiente muestra cómo funciona la coordinación dinámica:
  1. Las réplicas informan al nodo coordinador de que pueden procesar tareas; también pueden especificar cuánta carga de trabajo pueden procesar.
  2. El coordinador asigna tareas a las réplicas.
  1. Las réplicas 1 y 2 pueden terminar su tarea muy rápidamente. Entonces solicitarán otra tarea al nodo coordinador.
  2. El coordinador asigna nuevas tareas a las réplicas 1 y 2.
  1. Todas las réplicas ya han terminado de procesar su tarea. Solicitan más tareas.
  2. El coordinador, usando los anuncios, comprueba qué tareas quedan por procesar, pero no queda ninguna.
  3. El coordinador informa a las réplicas de que todo ya se ha procesado. Ahora combinará todos los estados fusionables y responderá a la consulta.

Gestión de la localidad de la caché

El último problema potencial que queda es cómo manejamos la localidad de la caché. Si la consulta se ejecuta varias veces, ¿cómo podemos asegurarnos de que la misma tarea se dirija a la misma réplica? En el ejemplo anterior, teníamos las siguientes tareas asignadas:
Réplica 1Réplica 2Réplica 3
Parte 1g1, g6, g7g2, g4, g5g3
Parte 2g1g2, g4, g5g3
Parte 3g1, g6g2, g4, g5g3
Para garantizar que las mismas tareas se asignen a las mismas réplicas y puedan beneficiarse de la caché, ocurren dos cosas. Se calcula un hash de la parte y del conjunto de gránulos (una tarea). Se aplica el módulo del número de réplicas para la asignación de tareas. En teoría, esto suena bien, pero en la práctica, una carga repentina en una réplica o una degradación de la red pueden introducir latencia de cola si se usa sistemáticamente la misma réplica para ejecutar determinadas tareas. Si max_parallel_replicas es menor que el número de réplicas, entonces se eligen réplicas aleatorias para la ejecución de consultas.

Robo de tareas

si una réplica procesa tareas más lentamente que las demás, otras réplicas intentarán ‘robar’ tareas que, en principio, pertenecen a esa réplica según el hash para reducir la latencia de cola.

Limitaciones

Esta funcionalidad tiene limitaciones conocidas, y en esta sección se documentan las principales.
Si encuentra un problema que no corresponde a ninguna de las limitaciones indicadas a continuación y sospecha que las réplicas paralelas son la causa, abra un issue en GitHub con la etiqueta comp-parallel-replicas.

Investigar problemas con las réplicas paralelas

Puedes comprobar qué configuraciones se están usando para cada consulta en la tabla system.query_log. También puedes consultar la tabla system.events para ver todos los eventos que han ocurrido en el servidor, y puedes usar la función de tabla clusterAllReplicas para ver las tablas en todas las réplicas (si usas Cloud, utiliza default).
Query
Response
La tabla system.text_log también contiene información sobre la ejecución de consultas usando réplicas paralelas:
Query
Response
Por último, también puede usar EXPLAIN PIPELINE. Muestra cómo ClickHouse va a ejecutar una consulta y qué recursos se van a utilizar durante la ejecución de la consulta. Tomemos la siguiente consulta como ejemplo:
Veamos el pipeline de consulta sin réplica paralela:
EXPLAIN PIPELINE (without parallel replica)
Y ahora, con réplica paralela:
EXPLAIN PIPELINE (with parallel replica)
Última modificación el 3 de julio de 2026