paint-brush
Evolution du partage de données vers l'automatisation et la flexibilité dans Apache Dorispar@shirleyfromapachedoris
446 lectures
446 lectures

Evolution du partage de données vers l'automatisation et la flexibilité dans Apache Doris

par Shirley H.29m2024/07/20
Read on Terminal Reader

Trop long; Pour lire

Apache Doris introduit la partition automatique dans la version 2.1.0. Il a simplifié la gestion des DDL et des partitions depuis Apache Doris 2.1.0. Il est utile dans le traitement de données à grande échelle et permet aux utilisateurs de migrer facilement d'autres systèmes de bases de données vers Apache Doris.
featured image - Evolution du partage de données vers l'automatisation et la flexibilité dans Apache Doris
Shirley H. HackerNoon profile picture


Pour gérer de grands ensembles de données, les bases de données distribuées introduisent des stratégies telles que le partitionnement et le regroupement. Les données sont divisées en unités plus petites basées sur des règles spécifiques et distribuées sur différents nœuds afin que les bases de données puissent effectuer un traitement parallèle pour des performances et une flexibilité de gestion des données supérieures.


Comme dans de nombreuses bases de données, Apache Doris divise les données en partitions, puis une partition est ensuite divisée en compartiments. Les partitions sont généralement définies par le temps ou d'autres valeurs continues. Cela permet aux moteurs de requêtes de localiser rapidement les données cibles lors des requêtes en éliminant les plages de données non pertinentes.


Le bucketing , quant à lui, distribue les données en fonction des valeurs de hachage d'une ou plusieurs colonnes, ce qui évite la distorsion des données.


Avant la version 2.1.0 , il existait deux manières de créer des partitions de données dans Apache Doris :


  • Partition manuelle : les utilisateurs spécifient les partitions dans l'instruction de création de table ou les modifient ultérieurement via des instructions DDL.


  • Partition dynamique : le système maintient automatiquement les partitions dans une plage prédéfinie en fonction du temps d'ingestion des données.


Dans Apache Doris 2.1.0, nous avons introduit la partition automatique . Il prend en charge le partitionnement des données par RANGE ou par LIST et améliore encore la flexibilité en plus du partitionnement automatique.

Evolution des stratégies de partitionnement chez Doris

Dans la conception de la distribution des données, nous nous concentrons davantage sur la planification des partitions, car le choix des colonnes de partition et des intervalles de partition dépend fortement des modèles de distribution de données réels, et une bonne conception de partition peut grandement améliorer l'efficacité des requêtes et du stockage de la table.


Dans Doris, la table de données est divisée en partitions puis en buckets de manière hiérarchique. Les données contenues dans le même compartiment forment ensuite une tablette de données, qui constitue l'unité de stockage physique minimale dans Doris pour la réplication des données, la planification des données inter-clusters et l'équilibrage de charge.


Partition manuelle

Doris permet aux utilisateurs de créer manuellement des partitions de données par RANGE et par LIST.


Pour les données horodatées telles que les journaux et les enregistrements de transactions, les utilisateurs créent généralement des partitions basées sur la dimension temporelle. Voici un exemple de l'instruction 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 table est partitionnée par date d'importation des données et 4 partitions ont été pré-créées. Au sein de chaque partition, les données sont ensuite divisées en 16 compartiments en fonction de la valeur de hachage du user_id .


Avec cette conception de partitionnement et de compartimentage, lors de l'interrogation de données à partir de 2018, le système n'a besoin que d'analyser la partition p2018 . Voici à quoi ressemble la requête 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 les données sont inégalement réparties sur les partitions, le mécanisme de regroupement basé sur le hachage peut diviser davantage les données en fonction de l' user_id . Cela permet d'éviter un déséquilibre de charge sur certaines machines lors des requêtes et du stockage.


Cependant, dans des scénarios commerciaux réels, un cluster peut contenir des dizaines de milliers de tables, ce qui signifie qu'il est impossible de les gérer manuellement.


 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 ( ...... );


Dans l'exemple ci-dessus, les données sont partitionnées sur une base mensuelle. Cela nécessite que l'administrateur de base de données (DBA) ajoute manuellement une nouvelle partition chaque mois et gère régulièrement le schéma de table. Imaginez le cas du traitement des données en temps réel, où vous pourriez avoir besoin de créer des partitions quotidiennement, voire toutes les heures, le faire manuellement n'est plus un choix. C'est pourquoi nous avons introduit la partition dynamique.

Partition dynamique

Par partition dynamique, Doris crée et récupère automatiquement des partitions de données tant que l'utilisateur spécifie l'unité de partition, le nombre de partitions historiques et le nombre de partitions futures. Cette fonctionnalité repose sur un thread fixe sur le Doris Frontend. Il interroge et vérifie en permanence les nouvelles partitions à créer ou les anciennes partitions à récupérer, et met à jour le schéma de partition de la table.


Ceci est un exemple d'instruction CREATE TABLE pour une table partitionnée par jour. Les paramètres start et end sont respectivement définis sur -7 et 3 , ce qui signifie que les partitions de données pour les 3 prochains jours seront pré-créées et que les partitions historiques datant de plus de 7 jours seront récupérées.


 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" );


Au fil du temps, la table conservera toujours les partitions dans la plage [current date - 7, current date + 3] . La partition dynamique est particulièrement utile pour les scénarios d'ingestion de données en temps réel, par exemple lorsque la couche ODS (Operational Data Store) reçoit directement des données de sources externes comme Kafka.


Les paramètres start et end définissent une plage fixe pour les partitions, permettant à l'utilisateur de gérer les partitions uniquement dans cette plage. Cependant, si l'utilisateur doit inclure davantage de données historiques, il devra composer la valeur start , ce qui pourrait entraîner une surcharge inutile des métadonnées dans le cluster.


Par conséquent, lors de l’application de la partition dynamique, il existe un compromis entre la commodité et l’efficacité de la gestion des métadonnées.

Le mot des développeurs

À mesure que la complexité des activités s'accroît, la partition dynamique devient inadéquate pour les raisons suivantes :


  • Il ne prend en charge que le partitionnement par RANGE mais pas par LIST.
  • Il ne peut être appliqué qu’aux horodatages actuels du monde réel.
  • Il ne prend en charge qu'une seule plage de partitions continue et ne peut pas accueillir de partitions en dehors de cette plage.


Compte tenu de ces limitations fonctionnelles, nous avons commencé à planifier un nouveau mécanisme de partitionnement capable à la fois d'automatiser la gestion des partitions et de simplifier la maintenance des tables de données.


Nous avons compris que l'implémentation idéale du partitionnement devrait :


  • Épargnez le besoin de créer manuellement des partitions après la création de la table ;
  • Être capable d’héberger toutes les données ingérées dans les partitions correspondantes.


Le premier est synonyme d’automatisation et le second de flexibilité. L’essence de la réalisation des deux consiste à associer la création de partition aux données réelles.


Nous avons ensuite commencé à réfléchir aux questions suivantes : que se passerait-il si nous attendions la création de partitions jusqu'à ce que les données soient ingérées, plutôt que de le faire lors de la création de la table ou via une interrogation régulière ? Au lieu de pré-construire la distribution des partitions, nous pouvons définir les règles de mappage « données vers partition » afin que les partitions soient créées après l'arrivée des données.


Comparé à la partition manuelle, l’ensemble de ce processus serait entièrement automatisé, éliminant ainsi le besoin de maintenance humaine. Par rapport à Dynamic Partition, cela évite d’avoir des partitions qui ne sont pas utilisées ou des partitions nécessaires mais non présentes.

Partition automatique

Avec Apache Doris 2.1.0 , nous concrétisons le plan ci-dessus. Lors de l'ingestion de données, Doris crée des partitions de données basées sur les règles configurées. Les nœuds Doris Backend responsables du traitement et de la distribution des données tenteront de trouver la partition appropriée pour chaque ligne de données dans l'opérateur DataSink du plan d'exécution. Il ne filtre plus les données qui ne rentrent dans aucune partition existante ni ne signale une erreur dans une telle situation, mais génère automatiquement des partitions pour toutes les données ingérées.

Partition automatique par GAMME

Auto Partition by RANGE fournit une solution de partitionnement optimisée basée sur la dimension temporelle. Il est plus flexible que Dynamic Partition en termes de configuration des paramètres. La syntaxe est la suivante :


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


La <partition_column> ci-dessus est la colonne de partition (c'est-à-dire la colonne sur laquelle le partitionnement est basé). <interval> spécifie l'unité de partition, qui est la largeur souhaitée de chaque partition.


Par exemple, si la colonne de partition est k0 et que vous souhaitez partitionner par mois, l'instruction de partition serait AUTO PARTITION BY RANGE (DATE_TRUNC(k0, 'month')) . Pour toutes les données importées, le système appellera DATE_TRUNC(k0, 'month') pour calculer le point final gauche de la partition, puis le point final droit en ajoutant un interval .


Maintenant, nous pouvons appliquer la partition automatique à la table DAILY_TRADE_VALUE introduite dans la section précédente sur la partition dynamique.


 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 ( ...... );


Après avoir importé quelques données, voici les partitions que nous obtenons :


 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)


Comme indiqué, les partitions sont automatiquement créées pour les données importées et ne créent pas de partitions dépassant la plage des données existantes.

Partition automatique par LISTE

La partition automatique par LIST consiste à partager des données en fonction de dimensions non temporelles, telles que region et department . Il comble cette lacune pour la partition dynamique, qui ne prend pas en charge le partitionnement des données par LIST.


Auto Partition by RANGE fournit une solution de partitionnement optimisée basée sur la dimension temporelle. Il est plus flexible que Dynamic Partition en termes de configuration des paramètres. La syntaxe est la suivante :


 AUTO PARTITION BY LIST (`partition_col`) ()


Ceci est un exemple de partition automatique par LISTE utilisant city comme colonne de partition :


 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)


Après avoir inséré les données des villes de Denver, Boston et Los Angeles, le système a automatiquement créé les partitions correspondantes en fonction des noms de villes. Auparavant, ce type de partitionnement personnalisé ne pouvait être réalisé que via des instructions DDL manuelles. C'est ainsi qu'Auto Partition by LIST simplifie la maintenance de la base de données.

Conseils et remarques

Ajuster manuellement les partitions historiques

Pour les tables qui reçoivent à la fois des données en temps réel et des mises à jour historiques occasionnelles, étant donné que la partition automatique ne récupère pas automatiquement les partitions historiques, nous recommandons deux options :


  • Utilisez la partition automatique, qui créera automatiquement des partitions pour les mises à jour occasionnelles des données historiques.

  • Utilisez la partition automatique et créez manuellement une partition LESS THAN pour prendre en charge les mises à jour historiques. Cela permet une séparation plus claire des données historiques et en temps réel et facilite la gestion des données.


 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)


Partition NULLE

Avec Auto Partition by LIST, Doris prend en charge le stockage des valeurs NULL dans des partitions NULL. Par exemple:


 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)


Cependant, la partition automatique par RANGE ne prend pas en charge les partitions NULL, car les valeurs NULL seront stockées dans la plus petite partition LESS THAN et il est impossible de déterminer de manière fiable la plage appropriée. Si la partition automatique devait créer une partition NULL avec une plage de (-INFINITY, MIN_VALUE), il y aurait un risque que cette partition soit supprimée par inadvertance en production, car la limite MIN_VALUE peut ne pas représenter avec précision la logique métier prévue.

Résumé

La partition automatique couvre la plupart des cas d'utilisation de la partition dynamique, tout en introduisant l'avantage de la définition initiale des règles de partition. Une fois les règles définies, l'essentiel du travail de création de partition est automatiquement géré par Doris au lieu d'un administrateur de base de données.


Avant d'utiliser la partition automatique, il est important de comprendre les limitations pertinentes :


  1. La partition automatique par LIST prend en charge le partitionnement basé sur plusieurs colonnes , mais chaque partition créée automatiquement ne contient qu'une seule valeur et le nom de la partition ne peut pas dépasser 50 caractères. Notez que les noms de partition suivent des conventions de dénomination spécifiques, qui ont des implications particulières pour la gestion des métadonnées. Cela signifie que la totalité de l'espace de 50 caractères n'est pas à la disposition de l'utilisateur.


  2. La partition automatique par RANGE ne prend en charge qu'une seule colonne de partition , qui doit être de type DATE ou DATETIME .


  3. La partition automatique par LIST prend en charge la colonne de partition NULLABLE et l'insertion de valeurs NULL. La partition automatique par RANGE ne prend pas en charge la colonne de partition NULLABLE.


  4. Il n'est pas recommandé d'utiliser la partition automatique avec la partition dynamique après Apache Doris 2.1.3.

Comparaison des performances

Les principales différences fonctionnelles entre la partition automatique et la partition dynamique résident dans la création et la suppression de partitions, les types de partitions pris en charge et leur impact sur les performances d'importation.


Dynamic Partition utilise des threads fixes pour créer et récupérer périodiquement des partitions. Il ne prend en charge que le partitionnement par RANGE. En revanche, Auto Partition prend en charge à la fois le partitionnement par RANGE et par LIST. Il crée automatiquement des partitions à la demande en fonction de règles spécifiques lors de l'ingestion de données, offrant ainsi un niveau supérieur d'automatisation et de flexibilité.


La partition dynamique ne ralentit pas la vitesse d'ingestion des données, tandis que la partition automatique entraîne une certaine perte de temps car elle vérifie d'abord les partitions existantes, puis en crée de nouvelles à la demande. Nous présenterons les résultats des tests de performances.



Partition automatique : workflow d'ingestion

Cette partie explique comment l'ingestion de données est implémentée avec le mécanisme de partition automatique, et nous utilisons Stream Load comme exemple. Lorsque Doris lance une importation de données, l'un des nœuds Doris Backend assume le rôle de coordinateur. Il est responsable du travail initial de traitement des données, puis de la distribution des données aux nœuds BE appropriés, appelés exécuteurs, pour exécution.



Dans le nœud Datasink final du pipeline d'exécution du coordinateur, les données doivent être acheminées vers les partitions, compartiments et emplacements de nœuds Doris Backend appropriés avant de pouvoir être transmises et stockées avec succès.


Pour permettre ce transfert de données, les nœuds Coordinateur et Exécuteur établissent des canaux de communication :


  • L'extrémité émettrice est appelée Node Channel.
  • L’extrémité réceptrice s’appelle Tablets Channel.


C'est ainsi que la partition automatique entre en jeu lors du processus de détermination des partitions correctes pour les données :



Auparavant, sans partition automatique, lorsqu'une table ne possède pas la partition requise, le comportement dans Doris consistait pour les nœuds BE à accumuler des erreurs jusqu'à ce qu'un DATA_QUALITY_ERROR soit signalé. Désormais, avec la partition automatique activée, une requête sera adressée au Doris Frontend pour créer la partition nécessaire à la volée. Une fois la transaction de création de partition terminée, le Doris Frontend répond au coordinateur, qui ouvre ensuite les canaux de communication correspondants (Node Channel et Tablets Channel) pour poursuivre le processus d'ingestion de données. Il s’agit d’une expérience transparente pour les utilisateurs.


Dans un environnement de cluster réel, le temps passé par le coordinateur à attendre que Doris Frontend termine la création de la partition peut entraîner des frais généraux importants. Cela est dû à la latence inhérente aux appels Thrift RPC, ainsi qu'aux conflits de verrouillage sur le frontend dans des conditions de charge élevée.


Pour améliorer l'efficacité de l'ingestion de données dans Auto Partition, Doris a implémenté le traitement par lots pour réduire considérablement le nombre d'appels RPC effectués vers FE. Cela apporte une amélioration notable des performances pour les opérations d’écriture de données.


Notez que lorsque le maître FE termine la transaction de création de partition, la nouvelle partition devient immédiatement visible. Toutefois, si le processus d'importation échoue ou est annulé, les partitions créées ne sont pas automatiquement récupérées.

Performances de la partition automatique

Nous avons testé les performances et la stabilité d'Auto Partition dans Doris, couvrant différents cas d'utilisation :


Cas 1 : 1 Frontend + 3 Backend ; 6 ensembles de données générés aléatoirement, chacun comportant 100 millions de lignes et 2 000 partitions ; ingéré les 6 ensembles de données simultanément dans 6 tables


  • Objectif : Évaluer les performances de Auto Partition sous haute pression et vérifier toute dégradation des performances.


  • Résultats : La partition automatique entraîne une perte de performances moyenne inférieure à 5 % , toutes les transactions d'importation s'exécutant de manière stable.



Cas 2 : 1 Frontend + 3 Backend ; ingérer 100 lignes par seconde à partir de Flink par routine Load ; tests avec 1, 10 et 20 transactions simultanées (tables), respectivement


  • Objectif : Identifier tout problème potentiel de retard de données qui pourrait survenir avec la partition automatique sous différents niveaux de concurrence.


  • Résultats : avec ou sans la partition automatique activée, l'ingestion des données a réussi sans aucun problème de contre-pression sur tous les niveaux de concurrence testés, même avec 20 transactions simultanées lorsque l'utilisation du processeur a atteint près de 100 %.



Pour conclure les résultats de ces tests, l'impact de l'activation de la partition automatique sur les performances d'ingestion de données est minime.

Conclusion et projets futurs

Auto Partition a simplifié la gestion des DDL et des partitions depuis Apache Doris 2.1.0. Il est utile dans le traitement de données à grande échelle et permet aux utilisateurs de migrer facilement d'autres systèmes de bases de données vers Apache Doris.


De plus, nous nous engageons à étendre les capacités de la partition automatique pour prendre en charge des types de données plus complexes.


Plans de partition automatique par GAMME :


  • Prend en charge les valeurs numériques ;


  • Permettre aux utilisateurs de spécifier les limites gauche et droite de la plage de partition.


Plans de partition automatique par LIST :


  • Autoriser la fusion de plusieurs valeurs dans la même partition en fonction de règles spécifiques.