risingwave_meta/manager/
env.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::ops::Deref;
16use std::path::PathBuf;
17use std::sync::Arc;
18
19use anyhow::Context;
20use risingwave_common::config::{
21    CompactionConfig, DefaultParallelism, ObjectStoreConfig, RpcClientConfig,
22};
23use risingwave_common::session_config::SessionConfig;
24use risingwave_common::system_param::reader::SystemParamsReader;
25use risingwave_common::{bail, system_param};
26use risingwave_meta_model::prelude::Cluster;
27use risingwave_pb::meta::SystemParams;
28use risingwave_rpc_client::{
29    FrontendClientPool, FrontendClientPoolRef, StreamClientPool, StreamClientPoolRef,
30};
31use sea_orm::EntityTrait;
32
33use crate::MetaResult;
34use crate::controller::SqlMetaStore;
35use crate::controller::id::{
36    IdGeneratorManager as SqlIdGeneratorManager, IdGeneratorManagerRef as SqlIdGeneratorManagerRef,
37};
38use crate::controller::session_params::{SessionParamsController, SessionParamsControllerRef};
39use crate::controller::system_param::{SystemParamsController, SystemParamsControllerRef};
40use crate::hummock::sequence::SequenceGenerator;
41use crate::manager::event_log::{EventLogManagerRef, start_event_log_manager};
42use crate::manager::{IdleManager, IdleManagerRef, NotificationManager, NotificationManagerRef};
43use crate::model::ClusterId;
44
45/// [`MetaSrvEnv`] is the global environment in Meta service. The instance will be shared by all
46/// kind of managers inside Meta.
47#[derive(Clone)]
48pub struct MetaSrvEnv {
49    /// id generator manager.
50    id_gen_manager_impl: SqlIdGeneratorManagerRef,
51
52    /// system param manager.
53    system_param_manager_impl: SystemParamsControllerRef,
54
55    /// session param manager.
56    session_param_manager_impl: SessionParamsControllerRef,
57
58    /// meta store.
59    meta_store_impl: SqlMetaStore,
60
61    /// notification manager.
62    notification_manager: NotificationManagerRef,
63
64    /// stream client pool memorization.
65    stream_client_pool: StreamClientPoolRef,
66
67    /// rpc client pool for frontend nodes.
68    frontend_client_pool: FrontendClientPoolRef,
69
70    /// idle status manager.
71    idle_manager: IdleManagerRef,
72
73    event_log_manager: EventLogManagerRef,
74
75    /// Unique identifier of the cluster.
76    cluster_id: ClusterId,
77
78    pub hummock_seq: Arc<SequenceGenerator>,
79
80    /// options read by all services
81    pub opts: Arc<MetaOpts>,
82}
83
84/// Options shared by all meta service instances
85#[derive(Clone, serde::Serialize)]
86pub struct MetaOpts {
87    /// Whether to enable the recovery of the cluster. If disabled, the meta service will exit on
88    /// abnormal cases.
89    pub enable_recovery: bool,
90    /// Whether to disable the auto-scaling feature.
91    pub disable_automatic_parallelism_control: bool,
92    /// The number of streaming jobs per scaling operation.
93    pub parallelism_control_batch_size: usize,
94    /// The period of parallelism control trigger.
95    pub parallelism_control_trigger_period_sec: u64,
96    /// The first delay of parallelism control.
97    pub parallelism_control_trigger_first_delay_sec: u64,
98    /// The maximum number of barriers in-flight in the compute nodes.
99    pub in_flight_barrier_nums: usize,
100    /// After specified seconds of idle (no mview or flush), the process will be exited.
101    /// 0 for infinite, process will never be exited due to long idle time.
102    pub max_idle_ms: u64,
103    /// Whether run in compaction detection test mode
104    pub compaction_deterministic_test: bool,
105    /// Default parallelism of units for all streaming jobs.
106    pub default_parallelism: DefaultParallelism,
107
108    /// Interval of invoking a vacuum job, to remove stale metadata from meta store and objects
109    /// from object store.
110    pub vacuum_interval_sec: u64,
111    /// The spin interval inside a vacuum job. It avoids the vacuum job monopolizing resources of
112    /// meta node.
113    pub vacuum_spin_interval_ms: u64,
114    pub time_travel_vacuum_interval_sec: u64,
115    /// Interval of hummock version checkpoint.
116    pub hummock_version_checkpoint_interval_sec: u64,
117    pub enable_hummock_data_archive: bool,
118    pub hummock_time_travel_snapshot_interval: u64,
119    pub hummock_time_travel_sst_info_fetch_batch_size: usize,
120    pub hummock_time_travel_sst_info_insert_batch_size: usize,
121    pub hummock_time_travel_epoch_version_insert_batch_size: usize,
122    pub hummock_gc_history_insert_batch_size: usize,
123    pub hummock_time_travel_filter_out_objects_batch_size: usize,
124    pub hummock_time_travel_filter_out_objects_v1: bool,
125    pub hummock_time_travel_filter_out_objects_list_version_batch_size: usize,
126    pub hummock_time_travel_filter_out_objects_list_delta_batch_size: usize,
127    /// The minimum delta log number a new checkpoint should compact, otherwise the checkpoint
128    /// attempt is rejected. Greater value reduces object store IO, meanwhile it results in
129    /// more loss of in memory `HummockVersionCheckpoint::stale_objects` state when meta node is
130    /// restarted.
131    pub min_delta_log_num_for_hummock_version_checkpoint: u64,
132    /// Objects within `min_sst_retention_time_sec` won't be deleted by hummock full GC, even they
133    /// are dangling.
134    pub min_sst_retention_time_sec: u64,
135    /// Interval of automatic hummock full GC.
136    pub full_gc_interval_sec: u64,
137    /// Max number of object per full GC job can fetch.
138    pub full_gc_object_limit: u64,
139    /// Duration in seconds to retain garbage collection history data.
140    pub gc_history_retention_time_sec: u64,
141    /// Max number of inflight time travel query.
142    pub max_inflight_time_travel_query: u64,
143    /// Enable sanity check when SSTs are committed
144    pub enable_committed_sst_sanity_check: bool,
145    /// Schedule compaction for all compaction groups with this interval.
146    pub periodic_compaction_interval_sec: u64,
147    /// Interval of reporting the number of nodes in the cluster.
148    pub node_num_monitor_interval_sec: u64,
149
150    /// The Prometheus endpoint for Meta Dashboard Service.
151    /// The Dashboard service uses this in the following ways:
152    /// 1. Query Prometheus for relevant metrics to find Stream Graph Bottleneck, and display it.
153    /// 2. Provide cluster diagnostics, at `/api/monitor/diagnose` to troubleshoot cluster.
154    ///    These are just examples which show how the Meta Dashboard Service queries Prometheus.
155    pub prometheus_endpoint: Option<String>,
156
157    /// The additional selector used when querying Prometheus.
158    pub prometheus_selector: Option<String>,
159
160    /// The VPC id of the cluster.
161    pub vpc_id: Option<String>,
162
163    /// A usable security group id to assign to a vpc endpoint
164    pub security_group_id: Option<String>,
165
166    /// Default tag for the endpoint created when creating a privatelink connection.
167    /// Will be appended to the tags specified in the `tags` field in with clause in `create
168    /// connection`.
169    pub privatelink_endpoint_default_tags: Option<Vec<(String, String)>>,
170
171    /// Schedule `space_reclaim_compaction` for all compaction groups with this interval.
172    pub periodic_space_reclaim_compaction_interval_sec: u64,
173
174    /// telemetry enabled in config file or not
175    pub telemetry_enabled: bool,
176    /// Schedule `ttl_reclaim_compaction` for all compaction groups with this interval.
177    pub periodic_ttl_reclaim_compaction_interval_sec: u64,
178
179    /// Schedule `tombstone_reclaim_compaction` for all compaction groups with this interval.
180    pub periodic_tombstone_reclaim_compaction_interval_sec: u64,
181
182    /// Schedule `periodic_scheduling_compaction_group_split_interval_sec` for all compaction groups with this interval.
183    pub periodic_scheduling_compaction_group_split_interval_sec: u64,
184
185    /// Whether config object storage bucket lifecycle to purge stale data.
186    pub do_not_config_object_storage_lifecycle: bool,
187
188    pub partition_vnode_count: u32,
189
190    /// threshold of high write throughput of state-table, unit: B/sec
191    pub table_high_write_throughput_threshold: u64,
192    /// threshold of low write throughput of state-table, unit: B/sec
193    pub table_low_write_throughput_threshold: u64,
194
195    pub compaction_task_max_heartbeat_interval_secs: u64,
196    pub compaction_task_max_progress_interval_secs: u64,
197    pub compaction_config: Option<CompactionConfig>,
198
199    /// hybird compaction group config
200    ///
201    /// `hybrid_partition_vnode_count` determines the granularity of vnodes in the hybrid compaction group for SST alignment.
202    /// When `hybrid_partition_vnode_count` > 0, in hybrid compaction group
203    /// - Tables with high write throughput will be split at vnode granularity
204    /// - Tables with high size tables will be split by table granularity
205    ///   When `hybrid_partition_vnode_count` = 0,no longer be special alignment operations for the hybird compaction group
206    pub hybrid_partition_node_count: u32,
207
208    pub event_log_enabled: bool,
209    pub event_log_channel_max_size: u32,
210    pub advertise_addr: String,
211    /// The number of traces to be cached in-memory by the tracing collector
212    /// embedded in the meta node.
213    pub cached_traces_num: u32,
214    /// The maximum memory usage in bytes for the tracing collector embedded
215    /// in the meta node.
216    pub cached_traces_memory_limit_bytes: usize,
217
218    /// l0 picker whether to select trivial move task
219    pub enable_trivial_move: bool,
220
221    /// l0 multi level picker whether to check the overlap accuracy between sub levels
222    pub enable_check_task_level_overlap: bool,
223    pub enable_dropped_column_reclaim: bool,
224
225    /// Whether to split the compaction group when the size of the group exceeds the threshold.
226    pub split_group_size_ratio: f64,
227
228    /// To split the compaction group when the high throughput statistics of the group exceeds the threshold.
229    pub table_stat_high_write_throughput_ratio_for_split: f64,
230
231    /// To merge the compaction group when the low throughput statistics of the group exceeds the threshold.
232    pub table_stat_low_write_throughput_ratio_for_merge: f64,
233
234    /// The window seconds of table throughput statistic history for split compaction group.
235    pub table_stat_throuput_window_seconds_for_split: usize,
236
237    /// The window seconds of table throughput statistic history for merge compaction group.
238    pub table_stat_throuput_window_seconds_for_merge: usize,
239
240    /// The configuration of the object store
241    pub object_store_config: ObjectStoreConfig,
242
243    /// The maximum number of trivial move tasks to be picked in a single loop
244    pub max_trivial_move_task_count_per_loop: usize,
245
246    /// The maximum number of times to probe for `PullTaskEvent`
247    pub max_get_task_probe_times: usize,
248
249    pub compact_task_table_size_partition_threshold_low: u64,
250    pub compact_task_table_size_partition_threshold_high: u64,
251
252    pub periodic_scheduling_compaction_group_merge_interval_sec: u64,
253
254    pub compaction_group_merge_dimension_threshold: f64,
255
256    // The private key for the secret store, used when the secret is stored in the meta.
257    pub secret_store_private_key: Option<Vec<u8>>,
258    /// The path of the temp secret file directory.
259    pub temp_secret_file_dir: String,
260
261    // Cluster limits
262    pub actor_cnt_per_worker_parallelism_hard_limit: usize,
263    pub actor_cnt_per_worker_parallelism_soft_limit: usize,
264
265    pub license_key_path: Option<PathBuf>,
266
267    pub compute_client_config: RpcClientConfig,
268    pub stream_client_config: RpcClientConfig,
269    pub frontend_client_config: RpcClientConfig,
270}
271
272impl MetaOpts {
273    /// Default opts for testing. Some tests need `enable_recovery=true`
274    pub fn test(enable_recovery: bool) -> Self {
275        Self {
276            enable_recovery,
277            disable_automatic_parallelism_control: false,
278            parallelism_control_batch_size: 1,
279            parallelism_control_trigger_period_sec: 10,
280            parallelism_control_trigger_first_delay_sec: 30,
281            in_flight_barrier_nums: 40,
282            max_idle_ms: 0,
283            compaction_deterministic_test: false,
284            default_parallelism: DefaultParallelism::Full,
285            vacuum_interval_sec: 30,
286            time_travel_vacuum_interval_sec: 30,
287            vacuum_spin_interval_ms: 0,
288            hummock_version_checkpoint_interval_sec: 30,
289            enable_hummock_data_archive: false,
290            hummock_time_travel_snapshot_interval: 0,
291            hummock_time_travel_sst_info_fetch_batch_size: 10_000,
292            hummock_time_travel_sst_info_insert_batch_size: 10,
293            hummock_time_travel_epoch_version_insert_batch_size: 1000,
294            hummock_gc_history_insert_batch_size: 1000,
295            hummock_time_travel_filter_out_objects_batch_size: 1000,
296            hummock_time_travel_filter_out_objects_v1: false,
297            hummock_time_travel_filter_out_objects_list_version_batch_size: 10,
298            hummock_time_travel_filter_out_objects_list_delta_batch_size: 1000,
299            min_delta_log_num_for_hummock_version_checkpoint: 1,
300            min_sst_retention_time_sec: 3600 * 24 * 7,
301            full_gc_interval_sec: 3600 * 24 * 7,
302            full_gc_object_limit: 100_000,
303            gc_history_retention_time_sec: 3600 * 24 * 7,
304            max_inflight_time_travel_query: 1000,
305            enable_committed_sst_sanity_check: false,
306            periodic_compaction_interval_sec: 60,
307            node_num_monitor_interval_sec: 10,
308            prometheus_endpoint: None,
309            prometheus_selector: None,
310            vpc_id: None,
311            security_group_id: None,
312            privatelink_endpoint_default_tags: None,
313            periodic_space_reclaim_compaction_interval_sec: 60,
314            telemetry_enabled: false,
315            periodic_ttl_reclaim_compaction_interval_sec: 60,
316            periodic_tombstone_reclaim_compaction_interval_sec: 60,
317            periodic_scheduling_compaction_group_split_interval_sec: 60,
318            compact_task_table_size_partition_threshold_low: 128 * 1024 * 1024,
319            compact_task_table_size_partition_threshold_high: 512 * 1024 * 1024,
320            table_high_write_throughput_threshold: 128 * 1024 * 1024,
321            table_low_write_throughput_threshold: 64 * 1024 * 1024,
322            do_not_config_object_storage_lifecycle: true,
323            partition_vnode_count: 32,
324            compaction_task_max_heartbeat_interval_secs: 0,
325            compaction_task_max_progress_interval_secs: 1,
326            compaction_config: None,
327            hybrid_partition_node_count: 4,
328            event_log_enabled: false,
329            event_log_channel_max_size: 1,
330            advertise_addr: "".to_owned(),
331            cached_traces_num: 1,
332            cached_traces_memory_limit_bytes: usize::MAX,
333            enable_trivial_move: true,
334            enable_check_task_level_overlap: true,
335            enable_dropped_column_reclaim: false,
336            object_store_config: ObjectStoreConfig::default(),
337            max_trivial_move_task_count_per_loop: 256,
338            max_get_task_probe_times: 5,
339            secret_store_private_key: Some(
340                hex::decode("0123456789abcdef0123456789abcdef").unwrap(),
341            ),
342            temp_secret_file_dir: "./secrets".to_owned(),
343            actor_cnt_per_worker_parallelism_hard_limit: usize::MAX,
344            actor_cnt_per_worker_parallelism_soft_limit: usize::MAX,
345            split_group_size_ratio: 0.9,
346            table_stat_high_write_throughput_ratio_for_split: 0.5,
347            table_stat_low_write_throughput_ratio_for_merge: 0.7,
348            table_stat_throuput_window_seconds_for_split: 60,
349            table_stat_throuput_window_seconds_for_merge: 240,
350            periodic_scheduling_compaction_group_merge_interval_sec: 60 * 10,
351            compaction_group_merge_dimension_threshold: 1.2,
352            license_key_path: None,
353            compute_client_config: RpcClientConfig::default(),
354            stream_client_config: RpcClientConfig::default(),
355            frontend_client_config: RpcClientConfig::default(),
356        }
357    }
358}
359
360impl MetaSrvEnv {
361    pub async fn new(
362        opts: MetaOpts,
363        mut init_system_params: SystemParams,
364        init_session_config: SessionConfig,
365        meta_store_impl: SqlMetaStore,
366    ) -> MetaResult<Self> {
367        let idle_manager = Arc::new(IdleManager::new(opts.max_idle_ms));
368        let stream_client_pool =
369            Arc::new(StreamClientPool::new(1, opts.stream_client_config.clone())); // typically no need for plural clients
370        let frontend_client_pool = Arc::new(FrontendClientPool::new(
371            1,
372            opts.frontend_client_config.clone(),
373        ));
374        let event_log_manager = Arc::new(start_event_log_manager(
375            opts.event_log_enabled,
376            opts.event_log_channel_max_size,
377        ));
378
379        // When license key path is specified, license key from system parameters can be easily
380        // overwritten. So we simply reject this case.
381        if opts.license_key_path.is_some()
382            && init_system_params.license_key
383                != system_param::default::license_key_opt().map(Into::into)
384        {
385            bail!(
386                "argument `--license-key-path` (or env var `RW_LICENSE_KEY_PATH`) and \
387                 system parameter `license_key` (or env var `RW_LICENSE_KEY`) may not \
388                 be set at the same time"
389            );
390        }
391
392        let cluster_first_launch = meta_store_impl.up().await.context(
393            "Failed to initialize the meta store, \
394            this may happen if there's existing metadata incompatible with the current version of RisingWave, \
395            e.g., downgrading from a newer release or a nightly build to an older one. \
396            For a single-node deployment, you may want to reset all data by deleting the data directory, \
397            typically located at `~/.risingwave`.",
398        )?;
399
400        let notification_manager =
401            Arc::new(NotificationManager::new(meta_store_impl.clone()).await);
402        let cluster_id = Cluster::find()
403            .one(&meta_store_impl.conn)
404            .await?
405            .map(|c| c.cluster_id.to_string().into())
406            .unwrap();
407
408        // For new clusters:
409        // - the name of the object store needs to be prefixed according to the object id.
410        //
411        // For old clusters
412        // - the prefix is ​​not divided for the sake of compatibility.
413        init_system_params.use_new_object_prefix_strategy = Some(cluster_first_launch);
414
415        let system_param_controller = Arc::new(
416            SystemParamsController::new(
417                meta_store_impl.clone(),
418                notification_manager.clone(),
419                init_system_params,
420            )
421            .await?,
422        );
423        let session_param_controller = Arc::new(
424            SessionParamsController::new(
425                meta_store_impl.clone(),
426                notification_manager.clone(),
427                init_session_config,
428            )
429            .await?,
430        );
431        Ok(Self {
432            id_gen_manager_impl: Arc::new(SqlIdGeneratorManager::new(&meta_store_impl.conn).await?),
433            system_param_manager_impl: system_param_controller,
434            session_param_manager_impl: session_param_controller,
435            meta_store_impl: meta_store_impl.clone(),
436            notification_manager,
437            stream_client_pool,
438            frontend_client_pool,
439            idle_manager,
440            event_log_manager,
441            cluster_id,
442            hummock_seq: Arc::new(SequenceGenerator::new(meta_store_impl.conn.clone())),
443            opts: opts.into(),
444        })
445    }
446
447    pub fn meta_store(&self) -> SqlMetaStore {
448        self.meta_store_impl.clone()
449    }
450
451    pub fn meta_store_ref(&self) -> &SqlMetaStore {
452        &self.meta_store_impl
453    }
454
455    pub fn id_gen_manager(&self) -> &SqlIdGeneratorManagerRef {
456        &self.id_gen_manager_impl
457    }
458
459    pub fn notification_manager_ref(&self) -> NotificationManagerRef {
460        self.notification_manager.clone()
461    }
462
463    pub fn notification_manager(&self) -> &NotificationManager {
464        self.notification_manager.deref()
465    }
466
467    pub fn idle_manager_ref(&self) -> IdleManagerRef {
468        self.idle_manager.clone()
469    }
470
471    pub fn idle_manager(&self) -> &IdleManager {
472        self.idle_manager.deref()
473    }
474
475    pub async fn system_params_reader(&self) -> SystemParamsReader {
476        self.system_param_manager_impl.get_params().await
477    }
478
479    pub fn system_params_manager_impl_ref(&self) -> SystemParamsControllerRef {
480        self.system_param_manager_impl.clone()
481    }
482
483    pub fn session_params_manager_impl_ref(&self) -> SessionParamsControllerRef {
484        self.session_param_manager_impl.clone()
485    }
486
487    pub fn stream_client_pool_ref(&self) -> StreamClientPoolRef {
488        self.stream_client_pool.clone()
489    }
490
491    pub fn stream_client_pool(&self) -> &StreamClientPool {
492        self.stream_client_pool.deref()
493    }
494
495    pub fn frontend_client_pool(&self) -> &FrontendClientPool {
496        self.frontend_client_pool.deref()
497    }
498
499    pub fn cluster_id(&self) -> &ClusterId {
500        &self.cluster_id
501    }
502
503    pub fn event_log_manager_ref(&self) -> EventLogManagerRef {
504        self.event_log_manager.clone()
505    }
506}
507
508#[cfg(any(test, feature = "test"))]
509impl MetaSrvEnv {
510    // Instance for test.
511    pub async fn for_test() -> Self {
512        Self::for_test_opts(MetaOpts::test(false)).await
513    }
514
515    pub async fn for_test_opts(opts: MetaOpts) -> Self {
516        Self::new(
517            opts,
518            risingwave_common::system_param::system_params_for_test(),
519            Default::default(),
520            SqlMetaStore::for_test().await,
521        )
522        .await
523        .unwrap()
524    }
525}