paint-brush
Sự phát triển của việc phân chia dữ liệu theo hướng tự động hóa và linh hoạt trong Apache Doristừ tác giả@shirleyfromapachedoris
446 lượt đọc
446 lượt đọc

Sự phát triển của việc phân chia dữ liệu theo hướng tự động hóa và linh hoạt trong Apache Doris

từ tác giả Shirley H.29m2024/07/20
Read on Terminal Reader

dài quá đọc không nổi

Apache Doris giới thiệu Phân vùng tự động trong V2.1.0. Nó đã đơn giản hóa việc quản lý phân vùng và DDL kể từ Apache Doris 2.1.0. Nó rất hữu ích trong việc xử lý dữ liệu quy mô lớn và giúp người dùng dễ dàng di chuyển từ các hệ thống cơ sở dữ liệu khác sang Apache Doris.
featured image - Sự phát triển của việc phân chia dữ liệu theo hướng tự động hóa và linh hoạt trong Apache Doris
Shirley H. HackerNoon profile picture


Để xử lý các tập dữ liệu lớn, cơ sở dữ liệu phân tán đưa ra các chiến lược như phân vùng và phân nhóm. Dữ liệu được chia thành các đơn vị nhỏ hơn dựa trên các quy tắc cụ thể và được phân phối trên các nút khác nhau để cơ sở dữ liệu có thể thực hiện xử lý song song để có hiệu suất cao hơn và tính linh hoạt trong quản lý dữ liệu.


Giống như trong nhiều cơ sở dữ liệu, Apache Doris chia dữ liệu thành các phân vùng và sau đó phân vùng đó lại được chia thành các nhóm. Các phân vùng thường được xác định theo thời gian hoặc các giá trị liên tục khác. Điều này cho phép các công cụ truy vấn nhanh chóng xác định vị trí dữ liệu mục tiêu trong quá trình truy vấn bằng cách cắt bớt các phạm vi dữ liệu không liên quan.


Mặt khác, Bucketing phân phối dữ liệu dựa trên giá trị băm của một hoặc nhiều cột, điều này ngăn ngừa sự sai lệch dữ liệu.


Trước phiên bản 2.1.0 , có hai cách bạn có thể tạo phân vùng dữ liệu trong Apache Doris:


  • Phân vùng thủ công : Người dùng chỉ định các phân vùng trong câu lệnh tạo bảng hoặc sửa đổi chúng thông qua các câu lệnh DDL sau đó.


  • Phân vùng động : Hệ thống tự động duy trì các phân vùng trong phạm vi được xác định trước dựa trên thời gian nhập dữ liệu.


Trong Apache Doris 2.1.0, chúng tôi đã giới thiệu Phân vùng tự động . Nó hỗ trợ phân vùng dữ liệu theo RANGE hoặc LIST và tăng cường hơn nữa tính linh hoạt của tính năng phân vùng tự động.

Sự phát triển của chiến lược phân vùng trong Doris

Trong thiết kế phân phối dữ liệu, chúng tôi tập trung nhiều hơn vào việc lập kế hoạch phân vùng vì việc lựa chọn các cột phân vùng và khoảng phân vùng phụ thuộc rất nhiều vào mẫu phân phối dữ liệu thực tế và một thiết kế phân vùng tốt có thể cải thiện phần lớn hiệu quả truy vấn và lưu trữ của bảng.


Trong Doris, bảng dữ liệu được chia thành các phân vùng rồi chia thành các nhóm theo cách phân cấp. Sau đó, dữ liệu trong cùng một nhóm sẽ tạo thành một bảng dữ liệu, là đơn vị lưu trữ vật lý tối thiểu trong Doris để sao chép dữ liệu, lập lịch dữ liệu giữa các cụm và cân bằng tải.


Phân vùng thủ công

Doris cho phép người dùng tạo phân vùng dữ liệu theo cách thủ công theo RANGE và LIST.


Đối với dữ liệu có dấu thời gian như nhật ký và bản ghi giao dịch, người dùng thường tạo phân vùng dựa trên thứ nguyên thời gian. Đây là một ví dụ về câu lệnh 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" );


Bảng được phân vùng theo date nhập dữ liệu và 4 phân vùng đã được tạo sẵn. Trong mỗi phân vùng, dữ liệu được chia thành 16 nhóm dựa trên giá trị băm của user_id .


Với thiết kế phân vùng và phân vùng này, khi truy vấn dữ liệu từ năm 2018 trở đi, hệ thống chỉ cần quét phân vùng p2018 . Đây là giao diện của truy vấn 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 | | | +--------------------------------------------------------------------------------------+


Nếu dữ liệu được phân phối không đồng đều trên các phân vùng, cơ chế phân nhóm dựa trên hàm băm có thể phân chia thêm dữ liệu dựa trên user_id . Điều này giúp tránh tình trạng mất cân bằng tải trên một số máy trong quá trình truy vấn và lưu trữ.


Tuy nhiên, trong các tình huống kinh doanh thực tế, một cụm có thể có hàng chục nghìn bảng, điều đó có nghĩa là không thể quản lý chúng theo cách thủ công.


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


Trong ví dụ trên, dữ liệu được phân vùng hàng tháng. Điều này yêu cầu quản trị viên cơ sở dữ liệu (DBA) phải thêm phân vùng mới theo cách thủ công mỗi tháng và duy trì lược đồ bảng thường xuyên. Hãy tưởng tượng trường hợp xử lý dữ liệu theo thời gian thực, trong đó bạn có thể cần tạo phân vùng hàng ngày hoặc thậm chí hàng giờ, việc thực hiện việc này theo cách thủ công không còn là một lựa chọn nữa. Đó là lý do tại sao chúng tôi giới thiệu Phân vùng động.

Phân vùng động

Bằng Phân vùng động, Doris tự động tạo và lấy lại các phân vùng dữ liệu miễn là người dùng chỉ định đơn vị phân vùng, số lượng phân vùng lịch sử và số lượng phân vùng trong tương lai. Chức năng này dựa trên một luồng cố định trên Doris Frontend. Nó liên tục thăm dò và kiểm tra các phân vùng mới được tạo hoặc các phân vùng cũ được thu hồi và cập nhật lược đồ phân vùng của bảng.


Đây là một ví dụ về câu lệnh CREATE TABLE cho một bảng được phân vùng theo ngày. Tham số startend được đặt lần lượt là -73 , nghĩa là các phân vùng dữ liệu trong 3 ngày tiếp theo sẽ được tạo trước và các phân vùng lịch sử cũ hơn 7 ngày sẽ được thu hồi.


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


Theo thời gian, bảng sẽ luôn duy trì các phân vùng trong phạm vi [current date - 7, current date + 3] . Phân vùng động đặc biệt hữu ích cho các tình huống nhập dữ liệu theo thời gian thực, chẳng hạn như khi lớp ODS (Kho lưu trữ dữ liệu hoạt động) trực tiếp nhận dữ liệu từ các nguồn bên ngoài như Kafka.


Các tham số startend xác định một phạm vi cố định cho các phân vùng, cho phép người dùng chỉ quản lý các phân vùng trong phạm vi này. Tuy nhiên, nếu người dùng cần bao gồm nhiều dữ liệu lịch sử hơn, họ sẽ phải quay số giá trị start và điều đó có thể dẫn đến chi phí siêu dữ liệu không cần thiết trong cụm.


Do đó, khi áp dụng Phân vùng động sẽ có sự đánh đổi giữa tính tiện lợi và hiệu quả của việc quản lý siêu dữ liệu.

Lời của nhà phát triển

Khi sự phức tạp của hoạt động kinh doanh tăng lên, Phân vùng động trở nên không phù hợp vì:


  • Nó chỉ hỗ trợ phân vùng theo RANGE chứ không hỗ trợ LIST.
  • Nó chỉ có thể được áp dụng cho dấu thời gian trong thế giới thực hiện tại.
  • Nó chỉ hỗ trợ một phạm vi phân vùng liên tục duy nhất và không thể chứa các phân vùng nằm ngoài phạm vi đó.


Do những hạn chế về chức năng này, chúng tôi bắt đầu lên kế hoạch cho một cơ chế phân vùng mới có thể vừa tự động hóa việc quản lý phân vùng vừa đơn giản hóa việc bảo trì bảng dữ liệu.


Chúng tôi đã tìm ra rằng việc triển khai phân vùng lý tưởng nên:


  • Tiết kiệm nhu cầu tạo phân vùng theo cách thủ công sau khi tạo bảng;
  • Có thể chứa tất cả dữ liệu đã nhập vào các phân vùng tương ứng.


Cái trước là viết tắt của tự động hóa và cái sau là sự linh hoạt. Bản chất của việc hiện thực hóa cả hai là liên kết việc tạo phân vùng với dữ liệu thực tế.


Sau đó, chúng tôi bắt đầu nghĩ về những điều sau: Điều gì sẽ xảy ra nếu chúng tôi tạm dừng việc tạo phân vùng cho đến khi dữ liệu được nhập, thay vì thực hiện việc đó trong quá trình tạo bảng hoặc thông qua bỏ phiếu thông thường? Thay vì xây dựng trước phân phối phân vùng, chúng ta có thể xác định quy tắc ánh xạ "dữ liệu tới phân vùng" để các phân vùng được tạo sau khi dữ liệu đến.


So với Phân vùng thủ công, toàn bộ quá trình này sẽ hoàn toàn tự động, loại bỏ nhu cầu bảo trì của con người. So với Phân vùng động, nó tránh được các phân vùng không được sử dụng hoặc các phân vùng cần thiết nhưng không có.

Tự động phân vùng

Với Apache Doris 2.1.0 , chúng tôi đã biến kế hoạch trên thành hiện thực. Trong quá trình nhập dữ liệu, Doris tạo các phân vùng dữ liệu dựa trên các quy tắc đã định cấu hình. Các nút Doris Backend chịu trách nhiệm xử lý và phân phối dữ liệu sẽ cố gắng tìm phân vùng thích hợp cho từng hàng dữ liệu trong toán tử DataSink của kế hoạch thực hiện. Nó không còn lọc ra dữ liệu không vừa với bất kỳ phân vùng hiện có nào hoặc báo lỗi trong tình huống như vậy mà tự động tạo phân vùng cho tất cả dữ liệu đã nhập.

Tự động phân vùng theo RANGE

Tự động phân vùng theo RANGE cung cấp giải pháp phân vùng được tối ưu hóa dựa trên thứ nguyên thời gian. Nó linh hoạt hơn Phân vùng động về mặt cấu hình tham số. Cú pháp cho nó như sau:


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


<partition_column> ở trên là cột phân vùng (tức là cột dựa vào đó để phân vùng). <interval> chỉ định đơn vị phân vùng, là độ rộng mong muốn của mỗi phân vùng.


Ví dụ: nếu cột phân vùng là k0 và bạn muốn phân vùng theo tháng, câu lệnh phân vùng sẽ là AUTO PARTITION BY RANGE (DATE_TRUNC(k0, 'month')) . Đối với tất cả dữ liệu đã nhập, hệ thống sẽ gọi DATE_TRUNC(k0, 'month') để tính điểm cuối bên trái của phân vùng và sau đó là điểm cuối bên phải bằng cách thêm một interval .


Bây giờ, chúng ta có thể áp dụng Phân vùng tự động cho bảng DAILY_TRADE_VALUE được giới thiệu ở phần trước về Phân vùng động.


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


Sau khi nhập một số dữ liệu, đây là các phân vùng chúng tôi nhận được:


 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)


Như được hiển thị, các phân vùng được tạo tự động cho dữ liệu đã nhập và nó không tạo các phân vùng nằm ngoài phạm vi của dữ liệu hiện có.

Tự động phân vùng theo LIST

Tự động phân vùng theo LIST là phân chia dữ liệu dựa trên các thứ nguyên không dựa trên thời gian, chẳng hạn như regiondepartment . Nó lấp đầy khoảng trống đó cho Phân vùng động, vốn không hỗ trợ phân vùng dữ liệu theo LIST.


Tự động phân vùng theo RANGE cung cấp giải pháp phân vùng được tối ưu hóa dựa trên kích thước thời gian. Nó linh hoạt hơn Phân vùng động về mặt cấu hình tham số. Cú pháp cho nó như sau:


 AUTO PARTITION BY LIST (`partition_col`) ()


Đây là ví dụ về Tự động phân vùng theo LIST sử dụng city làm cột phân vùng:


 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)


Sau khi chèn dữ liệu cho các thành phố Denver, Boston và Los Angeles, hệ thống sẽ tự động tạo các phân vùng tương ứng dựa trên tên thành phố. Trước đây, kiểu phân vùng tùy chỉnh này chỉ có thể đạt được thông qua các câu lệnh DDL thủ công. Đây là cách Tự động phân vùng theo LIST đơn giản hóa việc bảo trì cơ sở dữ liệu.

Mẹo và ghi chú

Điều chỉnh thủ công các phân vùng lịch sử

Đối với các bảng nhận cả dữ liệu thời gian thực và cập nhật lịch sử không thường xuyên, do Phân vùng tự động không tự động lấy lại các phân vùng lịch sử, chúng tôi khuyên bạn nên sử dụng hai tùy chọn:


  • Sử dụng Phân vùng tự động, tính năng này sẽ tự động tạo phân vùng để thỉnh thoảng cập nhật dữ liệu lịch sử.

  • Sử dụng Phân vùng tự động và tạo phân vùng LESS THAN theo cách thủ công để chứa các bản cập nhật lịch sử. Điều này cho phép phân tách rõ ràng hơn dữ liệu lịch sử và dữ liệu thời gian thực, đồng thời giúp quản lý dữ liệu dễ dàng hơn.


 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)


Phân vùng rỗng

Với Auto Phân vùng theo LIST, Doris hỗ trợ lưu trữ giá trị NULL trong phân vùng NULL. Ví dụ:


 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)


Tuy nhiên, Tự động phân vùng theo RANGE không hỗ trợ phân vùng NULL, vì các giá trị NULL sẽ được lưu trữ trong phân vùng LESS THAN nhỏ nhất và không thể xác định phạm vi thích hợp cho nó một cách đáng tin cậy. Nếu Phân vùng tự động tạo phân vùng NULL có phạm vi (-INFINITY, MIN_VALUE), thì sẽ có nguy cơ phân vùng này vô tình bị xóa trong quá trình sản xuất vì ranh giới MIN_VALUE có thể không thể hiện chính xác logic kinh doanh dự định.

Bản tóm tắt

Phân vùng tự động bao gồm hầu hết các trường hợp sử dụng Phân vùng động, đồng thời giới thiệu lợi ích của việc xác định quy tắc phân vùng trả trước. Khi các quy tắc được xác định, phần lớn công việc tạo phân vùng sẽ được Doris tự động xử lý thay vì DBA.


Trước khi sử dụng Phân vùng tự động, điều quan trọng là phải hiểu những hạn chế có liên quan:


  1. Auto Phân vùng theo LIST hỗ trợ phân vùng dựa trên nhiều cột , tuy nhiên mỗi phân vùng được tạo tự động chỉ chứa một giá trị duy nhất và tên phân vùng không được dài quá 50 ký tự. Lưu ý rằng tên phân vùng tuân theo các quy ước đặt tên cụ thể, có ý nghĩa cụ thể đối với việc quản lý siêu dữ liệu. Điều đó có nghĩa là không phải tất cả không gian 50 ký tự đều thuộc quyền sử dụng của người dùng.


  2. Tự động phân vùng theo RANGE chỉ hỗ trợ một cột phân vùng duy nhất , cột này phải thuộc loại DATE hoặc DATETIME .


  3. Tự động phân vùng theo LIST hỗ trợ cột phân vùng NULLABLE và chèn giá trị NULL. Phân vùng tự động theo RANGE không hỗ trợ cột phân vùng NULLABLE.


  4. Không nên sử dụng Phân vùng tự động kết hợp với Phân vùng động sau Apache Doris 2.1.3.

So sánh hiệu suất

Sự khác biệt chính về chức năng giữa Phân vùng tự động và Phân vùng động nằm ở việc tạo và xóa phân vùng, loại phân vùng được hỗ trợ và tác động của chúng đến hiệu suất nhập.


Phân vùng động sử dụng các luồng cố định để tạo và lấy lại các phân vùng theo định kỳ. Nó chỉ hỗ trợ phân vùng theo RANGE. Ngược lại, Phân vùng tự động hỗ trợ cả phân vùng theo RANGE và LIST. Nó tự động tạo các phân vùng theo yêu cầu dựa trên các quy tắc cụ thể trong quá trình nhập dữ liệu, mang lại mức độ tự động hóa và linh hoạt cao hơn.


Phân vùng động không làm chậm tốc độ nhập dữ liệu, trong khi Phân vùng tự động gây ra chi phí thời gian nhất định vì trước tiên nó kiểm tra các phân vùng hiện có rồi tạo phân vùng mới theo yêu cầu. Chúng tôi sẽ trình bày kết quả kiểm tra hiệu suất.



Phân vùng tự động: quy trình nhập

Phần này nói về cách triển khai việc nhập dữ liệu bằng cơ chế Phân vùng tự động và chúng tôi sử dụng Tải luồng làm ví dụ. Khi Doris bắt đầu nhập dữ liệu, một trong các nút Doris Backend sẽ đảm nhận vai trò Điều phối viên. Nó chịu trách nhiệm về công việc xử lý dữ liệu ban đầu và sau đó gửi dữ liệu đến các nút BE thích hợp, được gọi là Bộ thực thi, để thực thi.



Trong Nút Datasink cuối cùng của quy trình thực thi của Điều phối viên, dữ liệu cần được định tuyến đến các phân vùng, nhóm và vị trí nút Doris Backend chính xác trước khi có thể truyền và lưu trữ thành công.


Để cho phép truyền dữ liệu này, các nút Điều phối viên và Người thực thi thiết lập các kênh liên lạc:


  • Đầu gửi được gọi là Kênh Nút.
  • Đầu nhận được gọi là Kênh Máy tính bảng.


Đây là cách Phân vùng tự động phát huy tác dụng trong quá trình xác định phân vùng chính xác cho dữ liệu:



Trước đây, nếu không có Phân vùng tự động, khi một bảng không có phân vùng được yêu cầu, hoạt động trong Doris là để các nút BE tích lũy lỗi cho đến khi báo cáo DATA_QUALITY_ERROR . Giờ đây, khi bật Phân vùng tự động, một yêu cầu sẽ được gửi tới Doris Frontend để tạo phân vùng cần thiết một cách nhanh chóng. Sau khi giao dịch tạo phân vùng hoàn tất, Doris Frontend sẽ phản hồi Điều phối viên, sau đó Điều phối viên sẽ mở các kênh liên lạc tương ứng (Kênh Nút và Kênh Máy tính bảng) để tiếp tục quá trình nhập dữ liệu. Đây là một trải nghiệm liền mạch cho người dùng.


Trong môi trường cụm trong thế giới thực, thời gian mà Điều phối viên dành để chờ Doris Frontend hoàn thành việc tạo phân vùng có thể phát sinh chi phí lớn. Điều này là do độ trễ vốn có của các cuộc gọi Thrift RPC, cũng như sự tranh chấp khóa trên Frontend trong điều kiện tải cao.


Để cải thiện hiệu quả nhập dữ liệu trong Phân vùng tự động, Doris đã triển khai tính năng theo đợt để giảm đáng kể số lượng lệnh gọi RPC được thực hiện tới FE. Điều này mang lại sự nâng cao hiệu suất đáng chú ý cho các hoạt động ghi dữ liệu.


Lưu ý rằng khi FE Master hoàn tất giao dịch tạo phân vùng, phân vùng mới sẽ hiển thị ngay lập tức. Tuy nhiên, nếu quá trình nhập cuối cùng không thành công hoặc bị hủy thì các phân vùng đã tạo sẽ không được tự động lấy lại.

Hiệu suất phân vùng tự động

Chúng tôi đã kiểm tra hiệu suất và tính ổn định của Phân vùng tự động trong Doris, bao gồm các trường hợp sử dụng khác nhau:


Trường hợp 1 : 1 Frontend + 3 Backend; 6 bộ dữ liệu được tạo ngẫu nhiên, mỗi bộ có 100 triệu hàng và 2.000 phân vùng; nhập đồng thời 6 bộ dữ liệu vào 6 bảng


  • Mục tiêu : Đánh giá hiệu suất của Phân vùng tự động dưới áp suất cao và kiểm tra xem có bất kỳ sự suy giảm hiệu suất nào không.


  • Kết quả : Phân vùng tự động mang lại mức giảm hiệu suất trung bình dưới 5% , với tất cả các giao dịch nhập đều chạy ổn định.



Trường hợp 2 : 1 Frontend + 3 Backend; nhập 100 hàng mỗi giây từ Flink theo Tải thường xuyên; thử nghiệm với 1, 10 và 20 giao dịch đồng thời (bảng) tương ứng


  • Mục tiêu : Xác định mọi vấn đề tồn đọng dữ liệu tiềm ẩn có thể phát sinh với Phân vùng tự động ở các cấp độ đồng thời khác nhau.


  • Kết quả : Dù bật hoặc không bật Phân vùng tự động, quá trình nhập dữ liệu đã thành công mà không gặp bất kỳ vấn đề áp suất ngược nào trên tất cả các mức đồng thời được thử nghiệm, ngay cả ở 20 giao dịch đồng thời khi mức sử dụng CPU đạt gần 100%.



Để kết luận kết quả của những thử nghiệm này, tác động của việc bật Phân vùng tự động đến hiệu suất nhập dữ liệu là rất nhỏ.

Kết luận và kế hoạch tương lai

Phân vùng tự động đã đơn giản hóa việc quản lý phân vùng và DDL kể từ Apache Doris 2.1.0. Nó rất hữu ích trong việc xử lý dữ liệu quy mô lớn và giúp người dùng dễ dàng di chuyển từ các hệ thống cơ sở dữ liệu khác sang Apache Doris.


Hơn nữa, chúng tôi cam kết mở rộng khả năng của Phân vùng tự động để hỗ trợ các loại dữ liệu phức tạp hơn.


Các kế hoạch phân vùng tự động theo RANGE:


  • Hỗ trợ các giá trị số;


  • Cho phép người dùng chỉ định ranh giới bên trái và bên phải của phạm vi phân vùng.


Các phương án phân vùng tự động theo DANH SÁCH:


  • Cho phép hợp nhất nhiều giá trị vào cùng một phân vùng dựa trên các quy tắc cụ thể.