Run Batch Statements with Confluent Manager for Apache Flink
A batch statement runs its SQL query as an Apache Flink® batch job. The job reads a
bounded amount of input, writes its result and finishes. Use batch statements
for work that has an end, such as a backfill into a table or a report over a
fixed range of a topic. A statement runs in batch mode when
execution.runtime-mode is BATCH, set either in the statement’s
flinkConfiguration or in the environment’s statement defaults. When both
set it, the environment’s value wins, as described in
How CMF decides the runtime mode.
Batch statements have the following requirements:
The statement must run on a compute pool that runs Flink 2.x. On a compute pool that runs Flink 1.x, such as 1.19, CMF rejects the create request with a 400 and the message
batch statements require Flink 2.x.Every table the statement reads must be bounded. CMF accepts a batch statement that reads an unbounded source, but the statement moves to
FAILEDwith an error that says the query requires all referenced sources to be bounded.execution.runtime-modemust beBATCHorSTREAMING. CMF rejectsAUTOMATICwith a 400, in a statement and in an environment’s statement defaults.
Create a batch statement
A table backed by a Apache Kafka® topic is unbounded by default. To read it as a bounded
source, set the scan.bounded.mode table option, either with
CREATE TABLE or ALTER TABLE, or in a query hint as in the following
example. With latest-offset, the job reads each partition up to the
offset that was the latest when the job started. For the other values, see
Table options.
scan.bounded.mode sets only where the job stops reading. It starts reading
where the table’s scan.startup.mode says. To read a topic from its first
offset, whatever the table sets, also set scan.startup.mode to
earliest-offset in the hint.
The following statement copies all orders that exist when the job starts into
the orders_archive table:
{
"apiVersion": "cmf.confluent.io/v1",
"kind": "Statement",
"metadata": {
"name": "archive-orders"
},
"spec": {
"statement": "INSERT INTO orders_archive SELECT * FROM orders /*+ OPTIONS('scan.startup.mode'='earliest-offset', 'scan.bounded.mode'='latest-offset') */;",
"properties": {
"sql.current-catalog": "kafka-cat",
"sql.current-database": "kafka-db"
},
"flinkConfiguration": {
"execution.runtime-mode": "BATCH"
},
"computePoolName": "pool-flink-2"
}
}
Create the statement as described in Create Statements with Confluent Manager for Apache Flink. A
batch INSERT INTO statement or statement set does not need
execution.checkpointing.interval, because batch jobs do not checkpoint.
After CMF compiles the statement, status.traits.runtimeMode shows the
mode its job runs in, BATCH or STREAMING. Check this field rather than
the statement’s own flinkConfiguration, because the environment can
override it, as described in the next section.
When the job finishes, the statement moves to COMPLETED. For an
INSERT INTO statement or statement set, CMF then deletes the job’s Flink
resources, unless you turned off
INSERT statement resource cleanup. A batch
SELECT statement moves to COMPLETED when you read the last page of its
results. To run any batch statement again, create a new statement.
A batch SELECT statement buffers its results until you fetch them. The
buffer holds 4MiB by default, and when it is full, the job waits. For a
result larger than that, fetch the results while the statement runs, not
after it finishes. For details, see Manage Statements in Confluent Manager for Apache Flink.
How CMF decides the runtime mode
A statement’s runtime mode can come from two places:
The
flinkConfigurationof the statement.The environment’s statement defaults.
statementDefaults.interactiveapplies toSELECTstatements, andstatementDefaults.detachedapplies toINSERT INTOstatements and statement sets.
When both set execution.runtime-mode, the environment’s statement defaults
win. When neither sets it, the statement runs in streaming mode. The compute
pool’s Flink configuration and the environment’s computePoolDefaults do not
count: execution.runtime-mode set there has no effect on statements. A
SET 'execution.runtime-mode' = 'batch' statement fails with Statement
type not supported yet., so set the runtime mode in one of the two places
above.
This means that you can make every INSERT INTO statement and statement set
in an environment a batch statement by setting the runtime mode in the
detached statement defaults:
"statementDefaults": {
"detached": {
"flinkConfiguration": {
"execution.runtime-mode": "BATCH"
}
}
}
It also means that a statement that sets BATCH itself runs in streaming
mode when the environment’s defaults set STREAMING. This holds whether the
statement’s sources are bounded or not. A streaming INSERT INTO statement
or statement set needs a checkpoint interval. Without one, CMF rejects the
create request with a 400 and an error that says the environment’s defaults
take precedence over the statement’s BATCH.
CMF compiles a statement for the runtime mode it has when you create it, and
the statement keeps that mode. If you change execution.runtime-mode in an
environment’s statement defaults, CMF rejects the update with a 400 while any
statement in the environment would switch between batch and streaming mode,
and the error names those statements. Stopped statements block the update
too. Statements that are COMPLETED or FAILED do not. Delete the
statements the error names, and then update the environment.
How batch statements differ from streaming statements
Savepoints
Flink cannot take a savepoint of a batch job or start a batch job from one. CMF therefore rejects savepoint settings on batch statements:
Creating a batch statement with
spec.savepointSchedulefails with a 400. An update that adds a schedule fails with a 422.Creating or updating an environment whose
statementDefaults.detachedsets bothBATCHand asavepointSchedulefails with a 400.A statement that sets
BATCHin its ownflinkConfigurationdoes not inherit a savepoint schedule from the environment’s detached statement defaults.A request to create a savepoint for a batch statement fails with a 400.
An update that adds
spec.startFromSavepointto a batch statement fails with a 422.
Stop, resume, and rescale
Stopping a batch statement cancels its job immediately. A batch job cannot
continue from where it stopped, so starting it again would run the whole
query from the beginning and could write its output a second time. For a batch
INSERT INTO statement or statement set, CMF prevents this:
Resuming the statement after its job has run fails with a 400.
An update that would restart the running job, such as a change to
parallelism, fails with a 400. An update that does not touch the job, such as a label change, is accepted. If the environment’s defaults or the compute pool’s configuration changed since the job started, or CMF was upgraded or reconfigured, applying any update would restart the job, so a label change is rejected too.Stopping the statement is always accepted.
A statement that you create with "stopped": true has not run a job yet, so
you can start it once. To run the query again after its job has run, create a
new statement with another name, or delete the old statement first.
Task failures
Flink restarts a failed task only when a restart strategy is configured or
checkpointing is on, and batch jobs do not checkpoint. CMF therefore adds a
default restart strategy to batch INSERT INTO statements and statement
sets: exponential-delay with 10 attempts, which retries for about two
minutes before the statement fails. Operators can change this default, as
described in Configure the default restart strategy.
When Flink restarts the tasks of a batch job, the restarted tasks write their output again. A sink that is not transactional, such as an at-least-once Kafka sink, can then receive duplicate rows.
A batch SELECT statement gets no default restart strategy. Unless you
configure one, its job fails on the first task failure, such as a lost
TaskManager.
Known limitations
The following problems are known in CMF 2.5. Each has a workaround.
- Bounding a source in a window function
Flink does not accept a table hint on the
TABLEargument of a window function such asTUMBLE. The statement fails withSQL parse failed. Encountered "/*+". Instead, create a view in the environment catalog that reads the table with the hint, and run the window function over the view:CREATE VIEW orders_bounded AS SELECT * FROM `kafka-cat`.`kafka-db`.`orders` /*+ OPTIONS('scan.startup.mode'='earliest-offset', 'scan.bounded.mode'='latest-offset') */; SELECT window_start, window_end, COUNT(*) FROM TABLE( TUMBLE(TABLE orders_bounded, DESCRIPTOR(ts), INTERVAL '10' SECOND)) GROUP BY window_start, window_end;
SELECT *does not include the$rowtimecolumn of a Kafka table. If the window uses$rowtime, add it to the view’s select list.You can also set
scan.bounded.modeon the table itself withALTER TABLE, but then every statement that reads the table, including streaming statements, reads it as a bounded source.- Bounded-mode options are not checked
CMF does not check the
scan.bounded.*options. A missing or wrong option does not fail the statement at create:'scan.bounded.mode'='timestamp'withoutscan.bounded.timestamp-millisreads no rows, and the statement completes with an empty result.'scan.bounded.mode'='specific-offsets'with an offset beyond the end of a partition never finishes. Withoutscan.bounded.specific-offsets, the job fails after it starts.'scan.bounded.mode'='group-offsets'withoutproperties.group.idfails after the job starts.A misspelled option name fails with the error that the query requires bounded sources, and does not name the option.
Use
latest-offsetunless you need another end point, and set the option that each mode requires, as described in Table options.- Parallelism below the compute pool’s minimum
If the compute pool sets
execution.batch.adaptive.auto-parallelism.min-parallelismhigher than the statement’sparallelism, which defaults to 1, the job fails at start withMaximum parallelism should be greater than or equal to the minimum parallelism. Set the statement’sparallelismto at least the pool’s minimum.- Joins followed by
GROUP BYon the Default scheduler On a compute pool that sets
jobmanager.scheduler: default, a batch join followed by aGROUP BYon the join key fails at job start withCould not start the JobMaster. Do not setjobmanager.scheduleron compute pools that run batch statements, so that Flink uses its default adaptive batch scheduler.- Runtime filters
With
table.optimizer.runtime-filter.enabled: true, a batch join fails to compile, and the statement fails withUnable to serialize given ExecNodeGraph. Do not set this option.- The
NEST_LOOPjoin hint A batch query with a
/*+ NEST_LOOP(...) */hint compiles, but its job fails. Leave the join strategy to the planner, or use theSHUFFLE_HASHorSHUFFLE_MERGEhint.- Batch job recovery without high availability
If a compute pool sets
execution.batch.job-recovery.enabled: truebut nohigh-availability.storageDir, its JobManager fails at start, and every statement on the pool fails. The error appears only in the JobManager log. Sethigh-availability.storageDiron any pool that enables batch job recovery.- Reading Iceberg tables
A batch statement that reads an Iceberg table can start many TaskManagers for a small query, and can fail with
Insufficient number of network buffers. Addtable.exec.iceberg.infer-source-parallelism: falseto the statement’sflinkConfiguration.
Configure the default restart strategy
Operators set the restart strategy that CMF adds to batch INSERT INTO
statements and statement sets with the cmf.sql.batchRestartStrategy Helm
value.
Helm value |
Default |
Description |
|---|---|---|
|
|
Set to |
|
|
The Flink restart strategy options to add. Only |
CMF adds these options only when none of the following sets
restart-strategy.type: the statement, the environment’s statement
defaults, the compute pool, and the environment’s compute pool defaults. A
restart strategy that you set in any of these places is kept. CMF does not
store the options in the statement, so they do not appear in the statement’s
flinkConfiguration. They appear in the job configuration in the Flink web
UI.
To use a fixed delay between restarts instead, follow these steps:
Add the following to your Helm values file. Quote numbers, because the values must be strings.
cmf: sql: batchRestartStrategy: enabled: true flinkConfiguration: restart-strategy.type: fixed-delay restart-strategy.fixed-delay.attempts: "5" restart-strategy.fixed-delay.delay: "30 s"
Upgrade CMF:
helm upgrade --install cmf confluentinc/confluent-manager-for-apache-flink \ --version "~2.5.0" \ --namespace <namespace> \ -f values.yaml
Helm merges your flinkConfiguration with the default, so the default’s
restart-strategy.exponential-delay.attempts-before-reset-backoff option is
still added. Flink ignores it when restart-strategy.type is not
exponential-delay.
The chart’s schema rejects most invalid values when you run helm upgrade:
options that are not Flink restart strategy options, values that are not
strings, and a missing restart-strategy.type. If a value passes the schema
but Flink rejects it, CMF does not start, and its log names the option.
The change applies to batch statements that start after the upgrade. A batch job that is already running finishes with the restart strategy it started with.