> ## 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.

# How Does an Enterprise Changefeed Work?

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>;
};

When an Enterprise changefeed is started on a node, that node becomes the *coordinator* for the changefeed job (**Node 2** in the diagram). The coordinator node acts as an administrator: keeping track of all other nodes during job execution and the changefeed work as it completes. The changefeed job will run across all nodes in the cluster to access changed data in the watched table. Typically, the <InternalLink path="architecture/replication-layer#leases">leaseholder</InternalLink> for a particular range (or the range’s replica) determines which node emits the changefeed data.

New in v23.1.23: You can enable the `changefeed.random_replica_selection.enabled` cluster setting to change the way in which a changefeed distributes work across the cluster. With `changefeed.random_replica_selection.enabled` set to `true`, the job will evenly distribute changefeed work across the cluster by assigning it to any <InternalLink path="architecture/replication-layer">replica</InternalLink> for a particular range. For `changefeed.random_replica_selection.enabled` to take effect on changefeed jobs, ensure you enable the cluster setting and then <InternalLink path="pause-job">pause</InternalLink> and <InternalLink path="resume-job">resume</InternalLink> existing changefeeds.

Each node uses its *aggregator processors* to send back checkpoint progress to the coordinator, which gathers this information to update the *high-water mark timestamp*. The high-water mark acts as a checkpoint for the changefeed’s job progress, and guarantees that all changes before (or at) the timestamp have been emitted. In the unlikely event that the changefeed’s coordinating node were to fail during the job, that role will move to a different node and the changefeed will restart from the last checkpoint. If restarted, the changefeed may <InternalLink path="changefeed-messages#duplicate-messages">re-emit messages</InternalLink> starting at the high-water mark time to the current time. Refer to <InternalLink path="changefeed-messages#ordering-and-delivery-guarantees">Ordering Guarantees</InternalLink> for detail on CockroachDB's at-least-once-delivery-guarantee and how per-key message ordering is applied.

<img src="https://mintcdn.com/cockroachlabs/FhMa-CZ_ZuDiPeyi/images/v23.1/changefeed-structure.png?fit=max&auto=format&n=FhMa-CZ_ZuDiPeyi&q=85&s=67238529b1d677823c368f1869da2360" alt="Changefeed process in a 3-node cluster" width="4708" height="3887" data-path="images/v23.1/changefeed-structure.png" />

With <InternalLink path="create-changefeed">`resolved`</InternalLink> specified when a changefeed is started, the coordinator will send the resolved timestamp (i.e., the high-water mark) to each endpoint in the sink. For example, when using <InternalLink path="changefeed-sinks#kafka">Kafka</InternalLink> this will be sent as a message to each partition; for <InternalLink path="changefeed-sinks#cloud-storage-sink">cloud storage</InternalLink>, this will be emitted as a resolved timestamp file.

As rows are updated, added, and deleted in the targeted table(s), the node sends the row changes through the <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">rangefeed mechanism</InternalLink> to the changefeed encoder, which encodes these changes into the <InternalLink path="changefeed-messages#responses">final message format</InternalLink>. The message is emitted from the encoder to the sink—it can emit to any endpoint in the sink. In the diagram example, this means that the messages can emit to any Kafka Broker.

<Note>
  When you create a changefeed using <InternalLink path="cdc-queries">change data capture queries</InternalLink>, the <InternalLink path="cost-based-optimizer">optimizer</InternalLink> will evaluate and optimize the query before the job sends the selected row changes to the changefeed encoder. The optimizer can restrict the rows a changefeed job considers during table scans, initial scans, and catch-up scans, which can make these more efficient using CDC queries.
</Note>

If you are running changefeeds from a <InternalLink path="multiregion-overview">multi-region</InternalLink> cluster, you may want to define which nodes take part in running the changefeed job. You can use the <InternalLink path="changefeeds-in-multi-region-deployments#run-a-changefeed-job-by-locality">`execution_locality` option</InternalLink> with key-value pairs to specify the locality requirements nodes must meet. See <InternalLink path="changefeeds-in-multi-region-deployments#job-coordination-using-the-execution-locality-option">Job coordination using the execution locality option</InternalLink> for detail on how a changefeed job works with this option.

See the following for more detail on changefeed setup and use:

* <InternalLink path="create-and-configure-changefeeds#enable-rangefeeds">Enable rangefeeds</InternalLink>
* <InternalLink path="changefeed-sinks">Changefeed Sinks</InternalLink>
* <InternalLink path="changefeed-examples">Changefeed Examples</InternalLink>
