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

# Follower Reads Topology

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

In a multi-region deployment, <InternalLink path="follower-reads">follower reads</InternalLink> are a good choice for tables with the following requirements:

* Read latency must be low, but write latency can be higher.
* Reads can be historical.
* Rows in the table, and all latency-sensitive queries, **cannot** be tied to specific geographies (e.g., a reference table).
* Table data must remain available during a region failure.

If reads can use stale data, use <InternalLink path="follower-reads#stale-follower-reads">stale follower reads</InternalLink>. If reads must be exactly up-to-date, use <InternalLink path="global-tables">global tables</InternalLink> to achieve <InternalLink path="follower-reads#follower-read-types">strong follower reads</InternalLink>. Up-to-date reads are required by tables referenced by <InternalLink path="foreign-key">foreign keys</InternalLink>, for example.

## Before you begin

### Fundamentals

* Multi-region topology patterns are almost always table-specific. If you haven't already, <InternalLink path="topology-patterns#multi-region">review the full range of patterns</InternalLink> to ensure you choose the right one for each of your tables.
* Review how data is replicated and distributed across a cluster, and how this affects performance. It is especially important to understand the concept of the "leaseholder". For a summary, see <InternalLink path="architecture/reads-and-writes-overview">Reads and Writes in CockroachDB</InternalLink>. For a deeper dive, see the CockroachDB <InternalLink path="architecture/overview">Architecture Overview</InternalLink>.
* Review the concept of <InternalLink path="cockroach-start#locality">locality</InternalLink>, which CockroachDB uses to place and balance data based on how you define <InternalLink path="configure-replication-zones">replication controls</InternalLink>.
* Review the recommendations and requirements in our <InternalLink path="recommended-production-settings">Production Checklist</InternalLink>.
* This topology doesn't account for hardware specifications, so be sure to follow our <InternalLink path="recommended-production-settings#hardware">hardware recommendations</InternalLink> and perform a POC to size hardware for your use case. For optimal cluster performance, Cockroach Labs recommends that all nodes use the same hardware and operating system.
* Adopt relevant <InternalLink path="performance-best-practices-overview">SQL Best Practices</InternalLink> to ensure optimal performance.

### Cluster setup

Each <InternalLink path="topology-patterns#multi-region">multi-region pattern</InternalLink> assumes the following setup:

<img src="https://mintcdn.com/cockroachlabs/bulMe5iV6qsi6_Jh/images/v23.2/topology-patterns/topology_multi-region_hardware.png?fit=max&auto=format&n=bulMe5iV6qsi6_Jh&q=85&s=6f6b846a1d1d33ba5b322add7d45e5db" alt="Multi-region hardware setup" width="960" height="540" data-path="images/v23.2/topology-patterns/topology_multi-region_hardware.png" />

#### Hardware

* 3 regions
* Per region, 3+ AZs with 3+ VMs evenly distributed across them
* Region-specific app instances and load balancers
  * Each load balancer redirects to CockroachDB nodes in its region.
  * When CockroachDB nodes are unavailable in a region, the load balancer redirects to nodes in other regions.

#### Cluster startup

Start each node with the <InternalLink path="cockroach-start#locality">`--locality`</InternalLink> flag specifying its region and AZ combination. For example, the following command starts a node in the `west1` AZ of the `us-west` region:

```shell theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
$ cockroach start \
--locality=region=us-west,zone=west1 \
--certs-dir=certs \
--advertise-addr=<node1 internal address \
--join=<node1 internal address:26257,<node2 internal address:26257,<node3 internal address:26257 \
--cache=.25 \
--max-sql-memory=.25 \
--background
```

## Configuration

With each node started with the <InternalLink path="cockroach-start#locality">`--locality`</InternalLink> flag specifying its region and zone combination, CockroachDB will balance the replicas for a table across the three regions:

<img src="https://mintcdn.com/cockroachlabs/bulMe5iV6qsi6_Jh/images/v23.2/topology-patterns/topology_follower_reads1.png?fit=max&auto=format&n=bulMe5iV6qsi6_Jh&q=85&s=0ff698a7a584f5367e485547e413f60b" alt="Follower reads table replication" width="960" height="540" data-path="images/v23.2/topology-patterns/topology_follower_reads1.png" />

### Summary

You configure your application to use <InternalLink path="follower-reads">follower reads</InternalLink> by adding an <InternalLink path="as-of-system-time">`AS OF SYSTEM TIME`</InternalLink> clause when reading from the table. With this clause CockroachDB reads slightly historical data from the closest replica so as to avoid being routed to the leaseholder, which may be in an entirely different region. Writes, however, will still leave the region to get consensus for the table.

### Steps

1. Create the `postal_codes` table:

   ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   > CREATE TABLE postal_codes (
       id INT PRIMARY KEY,
       code STRING
   );
   ```
2. Insert data into the `postal_codes` table:

   ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
   > INSERT INTO postal_codes (ID, code) VALUES (1, '10001'), (2, '10002'), (3, '10003'), (4,'60601'), (5,'60602'), (6,'60603'), (7,'90001'), (8,'90002'), (9,'90003');
   ```
3. Decide which type of follower read to perform: exact staleness or bounded staleness. For more information about when to use each type of read, see <InternalLink path="follower-reads#when-to-use-exact-staleness-reads">when to use exact staleness reads</InternalLink> and <InternalLink path="follower-reads#when-to-use-bounded-staleness-reads">when to use bounded staleness reads</InternalLink>.
   * To use <InternalLink path="follower-reads#exact-staleness-reads">exact staleness follower reads</InternalLink>, configure your app to use <InternalLink path="as-of-system-time">`AS OF SYSTEM TIME`</InternalLink> with the <InternalLink path="functions-and-operators">`follower_read_timestamp()` function</InternalLink> whenever reading from the table:

     ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
     > SELECT code FROM postal_codes
         AS OF SYSTEM TIME follower_read_timestamp()
                 WHERE id = 5;
     ```

     You can also set the `AS OF SYSTEM TIME` value for all operations in a read-only transaction:

     ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
     > BEGIN;

     SET TRANSACTION AS OF SYSTEM TIME follower_read_timestamp();

       SELECT code FROM postal_codes
         WHERE id = 5;

       SELECT code FROM postal_codes
         WHERE id = 6;

     COMMIT;
     ```

<Tip>
  Using the <InternalLink path="set-transaction#use-the-as-of-system-time-option">`SET TRANSACTION`</InternalLink> statement as shown in the preceding example will make it easier to use exact staleness follower reads from <InternalLink path="install-client-drivers">drivers and ORMs</InternalLink>.
</Tip>

* To use <InternalLink path="follower-reads#bounded-staleness-reads">bounded staleness follower reads</InternalLink>, configure your app to use <InternalLink path="as-of-system-time">`AS OF SYSTEM TIME`</InternalLink> with the <InternalLink path="functions-and-operators#date-and-time-functions">`with_min_timestamp()` or `with_max_staleness()` function</InternalLink> whenever reading from the table. Note that only single-row point reads in single-statement (implicit) transactions are supported.

  ```sql theme={"theme":{"light":"catppuccin-mocha","dark":"catppuccin-mocha"}}
  SELECT code FROM postal_codes AS OF SYSTEM TIME with_max_staleness('10s') where id = 5;
  ```

## Characteristics

### Latency

#### Reads

Reads retrieve historical data from the closest replica and, therefore, never leave the region. This makes read latency very low but slightly stale.

For example, in the following diagram:

1. The read request in `us-central` reaches the regional load balancer.
2. The load balancer routes the request to a gateway node.
3. The gateway node routes the request to the closest replica for the table. In this case, the replica is *not* the leaseholder.
4. The replica retrieves the results as of your preferred staleness interval in the past and returns to the gateway node.
5. The gateway node returns the results to the client.

<img src="https://mintcdn.com/cockroachlabs/bulMe5iV6qsi6_Jh/images/v23.2/topology-patterns/topology_follower_reads_reads.png?fit=max&auto=format&n=bulMe5iV6qsi6_Jh&q=85&s=96355e815f11a5e19268c287ac6bb93d" alt="Follower reads topology reads" width="960" height="540" data-path="images/v23.2/topology-patterns/topology_follower_reads_reads.png" />

#### Writes

The replicas for the table are spread across all 3 regions, so writes involve multiple network hops across regions to achieve consensus. This increases write latency significantly.

For example, in the following animation:

1. The write request in `us-central` reaches the regional load balancer.
2. The load balancer routes the request to a gateway node.
3. The gateway node routes the request to the leaseholder replica for the table in `us-east`.
4. Once the leaseholder has appended the write to its Raft log, it notifies its follower replicas.
5. As soon as one follower has appended the write to its Raft log (and thus a majority of replicas agree based on identical Raft logs), it notifies the leaseholder and the write is committed on the agreeing replicas.
6. The leaseholder then returns acknowledgement of the commit to the gateway node.
7. The gateway node returns the acknowledgement to the client.

<img src="https://mintcdn.com/cockroachlabs/bulMe5iV6qsi6_Jh/images/v23.2/topology-patterns/topology_follower_reads_writes.gif?s=661b8223127e4e0a8f2d10a2bae85334" alt="Follower reads topology writes" width="960" height="540" data-path="images/v23.2/topology-patterns/topology_follower_reads_writes.gif" />

### Resiliency

Because this pattern balances the replicas for the table across regions, one entire region can fail without interrupting access to the table:

<img src="https://mintcdn.com/cockroachlabs/bulMe5iV6qsi6_Jh/images/v23.2/topology-patterns/topology_follower_reads_resiliency.png?fit=max&auto=format&n=bulMe5iV6qsi6_Jh&q=85&s=2de1ddd02a0030434c36c34842c707db" alt="Follower reads topology region failure" width="960" height="540" data-path="images/v23.2/topology-patterns/topology_follower_reads_resiliency.png" />

## See also

* <InternalLink path="multiregion-overview">Multi-Region Capabilities Overview</InternalLink>
* <InternalLink path="choosing-a-multi-region-configuration">How to Choose a Multi-Region Configuration</InternalLink>
* <InternalLink path="multiregion-survival-goals#when-to-use-zone-vs-region-survival-goals">When to Use `ZONE` vs. `REGION` Survival Goals</InternalLink>
* <InternalLink path="table-localities#when-to-use-regional-vs-global-tables">When to Use `REGIONAL` vs. `GLOBAL` Tables</InternalLink>
* <InternalLink path="demo-low-latency-multi-region-deployment">Low Latency Reads and Writes in a Multi-Region Cluster</InternalLink>
* <InternalLink path="migrate-to-multiregion-sql">Migrate to Multi-Region SQL</InternalLink>
* <InternalLink path="multiregion-overview#secondary-regions">Secondary regions</InternalLink>
* <InternalLink path="alter-database#set-secondary-region">`ALTER DATABASE... SET SECONDARY REGION`</InternalLink>
* <InternalLink path="alter-database#drop-secondary-region">`ALTER DATABASE... DROP SECONDARY REGION`</InternalLink>
* <InternalLink path="topology-patterns">Topology Patterns Overview</InternalLink>
  * Single-region patterns
    * <InternalLink path="topology-development">Development</InternalLink>
    * <InternalLink path="topology-basic-production">Basic Production</InternalLink>
  * Multi-region patterns
    * <InternalLink path="regional-tables">`REGIONAL` Tables</InternalLink>
    * <InternalLink path="global-tables">`GLOBAL` Tables</InternalLink>
    * <InternalLink path="topology-follower-reads">Follower Reads</InternalLink>
    * <InternalLink path="topology-follow-the-workload">Follow-the-Workload</InternalLink>
