paint-brush
Apache Doris における自動化と柔軟性に向けたデータ シャーディングの進化@shirleyfromapachedoris
461 測定値
461 測定値

Apache Doris における自動化と柔軟性に向けたデータ シャーディングの進化

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

長すぎる; 読むには

Apache Doris は、V2.1.0 で Auto Partition を導入しました。Apache Doris 2.1.0 以降、DDL とパーティション管理が簡素化されました。大規模なデータ処理に役立ち、ユーザーが他のデータベース システムから Apache Doris に簡単に移行できるようになります。
featured image - Apache Doris における自動化と柔軟性に向けたデータ シャーディングの進化
Shirley H. HackerNoon profile picture


大規模なデータセットを処理するために、分散データベースではパーティション分割やバケット化などの戦略が導入されています。データは特定のルールに基づいて小さな単位に分割され、異なるノードに分散されるため、データベースは並列処理を実行してパフォーマンスとデータ管理の柔軟性を高めることができます。


多くのデータベースと同様に、 Apache Doris はデータをパーティションに分割し、パーティションをさらにバケットに分割します。パーティションは通常、時間またはその他の連続値によって定義されます。これにより、クエリ エンジンは、無関係なデータ範囲をプルーニングすることで、クエリ中にターゲット データをすばやく見つけることができます。


一方、バケット化では、1 つ以上の列のハッシュ値に基づいてデータを分散し、データの偏りを防ぎます。


バージョン2.1.0より前では、Apache Doris でデータ パーティションを作成するには 2 つの方法がありました。


  • 手動パーティション: ユーザーはテーブル作成ステートメントでパーティションを指定するか、後で DDL ステートメントを使用してパーティションを変更します。


  • 動的パーティション: システムは、データの取り込み時間に基づいて、事前に定義された範囲内でパーティションを自動的に維持します。


Apache Doris 2.1.0 では、 Auto Partitionが導入されました。RANGE または LIST によるデータのパーティション分割をサポートし、自動パーティション分割の柔軟性をさらに高めます。

ドリスにおける分割戦略の進化

データ分散の設計では、パーティション列とパーティション間隔の選択は実際のデータ分散パターンに大きく依存し、適切なパーティション設計によってテーブルのクエリとストレージの効率が大幅に向上するため、パーティション計画に重点を置いています。


Doris では、データ テーブルは階層的にパーティションに分割され、さらにバケットに分割されます。同じバケット内のデータはデータタブレットを形成します。これは、データ レプリケーション、クラスター間データ スケジューリング、および負荷分散のための Doris の最小物理ストレージ ユニットです。


手動パーティション

Doris を使用すると、ユーザーは RANGE および LIST ごとにデータ パーティションを手動で作成できます。


ログやトランザクション レコードなどのタイムスタンプ付きデータの場合、ユーザーは通常、時間ディメンションに基づいてパーティションを作成します。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" );


テーブルはデータのインポート日dateによってパーティション分割されており、4 つのパーティションが事前に作成されています。各パーティション内では、データはuser_idのハッシュ値に基づいてさらに 16 個のバケットに分割されます。


このパーティション分割とバケット分割の設計により、2018 年以降のデータをクエリする場合、システムはp2018パーティションのみをスキャンする必要があります。クエリ 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 | | | +--------------------------------------------------------------------------------------+


データがパーティション間で不均等に分散されている場合、ハッシュベースのバケット化メカニズムは、 user_idに基づいてデータをさらに分割できます。これにより、クエリとストレージ中に一部のマシンで負荷の不均衡が発生するのを防ぐことができます。


ただし、実際のビジネス シナリオでは、1 つのクラスターに数万個のテーブルが存在する場合があり、手動で管理することは不可能です。


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


上記の例では、データは月ごとにパーティション分割されます。このため、データベース管理者 (DBA) は毎月新しいパーティションを手動で追加し、テーブル スキーマを定期的にメンテナンスする必要があります。リアルタイム データ処理の場合を想像してみてください。毎日、あるいは毎時間パーティションを作成する必要があるかもしれませんが、手動でこれを行うことはもはや選択肢ではありません。そのため、動的パーティションを導入しました。

ダイナミックパーティション

Dynamic Partition により、Doris は、ユーザーがパーティション ユニット、履歴パーティションの数、および将来のパーティションの数を指定する限り、データ パーティションを自動的に作成および再利用します。この機能は、Doris Frontend の固定スレッドに依存します。このスレッドは、作成される新しいパーティションまたは再利用される古いパーティションを継続的にポーリングしてチェックし、テーブルのパーティション スキーマを更新します。


これは、日ごとにパーティション化されたテーブルに対する CREATE TABLE ステートメントの例です。 startパラメータとendパラメータはそれぞれ-73に設定されており、次の 3 日間のデータ パーティションが事前に作成され、7 日より古い履歴パーティションが再利用されることを意味します。


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


時間が経つにつれて、テーブルは常に[current date - 7, current date + 3]の範囲内でパーティションを維持します。動的パーティションは、ODS (Operational Data Store) レイヤーが Kafka などの外部ソースからデータを直接受信する場合など、リアルタイムのデータ取り込みシナリオに特に役立ちます。


startパラメータとendパラメータはパーティションの固定範囲を定義し、ユーザーはこの範囲内でのみパーティションを管理できます。ただし、ユーザーがより多くの履歴データを含める必要がある場合は、 start値を上げる必要があり、クラスターで不要なメタデータのオーバーヘッドが発生する可能性があります。


したがって、動的パーティションを適用する場合、メタデータ管理の利便性と効率性の間にはトレードオフが生じます。

開発者の言葉

ビジネスの複雑さが増すにつれて、次の理由により動的パーティションでは不十分になります。


  • RANGE によるパーティション分割のみがサポートされ、LIST によるパーティション分割はサポートされません。
  • これは、現在の現実世界のタイムスタンプにのみ適用できます。
  • 単一の連続したパーティション範囲のみをサポートし、その範囲外のパーティションには対応できません。


これらの機能上の制限を考慮して、パーティション管理を自動化し、データ テーブルのメンテナンスを簡素化できる新しいパーティション分割メカニズムの計画を開始しました。


理想的なパーティショニングの実装は次のようになると考えました。


  • テーブル作成後にパーティションを手動で作成する必要がなくなります。
  • 取り込まれたすべてのデータを対応するパーティションに収容できるようになります。


前者は自動化を意味し、後者は柔軟性を意味します。これら両方を実現するための本質は、パーティションの作成を実際のデータに関連付けることです。


次に、次のことを考え始めました。テーブルの作成中や定期的なポーリングでパーティションを作成するのではなく、データが取り込まれるまでパーティションの作成を延期したらどうなるでしょうか。パーティションの分散を事前に構築する代わりに、「データからパーティションへの」マッピング ルールを定義して、データが到着した後にパーティションが作成されるようにすることができます。


手動パーティションと比較すると、このプロセス全体が完全に自動化され、人によるメンテナンスが不要になります。動的パーティションと比較すると、使用されていないパーティションや、必要だが存在しないパーティションが発生するのを回避できます。

自動パーティション

Apache Doris 2.1.0では、上記の計画が実現します。データの取り込み中、Doris は設定されたルールに基づいてデータ パーティションを作成します。データの処理と配布を担当する Doris バックエンド ノードは、実行プランの DataSink オペレーターで各データ行に適切なパーティションを見つけようとします。既存のパーティションに収まらないデータをフィルターしたり、そのような状況でエラーを報告したりすることはなくなり、取り込まれたすべてのデータに対してパーティションが自動的に生成されます。

RANGEによる自動パーティション

RANGE による自動パーティションは、時間ディメンションに基づいて最適化されたパーティション分割ソリューションを提供します。パラメータ構成の点では、動的パーティションよりも柔軟性があります。構文は次のとおりです。


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


上記の<partition_column>はパーティション列 (つまり、パーティション分割の基になる列) です。 <interval>パーティション単位 (各パーティションの希望する幅) を指定します。


たとえば、パーティション列がk0で、月ごとにパーティション分割する場合、パーティション ステートメントはAUTO PARTITION BY RANGE (DATE_TRUNC(k0, 'month'))になります。インポートされたすべてのデータに対して、システムはDATE_TRUNC(k0, 'month')を呼び出してパーティションの左端を計算し、次に 1 つのintervalを追加して右端を計算します。


ここで、前の動的パーティションのセクションで紹介したDAILY_TRADE_VALUEテーブルに自動パーティションを適用できます。


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


いくつかのデータをインポートすると、次のパーティションが作成されます。


 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)


示されているように、インポートされたデータに対してパーティションが自動的に作成され、既存のデータの範囲を超えるパーティションは作成されません。

LISTによる自動パーティション

LIST による自動パーティションは、 regiondepartmentなどの時間ベースではないディメンションに基づいてデータを分割します。これは、LIST によるデータ パーティション分割をサポートしていない動的パーティションのギャップを埋めます。


RANGE による自動パーティションは、時間ディメンションに基づいて最適化されたパーティション分割ソリューションを提供します。パラメータ構成の点では、動的パーティションよりも柔軟性があります。構文は次のとおりです。


 AUTO PARTITION BY LIST (`partition_col`) ()


これはcityパーティション列として使用して、LIST による自動パーティション分割を行う例です。


 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)


デンバー、ボストン、ロサンゼルスの各都市のデータを挿入すると、システムは都市名に基づいて対応するパーティションを自動的に作成しました。以前は、このタイプのカスタム パーティション分割は手動の DDL ステートメントでのみ実現できました。このようにして、Auto Partition by LIST はデータベースのメンテナンスを簡素化します。

ヒントと注意事項

履歴パーティションを手動で調整する

リアルタイム データと定期的な履歴更新の両方を受信するテーブルの場合、自動パーティションでは履歴パーティションが自動的に再利用されないため、次の 2 つのオプションをお勧めします。


  • 自動パーティションを使用すると、定期的な履歴データの更新用にパーティションが自動的に作成されます。

  • 自動パーティション機能を使用して、履歴更新に対応するLESS THANパーティションを手動で作成します。これにより、履歴データとリアルタイム データが明確に分離され、データ管理が容易になります。


 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)


NULLパーティション

Auto Partition by LIST を使用すると、Doris は NULL パーティションに NULL 値を格納することをサポートします。例:


 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)


ただし、RANGE による自動パーティションは NULL パーティションをサポートしていません。これは、NULL 値が最小のLESS THANパーティションに格納され、適切な範囲を確実に判断できないためです。自動パーティションが (-INFINITY、MIN_VALUE) の範囲で NULL パーティションを作成すると、MIN_VALUE 境界が意図したビジネス ロジックを正確に表さない可能性があるため、このパーティションが本番環境で誤って削除されるリスクがあります。

まとめ

自動パーティションは、動的パーティションのほとんどのユースケースをカバーし、事前のパーティション ルール定義の利点も提供します。ルールが定義されると、パーティション作成作業の大部分は DBA ではなく Doris によって自動的に処理されます。


自動パーティションを使用する前に、関連する制限事項を理解することが重要です。


  1. LIST による自動パーティションは、複数の列に基づくパーティション分割をサポートしますが、自動的に作成される各パーティションには単一の値のみが含まれ、パーティション名の長さは 50 文字を超えることはできません。パーティション名は特定の命名規則に従うことに注意してください。これは、メタデータ管理に特別な影響を及ぼします。つまり、50 文字のスペースのすべてをユーザーが自由に使用できるわけではありません。


  2. RANGE による自動パーティションは、単一のパーティション列のみをサポートし、その型はDATEまたはDATETIMEである必要があります。


  3. LIST による自動パーティションは、 NULLABLEパーティション列と NULL 値の挿入をサポートします。RANGE による自動パーティションは、NULLABLE パーティション列をサポートしません。


  4. Apache Doris 2.1.3 以降では、自動パーティションと動的パーティションを併用することは推奨されません。

パフォーマンス比較

自動パーティションと動的パーティションの主な機能上の違いは、パーティションの作成と削除、サポートされるパーティションの種類、およびそれらがインポート パフォーマンスに与える影響にあります。


Dynamic Partition は、固定スレッドを使用して定期的にパーティションを作成および再利用します。RANGE によるパーティション分割のみがサポートされます。一方、Auto Partition は、RANGE によるパーティション分割と LIST によるパーティション分割の両方をサポートします。データ取り込み中に特定のルールに基づいてオンデマンドでパーティションを自動的に作成し、より高いレベルの自動化と柔軟性を実現します。


動的パーティションではデータの取り込み速度は低下しませんが、自動パーティションでは最初に既存のパーティションをチェックし、その後必要に応じて新しいパーティションを作成するため、一定の時間オーバーヘッドが発生します。パフォーマンス テストの結果を紹介します。



自動パーティション: 取り込みワークフロー

この部分では、自動パーティション メカニズムを使用してデータ取り込みを実装する方法について説明します。例として、Stream Load を使用します。Doris がデータのインポートを開始すると、Doris バックエンド ノードの 1 つがコーディネーターの役割を担います。コーディネーターは、最初のデータ処理作業を担当し、その後、実行のために、データを適切な BE ノード (Executors と呼ばれる) にディスパッチします。



コーディネーターの実行パイプラインの最後のデータシンク ノードでは、データが正常に送信および保存される前に、データが正しいパーティション、バケット、および Doris バックエンド ノードの場所にルーティングされる必要があります。


このデータ転送を可能にするために、コーディネーター ノードとエグゼキューター ノードは通信チャネルを確立します。


  • 送信側はノード チャネルと呼ばれます。
  • 受信側はタブレット チャネルと呼ばれます。


データの正しいパーティションを決定するプロセス中に、自動パーティションが機能する仕組みは次のとおりです。



これまで、自動パーティション機能がない場合、テーブルに必要なパーティションがない場合、Doris の動作では、 DATA_QUALITY_ERRORが報告されるまで BE ノードがエラーを蓄積していました。自動パーティション機能を有効にすると、必要なパーティションをオンザフライで作成するように Doris フロントエンドに要求が送信されます。パーティション作成トランザクションが完了すると、Doris フロントエンドはコーディネーターに応答し、コーディネーターは対応する通信チャネル (ノード チャネルとタブレット チャネル) を開いて、データ取り込みプロセスを続行します。これは、ユーザーにとってシームレスなエクスペリエンスです。


実際のクラスター環境では、コーディネータが Doris フロントエンドのパーティション作成完了を待機する時間によって、大きなオーバーヘッドが発生する可能性があります。これは、Thrift RPC 呼び出しの固有の遅延と、高負荷状態でのフロントエンドのロック競合が原因です。


Auto Partition でのデータ取り込み効率を向上させるために、Doris はバッチ処理を実装し、FE への RPC 呼び出しの数を大幅に削減しました。これにより、データ書き込み操作のパフォーマンスが大幅に向上します。


FE マスターがパーティション作成トランザクションを完了すると、新しいパーティションがすぐに表示されることに注意してください。ただし、インポート プロセスが最終的に失敗するかキャンセルされた場合、作成されたパーティションは自動的に再利用されません。

自動パーティションのパフォーマンス

さまざまなユースケースをカバーして、Doris の自動パーティションのパフォーマンスと安定性をテストしました。


ケース 1 : フロントエンド 1 つ + バックエンド 3 つ。ランダムに生成されたデータセット 6 つ (それぞれ 1 億行、2,000 パーティション)。6 つのデータセットを 6 つのテーブルに同時に取り込みました。


  • 目的: 高圧下での自動パーティションのパフォーマンスを評価し、パフォーマンスの低下がないか確認します。


  • 結果: 自動パーティションにより、平均パフォーマンスの低下は 5% 未満となり、すべてのインポート トランザクションが安定して実行されます。



ケース 2 : フロントエンド 1 つ + バックエンド 3 つ。ルーチン ロードによって Flink から 1 秒あたり 100 行を取り込み、それぞれ 1、10、20 の同時トランザクション (テーブル) でテストします。


  • 目的: さまざまな同時実行レベルでの自動パーティションで発生する可能性のあるデータ バックログの問題を特定します。


  • 結果: 自動パーティションの有効/無効に関係なく、CPU 使用率が 100% 近くに達した 20 件の同時トランザクションでも、テストしたすべての同時実行レベルでバックプレッシャーの問題が発生することなく、データの取り込みは成功しました。



これらのテストの結果をまとめると、自動パーティションを有効にした場合のデータ取り込みパフォーマンスへの影響は最小限です。

結論と今後の計画

Auto Partition は、Apache Doris 2.1.0 以降、DDL とパーティション管理を簡素化しました。大規模なデータ処理に役立ち、ユーザーが他のデータベース システムから Apache Doris に簡単に移行できるようにします。


さらに、より複雑なデータ型をサポートするために、Auto Partition の機能を拡張することにも取り組んでいます。


RANGEによる自動パーティションのプラン:


  • 数値をサポートします。


  • ユーザーがパーティション範囲の左境界と右境界を指定できるようにします。


LISTによる自動パーティションの計画:


  • 特定のルールに基づいて複数の値を同じパーティションにマージできるようにします。