> ## Documentation Index
> Fetch the complete documentation index at: https://cockroachlabs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced Changefeed Configuration

export const InternalLink = ({version, path = "", children, ...props}) => {
  let detectedVersion = version || "stable";
  if (typeof window !== 'undefined' && !version) {
    const match = window.location.pathname.match(/\/docs\/([^/]+)/);
    if (match) {
      detectedVersion = match[1];
    }
  }
  const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
  return <a href={`/docs/${detectedVersion}/${normalizedPath}`} {...props}>
      {children}
    </a>;
};

<Danger>
  The configurations and settings explained on this page will have a significant impact on a changefeed's behavior and could potentially affect a cluster's performance. Thoroughly test before deploying any changes to production.
</Danger>

The following sections describe performance, settings, configurations, and details to tune <InternalLink path="change-data-capture-overview">changefeeds</InternalLink>:

* [Changefeed performance](#changefeed-performance)
* [High durability delivery](#tuning-for-high-durability-delivery)
* [High throughput](#tuning-for-high-throughput)

Some options for the `kafka_sink_config` and `webhook_sink_config` parameters are discussed on this page. However, for more information on specific tuning for Kafka and Webhook sinks, refer to the following pages:

* <InternalLink path="changefeed-sinks#kafka-sink-configuration">Kafka sinks</InternalLink>
* <InternalLink path="changefeed-sinks#webhook-sink-configuration">Webhook sinks</InternalLink>

## Changefeed performance

New in v23.1: By default, changefeeds are integrated with elastic CPU, which helps to prevent changefeeds from affecting foreground traffic. For example, <InternalLink path="changefeed-messages#schema-changes-with-column-backfill">changefeed backfills</InternalLink> and <InternalLink path="create-changefeed">initial scans</InternalLink> can be CPU-intensive. This integration will result in a cluster prioritizing SQL traffic over changefeeds. Since this may affect changefeed latency, you can monitor your cluster's <InternalLink path="admission-control">admission control system</InternalLink> on the <InternalLink path="ui-overload-dashboard">Overload Dashboard</InternalLink> and changefeed latency on the <InternalLink path="ui-cdc-dashboard">Changefeed Dashboard</InternalLink>.

This is controlled by the following <InternalLink path="cluster-settings">cluster settings</InternalLink>, which are by default enabled:

```
changefeed.cpu.per_event_elastic_control.enabled
kvadmission.rangefeed_catchup_scan_elastic_control.enabled
```

For a more technical explanation of elastic CPU, refer to the [Rubbing control theory on the Go scheduler](https://www.cockroachlabs.com/blog/rubbing-control-theory/) blog post.

### MuxRangefeed

<Note>
  **This feature is in <InternalLink path="cockroachdb-feature-availability">preview</InternalLink>** and subject to change. To share feedback and/or issues, contact [Support](https://support.cockroachlabs.com).
</Note>

`MuxRangefeed` is a subsystem that improves the performance of rangefeeds with scale. It significantly reduces the overhead of running <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">rangefeeds</InternalLink>. Without `MuxRangefeed` enabled the number of RPC streams is proportional with the number of ranges in a table. For example, a large table could have tens of thousands of ranges. With `MuxRangefeed` enabled, this proportion improves so that the number of RPC streams is relative to the number of nodes in a cluster.

You can enable its functionality with the `changefeed.mux_rangefeed.enabled` <InternalLink path="cluster-settings">cluster setting</InternalLink>.

Use the following workflow to enable `MuxRangefeed`:

1. Enable the cluster setting:

   ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   SET CLUSTER SETTING changefeed.mux_rangefeed.enabled = true;
   ```

2. After enabling the setting, pause the changefeed:

   ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   PAUSE JOB {job ID};
   ```

   You can use <InternalLink path="show-jobs#show-changefeed-jobs">`SHOW CHANGEFEED JOBS`</InternalLink> to retrieve the job ID.

3. Resume the changefeed for the cluster setting to take effect:

   ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   RESUME JOB {job ID};
   ```

### Latency in changefeeds

When you are running large workloads, changefeeds can **encounter** or **cause** latency in a cluster in the following ways:

* Changefeeds can have an impact on SQL latency in the cluster generally.
* Changefeeds can encounter latency in events emitting. This latency is the total time CockroachDB takes to:
  * Commit writes to the database.
  * Encode <InternalLink path="changefeed-messages">changefeed messages</InternalLink>.
  * Deliver the message to the <InternalLink path="changefeed-sinks">sink</InternalLink>.

The following <InternalLink path="cluster-settings">cluster settings</InternalLink> reduce bursts of <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">rangefeed</InternalLink> work so that updates are paced steadily over time.

<Danger>
  We do **not** recommend adjusting these settings unless you are running a large workload, or are working with the Cockroach Labs <InternalLink path="support-resources">support team</InternalLink>. Thoroughly test different cluster setting configurations before deploying to production.
</Danger>

#### `kv.closed_timestamp.target_duration`

**Default:** `3s`

<Note>
  Adjusting `kv.closed_timestamp.target_duration` could have a detrimental impact on <InternalLink path="follower-reads">follower reads</InternalLink>. If you are using follower reads, refer to the [`kv.rangefeed.closed_timestamp_refresh_interval`](#kv-rangefeed-closed_timestamp_refresh_interval) cluster setting instead to ease changefeed impact on foreground SQL latency.
</Note>

`kv.closed_timestamp.target_duration` controls the target <InternalLink path="architecture/transaction-layer#closed-timestamps">closed timestamp</InternalLink> lag duration, which determines how far behind the current time CockroachDB will attempt to maintain the closed timestamp. For example, with the default value of `3s`, if the current time is `12:30:00` then CockroachDB will attempt to keep the closed timestamp at `12:29:57` by possibly retrying or aborting ongoing writes that are below this time.

A changefeed aggregates checkpoints across all ranges, and once the timestamp on all the ranges advances, the changefeed can then <InternalLink path="how-does-an-enterprise-changefeed-work">checkpoint</InternalLink>. In the context of changefeeds, `kv.closed_timestamp.target_duration` affects how old the checkpoints will be, which will determine the latency before changefeeds can consider the history of an event complete.

#### `kv.rangefeed.closed_timestamp_refresh_interval`

**Default:** `0s`

This setting controls the interval at which <InternalLink path="architecture/transaction-layer#closed-timestamps">closed timestamp</InternalLink> updates are delivered to <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">rangefeeds</InternalLink> and in turn emitted as a <InternalLink path="how-does-an-enterprise-changefeed-work">changefeed checkpoint</InternalLink>.

At the `0s` interval default for this setting, every range with a rangefeed will emit a checkpoint event based on the [`kv.closed_timestamp.side_transport_interval`](#kv-closed_timestamp-side_transport_interval) value (default `200ms`). Increasing the interval value for `kv.rangefeed.closed_timestamp_refresh_interval` will lengthen the delay between each checkpoint, which will increase the latency of changefeed checkpoints, but reduce the impact on SQL latency due to <InternalLink path="admission-control#use-cases-for-admission-control">overload</InternalLink> on the cluster.

If you are running changefeeds at a large scale and notice foreground SQL latency, we recommend increasing this setting.

As a result, adjusting `kv.rangefeed.closed_timestamp_refresh_interval` can affect changefeeds encountering latency **and** changefeeds causing foreground SQL latency. In clusters running large-scale workloads, it may be helpful to:

* **Decrease** the value for a lower changefeed emission latency — that is, how often a client can confirm that all relevant events up to a certain timestamp have been emitted.
* **Increase** the value to reduce the potential impact of changefeeds on SQL latency. This will lower the resource cost of changefeeds, which can be especially important for workloads with tables in the TB range of data.

It is important to note that a changefeed at default configuration does not checkpoint more often than once every 30 seconds. When you create a changefeed with <InternalLink path="create-changefeed">`CREATE CHANGEFEED`</InternalLink>, you can adjust this with the <InternalLink path="create-changefeed">`min_checkpoint_frequency`</InternalLink> option.

#### `kv.closed_timestamp.side_transport_interval`

**Default:** `200ms`

The `kv.closed_timestamp.side_transport_interval` cluster setting controls how often the closed timestamp is updated. Although the closed timestamp is updated every `200ms` by default, CockroachDB will emit an event across the rangefeed containing the closed timestamp value as per the cluster's [`kv.rangefeed.closed_timestamp_refresh_interval`](#kv-rangefeed-closed_timestamp_refresh_interval) setting, which by default is `0s`.

`kv.closed_timestamp.side_transport_interval` is helpful when ranges are inactive. The closed timestamp subsystem usually propagates <InternalLink path="architecture/transaction-layer#closed-timestamps">closed timestamps via Raft commands</InternalLink>. However, an idle range that does not see any writes does not receive any Raft commands, so it would stall. This setting is an efficient mechanism to broadcast closed timestamp updates for all idle ranges between nodes.

Adjusting `kv.closed_timestamp.side_transport_interval` will affect both <InternalLink path="follower-reads">follower reads</InternalLink> and changefeeds. While you can use `kv.closed_timestamp.side_transport_interval` to tune the checkpointing interval, we recommend `kv.rangefeed.closed_timestamp_refresh_interval` if you are using follower reads.

#### `kv.rangefeed.closed_timestamp_smear_interval`

**Default:** `1ms`

This setting provides a mechanism to pace the <InternalLink path="architecture/transaction-layer#closed-timestamps">closed timestamp</InternalLink> notifications to follower replicas. At the default, the closed timestamp smear interval makes rangefeed closed timestamp delivery less spiky, which can reduce its impact on foreground SQL query latency.

For example, if you have a large table, and one of the nodes in the cluster is hosting 6000 ranges from this table. Normally, the rangefeed system will wake up every [`kv.rangefeed.closed_timestamp_refresh_interval`](#kv-rangefeed-closed_timestamp_refresh_interval) setting and will publish checkpoints for all 6000 ranges. In this scenario, the `kv.rangefeed.closed_timestamp_smear_interval` setting takes the `kv.rangefeed.closed_timestamp_refresh_interval` frequency and divides it into `1ms` chunks. Instead of publishing checkpoints for all 6000 ranges, it will publish checkpoints for the calculated ranges every `1ms`. This produces a more predictable and level load, rather than spiky, large bursts of workload.

<Note>
  The default of [`kv.rangefeed.closed_timestamp_refresh_interval`](#kv-rangefeed-closed_timestamp_refresh_interval) is `0s`, so the event emission will fall back to [`kv.closed_timestamp.side_transport_interval`](#kv-closed_timestamp-side_transport_interval), which updates the closed timestamp (default `200ms`).
</Note>

### Lagging ranges

New in v23.1.12: Use the `changefeed.lagging_ranges` metric to track the number of <InternalLink path="architecture/overview">ranges</InternalLink> that are behind in a changefeed. This is calculated based on the <InternalLink path="cluster-settings">cluster settings</InternalLink>:

* `changefeed.lagging_ranges_threshold` sets a duration from the present that determines the length of time a range is considered to be lagging behind, which will then track in the <InternalLink path="monitor-and-debug-changefeeds#using-changefeed-metrics-labels">`lagging_ranges`</InternalLink> metric. Note that ranges undergoing an <InternalLink path="create-changefeed">initial scan</InternalLink> for longer than the threshold duration are considered to be lagging. Starting a changefeed with an initial scan on a large table will likely increment the metric for each range in the table. As ranges complete the initial scan, the number of ranges lagging behind will decrease.
  * **Default:** `3m`
* `changefeed.lagging_ranges_polling_interval` sets the interval rate for when lagging ranges are checked and the `lagging_ranges` metric is updated. Polling adds latency to the `lagging_ranges` metric being updated. For example, if a range falls behind by 3 minutes, the metric may not update until an additional minute afterward.
  * **Default:** `1m`

New in v23.1.29: Use the `changefeed.total_ranges` metric to monitor the number of ranges that are watched by <InternalLink path="how-does-an-enterprise-changefeed-work">aggregator processors</InternalLink> participating in the changefeed job. If you're experiencing lagging ranges, `changefeed.total_ranges` may indicate that the number of ranges watched by aggregator processors in the job is unbalanced. You may want to try <InternalLink path="pause-job">pausing</InternalLink> the changefeed and then <InternalLink path="resume-job">resuming</InternalLink> it, so that the changefeed replans the work in the cluster. `changefeed.total_ranges` shares the same polling interval as the `changefeed.lagging_ranges` metric, which is controlled by the `changefeed.lagging_ranges_polling_interval` cluster setting.

<Tip>
  You can use the <InternalLink path="monitor-and-debug-changefeeds#using-changefeed-metrics-labels">`metrics_label`</InternalLink> option to track the `lagging_ranges` and `total_ranges` metric per changefeed.
</Tip>

## Tuning for high durability delivery

When designing a system that relies on high durability message delivery—that is, not missing any message acknowledgement at the downstream sink—consider the following settings and configuration in this section:

* [Pausing changefeeds and garbage collection](#pausing-changefeeds-and-garbage-collection)
* [Defining Kafka message acknowledgment](#defining-kafka-message-acknowledgment)
* [Choosing changefeed sinks](#choosing-changefeed-sinks)
* [Defining schema change behavior](#defining-schema-change-behavior)

Before tuning these settings, we recommend reading details on our <InternalLink path="changefeed-messages#ordering-and-delivery-guarantees">changefeed at-least-once-delivery guarantee</InternalLink>.

### Pausing changefeeds and garbage collection

By default, <InternalLink path="architecture/storage-layer#protected-timestamps">protected timestamps</InternalLink> will protect changefeed data from <InternalLink path="architecture/storage-layer#garbage-collection">garbage collection</InternalLink> up to the time of the <InternalLink path="how-does-an-enterprise-changefeed-work">*checkpoint*</InternalLink>. Protected timestamps will protect changefeed data from garbage collection if the downstream <InternalLink path="changefeed-sinks">changefeed sink</InternalLink> is unavailable until you either <InternalLink path="cancel-job">cancel</InternalLink> the changefeed or the sink becomes available once again.

However, if the changefeed lags too far behind, the protected changes could lead to an accumulation of garbage. This could result in increased disk usage and degraded performance for some workloads.

For more detail on changefeeds and protected timestamps, refer to <InternalLink path="changefeed-messages#garbage-collection-and-changefeeds">Garbage collection and changefeeds</InternalLink>.

To balance protecting change data and prevent the over-accumulation of garbage, Cockroach Labs recommends creating a changefeed with [options to define your protection duration](#protecting-change-data-on-pause) and [monitoring your changefeed](#monitoring-protected-timestamp-records) for protected timestamp record collection.

#### Protecting change data on pause

<InternalLink path="create-changefeed">Create changefeeds</InternalLink> with the following options so that your changefeed protects data when it is <InternalLink path="pause-job">paused</InternalLink>:

* <InternalLink path="create-changefeed">`protect_data_from_gc_on_pause`</InternalLink>: to protect changes while the changefeed is paused until you <InternalLink path="resume-job">resume</InternalLink> the changefeed.
* <InternalLink path="create-changefeed">`on_error=pause`</InternalLink>: to pause the changefeed when it encounters an error. By default, changefeeds treat errors as retryable apart from some <InternalLink path="monitor-and-debug-changefeeds">exceptions</InternalLink>.
* New in v23.1: <InternalLink path="create-changefeed">`gc_protect_expires_after`</InternalLink>: to automatically expire the <InternalLink path="architecture/storage-layer#protected-timestamps">protected timestamp records</InternalLink> that are older than your defined duration and <InternalLink path="cancel-job">cancel</InternalLink> the changefeed job.

#### Monitoring protected timestamp records

New in v23.1: You can monitor changefeed jobs for <InternalLink path="architecture/storage-layer#protected-timestamps">protected timestamp</InternalLink> usage. We recommend setting up  monitoring  <InternalLink path="monitor-and-debug-changefeeds">monitoring</InternalLink> for the following metrics:

* `jobs.changefeed.protected_age_sec`: Tracks the age of the oldest <InternalLink path="architecture/storage-layer#protected-timestamps">protected timestamp</InternalLink> record protected by changefeed jobs. We recommend monitoring if `protected_age_sec` is greater than <InternalLink path="configure-replication-zones">`gc.ttlseconds`</InternalLink>. As `protected_age_sec` increases, garbage accumulation increases. <InternalLink path="architecture/storage-layer#garbage-collection">Garbage collection</InternalLink> will not progress on a table, database, or cluster if the protected timestamp record is present.
* `jobs.changefeed.currently_paused`: Tracks the number of changefeed jobs currently considered <InternalLink path="pause-job">paused</InternalLink>. Since paused changefeed jobs can accumulate garbage, it is important to <InternalLink path="pause-job#monitoring-paused-jobs">monitor the number of paused changefeeds</InternalLink>.
* `jobs.changefeed.expired_pts_records`: Tracks the number of expired <InternalLink path="architecture/storage-layer#protected-timestamps">protected timestamp</InternalLink> records owned by changefeed jobs. You can monitor this metric in conjunction with the <InternalLink path="create-changefeed">`gc_protect_expires_after` option</InternalLink>.
* `jobs.changefeed.protected_record_count`: Tracks the number of <InternalLink path="architecture/storage-layer#protected-timestamps">protected timestamp</InternalLink> records held by changefeed jobs.

### Defining Kafka message acknowledgment

To determine what a successful write to Kafka is, you can configure the <InternalLink path="changefeed-sinks#kafka-sink-configuration">`kafka_sink_config` option</InternalLink>. The `'RequiredAcks'` field specifies what a successful write to Kafka is. CockroachDB <InternalLink path="changefeed-messages#ordering-and-delivery-guarantees">guarantees at least once delivery of messages</InternalLink>—the `'RequiredAcks'` value defines the **delivery**.

For high durability delivery, Cockroach Labs recommends setting:

```
kafka_sink_config='{'RequiredAcks': 'ALL'}'
```

`ALL` provides the highest consistency level. A quorum of Kafka brokers that have committed the message must be reached before the leader can acknowledge the write.

You must also set `acks` to `ALL` in your [server-side Kafka configuration](https://kafka.apache.org/documentation/#producerconfigs_acks) for this to provide high durability delivery.

### Choosing changefeed sinks

Use <InternalLink path="changefeed-sinks#kafka">Kafka</InternalLink> or <InternalLink path="changefeed-sinks#cloud-storage-sink">cloud storage</InternalLink> sinks when tuning for high durability delivery in changefeeds. Both Kafka and cloud storage sinks offer built-in advanced protocols, whereas the <InternalLink path="changefeed-sinks#webhook-sink">webhook sink</InternalLink>, while flexible, requires an understanding of how messages are acknowledged and committed by the particular system used for the webhook in order to ensure the durability of message delivery.

<Note>
  New in v23.1: Enable the `changefeed.new_webhook_sink_enabled` <InternalLink path="cluster-settings">cluster setting</InternalLink> to improve the throughput of changefeeds emitting to  webhook sinks.  <InternalLink path="changefeed-sinks#webhook-sink">webhook sinks</InternalLink>.
</Note>

### Defining schema change behavior

Ensure that data is ingested downstream in its new format after a <InternalLink path="online-schema-changes">schema change</InternalLink> by using the <InternalLink path="create-changefeed">`schema_change_events`</InternalLink> and <InternalLink path="create-changefeed">`schema_schange_policy`</InternalLink> options. For example, setting `schema_change_events=column_changes` and `schema_change_policy=stop` will trigger an error to the `cockroach.log` file on a <InternalLink path="changefeed-messages#schema-changes-with-column-backfill">schema change</InternalLink> and the changefeed to fail.

## Tuning for high throughput

When designing a system that needs to emit a lot of changefeed messages, whether it be steady traffic or a burst in traffic, consider the following settings and configuration in this section:

* [Setting the `resolved` option](#setting-the-resolved-option)
* [Batching and buffering messages](#batching-and-buffering-messages)
* [Configuring file and message format](#configuring-file-and-message-format)
* [Configuring for tables with many ranges](#configuring-for-tables-with-many-ranges)
* [Adjusting concurrent changefeed work](#adjusting-concurrent-changefeed-work)

### Setting the `resolved` option

When a changefeed emits a <InternalLink path="create-changefeed">resolved</InternalLink> message, it force flushes all outstanding messages that have buffered, which will diminish your changefeed's throughput while the flush completes. Therefore, if you are aiming for higher throughput, we suggest setting the duration higher (e.g., 10 minutes), or **not** using the `resolved` option.

If you are setting the `resolved` option when you are aiming for high throughput, you must also consider the <InternalLink path="create-changefeed">`min_checkpoint_frequency`</InternalLink> option, which defaults to `30s`. This option controls how often nodes flush their progress to the <InternalLink path="how-does-an-enterprise-changefeed-work">coordinating changefeed node</InternalLink>. As a result, `resolved` messages will not be emitted more frequently than the configured `min_checkpoint_frequency`. Set this option to at least as long as your `resolved` option duration.

### Batching and buffering messages

* Batch messages to your sink:
  * For a <InternalLink path="changefeed-sinks#kafka">Kafka sink</InternalLink>, refer to the <InternalLink path="changefeed-sinks">`Flush`</InternalLink> parameter for the `kafka_sink_config` option.
  * For a <InternalLink path="changefeed-sinks#cloud-storage-sink">cloud storage sink</InternalLink>, use the <InternalLink path="create-changefeed">`file_size`</InternalLink> parameter to flush a file when it exceeds the specified size.
  * For a <InternalLink path="changefeed-sinks#webhook-sink">webhook sink</InternalLink>, refer to the <InternalLink path="changefeed-sinks#webhook-sink-configuration">`Flush`</InternalLink> parameter for the `webhook_sink_config` option.
* Set the <InternalLink path="cluster-settings">`changefeed.memory.per_changefeed_limit`</InternalLink> cluster setting to a higher limit to give more memory for buffering changefeed data. This setting influences how often the changefeed will flush buffered messages. This is useful during heavy traffic.

### Configuring file and message format

* Use `avro` as the emitted message <InternalLink path="create-changefeed">format</InternalLink> option with Kafka sinks; JSON encoding can potentially create a slowdown.

#### Compression

* Use the <InternalLink path="create-changefeed">`compression` option</InternalLink> when you create a changefeed emitting data files to a <InternalLink path="changefeed-sinks#cloud-storage-sink">cloud storage sink</InternalLink>. For larger files, set `compression` to the `zstd` format.
* Use the `snappy` compression format to emit messages to a <InternalLink path="changefeed-sinks">Kafka</InternalLink> sink. If you're intending to do large batching for Kafka, use the `lz4` compression format.

#### File size

To configure changefeeds emitting to <InternalLink path="changefeed-sinks#cloud-storage-sink">cloud storage sinks</InternalLink> for high throughput, you should consider:

* Increasing the <InternalLink path="create-changefeed">`file_size`</InternalLink> parameter to control the size of the files that the changefeed sends to the sink. The default is `16MB`. To configure for high throughput, we recommend `32MB`–`128MB`. Note that this is not a hard limit, and a changefeed will flush the file when it reaches the specified size.
* When you [compress](#compression) a file, it will contain many more events.
* File size is also dependent on what kind of data the changefeed job is writing. For example, large JSON blobs will quickly fill up the `file_size` value compared to small rows.
* When you change or increase `file_size`, ensure that you adjust the `changefeed.memory.per_changefeed_limit` <InternalLink path="cluster-settings">cluster setting</InternalLink>, which has a default of `512MiB`. Buffering messages can quickly reach this limit if you have increased the file size.

### Configuring for tables with many ranges

If you have a table with 10,000 or more <InternalLink path="architecture/overview#range">ranges</InternalLink>, you should consider increasing the following two <InternalLink path="cluster-settings">cluster settings</InternalLink>. We strongly recommend increasing these settings slowly. That is, increase the setting and then <InternalLink path="monitor-and-debug-changefeeds">monitor</InternalLink> its impact before adjusting further:

* `kv.rangefeed.catchup_scan_concurrency`: The number of catchups a <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">rangefeed</InternalLink> can execute concurrently. The default is `8`.
* `kv.rangefeed.concurrent_catchup_iterators`: The number of <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">rangefeed</InternalLink> catchup iterators a store will allow concurrently before queuing. The default is `16`.

### Adjusting concurrent changefeed work

* Increase the <InternalLink path="cluster-settings">`changefeed.backfill.concurrent_scan_requests` setting</InternalLink>, which controls the number of concurrent scan requests per node issued during a <InternalLink path="changefeed-messages#schema-changes-with-column-backfill">backfill event</InternalLink>. The default behavior, when this setting is at `0`, is that the number of scan requests will be 3 times the number of nodes in the cluster (to a maximum of 100). While increasing this number will allow for higher throughput, it **will increase the cluster load overall**, including CPU and IO usage.
* The <InternalLink path="cluster-settings">`kv.rangefeed.catchup_scan_iterator_optimization.enabled` setting</InternalLink> is `on` by default. This causes <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">rangefeeds</InternalLink> to use time-bound iterators for catch-up scans when possible. Catch-up scans are run for each rangefeed request. This setting improves the performance of changefeeds during some <InternalLink path="architecture/distribution-layer#range-splits">range-split operations</InternalLink>.

## See also

* <InternalLink path="cluster-settings">Cluster Settings</InternalLink>
* <InternalLink path="changefeed-sinks">Changefeed Sinks</InternalLink>
* <InternalLink path="create-changefeed">`CREATE CHANGEFEED`</InternalLink>
