Skip to main content

risingwave_common/config/
streaming.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::time::Duration;
16
17use risingwave_common_proc_macro::serde_prefix_all;
18
19use super::*;
20
21mod async_stack_trace;
22mod join_encoding_type;
23mod over_window;
24
25pub use async_stack_trace::*;
26pub use join_encoding_type::*;
27pub use over_window::*;
28
29/// The section `[streaming]` in `risingwave.toml`.
30#[serde_with::apply(Option => #[serde(with = "none_as_empty_string")])]
31#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
32pub struct StreamingConfig {
33    /// The maximum number of barriers in-flight in the compute nodes.
34    #[serde(default = "default::streaming::in_flight_barrier_nums")]
35    pub in_flight_barrier_nums: usize,
36
37    /// The thread number of the streaming actor runtime in the compute node. The default value is
38    /// decided by `tokio`.
39    #[serde(default)]
40    pub actor_runtime_worker_threads_num: Option<usize>,
41
42    /// Enable async stack tracing through `await-tree` for risectl.
43    #[serde(default = "default::streaming::async_stack_trace")]
44    pub async_stack_trace: AsyncStackTraceOption,
45
46    #[serde(default)]
47    #[config_doc(nested)]
48    pub developer: StreamingDeveloperConfig,
49
50    /// Max unique user stream errors per actor
51    #[serde(default = "default::streaming::unique_user_stream_errors")]
52    pub unique_user_stream_errors: usize,
53
54    /// Disable strict stream consistency checks.
55    #[serde(default = "default::streaming::unsafe_disable_strict_consistency")]
56    pub unsafe_disable_strict_consistency: bool,
57
58    #[serde(default, flatten)]
59    #[config_doc(omitted)]
60    pub unrecognized: Unrecognized<Self>,
61}
62
63/// The subsections `[streaming.developer]`.
64///
65/// It is put at [`StreamingConfig::developer`].
66#[serde_prefix_all("stream_", mode = "alias")]
67#[serde_with::apply(Option => #[serde(with = "none_as_empty_string")])]
68#[derive(Clone, Debug, Serialize, Deserialize, DefaultFromSerde, ConfigDoc)]
69pub struct StreamingDeveloperConfig {
70    /// Set to true to enable per-executor row count metrics. This will produce a lot of timeseries
71    /// and might affect the prometheus performance. If you only need actor input and output
72    /// rows data, see `stream_actor_in_record_cnt` and `stream_actor_out_record_cnt` instead.
73    #[serde(default = "default::developer::stream_enable_executor_row_count")]
74    pub enable_executor_row_count: bool,
75
76    /// The capacity of the chunks in the channel that connects between `ConnectorSource` and
77    /// `SourceExecutor`.
78    #[serde(default = "default::developer::connector_message_buffer_size")]
79    pub connector_message_buffer_size: usize,
80
81    /// Limit number of the cached entries in an extreme aggregation call.
82    #[serde(default = "default::developer::unsafe_stream_extreme_cache_size")]
83    pub unsafe_extreme_cache_size: usize,
84
85    /// Minimum cache size for TopN cache per group key.
86    #[serde(default = "default::developer::stream_topn_cache_min_capacity")]
87    pub topn_cache_min_capacity: usize,
88
89    /// The maximum size of the chunk produced by executor at a time.
90    #[serde(default = "default::developer::stream_chunk_size")]
91    pub chunk_size: usize,
92
93    /// The initial permits that a channel holds, i.e., the maximum row count can be buffered in
94    /// the channel.
95    #[serde(default = "default::developer::stream_exchange_initial_permits")]
96    pub exchange_initial_permits: usize,
97
98    /// The permits that are batched to add back, for reducing the backward `AddPermits` messages
99    /// in remote exchange.
100    #[serde(default = "default::developer::stream_exchange_batched_permits")]
101    pub exchange_batched_permits: usize,
102
103    /// The maximum number of concurrent barriers in an exchange channel.
104    #[serde(default = "default::developer::stream_exchange_concurrent_barriers")]
105    pub exchange_concurrent_barriers: usize,
106
107    /// The concurrency for dispatching messages to different downstream jobs.
108    ///
109    /// - `1` means no concurrency, i.e., dispatch messages to downstream jobs one by one.
110    /// - `0` means unlimited concurrency.
111    #[serde(default = "default::developer::stream_exchange_concurrent_dispatchers")]
112    pub exchange_concurrent_dispatchers: usize,
113
114    /// The maximum number of chunks that `ProjectExecutor` evaluates concurrently.
115    ///
116    /// - `1` means no chunk-level concurrency.
117    /// - `0` means unlimited concurrency.
118    #[serde(default = "default::developer::stream_project_expr_concurrency")]
119    pub project_expr_concurrency: usize,
120
121    /// The maximum number of in-flight projection evaluation requests in `ProjectExecutor`.
122    ///
123    /// An in-flight request has started projection evaluation but has not finished yet. A finished
124    /// request no longer counts against this limit even if its result is still waiting to be emitted
125    /// in order.
126    ///
127    /// - `0` means unlimited in-flight requests.
128    #[serde(default = "default::developer::stream_project_expr_inflight_request_concurrency")]
129    pub project_expr_inflight_request_concurrency: usize,
130
131    /// The initial permits for a dml channel, i.e., the maximum row count can be buffered in
132    /// the channel.
133    #[serde(default = "default::developer::stream_dml_channel_initial_permits")]
134    pub dml_channel_initial_permits: usize,
135
136    /// The max heap size of dirty groups of `HashAggExecutor`.
137    #[serde(default = "default::developer::stream_hash_agg_max_dirty_groups_heap_size")]
138    pub hash_agg_max_dirty_groups_heap_size: usize,
139
140    #[serde(default = "default::developer::memory_controller_threshold_aggressive")]
141    pub memory_controller_threshold_aggressive: f64,
142
143    #[serde(default = "default::developer::memory_controller_threshold_graceful")]
144    pub memory_controller_threshold_graceful: f64,
145
146    #[serde(default = "default::developer::memory_controller_threshold_stable")]
147    pub memory_controller_threshold_stable: f64,
148
149    #[serde(default = "default::developer::memory_controller_eviction_factor_aggressive")]
150    pub memory_controller_eviction_factor_aggressive: f64,
151
152    #[serde(default = "default::developer::memory_controller_eviction_factor_graceful")]
153    pub memory_controller_eviction_factor_graceful: f64,
154
155    #[serde(default = "default::developer::memory_controller_eviction_factor_stable")]
156    pub memory_controller_eviction_factor_stable: f64,
157
158    #[serde(default = "default::developer::memory_controller_update_interval_ms")]
159    pub memory_controller_update_interval_ms: usize,
160
161    #[serde(default = "default::developer::memory_controller_sequence_tls_step")]
162    pub memory_controller_sequence_tls_step: u64,
163
164    #[serde(default = "default::developer::memory_controller_sequence_tls_lag")]
165    pub memory_controller_sequence_tls_lag: u64,
166
167    #[serde(default = "default::developer::stream_enable_arrangement_backfill")]
168    /// Deprecated and ignored for new streaming jobs. Arrangement backfill is always used as the
169    /// fallback backfill type.
170    #[deprecated(
171        note = "Deprecated and ignored for new streaming jobs. Arrangement backfill is always used as the fallback backfill type."
172    )]
173    pub enable_arrangement_backfill: bool,
174
175    #[serde(default = "default::developer::stream_enable_snapshot_backfill")]
176    /// Enable snapshot backfill
177    /// If false, the snapshot backfill will be disabled,
178    /// even if session variable set.
179    /// If true, it's decided by session variable `streaming_use_snapshot_backfill` (default true)
180    pub enable_snapshot_backfill: bool,
181
182    #[serde(default = "default::developer::stream_high_join_amplification_threshold")]
183    /// If number of hash join matches exceeds this threshold number,
184    /// it will be logged.
185    pub high_join_amplification_threshold: usize,
186
187    #[serde(default = "default::developer::stream_high_gap_fill_amplification_threshold")]
188    /// If number of rows generated by gap fill between two anchor rows exceeds this threshold
189    /// number, it will be logged.
190    pub high_gap_fill_amplification_threshold: usize,
191
192    /// Actor tokio metrics is enabled if `enable_actor_tokio_metrics` is set or metrics level >= Debug.
193    #[serde(default = "default::developer::enable_actor_tokio_metrics")]
194    pub enable_actor_tokio_metrics: bool,
195
196    /// The number of the connections for streaming remote exchange between two nodes.
197    /// If not specified, the value of `server.connection_pool_size` will be used.
198    #[serde(default = "default::developer::stream_exchange_connection_pool_size")]
199    pub(super) exchange_connection_pool_size: Option<u16>,
200
201    /// A flag to allow disabling the auto schema change handling
202    #[serde(default = "default::developer::stream_enable_auto_schema_change")]
203    pub enable_auto_schema_change: bool,
204
205    #[serde(default = "default::developer::enable_shared_source")]
206    /// Enable shared source
207    /// If false, the shared source will be disabled,
208    /// even if session variable set.
209    /// If true, it's decided by session variable `streaming_use_shared_source` (default true)
210    pub enable_shared_source: bool,
211
212    #[serde(default = "default::developer::switch_jdbc_pg_to_native")]
213    /// When true, all jdbc sinks with connector='jdbc' and jdbc.url="jdbc:postgresql://..."
214    /// will be switched from jdbc postgresql sinks to rust native (connector='postgres') sinks.
215    pub switch_jdbc_pg_to_native: bool,
216
217    /// The maximum number of consecutive barriers allowed in a message when sent between actors.
218    #[serde(default = "default::developer::stream_max_barrier_batch_size")]
219    pub max_barrier_batch_size: u32,
220
221    /// Configure the system-wide cache row cardinality of hash join.
222    /// For example, if this is set to 1000, it means we can have at most 1000 rows in cache.
223    #[serde(default = "default::developer::streaming_hash_join_entry_state_max_rows")]
224    pub hash_join_entry_state_max_rows: usize,
225
226    /// Number of processed rows between periodic join cache evictions.
227    /// Values smaller than 1 will be clamped to 1 by the executor.
228    #[serde(default = "default::developer::streaming_join_hash_map_evict_interval_rows")]
229    pub join_hash_map_evict_interval_rows: u32,
230
231    #[serde(default = "default::developer::streaming_now_progress_ratio")]
232    pub now_progress_ratio: Option<f32>,
233
234    /// Enable / Disable profiling stats used by `EXPLAIN ANALYZE`
235    #[serde(default = "default::developer::enable_explain_analyze_stats")]
236    pub enable_explain_analyze_stats: bool,
237
238    #[serde(default)]
239    pub compute_client_config: RpcClientConfig,
240
241    /// The interval in seconds to rebuild snapshot iterators during snapshot backfill.
242    #[serde(default = "default::developer::stream_snapshot_iter_rebuild_interval_secs")]
243    pub snapshot_iter_rebuild_interval_secs: u64,
244
245    /// `IcebergListExecutor`: The interval in seconds for Iceberg source to list new files.
246    #[serde(default = "default::developer::iceberg_list_interval_sec")]
247    pub iceberg_list_interval_sec: u64,
248
249    /// `IcebergFetchExecutor`: The number of files the executor will fetch concurrently in a batch.
250    #[serde(default = "default::developer::iceberg_fetch_batch_size")]
251    pub iceberg_fetch_batch_size: u64,
252
253    /// `IcebergSink`: The size of the cache for positional delete in the sink.
254    #[serde(default = "default::developer::iceberg_sink_positional_delete_cache_size")]
255    pub iceberg_sink_positional_delete_cache_size: usize,
256
257    /// `IcebergSink`: The maximum number of rows in a row group when writing Parquet files.
258    #[serde(default = "default::developer::iceberg_sink_write_parquet_max_row_group_rows")]
259    pub iceberg_sink_write_parquet_max_row_group_rows: usize,
260
261    /// When enabled, materialized views using default `NoCheck` conflict behavior will be forced
262    /// to use `Overwrite`. Useful to avoid propagating inconsistent changelog downstream.
263    #[serde(default = "default::developer::materialize_force_overwrite_on_no_check")]
264    pub materialize_force_overwrite_on_no_check: bool,
265
266    /// Whether by default enable preloading all rows in memory for state table.
267    /// If true, all capable state tables will preload its state to memory
268    #[serde(default = "default::streaming::default_enable_mem_preload_state_table")]
269    pub default_enable_mem_preload_state_table: bool,
270
271    /// The list of state table ids to *enable* preloading all rows in memory for state table.
272    /// Only takes effect when `default_enable_mem_preload_state_table` is false.
273    #[serde(default)]
274    pub mem_preload_state_table_ids_whitelist: Vec<u32>,
275
276    /// The list of state table ids to *disable* preloading all rows in memory for state table.
277    /// Only takes effect when `default_enable_mem_preload_state_table` is true.
278    #[serde(default)]
279    pub mem_preload_state_table_ids_blacklist: Vec<u32>,
280
281    /// Eliminate unnecessary updates aggressively, even if it impacts performance. Enable this
282    /// only if it's confirmed that no-op updates are causing significant streaming amplification.
283    #[serde(default)]
284    pub aggressive_noop_update_elimination: bool,
285
286    /// The interval in seconds for the refresh scheduler to check and trigger scheduled refreshes.
287    #[serde(default = "default::developer::refresh_scheduler_interval_sec")]
288    pub refresh_scheduler_interval_sec: u64,
289
290    /// Determine which encoding will be used to encode join rows in operator cache.
291    #[serde(default)]
292    pub join_encoding_type: JoinEncodingType,
293
294    /// The timeout for reading from the buffer of the sync log store on barrier.
295    /// Every epoch we will attempt to read the full buffer of the sync log store.
296    /// If we hit the timeout, we will stop reading and continue.
297    #[serde(default = "default::developer::sync_log_store_pause_duration_ms")]
298    pub sync_log_store_pause_duration_ms: usize,
299
300    /// The max buffer size for sync logstore, before we start flushing.
301    #[serde(default = "default::developer::sync_log_store_buffer_size")]
302    pub sync_log_store_buffer_size: usize,
303
304    /// Disable the optimized dispatcher path for sync log store.
305    #[serde(default = "default::developer::disable_sync_log_store_dispatcher")]
306    pub disable_sync_log_store_dispatcher: bool,
307
308    /// Cache policy for partition cache in streaming over window.
309    /// Can be `full`, `recent`, `recent_first_n` or `recent_last_n`.
310    #[serde(default)]
311    pub over_window_cache_policy: OverWindowCachePolicy,
312
313    /// When enabled, vnode stats pruning is applied in production.
314    /// When disabled, vnode stats pruning is in dry-run mode: we still maintain vnode stats
315    /// and verify that pruning would be correct, but we don't actually use the pruning
316    /// results — we still use cache and storage to fulfill the read. This is useful for
317    /// validating the correctness of vnode stats pruning before enabling it in production.
318    #[serde(default = "default::developer::enable_state_table_vnode_stats_pruning")]
319    pub enable_state_table_vnode_stats_pruning: bool,
320
321    /// Whether `MaterializeExecutor` enables vnode key stats for its state table.
322    #[serde(default = "default::developer::enable_vnode_key_stats_for_materialize")]
323    pub enable_vnode_key_stats_for_materialize: bool,
324
325    /// The maximum number of kv log store readers that can concurrently read historical data
326    /// (i.e., from the state store) during initialization. A reader is considered "initializing"
327    /// until it has read at least one row from the historical stream or the stream returns empty.
328    /// Set to 0 to disable the limit (unlimited concurrency).
329    #[serde(default = "default::developer::max_concurrent_kv_log_store_historical_read")]
330    pub max_concurrent_kv_log_store_historical_read: usize,
331
332    #[serde(default, flatten)]
333    #[serde_prefix_all(skip)]
334    #[config_doc(omitted)]
335    pub unrecognized: Unrecognized<Self>,
336}
337
338impl StreamingDeveloperConfig {
339    pub fn snapshot_iter_rebuild_interval(&self) -> Duration {
340        let rebuild_interval = if self.snapshot_iter_rebuild_interval_secs < 10 {
341            tracing::warn!(
342                "too small rebuild_interval {} second. rewrite to 10",
343                self.snapshot_iter_rebuild_interval_secs
344            );
345            10
346        } else {
347            self.snapshot_iter_rebuild_interval_secs
348        };
349        Duration::from_secs(rebuild_interval)
350    }
351}
352
353impl StreamingConfig {
354    /// Returns the dot-separated keys of all unrecognized fields, including those in `developer` section.
355    pub fn unrecognized_keys(&self) -> impl Iterator<Item = String> {
356        std::iter::from_coroutine(
357            #[coroutine]
358            || {
359                for k in self.unrecognized.inner().keys() {
360                    yield format!("streaming.{k}");
361                }
362                for k in self.developer.unrecognized.inner().keys() {
363                    yield format!("streaming.developer.{k}");
364                }
365            },
366        )
367    }
368}
369
370pub mod default {
371    pub use crate::config::default::developer;
372
373    pub mod streaming {
374        use tracing::info;
375
376        use crate::config::AsyncStackTraceOption;
377        use crate::util::env_var::env_var_is_true;
378
379        pub fn in_flight_barrier_nums() -> usize {
380            // quick fix
381            // TODO: remove this limitation from code
382            10000
383        }
384
385        pub fn async_stack_trace() -> AsyncStackTraceOption {
386            AsyncStackTraceOption::default()
387        }
388
389        pub fn unique_user_stream_errors() -> usize {
390            10
391        }
392
393        pub fn unsafe_disable_strict_consistency() -> bool {
394            false
395        }
396
397        pub fn default_enable_mem_preload_state_table() -> bool {
398            if env_var_is_true("DEFAULT_ENABLE_MEM_PRELOAD_STATE_TABLE") {
399                info!("enabled mem_preload_state_table globally by env var");
400                true
401            } else {
402                false
403            }
404        }
405    }
406}