paint-brush
Evolución de la fragmentación de datos hacia la automatización y la flexibilidad en Apache Dorispor@frankzzz
Nueva Historia

Evolución de la fragmentación de datos hacia la automatización y la flexibilidad en Apache Doris

por Frank Z29m2024/07/20
Read on Terminal Reader

Demasiado Largo; Para Leer

Apache Doris presenta la partición automática en V2.1.0. Ha simplificado la gestión de particiones y DDL desde Apache Doris 2.1.0. Es útil en el procesamiento de datos a gran escala y facilita a los usuarios la migración desde otros sistemas de bases de datos a Apache Doris.
featured image - Evolución de la fragmentación de datos hacia la automatización y la flexibilidad en Apache Doris
Frank Z HackerNoon profile picture


Para manejar grandes conjuntos de datos, las bases de datos distribuidas introducen estrategias como la partición y el agrupamiento. Los datos se dividen en unidades más pequeñas según reglas específicas y se distribuyen en diferentes nodos para que las bases de datos puedan realizar procesamiento paralelo para lograr un mayor rendimiento y flexibilidad en la gestión de datos.


Como en muchas bases de datos, Apache Doris fragmenta los datos en particiones y luego una partición se divide en depósitos. Las particiones normalmente se definen por tiempo u otros valores continuos. Esto permite a los motores de consulta localizar rápidamente los datos de destino durante las consultas eliminando rangos de datos irrelevantes.


El agrupamiento , por otro lado, distribuye datos en función de los valores hash de una o más columnas, lo que evita la distorsión de los datos.


Antes de la versión 2.1.0 , había dos formas de crear particiones de datos en Apache Doris:


  • Partición manual : los usuarios especifican las particiones en la declaración de creación de la tabla o las modifican mediante declaraciones DDL posteriormente.


  • Partición dinámica : el sistema mantiene automáticamente particiones dentro de un rango predefinido en función del tiempo de ingesta de datos.


En Apache Doris 2.1.0, hemos introducido Auto Partition . Admite la partición de datos por RANGO o por LISTA y mejora aún más la flexibilidad además de la partición automática.

Evolución de las estrategias de compartimentación en Doris

En el diseño de la distribución de datos, nos centramos más en la planificación de particiones porque la elección de las columnas de partición y los intervalos de partición depende en gran medida de los patrones de distribución de datos reales, y un buen diseño de partición puede mejorar en gran medida la eficiencia de consulta y almacenamiento de la tabla.


En Doris, la tabla de datos se divide en particiones y luego en depósitos de forma jerárquica. Los datos dentro del mismo depósito forman una tableta de datos, que es la unidad de almacenamiento físico mínima en Doris para la replicación de datos, la programación de datos entre clústeres y el equilibrio de carga.


Partición manual

Doris permite a los usuarios crear manualmente particiones de datos por RANGO y por LISTA.


Para datos con marca de tiempo, como registros y registros de transacciones, los usuarios suelen crear particiones basadas en la dimensión de tiempo. Aquí hay un ejemplo de la declaración CREATE TABLE:


 CREATE TABLE IF NOT EXISTS example_range_tbl ( `user_id` LARGEINT NOT NULL COMMENT "User ID", `date` DATE NOT NULL COMMENT "Data import date", `timestamp` DATETIME NOT NULL COMMENT "Data import timestamp", `city` VARCHAR(20) COMMENT "Location of user", `age` SMALLINT COMMENT "Age of user", `sex` TINYINT COMMENT "Sex of user", `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "Last visit date of user", `cost` BIGINT SUM DEFAULT "0" COMMENT "User consumption", `max_dwell_time` INT MAX DEFAULT "0" COMMENT "Maximum dwell time of user", `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "Minimum dwell time of user" ) ENGINE=OLAP AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`) PARTITION BY RANGE(`date`) ( PARTITION `p201701` VALUES LESS THAN ("2017-02-01"), PARTITION `p201702` VALUES LESS THAN ("2017-03-01"), PARTITION `p201703` VALUES LESS THAN ("2017-04-01"), PARTITION `p2018` VALUES [("2018-01-01"), ("2019-01-01")) ) DISTRIBUTED BY HASH(`user_id`) BUCKETS 16 PROPERTIES ( "replication_num" = "1" );


La tabla está particionada por la date de importación de datos y se han creado previamente 4 particiones. Dentro de cada partición, los datos se dividen en 16 depósitos según el valor hash de user_id .


Con este diseño de partición y agrupación, al consultar datos desde 2018 en adelante, el sistema solo necesita escanear la partición p2018 . Así es como se ve la consulta SQL:


 mysql> desc select count() from example_range_tbl where date >= '20180101'; +--------------------------------------------------------------------------------------+ | Explain String(Nereids Planner) | +--------------------------------------------------------------------------------------+ | PLAN FRAGMENT 0 | | OUTPUT EXPRS: | | count(*)[#11] | | PARTITION: UNPARTITIONED | | | | ...... | | | | 0:VOlapScanNode(193) | | TABLE: test.example_range_tbl(example_range_tbl), PREAGGREGATION: OFF. | | PREDICATES: (date[#1] >= '2018-01-01') | | partitions=1/4 (p2018), tablets=16/16, tabletList=561490,561492,561494 ... | | cardinality=0, avgRowSize=0.0, numNodes=1 | | pushAggOp=NONE | | | +--------------------------------------------------------------------------------------+


Si los datos se distribuyen de manera desigual entre las particiones, el mecanismo de agrupamiento basado en hash puede dividir aún más los datos según el user_id . Esto ayuda a evitar el desequilibrio de carga en algunas máquinas durante la consulta y el almacenamiento.


Sin embargo, en escenarios empresariales del mundo real, un clúster puede tener decenas de miles de tablas, lo que significa que es imposible gestionarlas manualmente.


 CREATE TABLE `DAILY_TRADE_VALUE` ( `TRADE_DATE` datev2 NOT NULL COMMENT 'Trade date', `TRADE_ID` varchar(40) NOT NULL COMMENT 'Trade ID', ...... ) UNIQUE KEY(`TRADE_DATE`, `TRADE_ID`) PARTITION BY RANGE(`TRADE_DATE`) ( PARTITION p_200001 VALUES [('2000-01-01'), ('2000-02-01')), PARTITION p_200002 VALUES [('2000-02-01'), ('2000-03-01')), PARTITION p_200003 VALUES [('2000-03-01'), ('2000-04-01')), PARTITION p_200004 VALUES [('2000-04-01'), ('2000-05-01')), PARTITION p_200005 VALUES [('2000-05-01'), ('2000-06-01')), PARTITION p_200006 VALUES [('2000-06-01'), ('2000-07-01')), PARTITION p_200007 VALUES [('2000-07-01'), ('2000-08-01')), PARTITION p_200008 VALUES [('2000-08-01'), ('2000-09-01')), PARTITION p_200009 VALUES [('2000-09-01'), ('2000-10-01')), PARTITION p_200010 VALUES [('2000-10-01'), ('2000-11-01')), PARTITION p_200011 VALUES [('2000-11-01'), ('2000-12-01')), PARTITION p_200012 VALUES [('2000-12-01'), ('2001-01-01')), PARTITION p_200101 VALUES [('2001-01-01'), ('2001-02-01')), ...... ) DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 PROPERTIES ( ...... );


En el ejemplo anterior, los datos se dividen mensualmente. Esto requiere que el administrador de la base de datos (DBA) agregue manualmente una nueva partición cada mes y mantenga el esquema de la tabla con regularidad. Imagine el caso del procesamiento de datos en tiempo real, donde es posible que necesite crear particiones diariamente o incluso cada hora; hacerlo manualmente ya no es una opción. Por eso introdujimos la partición dinámica.

Partición dinámica

Mediante la partición dinámica, Doris crea y recupera automáticamente particiones de datos siempre que el usuario especifique la unidad de partición, la cantidad de particiones históricas y la cantidad de particiones futuras. Esta funcionalidad se basa en un hilo fijo en Doris Frontend. Sondea y comprueba continuamente si se van a crear nuevas particiones o si se deben recuperar particiones antiguas, y actualiza el esquema de partición de la tabla.


Este es un ejemplo de instrucción CREATE TABLE para una tabla particionada por día. Los parámetros start y end se establecen en -7 y 3 , respectivamente, lo que significa que las particiones de datos para los próximos 3 días se crearán previamente y las particiones históricas que tengan más de 7 días se recuperarán.


 CREATE TABLE `DAILY_TRADE_VALUE` ( `TRADE_DATE` datev2 NOT NULL COMMENT 'Trade date', `TRADE_ID` varchar(40) NOT NULL COMMENT 'Trade ID', ...... ) UNIQUE KEY(`TRADE_DATE`, `TRADE_ID`) PARTITION BY RANGE(`TRADE_DATE`) () DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 PROPERTIES ( "dynamic_partition.enable" = "true", "dynamic_partition.time_unit" = "DAY", "dynamic_partition.start" = "-7", "dynamic_partition.end" = "3", "dynamic_partition.prefix" = "p", "dynamic_partition.buckets" = "10" );


Con el tiempo, la tabla siempre mantendrá particiones dentro del rango de [current date - 7, current date + 3] . La partición dinámica es particularmente útil para escenarios de ingesta de datos en tiempo real, como cuando la capa ODS (Operational Data Store) recibe directamente datos de fuentes externas como Kafka.


Los parámetros start y end definen un rango fijo para las particiones, lo que permite al usuario administrar las particiones solo dentro de este rango. Sin embargo, si el usuario necesita incluir más datos históricos, tendría que marcar el valor start y eso podría generar una sobrecarga innecesaria de metadatos en el clúster.


Por lo tanto, cuando se aplica la partición dinámica, existe un equilibrio entre la conveniencia y la eficiencia de la gestión de metadatos.

Palabras de los desarrolladores

A medida que aumenta la complejidad del negocio, la partición dinámica se vuelve inadecuada porque:


  • Solo admite la partición por RANGO pero no por LISTA.
  • Solo se puede aplicar a las marcas de tiempo actuales del mundo real.
  • Solo admite un único rango de partición continua y no puede admitir particiones fuera de ese rango.


Dadas estas limitaciones funcionales, comenzamos a planificar un nuevo mecanismo de partición que pueda automatizar la administración de particiones y simplificar el mantenimiento de las tablas de datos.


Descubrimos que la implementación de partición ideal debería:


  • Evite la necesidad de crear particiones manualmente después de la creación de la tabla;
  • Ser capaz de acomodar todos los datos ingeridos en las particiones correspondientes.


El primero significa automatización y el segundo, flexibilidad. La esencia de realizar ambos es asociar la creación de particiones con los datos reales.


Luego comenzamos a pensar en lo siguiente: ¿Qué pasaría si postergamos la creación de particiones hasta que se ingieran los datos, en lugar de hacerlo durante la creación de la tabla o mediante un sondeo regular? En lugar de preconstruir la distribución de particiones, podemos definir las reglas de mapeo de "datos a partición" para que las particiones se creen después de que lleguen los datos.


En comparación con la partición manual, todo este proceso estaría completamente automatizado, eliminando la necesidad de mantenimiento humano. En comparación con la partición dinámica, evita tener particiones que no se utilizan o particiones que son necesarias pero no están presentes.

Partición automática

Con Apache Doris 2.1.0 , hacemos realidad el plan anterior. Durante la ingesta de datos, Doris crea particiones de datos según las reglas configuradas. Los nodos Doris Backend que son responsables del procesamiento y distribución de datos intentarán encontrar la partición adecuada para cada fila de datos en el operador DataSink del plan de ejecución. Ya no filtra datos que no caben en ninguna partición existente ni informa un error para tal situación, sino que genera automáticamente particiones para todos los datos ingeridos.

Partición automática por RANGO

Auto Partition de RANGE proporciona una solución de partición optimizada basada en la dimensión del tiempo. Es más flexible que la partición dinámica en términos de configuración de parámetros. La sintaxis para ello es la siguiente:


 AUTO PARTITION BY RANGE (FUNC_CALL_EXPR) () FUNC_CALL_EXPR ::= DATE_TRUNC ( <partition_column>, '<interval>' )


La <partition_column> anterior es la columna de partición (es decir, la columna en la que se basa la partición). <interval> especifica la unidad de partición, que es el ancho deseado de cada partición.


Por ejemplo, si la columna de partición es k0 y desea realizar la partición por mes, la declaración de partición sería AUTO PARTITION BY RANGE (DATE_TRUNC(k0, 'month')) . Para todos los datos importados, el sistema llamará a DATE_TRUNC(k0, 'month') para calcular el punto final izquierdo de la partición y luego el punto final derecho agregando un interval .


Ahora, podemos aplicar la partición automática a la tabla DAILY_TRADE_VALUE introducida en la sección anterior sobre Partición dinámica.


 CREATE TABLE DAILY_TRADE_VALUE ( `TRADE_DATE` DATEV2 NOT NULL COMMENT 'Trade Date', `TRADE_ID` VARCHAR(40) NOT NULL COMMENT 'Trade ID', ...... ) AUTO PARTITION BY RANGE (DATE_TRUNC(`TRADE_DATE`, 'month')) () DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 PROPERTIES ( ...... );


Después de importar algunos datos, estas son las particiones que obtenemos:


 mysql> show partitions from DAILY_TRADE_VALUE; Empty set (0.10 sec) mysql> insert into DAILY_TRADE_VALUE values ('2015-01-01', 1), ('2020-01-01', 2), ('2024-03-05', 10000), ('2024-03-06', 10001); Query OK, 4 rows affected (0.24 sec) {'label':'label_2a7353a3f991400e_ae731988fa2bc568', 'status':'VISIBLE', 'txnId':'85097'} mysql> show partitions from DAILY_TRADE_VALUE; +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 588395 | p20150101000000 | 2 | 2024-06-01 19:02:40 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2015-01-01]; ..types: [DATEV2]; keys: [2015-02-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 588437 | p20200101000000 | 2 | 2024-06-01 19:02:40 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2020-01-01]; ..types: [DATEV2]; keys: [2020-02-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 588416 | p20240301000000 | 2 | 2024-06-01 19:02:40 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2024-03-01]; ..types: [DATEV2]; keys: [2024-04-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.09 sec)


Como se muestra, las particiones se crean automáticamente para los datos importados y no crean particiones que estén más allá del rango de los datos existentes.

Partición automática por LISTA

La partición automática por LISTA consiste en fragmentar datos en función de dimensiones no basadas en el tiempo, como region y department . Llena ese vacío para la partición dinámica, que no admite la partición de datos mediante LIST.


Auto Partition de RANGE proporciona una solución de partición optimizada basada en la dimensión del tiempo. Es más flexible que la partición dinámica en términos de configuración de parámetros. La sintaxis para ello es la siguiente:


 AUTO PARTITION BY LIST (`partition_col`) ()


Este es un ejemplo de partición automática por LISTA usando city como columna de partición:


 mysql> CREATE TABLE `str_table` ( -> `city` VARCHAR NOT NULL, -> ...... -> ) -> DUPLICATE KEY(`city`) -> AUTO PARTITION BY LIST (`city`) -> () -> DISTRIBUTED BY HASH(`city`) BUCKETS 10 -> PROPERTIES ( -> ...... -> ); Query OK, 0 rows affected (0.09 sec) mysql> insert into str_table values ("Denver"), ("Boston"), ("Los_Angeles"); Query OK, 3 rows affected (0.25 sec) mysql> show partitions from str_table; +-------------+-----------------+----------------+---------------------+--------+--------------+-------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+-----------------+----------------+---------------------+--------+--------------+-------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 589685 | pDenver7 | 2 | 2024-06-01 20:12:37 | NORMAL | city | [types: [VARCHAR]; keys: [Denver]; ] | city | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 589643 | pLos5fAngeles11 | 2 | 2024-06-01 20:12:37 | NORMAL | city | [types: [VARCHAR]; keys: [Los_Angeles]; ] | city | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 589664 | pBoston8 | 2 | 2024-06-01 20:12:37 | NORMAL | city | [types: [VARCHAR]; keys: [Boston]; ] | city | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+-----------------+----------------+---------------------+--------+--------------+-------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.10 sec)


Después de insertar datos para las ciudades de Denver, Boston y Los Ángeles, el sistema creó automáticamente las particiones correspondientes basadas en los nombres de las ciudades. Anteriormente, este tipo de partición personalizada solo se podía lograr mediante declaraciones DDL manuales. Así es como Auto Partition by LIST simplifica el mantenimiento de la base de datos.

Consejos y notas

Ajustar manualmente las particiones históricas

Para las tablas que reciben datos en tiempo real y actualizaciones históricas ocasionales, dado que Auto Partition no recupera automáticamente las particiones históricas, recomendamos dos opciones:


  • Utilice Auto Partition, que creará particiones automáticamente para las actualizaciones ocasionales de datos históricos.

  • Utilice la partición automática y cree manualmente una partición LESS THAN para acomodar las actualizaciones históricas. Esto permite una separación más clara de los datos históricos y en tiempo real y facilita la gestión de datos.


 mysql> CREATE TABLE DAILY_TRADE_VALUE -> ( -> `TRADE_DATE` DATEV2 NOT NULL COMMENT 'Trade Date', -> `TRADE_ID` VARCHAR(40) NOT NULL COMMENT 'Trade ID' -> ) -> AUTO PARTITION BY RANGE (DATE_TRUNC(`TRADE_DATE`, 'DAY')) -> ( -> PARTITION `pHistory` VALUES LESS THAN ("2024-01-01") -> ) -> DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 -> PROPERTIES -> ( -> "replication_num" = "1" -> ); Query OK, 0 rows affected (0.11 sec) mysql> insert into DAILY_TRADE_VALUE values ('2015-01-01', 1), ('2020-01-01', 2), ('2024-03-05', 10000), ('2024-03-06', 10001); Query OK, 4 rows affected (0.25 sec) {'label':'label_96dc3d20c6974f4a_946bc1a674d24733', 'status':'VISIBLE', 'txnId':'85092'} mysql> show partitions from DAILY_TRADE_VALUE; +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 577871 | pHistory | 2 | 2024-06-01 08:53:49 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [0000-01-01]; ..types: [DATEV2]; keys: [2024-01-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577940 | p20240305000000 | 2 | 2024-06-01 08:53:49 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2024-03-05]; ..types: [DATEV2]; keys: [2024-03-06]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577919 | p20240306000000 | 2 | 2024-06-01 08:53:49 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2024-03-06]; ..types: [DATEV2]; keys: [2024-03-07]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.10 sec)


partición NULA

Con Auto Partition by LIST, Doris admite el almacenamiento de valores NULL en particiones NULL. Por ejemplo:


 mysql> CREATE TABLE list_nullable -> ( -> `str` varchar NULL -> ) -> AUTO PARTITION BY LIST (`str`) -> () -> DISTRIBUTED BY HASH(`str`) BUCKETS auto -> PROPERTIES -> ( -> "replication_num" = "1" -> ); Query OK, 0 rows affected (0.10 sec) mysql> insert into list_nullable values ('123'), (''), (NULL); Query OK, 3 rows affected (0.24 sec) {'label':'label_f5489769c2f04f0d_bfb65510f9737fff', 'status':'VISIBLE', 'txnId':'85089'} mysql> show partitions from list_nullable; +-------------+---------------+----------------+---------------------+--------+--------------+------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+---------------+----------------+---------------------+--------+--------------+------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 577297 | pX | 2 | 2024-06-01 08:19:21 | NORMAL | str | [types: [VARCHAR]; keys: [NULL]; ] | str | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577276 | p0 | 2 | 2024-06-01 08:19:21 | NORMAL | str | [types: [VARCHAR]; keys: []; ] | str | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577255 | p1233 | 2 | 2024-06-01 08:19:21 | NORMAL | str | [types: [VARCHAR]; keys: [123]; ] | str | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+---------------+----------------+---------------------+--------+--------------+------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.11 sec)


Sin embargo, la partición automática por RANGE no admite particiones NULL, porque los valores NULL se almacenarán en la partición LESS THAN pequeña y es imposible determinar de manera confiable el rango apropiado para ello. Si Auto Partition creara una partición NULL con un rango de (-INFINITY, MIN_VALUE), existiría el riesgo de que esta partición se elimine inadvertidamente en producción, ya que el límite MIN_VALUE puede no representar con precisión la lógica empresarial prevista.

Resumen

La partición automática cubre la mayoría de los casos de uso de la partición dinámica, al tiempo que presenta el beneficio de la definición inicial de reglas de partición. Una vez definidas las reglas, la mayor parte del trabajo de creación de particiones lo maneja automáticamente Doris en lugar de un DBA.


Antes de utilizar Auto Partition, es importante comprender las limitaciones relevantes:


  1. Auto Partition by LIST admite la partición basada en múltiples columnas , pero cada partición creada automáticamente solo contiene un único valor y el nombre de la partición no puede exceder los 50 caracteres de longitud. Tenga en cuenta que los nombres de las particiones siguen convenciones de nomenclatura específicas, que tienen implicaciones particulares para la gestión de metadatos. Esto significa que no todo el espacio de 50 caracteres está a disposición del usuario.


  2. La partición automática por RANGE solo admite una única columna de partición , que debe ser del tipo DATE o DATETIME .


  3. La partición automática por LISTA admite la columna de partición NULLABLE y la inserción de valores NULL. La partición automática por RANGE no admite la columna de partición NULLABLE.


  4. No se recomienda utilizar la partición automática junto con la partición dinámica después de Apache Doris 2.1.3.

Comparación de rendimiento

Las principales diferencias funcionales entre la partición automática y la partición dinámica radican en la creación y eliminación de particiones, los tipos de particiones admitidos y su impacto en el rendimiento de la importación.


La partición dinámica utiliza subprocesos fijos para crear y recuperar particiones periódicamente. Sólo admite la partición por RANGE. Por el contrario, Auto Partition admite particiones por RANGO y por LISTA. Crea automáticamente particiones bajo demanda basadas en reglas específicas durante la ingesta de datos, lo que proporciona un mayor nivel de automatización y flexibilidad.


La partición dinámica no ralentiza la velocidad de ingestión de datos, mientras que la partición automática provoca ciertos gastos generales de tiempo porque primero comprueba las particiones existentes y luego crea otras nuevas según demanda. Presentaremos los resultados de las pruebas de rendimiento.



Partición automática: flujo de trabajo de ingesta

Esta parte trata sobre cómo se implementa la ingesta de datos con el mecanismo de partición automática y usamos Stream Load como ejemplo. Cuando Doris inicia una importación de datos, uno de los nodos Backend de Doris asume el rol de Coordinador. Es responsable del trabajo inicial de procesamiento de datos y luego de enviarlos a los nodos BE apropiados, conocidos como Ejecutores, para su ejecución.



En el nodo Datasink final de la canalización de ejecución del Coordinador, los datos deben enrutarse a las particiones, depósitos y ubicaciones de nodos Doris Backend correctos antes de que puedan transmitirse y almacenarse exitosamente.


Para posibilitar esta transferencia de datos, los nodos Coordinador y Ejecutor establecen canales de comunicación:


  • El extremo emisor se denomina canal de nodo.
  • El extremo receptor se llama Canal de Tabletas.


Así es como entra en juego la partición automática durante el proceso de determinar las particiones correctas para los datos:



Anteriormente, sin partición automática, cuando una tabla no tiene la partición requerida, el comportamiento en Doris es que los nodos BE acumulan errores hasta que se informa un DATA_QUALITY_ERROR . Ahora, con la partición automática habilitada, se iniciará una solicitud al Doris Frontend para crear la partición necesaria sobre la marcha. Una vez completada la transacción de creación de la partición, Doris Frontend responde al Coordinador, que luego abre los canales de comunicación correspondientes (Canal de Nodo y Canal de Tabletas) para continuar con el proceso de ingesta de datos. Esta es una experiencia perfecta para los usuarios.


En un entorno de clúster del mundo real, el tiempo que pasa el Coordinador esperando que Doris Frontend complete la creación de la partición puede generar grandes gastos generales. Esto se debe a la latencia inherente de las llamadas Thrift RPC, así como a la contención de bloqueos en el frontend en condiciones de alta carga.


Para mejorar la eficiencia de la ingesta de datos en Auto Partition, Doris ha implementado procesamiento por lotes para reducir en gran medida la cantidad de llamadas RPC realizadas al FE. Esto aporta una notable mejora del rendimiento para las operaciones de escritura de datos.


Tenga en cuenta que cuando el FE Master completa la transacción de creación de la partición, la nueva partición se vuelve inmediatamente visible. Sin embargo, si el proceso de importación finalmente falla o se cancela, las particiones creadas no se reclaman automáticamente.

Rendimiento de la partición automática

Probamos el rendimiento y la estabilidad de Auto Partition en Doris, cubriendo diferentes casos de uso:


Caso 1 : 1 Frontend + 3 Backend; 6 conjuntos de datos generados aleatoriamente, cada uno con 100 millones de filas y 2000 particiones; ingirió los 6 conjuntos de datos simultáneamente en 6 tablas


  • Objetivo : Evaluar el rendimiento de Auto Partition bajo alta presión y comprobar si hay alguna degradación del rendimiento.


  • Resultados : la partición automática genera una pérdida de rendimiento promedio inferior al 5 % , y todas las transacciones de importación se ejecutan de manera estable.



Caso 2 : 1 Frontend + 3 Backend; ingerir 100 filas por segundo de Flink mediante carga de rutina; pruebas con 1, 10 y 20 transacciones simultáneas (tablas), respectivamente


  • Objetivo : identificar posibles problemas de acumulación de datos que puedan surgir con la partición automática en diferentes niveles de simultaneidad.


  • Resultados : con o sin partición automática habilitada, la ingesta de datos se realizó correctamente sin problemas de contrapresión en todos los niveles de simultaneidad probados, incluso en 20 transacciones simultáneas cuando la utilización de la CPU alcanzó cerca del 100 %.



Para concluir los resultados de estas pruebas, el impacto de habilitar la partición automática en el rendimiento de la ingesta de datos es mínimo.

Conclusión y planes futuros

Auto Partition ha simplificado la gestión de particiones y DDL desde Apache Doris 2.1.0. Es útil en el procesamiento de datos a gran escala y facilita a los usuarios la migración desde otros sistemas de bases de datos a Apache Doris.


Además, estamos comprometidos a ampliar las capacidades de Auto Partition para admitir tipos de datos más complejos.


Planes de Auto Partición por GAMA:


  • Admite valores numéricos;


  • Permitir a los usuarios especificar los límites izquierdo y derecho del rango de partición.


Planes de partición automática por LISTA:


  • Permitir fusionar varios valores en la misma partición según reglas específicas.