Skip to content

[flink] Support bounded streaming read for Fluss source - #4022

Open
naivedogger wants to merge 9 commits into
apache:mainfrom
naivedogger:feature/flink-bounded-streaming-source
Open

[flink] Support bounded streaming read for Fluss source#4022
naivedogger wants to merge 9 commits into
apache:mainfrom
naivedogger:feature/flink-bounded-streaming-source

Conversation

@naivedogger

Copy link
Copy Markdown
Contributor

Purpose

Linked issue: close #4021

Brief change log

Tests

API and Format

Documentation

Similar to the Kafka connector's bounded read, a streaming job can now
read from a given starting position up to a given stopping position and
then finish, which is useful for replaying a bounded time range of the
log, backfilling and archiving.

- FlinkSource reports BOUNDED when stopping offsets are supplied, and
  passes them through createEnumerator/restoreEnumerator.
- FlinkSourceEnumerator treats a streaming read with stopping offsets as
  bounded: one-time partition discovery and NoMoreSplits signaling, so
  the job finishes once all splits reach their stopping offsets.
- scan.bounded.mode is supported for log tables, the changelog of
  primary key tables (earliest/latest/timestamp startup mode) and the
  $changelog/$binlog virtual tables; the full startup mode of primary
  key tables and the datalake union read are rejected explicitly.
- FlussSourceBuilder#setBounded(OffsetsInitializer) enables bounded
  streaming reads in the DataStream API.
@naivedogger

Copy link
Copy Markdown
Contributor Author

cc @loserwang1024

@loserwang1024 loserwang1024 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have left some comment. maybe we can keep the same behavior with kafka to simplify the model.

"Only OffsetsInitializer.latest() and OffsetsInitializer.timestamp(...) are "
+ "supported as stopping offsets, but was %s.",
checkedStoppingOffsetsInitializer.getClass().getName());
this.stoppingOffsetsInitializer = checkedStoppingOffsetsInitializer;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please set private boolean bounded; as true, and add comment about this is place the org.apache.fluss.flink.source.FlussSourceBuilder#setBounded and compatility. And In org.apache.fluss.flink.source.FlussSourceBuilder#setBounded, set stoppingOffsetsInitializer as OffsetsInitializer.latest().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I kept bounded as the legacy batch-mode flag because it is used as streaming = !bounded. Setting it in the parameterized overload would incorrectly turn bounded streaming into batch execution.

The no-argument setBounded() now sets bounded = true, Boundedness.BOUNDED, and OffsetsInitializer.latest(), with a compatibility comment added.

public static OffsetsInitializer toStoppingOffsetsInitializer(BoundedOptions boundedOptions) {
switch (boundedOptions.boundedMode) {
case UNBOUNDED:
return null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not return null, please reference kafka:

Image

In DynamicKafkaSourceBuilder, if boundedOptions.boundedMode is UNBOUNDED, will use the default NoStoppingOffsetsInitializer:

 DynamicKafkaSourceBuilder() {
        this.kafkaStreamSubscriber = null;
        this.kafkaMetadataService = null;
        this.deserializationSchema = null;
        this.startingOffsetsInitializer = OffsetsInitializer.earliest();
        this.stoppingOffsetsInitializer = new NoStoppingOffsetsInitializer();
        this.boundedness = Boundedness.CONTINUOUS_UNBOUNDED;
        this.props = new Properties();
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Unbounded reads now use NoStoppingOffsetsInitializer, so the stopping initializer is always non-null. Batch reads still default to OffsetsInitializer.latest().

* user-supplied stopping offsets. A bounded read only performs a one-time partition discovery,
* since partitions created after startup are outside the bounded range captured at startup.
*/
private final boolean bounded;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can use org.apache.flink.api.connector.source.Boundedness as what kafka connector does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Boundedness is now propagated explicitly from the builder or table source to FlinkSource and FlinkSourceEnumerator.

streaming ? new NoStoppingOffsetsInitializer() : OffsetsInitializer.latest();
stoppingOffsetsInitializer != null
? stoppingOffsetsInitializer
: (streaming

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can done in FlussSourceBuilder.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. The stopping initializer is now resolved before constructing the enumerator, and the enumerator requires a non-null value.

this.splitPerAssignmentBatchSize = splitPerAssignmentBatchSize;
this.initialDiscoveryFinished = initialDiscoveryFinished;
this.unassignedSplits = new ArrayList<>(unassignedSplits);
this.noMoreNewSplits = initialDiscoveryFinished && isBoundedStreamingRead();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrent, we can see what kafka says:

    // This flag will be marked as true if periodically partition discovery is disabled AND the
    // initializing partition discovery has finished.
    private boolean noMoreNewPartitionSplits = false;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. I removed the constructor initialization based on restored state. noMoreNewSplits is now set only after initialization finishes when periodic partition discovery is disabled.

}

if (scanPartitionDiscoveryIntervalMs > 0) {
if (restoredBoundedPartitionSet) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to make the thread more complicate, when restart read new partition is also no pronlem.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. I removed the bounded-restore special case. A restored bounded source now follows the normal one-time partition discovery path.

return;
}
if (t != null) {
if (isBoundedStreamingRead()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dito

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. I removed the bounded-specific partition discovery failure handling and kept the existing generic behavior.

@naivedogger

Copy link
Copy Markdown
Contributor Author

Thanks @loserwang1024 for the detailed review! I’ve addressed the comments and aligned the implementation more closely with Kafka’s model. Please take another look when convenient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[flink] Support bounded streaming read for Fluss source

2 participants