Broker Load is an asynchronous import method for loading large volumes of data from HDFS, Baidu Object Storage (BOS), or Andrew File System (AFS) into Doris. Use it when Spark computing resources are unavailable and you need to import tens to hundreds of GB of data stored in a broker-accessible file system.
Broker Load is the only asynchronous import method for a single import job. If Spark resources are available, use Spark Load instead—it uses fewer Doris cluster resources for large-volume historical data migration.
How it works
After you submit an import job, the Frontend (FE) generates an execution plan and distributes it across available Backends (BE) based on the number of BEs and the source file size. Each BE pulls data from a broker, transforms it, and loads it into the system. Once all BEs complete, the FE determines whether the job succeeded.
| 1. User submits a Broker Load job
v
+----+----+
| |
| FE |
| |
+----+----+
|
| 2. Each BE runs extract, transform, and load
+--------------------------+
| | |
+---v---+ +--v----+ +---v---+
| | | | | |
| BE | | BE | | BE |
| | | | | |
+---+-^-+ +---+-^-+ +--+-^--+
| | | | | |
| | | | | | 3. Each BE pulls data from a broker
+---v-+-+ +---v-+-+ +--v-+--+
| | | | | |
|Broker | |Broker | |Broker |
| | | | | |
+---+-^-+ +---+-^-+ +---+-^-+
| | | | | |
+---v-+-----------v-+----------v-+-+
| HDFS/BOS/AFS Cluster |
| |
+----------------------------------+Prerequisites
Before you begin, ensure that you have:
A running Doris cluster with at least one BE
Source data stored in a broker-accessible file system (HDFS, BOS, or AFS)
A Doris target table created for the import
Submit an import job
Import data from a partitioned Hive table
This example imports data from a partitioned Hive table using the default CSV format.
Create a Hive table with a
daypartition field.-- Default data format (CSV), partition field: day CREATE TABLE `ods_demo_detail`( `id` string, `store_id` string, `company_id` string, `tower_id` string, `commodity_id` string, `commodity_name` string, `commodity_price` double, `member_price` double, `cost_price` double, `unit` string, `quantity` double, `actual_price` double ) PARTITIONED BY (day string) row format delimited fields terminated by ',' lines terminated by '\n'Load data into the Hive table.
load data local inpath '/opt/custorm' into table ods_demo_detail;Create the target Doris table.
CREATE TABLE `doris_ods_test_detail` ( `rq` date NULL, `id` varchar(32) NOT NULL, `store_id` varchar(32) NULL, `company_id` varchar(32) NULL, `tower_id` varchar(32) NULL, `commodity_id` varchar(32) NULL, `commodity_name` varchar(500) NULL, `commodity_price` decimal(10, 2) NULL, `member_price` decimal(10, 2) NULL, `cost_price` decimal(10, 2) NULL, `unit` varchar(50) NULL, `quantity` int(11) NULL, `actual_price` decimal(10, 2) NULL ) ENGINE=OLAP UNIQUE KEY(`rq`, `id`, `store_id`) PARTITION BY RANGE(`rq`) ( PARTITION P_202204 VALUES [('2022-04-01'), ('2022-05-01'))) DISTRIBUTED BY HASH(`store_id`) BUCKETS 1 PROPERTIES ( "replication_allocation" = "tag.location.default: 3", "dynamic_partition.enable" = "true", "dynamic_partition.time_unit" = "MONTH", "dynamic_partition.start" = "-2147483648", "dynamic_partition.end" = "2", "dynamic_partition.prefix" = "P_", "dynamic_partition.buckets" = "1", "in_memory" = "false", "storage_format" = "V2" );Submit the import job. The
SETclause maps the Hive partition fielddayto the Doris date columnrqusingstr_to_date.LOAD LABEL broker_load_2022_03_23 ( DATA INFILE("hdfs://192.168.**.**:8020/user/hive/warehouse/ods.db/ods_demo_detail/*/*") INTO TABLE doris_ods_test_detail COLUMNS TERMINATED BY "," (id,store_id,company_id,tower_id,commodity_id,commodity_name,commodity_price,member_price,cost_price,unit,quantity,actual_price) COLUMNS FROM PATH AS (`day`) SET (rq = str_to_date(`day`,'%Y-%m-%d'),id=id,store_id=store_id,company_id=company_id,tower_id=tower_id,commodity_id=commodity_id,commodity_name=commodity_name,commodity_price=commodity_price,member_price=member_price,cost_price=cost_price,unit=unit,quantity=quantity,actual_price=actual_price) ) WITH BROKER "broker_name_1" ( "username" = "hdfs", "password" = "" ) PROPERTIES ( "timeout"="1200", "max_filter_ratio"="0.1" );
Import data from a partitioned Hive table in ORC format
This example imports from a Hive table stored in Optimized Row Columnar (ORC) format. The key difference from the CSV example is the FORMAT AS "orc" clause.
Create a partitioned Hive table in ORC format.
-- Data format: ORC, partition field: day CREATE TABLE `ods_demo_orc_detail`( `id` string, `store_id` string, `company_id` string, `tower_id` string, `commodity_id` string, `commodity_name` string, `commodity_price` double, `member_price` double, `cost_price` double, `unit` string, `quantity` double, `actual_price` double ) PARTITIONED BY (day string) row format delimited fields terminated by ',' lines terminated by '\n' STORED AS ORCCreate the target Doris table using the same schema as in the previous example.
CREATE TABLE `doris_ods_test_detail` ( `rq` date NULL, `id` varchar(32) NOT NULL, `store_id` varchar(32) NULL, `company_id` varchar(32) NULL, `tower_id` varchar(32) NULL, `commodity_id` varchar(32) NULL, `commodity_name` varchar(500) NULL, `commodity_price` decimal(10, 2) NULL, `member_price` decimal(10, 2) NULL, `cost_price` decimal(10, 2) NULL, `unit` varchar(50) NULL, `quantity` int(11) NULL, `actual_price` decimal(10, 2) NULL ) ENGINE=OLAP UNIQUE KEY(`rq`, `id`, `store_id`) PARTITION BY RANGE(`rq`) ( PARTITION P_202204 VALUES [('2022-04-01'), ('2022-05-01'))) DISTRIBUTED BY HASH(`store_id`) BUCKETS 1 PROPERTIES ( "replication_allocation" = "tag.location.default: 3", "dynamic_partition.enable" = "true", "dynamic_partition.time_unit" = "MONTH", "dynamic_partition.start" = "-2147483648", "dynamic_partition.end" = "2", "dynamic_partition.prefix" = "P_", "dynamic_partition.buckets" = "1", "in_memory" = "false", "storage_format" = "V2" );Submit the import job with
FORMAT AS "orc".LOAD LABEL dish_2022_03_23 ( DATA INFILE("hdfs://10.220.**.**:8020/user/hive/warehouse/ods.db/ods_demo_orc_detail/*/*") INTO TABLE doris_ods_test_detail COLUMNS TERMINATED BY "," FORMAT AS "orc" (id,store_id,company_id,tower_id,commodity_id,commodity_name,commodity_price,member_price,cost_price,unit,quantity,actual_price) COLUMNS FROM PATH AS (`day`) SET (rq = str_to_date(`day`,'%Y-%m-%d'),id=id,store_id=store_id,company_id=company_id,tower_id=tower_id,commodity_id=commodity_id,commodity_name=commodity_name,commodity_price=commodity_price,member_price=member_price,cost_price=cost_price,unit=unit,quantity=quantity,actual_price=actual_price) ) WITH BROKER "broker_name_1" ( "username" = "hdfs", "password" = "" ) PROPERTIES ( "timeout"="1200", "max_filter_ratio"="0.1" );
Import data directly from HDFS
To import a tab-delimited text file from HDFS without going through a Hive table, use the WITH HDFS clause instead of WITH BROKER.
LOAD LABEL demo.label_20220402
(
DATA INFILE("hdfs://10.220.**.**:8020/tmp/test_hdfs.txt")
INTO TABLE `ods_dish_detail_test`
COLUMNS TERMINATED BY "\t" (id,store_id,company_id,tower_id,commodity_id,commodity_name,commodity_price,member_price,cost_price,unit,quantity,actual_price)
)
WITH HDFS (
"fs.defaultFS"="hdfs://10.220.**.**:8020",
"hadoop.username"="root"
)
PROPERTIES
(
"timeout"="1200",
"max_filter_ratio"="0.1"
);Check import job status
Run the following statement to view the most recently submitted import job.
show load order by createtime desc limit 1\G;Example output:
*************************** 1. row ***************************
JobId: 4132****
Label: broker_load_2022_03_23
State: FINISHED
Progress: ETL:100%; LOAD:100%
Type: BROKER
EtlInfo: unselected.rows=0; dpp.abnorm.ALL=0; dpp.norm.ALL=27
TaskInfo: cluster:N/A; timeout(s):1200; max_filter_ratio:0.1
ErrorMsg: NULL
CreateTime: 2022-04-01 18:59:06
EtlStartTime: 2022-04-01 18:59:11
EtlFinishTime: 2022-04-01 18:59:11
LoadStartTime: 2022-04-01 18:59:11
LoadFinishTime: 2022-04-01 18:59:11
URL: NULL
JobDetails: {"Unfinished backends":{"5072bde59b74b65-8d2c0ee5b029****":[]},"ScannedRows":27,"TaskNumber":1,"All backends":{"5072bde59b74b65-8d2c0ee5b029****":[36728051]},"FileNumber":1,"FileSize":5540}
1 row in set (0.01 sec)Key fields in the output:
| Field | Description |
|---|---|
State | Job state: PENDING, LOADING, FINISHED, or CANCELLED |
Progress | ETL and LOAD progress percentages |
EtlInfo | Row counts: dpp.norm.ALL = successfully loaded rows, dpp.abnorm.ALL = filtered rows |
TaskInfo | Timeout and max_filter_ratio settings in effect |
ErrorMsg | Error message if the job failed; NULL if successful |
Cancel an import job
Cancel a job only while its state is PENDING or LOADING. Specify the job label in the CANCEL LOAD statement.
CANCEL LOAD FROM demo WHERE LABEL = "broker_load_2022_03_23";System configurations
FE configurations
These parameters in fe.conf apply to all Broker Load jobs in the cluster and control how the FE distributes work across BEs.
| Parameter | Default | Unit | Description |
|---|---|---|---|
min_bytes_per_broker_scanner | 64 MB | bytes | Minimum data processed by a single BE per job |
max_bytes_per_broker_scanner | 3 GB | bytes | Maximum data processed by a single BE per job |
max_broker_concurrency | 10 | — | Maximum concurrent tasks per import job |
desired_max_waiting_jobs | 100 | — | Maximum PENDING + LOADING jobs in the cluster; new jobs are rejected when this threshold is exceeded |
async_pending_load_task_pool_size | 10 | — | Maximum pending tasks running concurrently; limits how many jobs enter LOADING state |
async_loading_load_task_pool_size | — | — | Maximum loading tasks running concurrently; must be >= async_pending_load_task_pool_size |
The FE calculates concurrency for each import job using these formulas:
Concurrency = Math.min(
Source file size / min_bytes_per_broker_scanner,
max_broker_concurrency,
Number of BEs
)
Data per BE = Source file size / ConcurrencyThe maximum data importable in a single job equals max_bytes_per_broker_scanner x Number of BEs. To import more data than this limit, increase max_bytes_per_broker_scanner.
Each Broker Load job consists of one pending task and one or more loading tasks. The number of loading tasks equals the number ofDATA INFILEclauses in theLOAD LABELstatement.
Broker parameters
Different brokers require different authentication parameters to access remote storage. Refer to your broker documentation for the required connection properties.
Best practices
Choosing data volume per job
The following thresholds assume a single-BE cluster. For multi-BE clusters, multiply by the number of BEs (for example, a 3-BE cluster raises the <= 3 GB threshold to <= 9 GB).
| Data size | Action |
|---|---|
| <= 3 GB | Submit directly with default settings |
| > 3 GB | Adjust FE configurations before submitting (see below) |
| > 500 GB | Split into multiple files and import in batches |
Configuring for large files (> 3 GB)
For a file that exceeds 3 GB, follow these steps before submitting the job.
Step 1: Set concurrency and per-BE data limit in `fe.conf`.
max_broker_concurrency = <number of BEs>
max_bytes_per_broker_scanner >= <source file size> / max_broker_concurrencyExample: 100 GB file, 10 BEs.
max_broker_concurrency = 10
max_bytes_per_broker_scanner >= 10 GB (100 GB / 10)With these settings, all 10 BEs process the job in parallel, each handling 10 GB.
These FE settings apply to all Broker Load jobs in the cluster, not just the current job.
Step 2: Set the job timeout.
Calculate timeout using the import speed of your cluster. Use 10 MB/s as a conservative lower bound.
Data per BE / Slowest import speed of your cluster (MB/s) >= Timeout >= Data per BE / 10 MB/sExample: 10 GB per BE, timeout >= 1,000 s.
Set the timeout in the PROPERTIES block when submitting the job.
Step 3: Split files that require more than 4 hours.
The default maximum timeout is 4 hours. If your calculation exceeds this, do not increase the maximum timeout—split the source file instead. A failed job that ran for more than 4 hours takes equally long to retry.
Use this formula to find the largest file size that fits within 4 hours:
Max data per batch = 14,400 s x 10 MB/s x Number of BEsExample: 10 BEs, max per batch = 14,400 s x 10 MB/s x 10 = 1,440 GB.
In practice, import speed rarely reaches 10 MB/s. Split any file larger than 500 GB into smaller batches.
Managing job scheduling
The desired_max_waiting_jobs parameter limits how many jobs can be in PENDING or LOADING state at once (default: 100). New jobs submitted beyond this threshold are rejected.
The async_pending_load_task_pool_size parameter (default: 10) caps the number of jobs that actively enter LOADING state. For example, if you submit 100 jobs, only 10 run concurrently—the rest wait in PENDING state.