From 48e6c934c37792f79e1a08ba945db2d6b90520db Mon Sep 17 00:00:00 2001 From: Alex Feinberg Date: Thu, 11 Jan 2024 18:42:42 -0800 Subject: [PATCH] RFC: Periodic full compaction (#110) (#110) * RFC: Periodic Full Compaction (#110) Signed-off-by: Alex Feinberg * More writeup. Signed-off-by: Alex Feinberg * Fix spelling. Signed-off-by: Alex Feinberg * Grammar. Signed-off-by: Alex Feinberg * Reformat Signed-off-by: Alex Feinberg * Add Tony's suggestion. Signed-off-by: Alex Feinberg * Document metrics, add demo/test. Signed-off-by: Alex Feinberg * Rewrite a paragraph. Signed-off-by: Alex Feinberg * Add future work section on disk metrics. Signed-off-by: Alex Feinberg --------- Signed-off-by: Alex Feinberg --- media/periodic-full-compaction-1.png | Bin 0 -> 55471 bytes text/0110-periodic-full-compaction.md | 391 ++++++++++++++++++++++++++ 2 files changed, 391 insertions(+) create mode 100644 media/periodic-full-compaction-1.png create mode 100644 text/0110-periodic-full-compaction.md diff --git a/media/periodic-full-compaction-1.png b/media/periodic-full-compaction-1.png new file mode 100644 index 0000000000000000000000000000000000000000..9d52d5d62f31da0b0cc4e7b2bb922939a59dba15 GIT binary patch literal 55471 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 An*aa+ literal 0 HcmV?d00001 diff --git a/text/0110-periodic-full-compaction.md b/text/0110-periodic-full-compaction.md new file mode 100644 index 00000000..fa6d9710 --- /dev/null +++ b/text/0110-periodic-full-compaction.md @@ -0,0 +1,391 @@ +# Periodic Full Compaction + +Author: [Alex Feinberg](https://github.com/afeinberg) + +Reviewers: [Connor](https://github.com/Connor1996), +[Tony](https://github.com/tonyxuqqi), [Andy](https://github.com/v01dstar), +others + +## Introduction + +**Periodic full compaction** is a scheduled task that starts at specified times +of the day on each TiKV node and compacts the column families of all regions *at +all levels including the bottommost (L6)*. In order to reduce to impact running +such a heavy-weight task would have on the cluster's ability to serve traffic, +full compaction is incremental: before the next range (presently a region) is +compacted, we check if the load is below a certain threshold; if the threshold +is exceeded, we pause the task until the load is again below a certain +threshold. + +## Motivation + +Presently, we have no way to periodically execute a RocksDB compaction across +all levels. This has a number of implications: compaction filters (used to +remove tombstones) only run when the bottom-most (L6) compaction is executed; a +system with a high number of deletes that experiences a heavy read-only (but +little or no writes) might thus have accumulated tombstones markers that are not +deleted. + +Using `tikv-ctl compact-cluster` is not suitable for this goal: while it executes +a full compaction, it may impact online user traffic which makes it non-viable +for production usage without downtime. Periodic full compaction provides a way to +achieve the same goal in a more controllable way. + +## Detailed design + +### Periodic scheduling + +#### Configuration + +To enable periodic full compaction, specify the hours during which we wish to +schedule full compaction to run in tikv's configuration and a maximum CPU +utilization threshold. CPU utilization is calculated by using process stats in +`/proc` over a 10-minute window. (See *Conditions for full compaction to run* +below.) + +> +> `tikv.toml` setting to run compaction at 03:00 and 23:00 +> (3am and 11pm respectively) in the tikv nodes' local timezone if CPU +> usage is below 90%: +> +> ```toml +>[raftstore] +>periodic-full-compact-start-max-cpu = 0.9 +>periodic-full-compact-start-times = ["03:00", "23:00"] +>``` + +### Executing a `PeriodicFullCompact` task + +>`compact.rs`: +> +>```rust +>pub enum Task { +> PeriodicFullCompact { +> ranges: Vec<(Key, Key)>, +> compact_load_controller: FullCompactController, +> }, +>``` + +#### Choosing ranges + +We use ranges defined by the start and end keys of all of the store's regions as +increments: + +> See `StoreFsmDelegate::regions_for_full_compact` in `store.rs`: +> +>```rust +> /// Use ranges assigned to each region as increments for full compaction. +> fn ranges_for_full_compact(&self) -> Vec<(Vec, Vec)> { +>``` + +#### Controlling full compaction + +>`compact.rs`: +> +>```rust +>pub struct FullCompactController { +> /// Initial delay between retries for ``FullCompactController::pause``. +> pub initial_pause_duration_secs: u64, +> /// Max delay between retries. +> pub max_pause_duration_secs: u64, +> /// Predicate function to evaluate that indicates if we can proceed with +> /// full compaction. +> pub incremental_compaction_pred: CompactPredicateFn, +>} +>``` + +##### Conditions for full compaction to run + +###### Compact predicate function (`CompactPredicateFn`) + +> +> `CompactPredicateFn` is defined in `compact.rs` as an `Fn()` that returns true +> if it is safe to start compaction or compact the next range in `ranges.` +> +>```rust +>type CompactPredicateFn = Box bool + Send + Sync>; +>``` +> + +###### Using `CompactPredicateFn` + +We evaluate the compaction predicate function in the following cases: + +1. Before starting a full compaction task. + + See `StoreFsmDelegate::on_full_compact_tick` in `store.rs`, where we return + early if the predicate returns false. + + ```rust + // Do not start if the load is high. + if !compact_predicate_fn() { + return; + } + ``` + +2. After finishing an incremental full compaction for a range, if more ranges remain. + + See `CompactRunner::full_compact` in `compact.rs`, where we pause (see + *Pausing* below) if the predicate returns false: + + ```rust + if let Some(next_range) = ranges.front() { + if !(compact_controller.incremental_compaction_pred)() { + // ... + compact_controller.pause().await?; + ``` + +###### Load-based `CompactPredicateFn` implementation + +> This is returned by ```StoreFsmDelegate::is_low_load_for_full_compact``` in +> `store.rs` which checks that the raftstore is > busy and checks if the CPU +> usage within over the last 10 minute window is within the threshold specified +> by `periodic-full-compact-start-max-cpu`. +> +> ```rust +> fn is_low_load_for_full_compact(&self) -> impl Fn() -> bool { +>``` + +##### Pausing + +Full compaction tasks are intended to be long-running and may spend up to 15 +minutes at a time waiting for `CompactPredicateFn` to evaluate to true. As in +other places in tikv when we need pause or sleep, we call +```GLOBAL_TIMER_HANDLE.delay``` in an async context. + +> `compact.rs` +> +>```rust +>impl FullCompactController { +> pub async fn pause(&self) -> Result<(), Error> { +> let mut duration_secs = self.initial_pause_duration_secs; +> loop { +> box_try!( +> GLOBAL_TIMER_HANDLE +> .delay(std::time::Instant::now() + Duration::from_secs(duration_secs)) +> .compat() +> .await +> ); +> if (self.incremental_compaction_pred)() { +> break; +> }; +> duration_secs = self +> .max_pause_duration_secs +> .max(duration_secs * 2); +> } +> Ok(()) +> } +>``` + +##### Using background worker to execute compaction + +Since `FullCompactController::pause` is asynchronous (see *Pausing* above), +`PeriodicFullCompact` tasks are scheduled using the background worker pool. This +means that other cleanup and compaction tasks can while full compaction is +paused. + +> `store.rs` +> +>```rust +>impl RaftBatchSystem { +> pub fn spawn( +> &mut self, +> // ... +> background_worker: Worker, +> // ... +> ) -> Result<()> { +> // ... +> let bg_remote = background_worker.remote(); +> // ... +> let compact_runner = CompactRunner::new(engines.kv.clone(), bg_remote); +> // ... +>``` +> +> Using `Remote::spawn` to asynchronously execute full compaction in +> `yatp_pool::FuturePool`. +> +>```rust +>impl Runnable for CompactRunner { +> fn run(&mut self, task: Task) { +> match task { +> Task::PeriodicFullCompact { +> ranges, +> compact_load_controller, +> } => { +> // ... +> let engine = self.engine.clone(); +> self.remote.spawn(async move { // NOTE the use of `self.remote` +> if let Err(e) = Self::full_compact(engine, ranges, compact_load_controller).await { +> // ... +>``` + +Note that `CompactRunner::full_compact` is an `async fn`, yet it invokes +RocksDB's manual compaction API which blocks the current thread: this is +supported by `FuturePool` and happens in other places in our code. + +### Full compaction of a range + +We use `CompactExt::compact_range` to perform the compaction of each region, +which calls `compact_range_cf` on all the column families. Note that +`exclusive_manual` is `false` and `subcompactions` is `1` - meaning all +sub-compactions are executed on one RocksDb thread - to limit resource usage. + +> From `full_compact` in `compact.rs`: +> +>```rust +> box_try!(engine.compact_range( +> range.0, range.1, +> false, // non-exclusive +> 1, // number of threads threads +> )); +>``` +> +> From `CompactExt` in `components/engine_traits/src/compact.rs`: +> +>```rust +> fn compact_range( +> &self, +> start_key: Option<&[u8]>, +> end_key: Option<&[u8]>, +> exclusive_manual: bool, +> max_subcompactions: u32, // Controls the number of engine worker threads. +> ) -> Result<()> { +> for cf in self.cf_names() { +> self.compact_range_cf(cf, start_key, end_key, exclusive_manual, max_subcompactions)?; +> } +>``` +> +> The `RocksEngine` implementation of `compact_range_cf`. See [Manual +> Compaction](https://github.com/facebook/rocksdb/wiki/Manual-Compaction) in +> RocksDb documentation for more info. +> +> ```rust +> let mut compact_opts = CompactOptions::new(); +> compact_opts.set_exclusive_manual_compaction(exclusive_manual); +> compact_opts.set_max_subcompactions(max_subcompactions as i32); +> db.compact_range_cf_opt(handle, &compact_opts, start_key, end_key); +>``` + +### Implementation + + | Sub-task | Status | + | - | - | + | Periodic schedule full compaction |**Merged** [tikv/tikv#12729](https://github.com/tikv/tikv/pull/15853)| + | Incrementalism, pausing | **Merged** [tikv/tikv#15995](https://github.com/tikv/tikv/pull/15995)| + +#### Alternatives considered + +##### Compacting by file or level instead of a range + +*Not applicable*: doing so would not guarantee that the compaction filters are able to run. + +###### Using a rate limiter to control load during full compaction + +*Not applicable*: compaction happens in increments of regions (`512MB` at a +time), which would not work with the current token-bucket-based rate limiter +APIs. + +##### Using metrics other than CPU load + +*Future work*. This is feasible but would need additional implementation and +tuning load. See `io_load.rs` + +### Metrics + +| Metric | Description | +|--------|-------------| +| `tikv_storage_full_compact_duration_seconds` | Bucketed histogram of periodic full compaction run duration | +| `tikv_storage_full_compact_increment_duration_seconds` | Bucketed histogram of full compaction *increments* | +| `tikv_storage_full_compact_pause_duration_seconds` | Bucketed histogram of full compaction pauses | +| `tikv_storage_process_stat_cpu_usage` | CPU useage over a 10 minute window | + +## Demonstration + +### Setup + +#### Configure periodic full compaction + +```toml +[raftstore] +periodic-full-compact-start-max-cpu = 0.33 +periodic-full-compact-start-times = ["11:00", "22:00", "23:00"] +``` + +> **Note:** set `periodic-full-compact-start-max-cpu` to observe pauses. + +#### Test periodic full compaction + +##### Populate a table + +``` sql +create database compact_test; +-- Query OK, 0 rows affected (0.10 sec)= +use compact_test; +-- Database changed +create table t1(f1 integer primary key auto_increment, f2 integer); +-- Query OK, 0 rows affected (0.09 sec) +insert into t1(f2) values(1),(2),(3); +-- Query OK, 3 rows affected (0.01 sec) +-- 3 Duplicates: 0 Warnings: 0 + +-- repeat below command N times +insert into t1(f2) select f1+f2 from t1; +-- Query OK, 3 rows affected (0.00 sec) +-- Records: 3 Duplicates: 0 Warnings: 0 +-- ... +-- +-- Query OK, 6291456 rows affected (36.25 sec) +-- Records: 6291456 Duplicates: 0 Warnings: 0 +``` + +##### Generate deletes + +```sql +delete from t1 where f1 in (select f1 from t1 where mod(f2,3) = 0); +--- Query OK, 6428311 rows affected (32.15 sec) +``` + +##### Observe metrics and logs + +```log +[2024/01/10 11:27:07.280 -08:00] [INFO] [compact.rs:236] ["full compaction started"] [thread_id=0x5] +[2024/01/10 11:27:45.910 -08:00] [INFO] [compact.rs:291] ["full compaction finished"] [time_takes=38.630410698s] [thread_id=0x5] +``` + +![Metrics showing full compaction running without a pause](../media/periodic-full-compaction-1.png) +> **Note that** in the screenshot above, CPU usage was below 33%: this allowed +> full compaction to run without any pauses between increments. + +## Future work + +### Additional load criteria + +* Incorporate other load statistics besides the CPU such as disk or network I/O. + * Incorporating disk seek time, throughput, utilization, and/or file-sync + latency statistics specifically will further limit the impact of full + compaction runs on read and write latency. **Note that** the existing + implementation suggests using `raftstore.periodic-full-compact-start-times` + to configure full compaction to only start during off-peak periods. + +### Smarter range selection + +Possibly options: + +* Do not compact an entire region at all once +* Compact the ranges with most versions first + +### Stopping compaction + +* Add a mechanism to monitor which full compactions are in progress. +* Manually pausing: allow all or some manual compaction tasks to be paused for a + specified amount of time. +* Manually stopping: allow setting a flag for an individual full compaction task + that would terminate the task as soon as possible instead of starting the next + increment. + +### Manual invocation + +* Support manually starting a full compaction for the entire store. Can be done + via the CLI. +* Support manually compacting all or some regions of a given table. Would need + to be integrated into TiDB syntax.