From 31071c6dabe79581f8ac77c3236e059da1b40067 Mon Sep 17 00:00:00 2001 From: Eric Fu Date: Thu, 17 Aug 2023 23:16:45 +0800 Subject: [PATCH 1/4] first version --- rfcs/0061-reusable-source.md | 80 ++++++++++++++++++ .../0061-reusable-source/reusable-source.png | Bin 0 -> 89002 bytes 2 files changed, 80 insertions(+) create mode 100644 rfcs/0061-reusable-source.md create mode 100644 rfcs/images/0061-reusable-source/reusable-source.png diff --git a/rfcs/0061-reusable-source.md b/rfcs/0061-reusable-source.md new file mode 100644 index 00000000..dea25894 --- /dev/null +++ b/rfcs/0061-reusable-source.md @@ -0,0 +1,80 @@ +--- +feature: Reusable Source Executor +authors: + - "Eric Fu" +start_date: "2023/08/17" +--- + +# Reusable Source Executor + + +## Motivation + +Conceptionally, a source is far different from a table or sink in terms of whether it is **instantiated**. A source defined by a `create source` statement is not an instance but only a set of metadata stored in the catalog, until it's been referenced by a meterialized view, upon which time a `SourceExecutor` is instantiated. + +As a result, when creating multiple materialized views on top of one source, the `SourceExecutor` is not reused between them. It leads to multiple times of resource ultilization and multiple consuming offsets, metrics, etc. Furthermore, it will become a bug if the source definistion uses some exclusive property, such as the consumer group of Kafka source. + +## Design + +Recall that most source has more or less histrical data. For message brokers including Kafka, Pulsar, Kinesis, etc, this can be configured with option `scan.startup.mode`. When `scan.startup.mode` is not `latest`, the consumer must read all the historical data before consuming any new events. This process is implicitly done by the client library, and RisingWave is not aware of it. + +Let's assume that the Kafka client library is stupid and RisingWave needs to read the historical data by itself. Then, it turns out this procedure is quite similar to the backfilling procedure of tables. Recall that when a new materialized view is created, we introduce a `BackfillExecutor` to read the historical data. Here we can solve the problem with exactly the same idea by dividing it into 2 phases: 1) backfill and 2) consume new events. + +![](images/0061-reusable-source/reusable-source.png) + +Here, + +- `KafkaSourceExecutor` is created on executing `CREATE SOURCE` statement, although a trivial optimization is doing nothing when there is no downstream operator attached. +- `KafkaBackfillExecutor` is created along with the `CREATE MATERIALIZED VIEW` statement. Each MV has its own `KafkaBackfillExecutor` respectively. + +Obviously, for a source without histrical data or message broker source `scan.startup.mode = latest`, the `BackfillExecutor` can be omitted. + +### Implementation for Message Brokers + +Events from Kafka should be processed according to their sequence in partition, no matter for historical events or new incomming events. + +So how to combine the backfill data with incoming data without duplicated or missing events? + +Since everything happen inside the `BackfillExecutor`, the implementation is not difficult. Here is the pesedo-code. + +```rust +let source_stream = the stream from upstreaming SourceExecutor +let backfill_stream = read_from_mq(scan_startup_mode) + +// In fact, these should be per kafka partition +let backfill_offset = 0; +let backfill_completed = false; + +next_event = select! { + biased; + e = source_stream.next() => { + if backfill_completed { + yield e; + } else if e.offset > backfill_offset { + // do nothing. ignore e + } else { + // the progress catched up. backfilling is completed + backfill_stream.close(); + backfill_completed = true; + yield e; + } + } + e = backfill_stream.next() => { + assert!(!backfill_completed); + backfill_offset = e.offset; + yield e; + } +} +``` + +### Implementation for File Source + +Naturally, the file source doesn't have any guarentee on ordering. This actually makes it more difficult to do backfilling because it become more challenging to record which part of data has been consumed. + +A intuitive approach is to take a snapshot of current progress of the `SourceExecutor`, which is a list of `file_name:offset`. Then, the `BackfillExecutor` scans files according to this list. Meanwhile, all of the new incoming events will be streamed, because the event order doesn't matter. + +Note that the snapshot i.e. the list of `file_name:offset` for backfilling is large it might need to be persisted as a state in order to achieve fault-tolerance. This is why I say it is more difficult. + +### Batch Scan (Kafka-only) + +Batch scan is exactly the same as the backfilling process. Hopefully we should reuse the implementation as much as possible. diff --git a/rfcs/images/0061-reusable-source/reusable-source.png b/rfcs/images/0061-reusable-source/reusable-source.png new file mode 100644 index 0000000000000000000000000000000000000000..0f111bfb6b063671d8de9da6d2163eee07a327e3 GIT binary patch literal 89002 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

3up7K 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 W&&UU-mwRpjKRVj_7mCi?-un;u{DIE^ literal 0 HcmV?d00001 From 6ad291a6b520fd7ce65f1062a429a73af6c230b5 Mon Sep 17 00:00:00 2001 From: Eric Fu Date: Fri, 18 Aug 2023 11:12:18 +0800 Subject: [PATCH 2/4] refine --- rfcs/0061-reusable-source.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/rfcs/0061-reusable-source.md b/rfcs/0061-reusable-source.md index dea25894..93eef3f5 100644 --- a/rfcs/0061-reusable-source.md +++ b/rfcs/0061-reusable-source.md @@ -10,15 +10,15 @@ start_date: "2023/08/17" ## Motivation -Conceptionally, a source is far different from a table or sink in terms of whether it is **instantiated**. A source defined by a `create source` statement is not an instance but only a set of metadata stored in the catalog, until it's been referenced by a meterialized view, upon which time a `SourceExecutor` is instantiated. +Conceptually, a source is very different from a table or a sink in terms of whether it is instantiated. A source defined by a `CREATE SOURCE` statement is not an instance, it's just a set of metadata stored in the catalog until it's referenced by a materialized view, at which point a `SourceExecutor` is instantiated. -As a result, when creating multiple materialized views on top of one source, the `SourceExecutor` is not reused between them. It leads to multiple times of resource ultilization and multiple consuming offsets, metrics, etc. Furthermore, it will become a bug if the source definistion uses some exclusive property, such as the consumer group of Kafka source. +As a result, when creating multiple materialized views on top of one source, the `SourceExecutor` is not reused between them. It leads to multiple times of resource utilization and multiple consuming offsets, metrics, etc. Furthermore, it becomes a bug if the source definition uses some exclusive property, such as the consumer group of Kafka source. ## Design -Recall that most source has more or less histrical data. For message brokers including Kafka, Pulsar, Kinesis, etc, this can be configured with option `scan.startup.mode`. When `scan.startup.mode` is not `latest`, the consumer must read all the historical data before consuming any new events. This process is implicitly done by the client library, and RisingWave is not aware of it. +Recall that most source has more or less historical data. For message brokers including Kafka, Pulsar, Kinesis, etc, this can be configured with option `scan.startup.mode`. When `scan.startup.mode` is not set to `latest`, the consumer must read the historical data before consuming any new events. This process is implicitly done by the client library, and RisingWave is not aware of it. -Let's assume that the Kafka client library is stupid and RisingWave needs to read the historical data by itself. Then, it turns out this procedure is quite similar to the backfilling procedure of tables. Recall that when a new materialized view is created, we introduce a `BackfillExecutor` to read the historical data. Here we can solve the problem with exactly the same idea by dividing it into 2 phases: 1) backfill and 2) consume new events. +Let's assume that the Kafka client library is stupid and RisingWave needs to read the historical data by itself. Then, it turns out this procedure is quite similar to the backfilling procedure of tables. Recall that when a new materialized view is created, we introduce a `BackfillExecutor` to read the historical data. Here we can solve the problem with the same idea by dividing it into 2 phases: 1) backfill and 2) consume new events. ![](images/0061-reusable-source/reusable-source.png) @@ -27,19 +27,21 @@ Here, - `KafkaSourceExecutor` is created on executing `CREATE SOURCE` statement, although a trivial optimization is doing nothing when there is no downstream operator attached. - `KafkaBackfillExecutor` is created along with the `CREATE MATERIALIZED VIEW` statement. Each MV has its own `KafkaBackfillExecutor` respectively. -Obviously, for a source without histrical data or message broker source `scan.startup.mode = latest`, the `BackfillExecutor` can be omitted. +Obviously, for a source without historical data or message broker source `scan.startup.mode = latest`, the `BackfillExecutor` can be omitted. + +Note that our design only applies to sources, excluding the tables with connectors, which are already instantiated and shared between all materialized views. By the way, [RFC: CDC Source with Backfill](https://github.com/risingwavelabs/rfcs/pull/63) takes a similar idea by introducing a dedicated `CdcBackfillExecutor` operator. ### Implementation for Message Brokers -Events from Kafka should be processed according to their sequence in partition, no matter for historical events or new incomming events. +Events from Kafka should be processed according to their sequence in partition, no matter for historical events or new incoming events. -So how to combine the backfill data with incoming data without duplicated or missing events? +So how to combine the backfill data with incoming data without duplicating or missing events? -Since everything happen inside the `BackfillExecutor`, the implementation is not difficult. Here is the pesedo-code. +Since everything happens inside the `BackfillExecutor`, the implementation is not difficult. Here is the pseudo-code. ```rust -let source_stream = the stream from upstreaming SourceExecutor -let backfill_stream = read_from_mq(scan_startup_mode) +let source_stream = the stream from upstream SourceExecutor i.e. new events +let backfill_stream = read from message brokers with user-defined scan_startup_mode) i.e. historical events // In fact, these should be per kafka partition let backfill_offset = 0; @@ -69,12 +71,13 @@ next_event = select! { ### Implementation for File Source -Naturally, the file source doesn't have any guarentee on ordering. This actually makes it more difficult to do backfilling because it become more challenging to record which part of data has been consumed. +Naturally, the file source doesn't have any guarantee on ordering. This makes it more difficult to do backfilling because it becomes more challenging to record which part of the data has been consumed. -A intuitive approach is to take a snapshot of current progress of the `SourceExecutor`, which is a list of `file_name:offset`. Then, the `BackfillExecutor` scans files according to this list. Meanwhile, all of the new incoming events will be streamed, because the event order doesn't matter. +An intuitive approach is to take a snapshot of the current progress of the `SourceExecutor`, which is a list of `file_name:offset`. Then, the `BackfillExecutor` scans files according to this list. Meanwhile, all of the new incoming events will also be streamed, because the event order doesn't matter. -Note that the snapshot i.e. the list of `file_name:offset` for backfilling is large it might need to be persisted as a state in order to achieve fault-tolerance. This is why I say it is more difficult. +Note that the snapshot i.e. the list of `file_name:offset` for backfilling is large it might need to be persisted as a state to achieve fault tolerance. This is why I say it is more difficult. ### Batch Scan (Kafka-only) -Batch scan is exactly the same as the backfilling process. Hopefully we should reuse the implementation as much as possible. +The batch scan operation is actually the same as the backfilling process - it reads all existing data and ignores any new incoming events. Hopefully, we should reuse the implementation as much as possible. + From 3a043a62a1429e1211dd3dec454254025a216a44 Mon Sep 17 00:00:00 2001 From: Eric Fu Date: Tue, 22 Aug 2023 12:23:10 +0800 Subject: [PATCH 3/4] fix RFC number --- ...1-reusable-source.md => 0072-reusable-source.md} | 0 .../reusable-source.png | Bin 2 files changed, 0 insertions(+), 0 deletions(-) rename rfcs/{0061-reusable-source.md => 0072-reusable-source.md} (100%) rename rfcs/images/{0061-reusable-source => 0072-reusable-source}/reusable-source.png (100%) diff --git a/rfcs/0061-reusable-source.md b/rfcs/0072-reusable-source.md similarity index 100% rename from rfcs/0061-reusable-source.md rename to rfcs/0072-reusable-source.md diff --git a/rfcs/images/0061-reusable-source/reusable-source.png b/rfcs/images/0072-reusable-source/reusable-source.png similarity index 100% rename from rfcs/images/0061-reusable-source/reusable-source.png rename to rfcs/images/0072-reusable-source/reusable-source.png From 459483e0939ada24b92f942fa1cb2fef01dc7683 Mon Sep 17 00:00:00 2001 From: xxchan Date: Thu, 9 Nov 2023 17:06:22 +0800 Subject: [PATCH 4/4] fix image --- rfcs/0072-reusable-source.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0072-reusable-source.md b/rfcs/0072-reusable-source.md index 93eef3f5..d574bcaf 100644 --- a/rfcs/0072-reusable-source.md +++ b/rfcs/0072-reusable-source.md @@ -20,7 +20,7 @@ Recall that most source has more or less historical data. For message brokers in Let's assume that the Kafka client library is stupid and RisingWave needs to read the historical data by itself. Then, it turns out this procedure is quite similar to the backfilling procedure of tables. Recall that when a new materialized view is created, we introduce a `BackfillExecutor` to read the historical data. Here we can solve the problem with the same idea by dividing it into 2 phases: 1) backfill and 2) consume new events. -![](images/0061-reusable-source/reusable-source.png) +![](images/0072-reusable-source/reusable-source.png) Here,