Redis 8.2 release notes and breaking changes

Summary: Release notes and breaking changes for Redis 8.2 on Redis Cloud.

Overview

Redis 8.2 builds on the foundation of Redis 8.0 with significant performance and memory optimizations, enhanced streaming capabilities, and improved cluster management tools. For more information on the changes in Redis 8.2, see [What's new in Redis 8.2]() and review the Redis Open Source [8.2 release notes]().

Breaking changes

When new versions of Redis Open Source change existing commands, upgrading your database to a new version can potentially break some functionality. Before you upgrade, read the provided list of breaking changes that affect Redis Cloud and update any applications that connect to your database to handle these changes.

If you are upgrading from Redis 7.4, review the [Redis 8.0 breaking changes]() before upgrading.

Terraform compatibility limitation

If you use the [Redis Cloud Terraform provider]() versions 2.1.2 through 2.4.5 with Redis 8.2 databases, database creation will fail. This issue only affects the Terraform provider and does not impact existing databases or data.

To resolve this issue, upgrade to the [latest supported version](https://registry.terraform.io/providers/RedisLabs/rediscloud/latest) and run `terraform init -upgrade`.


Redis 8.4 release notes and breaking changes

Summary: Release notes and breaking changes for Redis 8.4 on Redis Cloud.

Overview

Redis 8.4 builds on the foundation of Redis 8.2 with significant enhancements to cluster operations, string manipulation, and stream processing capabilities.. For more information on the changes in Redis 8.4, see [What's new in Redis 8.4]() and review the Redis Open Source [8.4 release notes]().

Known limitations

When using Redis 8.4, be aware of these current limitations:

- Search commands (`FT.SEARCH`, `FT.AGGREGATE`, `FT.CURSOR`, `FT.HYBRID`) and time series commands (`TS.MGET`, `TS.MRANGE`, `TS.MREVRANGE`, `TS.QUERYINDEX`) may return partial results or duplicates during atomic slot migration.
- `FT.PROFILE`, `FT.EXPLAIN`, and `FT.EXPLAINCLI` don't include `FT.HYBRID` options.
- `FT.HYBRID` metrics aren't displayed in `FT.INFO` and `INFO` commands.
- Several `FT.HYBRID` options (`EXPLAINSCORE`, `SHARD_K_RATIO`, `YIELD_DISTANCE_AS`, `WITHCURSOR`) are not yet available.
- Post-filtering after the `COMBINE` step using `FILTER` is not currently supported.


Redis version release notes and breaking changes

Summary: Lists release notes and breaking changes for available Redis database versions on Redis Cloud.

Summary: Release notes and breaking changes for Redis 8.0 on Redis Cloud.

Redis 8.0 release notes and breaking changes

Summary: Release notes and breaking changes for Redis 7.4 on Redis Cloud.

Redis 7.4 release notes and breaking changes

Summary: Release notes and breaking changes for Redis 7.2 on Redis Cloud.

Redis 7.2 release notes and breaking changes

Content

When new versions of Redis Open Source change existing commands, upgrading your Redis Cloud database to a new version can potentially break some functionality. Before you upgrade, read the provided list of changes that affect Redis Cloud and update any applications that connect to your database to handle these changes.


Archive

Summary: Describes where to view the archive of Redis Cloud documentation.

Content

Previous versions of Redis Cloud documentation are available on the [Redis Cloud documentation archive](https://docs.redis.com/2024-04-07/rc/).


Sign up for Redis Cloud with AWS Marketplace

Summary: Shows how to subscribe to Redis Cloud using AWS Marketplace

Overview

You can use AWS Marketplace to subscribe to Redis Cloud through AWS Marketplace.  This lets you provision according to your needs and pay using your AWS account.

Subscribe to Redis Cloud with AWS Marketplace

Here's how to subscribe to Redis Cloud with AWS Marketplace:

1.  Sign in to the [AWS console](https://console.aws.amazon.com/).

1.  Search AWS Marketplace for [Redis Cloud Pay as you go with 14-day free trial](https://aws.amazon.com/marketplace/pp/prodview-mwscixe4ujhkq) and subscribe to the listing.

    Or, click on the URL provided by your Redis seller for a private offer for [Redis Cloud - Annual Commits](https://aws.amazon.com/marketplace/pp/prodview-e6y7ork67pjwg?sr=0-3&ref_=beagle&applicationId=AWSMPContessa) and accept the private offer.

1.  Locate the **Set Up Your Account button**, and then select it to begin mapping your Redis Cloud account with your AWS Marketplace account.

1.  Sign in to the [Redis Cloud console](https://cloud.redis.io). If you do not yet have an account, you will need to create one. You must have the **Account Owner** role.

1.  Select the Redis Cloud account(s) to be mapped to your AWS Marketplace account and confirm that your Marketplace account will pay for your Redis Cloud resources going forward.

1.  Use the **Connect account** button to confirm your choice.

You must complete this step to bill your Redis Cloud resources to your AWS Marketplace account.

1.  Once your Redis account is mapped to your AWS Marketplace account, your AWS Marketplace account will be charged for all your Redis Cloud resources going forward.

At this point, you can create a new database using the [standard workflow](), with one important change. You don't need to enter a payment method, as it's automatically assigned to your AWS Marketplace account.

To confirm this, review the payment method associated with your subscription.

If your AWS Marketplace account is deactivated or otherwise unavailable, you won't be able to use your databases until the billing method is updated.  For help, [contact support](https://redis.io/support/).

Add additional Redis accounts to AWS Marketplace

If you are the owner of more than one Redis Cloud account and have already associated your AWS marketplace account with one or more of your Redis accounts, you can add your AWS marketplace account to your other Redis Cloud accounts.

Switch from Annual to Pay as You Go

If you have an Annual private offer and want to switch to a Pay as You Go subscription, you can do so by subscribing to the [Redis Cloud Pay as you go with 14-day free trial](https://aws.amazon.com/marketplace/pp/prodview-mwscixe4ujhkq) listing. Both existing and future resources will continue to be billed under the Annual offer until it expires, after which they will be billed under the Pay as You Go offer.

Disconnect AWS Marketplace account

See [Disconnect AWS Marketplace account](https://support.redislabs.com/hc/en-us/articles/29215779949074-Disconnect-Redis-Cloud-from-AWS-Marketplace) on the Redis knowledge base for help disconnecting your AWS Marketplace account from your Redis Cloud account.


Sign up for Redis Cloud with Google Cloud Marketplace

Summary: Shows how to subscribe to Redis Cloud using Google Cloud marketplace

Summary: Shows how to add users in a legacy version of the Google Cloud Marketplace subscription.

Google Cloud Marketplace team management

Overview

You can use Google Cloud marketplace to subscribe to Redis Cloud. This lets you provision according to your needs and pay using your Google Cloud account.

Subscribe to Redis Cloud using Google Cloud marketplace

Here's how to subscribe to Redis Cloud with Google Cloud marketplace:

1.  Sign in to the [Google Cloud console](https://console.cloud.google.com/).

1. Identify the Google Cloud Billing account that will subscribe to Redis Cloud. This account must have one of the following sets of Identity and Access Management (IAM) Roles:

    - [Billing Administrator](https://cloud.google.com/billing/docs/how-to/billing-access#overview-of-cloud-billing-roles-in-cloud-iam) (`roles/billing.admin`), OR
    - [Billing User](https://cloud.google.com/billing/docs/how-to/billing-access#overview-of-cloud-billing-roles-in-cloud-iam) (`roles/billing.user`) AND [Consumer Procurement Order Administrator](https://cloud.google.com/marketplace/docs/access-control#roles-permissions)

    If you don't have the correct roles, request access from your Google Cloud Billing Administrator or Organization Administrator. For more information about granting roles, see [Access control for Google Cloud Marketplace](https://cloud.google.com/marketplace/docs/access-control).

1.  Search Google Cloud Marketplace for [Redis® Cloud Cache and Vector Database](https://console.cloud.google.com/marketplace/product/redis-marketplace-isaas/redis-enterprise-cloud-flexible-plan).

    Alternatively, in the navigation panel, select **View all products** and select **Redis Cloud** under **Databases**. You can pin Redis Cloud for easy access.

    Or, click on the URL provided by your Redis seller for a private offer for **Redis Cloud - Annual** and accept the private offer.

1.  Select the **Subscribe** button. This redirects you to the subscription details page.

1. Under **Purchase Details**, select the Google Cloud Billing account that will subscribe to Redis Cloud. Review the subscription details, accept the terms, and select **Subscribe**.

1. When you subscribe for the first time, select **Sign Up with Redis**. This will redirect you to the [Redis Cloud console](https://cloud.redis.io).

1. Create a Redis Cloud account or sign in to an existing account. You must have the **Account Owner** role.

1.  Select the Redis account to be mapped to your GCP Marketplace account and confirm that your Marketplace account will pay for your Redis Cloud resources going forward.

1.  Select **Connect account** to confirm your choice.

You must complete this step to bill your Redis Cloud resources to your Google Cloud Marketplace account.

1.  After you connect your Redis account to your Google Cloud Marketplace account, your Google Cloud Marketplace account will be charged for all your Redis Cloud resources going forward.

1. On the Google Cloud Marketplace listing, select **Manage on provider** to go to the [Redis Cloud console](https://cloud.redis.io).

At this point, you can create a new database using the [standard workflow](), with one important change. You don't need to enter a payment method, as it automatically uses your Google Cloud Marketplace account.

To confirm this, review the payment method associated with your subscription.

Additional users can be added on the Redis Cloud console using the [Access Management]() page.

If your Google Cloud Marketplace account is deactivated or otherwise unavailable, you can't use your subscription until you update the billing method.  For help, [contact support](https://redis.io/support/).

Add additional Redis accounts to Google Cloud marketplace

If you are the owner of more than one Redis Cloud account and have already associated your Google Cloud marketplace account with one or more of your Redis accounts, you can add your Google Cloud marketplace account to your other Redis Cloud accounts.

Switch from Annual to Pay as You Go

If you have an Annual private offer and want to switch to a Pay as You Go subscription, you can do so by subscribing to the [Redis® Cloud Cache and Vector Database](https://console.cloud.google.com/marketplace/product/redis-marketplace-isaas/redis-enterprise-cloud-flexible-plan) listing. Both existing and future resources will continue to be billed under the Annual offer until it expires, after which they will be billed under the Pay as You Go offer.

Disconnect Google Cloud marketplace account

See [Disconnect Google Cloud Marketplace account](https://support.redislabs.com/hc/en-us/articles/29209085344018-Disconnect-Redis-Cloud-from-Google-Cloud-Marketplace) on the Redis knowledge base for help disconnecting your Google Cloud Marketplace account from your Redis Cloud account.


Content

This article applies to an earlier Google Cloud marketplace listing. For the current [Redis Cloud - Pay as You Go](https://console.cloud.google.com/marketplace/product/redis-marketplace-isaas/redis-enterprise-cloud-flexible-plan) listing, manage your team through the [Access Management]() screen. See [Sign up for Redis Cloud with Google Cloud Marketplace]() for more information.

If you subscribed to Redis Cloud through Google Cloud Marketplace using the **Redis Cloud** listing, use the IAM section of the Google Cloud console to manage your team.

To grant Redis Cloud access to a Google Cloud user, select **Add** to add a member, insert the email address, and then assign the following roles to the user:
- To designate a viewer, assign `editor`, `serviceusage.serviceUsageViewer`, and `redisenterprisecloud.viewer`
- To designate an owner, assign `editor`, `serviceusage.serviceUsageViewer`, and `redisenterprisecloud.admin`

If these roles are not available, you can add them to your project.

1. Select **Manage Roles**.
2. Use the filter table field to locate the role. (Search for "service usage viewer" or "Redis Cloud admin".)
3. Select the role.
4. Select **Create role from selection** and then select **Create**.
5. Use IAM to add a member and assign the desired role.

Users must sign in to Redis Cloud using their single sign-on credentials before they appear in the team member list.


Deploy Redis Cloud as a Heroku add-on

Summary: Add Redis Cloud to your Heroku applications for fast data storage and caching.


Manage marketplace integrations

Summary: Describes how to integrate Redis Cloud subscriptions into existing cloud provider services, whether existing subscriptions or through vendor marketplaces.

Summary: Shows how to create a Redis Cloud database with Vercel integration.

Create a Redis Cloud database with the Vercel integration

Deploy Redis Cloud as a Heroku add-on

Overview

By default, Redis Cloud subscriptions are hosted in cloud vendor accounts owned and managed by Redis.

To integrate Redis Cloud into an existing cloud vendor account, you can:

- Subscribe to Redis Cloud through [AWS Marketplace]().

- Subscribe to Redis Cloud through [Google Cloud Marketplace]().

When you subscribe to Redis Cloud through a cloud vendor marketplace, billing is handled through the marketplace.

Redis also offers monthly and annual commitments through cloud vendor marketplaces. [Contact sales](https://redis.io/meeting/) if you're interested in a monthly or annual offer.

Marketplace billing considerations

Cloud vendor marketplaces provide a convenient way to handle multiple subscription fees.  However, this also means that billing issues impact multiple subscriptions, including Redis Cloud.

When billing details change, you should verify that each service is operating normally and reflects the updated billing details.  Otherwise, you might experience unexpected consequences, such as data loss or subscription removal.

For best results, we recommend:

- [Backing up all data]() _before_ updating billing details.

- Contacting [support](https://redis.io/support/) or your account team for assistance.


Overview

The [Redis Cloud Vercel integration](https://vercel.com/marketplace/redis-cloud) lets you create a new Redis database from your Vercel account and connect it to your Vercel project(s).

Create database

1. Log in to your Vercel account (or create a new one).

1. Navigate to the **Storage** tab and select **Create database**.

1. Under **Storage partners**, select **View all partners**.

1. Find **Redis Cloud** and select **Continue**.

1. In the **Create Database** dialog, select your plan and **Continue**.

    More configuration options are coming soon, such as region selection and multi-zone high availability.

1. Enter your database name or use the automatically generated name.

1. Select **Create**.

Connect to your database

After creation, you will see your database details. After provisioning is complete, the status will change from `Initializing` to `Available` (you may need to refresh your browser).

You can use the connection string shown under **Quickstart** to [connect to your database]().

Link database to your project

1. Navigate to the **Storage** tab.
1. Find your new database in the list of your team's databases.
1. Select **Connect Project**.

1. Choose your project and environments and select **Connect**.

Manage your database

From the database details page, you can make edits to your database under **Settings**.

More configuration options are coming soon, including plan changes, multi-zone high availability, and region selection.

Configure from Redis Cloud

You can also edit some configuration options in Redis Cloud.

From the database detail page, select **Open in Redis Cloud**.

Your Redis Cloud account is linked to your Vercel account. All your team's Redis databases will be listed under **Databases** in Redis Cloud.

Select your new database to make configuration changes such as passwords or the eviction policy.

 The [eviction policy]() defaults to `no eviction` for new databases.  You can change this by [editing the database details]().


Summary: Redis Cloud compatibility with Redis Open Source.

Overview

Both [Redis Software]() and Redis Cloud are compatible with Redis Open Source.

RESP compatibility

Redis Software and Redis Cloud support RESP2 and RESP3. In Redis Cloud, you can choose between RESP2 and RESP3 when you [create a database]() and you can change it when you [edit a database](). For more information about the different RESP versions, see the [Redis serialization protocol specification](#resp-versions).

Client-side caching compatibility

Redis Software and Redis Cloud support [client-side caching]() for databases with Redis versions 7.4 or later. See [Client-side caching compatibility with Redis Software and Redis Cloud]() for more information about compatibility.

Compatibility with Redis Cluster API

Redis Cloud supports [Redis Cluster API]() on Redis Cloud Pro if it is enabled for a database. Review [Redis Cluster API architecture]() to determine if you should enable this feature for your database.


Create an Active-Active database

Summary: Shows how to create an Active-Active database

Overview

Active-Active databases store data across multiple regions and availability zones.  This improves scalability, performance, and availability, especially when compared to standalone databases. See [Active-Active Redis]() for more information.

To deploy Active-Active databases in Redis Cloud, you need a Redis Cloud Pro plan that enables Active-Active Redis and defines the regions for each copy of your databases.

Active-Active databases consist of multiple copies (also called _instances_) deployed to different regions throughout the world.

This reduces latency for local users and improves availability should a region fail.

Redis Cloud maintains consistency among instances in the background; that is, each copy eventually includes updates from every region.  As a result, memory limit and throughput increase.

Create an Active-Active database

3. Select the type of [subscription]() you need. For this guide, select **Pro**.

This guide shows how to create an Active-Active database with a new Pro subscription. If you already have an Active-Active subscription and want to add a database to it, see [Create a Pro database in an existing subscription](). Active-Active subscriptions can host a maximum of 10 databases.

After you select **Pro**, the **Database settings** section will appear.

For this guide, select **Custom settings**. For an Active-Active database, you will need to:

1. Set up the deployment options, including cloud vendor and region details for each instance.

2. Define the database size requirements.

3. Review your choices, provide payment details, and then create your databases.

The following sections provide more information.

Set up deployment details

The **Setup** tab specifies general settings for your Redis deployment.

There are two sections on this tab:

- [General settings](#general-settings) include the cloud provider details and specific configuration options.
- [Advanced options](#advanced-options) define settings for high availability and security. Configurable settings vary according to cloud provider.

#### General settings {#general-settings}

Select **Active-Active (Multi-region)** to turn on Active-Active.

When you enable Active-Active Redis, two regions are selected by default. Select the drop-down arrow to display a list of provider regions that support Active-Active databases.

Active-Active subscriptions on Redis Cloud are limited to a maximum of 10 regions.

Use the checkboxes in the list to select or remove regions.  The Search box lets you locate specific regions.

You can use a region's Remove button to remove it from the list.

#### Advanced options {#advanced-options}

In the **Advanced options** section, you can:

- Choose to deploy your Active-Active database to an existing Cloud Account, if [Redis Cloud Bring your own Cloud]() is enabled.

- Define CIDR addresses for each region in the **VPC configuration** section.

    If you chose to deploy your Active-Active database to an existing [Bring your own Cloud]() account, you can also define the VPC ID for each region. Select **In existing VPC** and the set the VPC ID for each selected region.

- Set your [maintenance]() settings in the **Maintenance windows** section. Select **Manual** if you want to set [manual maintenance windows]().

Multi-AZ replication is required for all Active-Active databases.

When finished, choose **Continue** to determine your size requirements.

Sizing tab

The **Sizing** tab helps you specify the database, memory, and throughput requirements for your subscription.

When you first visit the **Sizing** tab, there are no databases defined.  Select the **Add** button to create one.

This opens the **Database configurations** dialog, which lets you define the requirements for your new database.

By default, you're shown basic settings, which include:

- **Name**: A custom name for your database.
- **Version**: The Redis version for your database. We recommend you choose the latest available version.
- **Advanced Capabilities**: Advanced data types or features used by the database. Active-Active databases support the [JSON]() data type and [Search and query]() features.

    For Redis versions prior to 8.0, we select both capabilities for you automatically. You can remove a capability by clicking on it while selected. Selected capabilities will be available in all regions, including those added in the future.

    Starting with Redis 8.0, JSON and Search and query are included by default.

    See [Search and query Active-Active databases]() to learn how to use Search and query on Active-Active databases.

- **Dataset size**: The amount of data needed for your dataset in GB.

    For Search and query databases, use the [Sizing calculator](https://redis.io/redisearch-sizing-calculator/) to estimate your index size and throughput requirements. When you're entering the dataset size for your database, add the estimated index size from the Sizing calculator to your expected dataset size.

- **Hashing policy**: Determines how data is distributed across multiple Redis processes of a database. Available options depend on your account creation date. See [Clustering]() for more information.

- **Throughput**: When you create an Active-Active database, you define the throughput for each instance. The total operations per second combines the total read ops/sec and applies the write ops/sec for each region across every region.

    The total ops/sec for each region is calculated as follows:

    [code example]

    The total ops/sec for the database is the sum of the ops/sec for each region.

    Because each instance needs the ability to write to every other instance, write operations significantly affect the total number of ops/sec.

    Select a tab to see examples of throughput calculations for different Active-Active configurations.

    **Two regions, balanced between regions:**

For this database, we have two regions where read and write operations are balanced between the regions, as described in the table below:

| Region | Local read ops/sec | Local write ops/sec |
|:------:|:------------------:|:-------------------:|
| Region 1 | 2000 | 1000 |
| Region 2 | 2000 | 1000 |

The total ops/sec for this database is calculated as follows:

[code example]

**Two regions, read/write heavy in one region:**

For this database, we have two regions where one region has more read and write operations than the other region, as described in the table below:

| Region | Local read ops/sec | Local write ops/sec |
|:------:|:------------------:|:-------------------:|
| Region 1 | 2000 | 1000 |
| Region 2 | 4000 | 2000 |

The total ops/sec for this database is calculated as follows:

[code example]

**Three regions, balanced between regions:**

For this database, we have three regions where read and write operations are balanced between the regions, as described in the table below:

| Region | Local read ops/sec | Local write ops/sec |
|:------:|:------------------:|:-------------------:|
| Region 1 | 2000 | 1000 |
| Region 2 | 2000 | 1000 |
| Region 3 | 2000 | 1000 |

The total ops/sec for this database is calculated as follows:

[code example]

**Three regions, different read/write in each region:**

For this database, we have three regions where read and write operations are different between the regions, as described in the table below:

| Region | Local read ops/sec | Local write ops/sec |
|:------:|:------------------:|:-------------------:|
| Region 1 | 3000 | 1000 |
| Region 2 | 4000 | 3000 |
| Region 3 | 1000 | 2000 |

The total ops/sec for this database is calculated as follows:

[code example]

    For Search and query databases, the estimated throughput from the [Sizing calculator](https://redis.io/redisearch-sizing-calculator/) is the total amount of throughput you need. When setting throughput for your Active-Active database, use the total amount for each region and divide it depending on your read (query) and write (update) needs for each region. For example, if the total amount of throughput needed is 50000 ops/sec, you could set each region to have 20000 ops/sec for reads (queries) and 30000 ops/sec for writes (updates).

- **Data Persistence**: Defines the data persistence policy, if any. See [Database persistence]().
- **Supported Protocol(s)**: Choose between RESP2 and RESP3 _(Redis 7.2 or later)_. See [Redis serialization protocol](#resp-versions) for details.
- **Quantity**: Number of databases to create with these settings.

When finished, select **Save configuration** to save your database configuration.

Use the **Add database** button to define additional databases or select the **Continue button** to display the **Review and create** tab.

Hover over a database to see the **Edit** and **Delete** icons. You can use the **Edit** icon to change a database or the **Delete** icon to remove a database from the list.

Review and Create tab

The **Review and Create** tab provides a cost estimate for your Redis Cloud Pro plan:

Redis breaks down your databases to Redis Billing Units (RBUs), each with their own size and throughput requirements. For more info, see [Billing unit types](#billing-unit-types).

The **Payment methods** section of this tab shows which payment method you're using for this database. Select the arrow on the top right of this section to view all available payment methods.

If you have not added a payment method or want to add a new payment method, select **Add credit card** to add a new credit card.

Select **Back to Sizing** to make changes or **Confirm & Pay** to create your databases.

Note that databases are created in the background.  While they are provisioning, you aren't allowed to make changes. This process generally takes 10-15 minutes.

Use the **Database list** to check the status of your databases.

More info

- [Create a Pro database with a new subscription]()
- [Active-Active Redis]()
- [Develop applications with Active-Active databases]()
- Database [memory limit]()
- Redis Cloud [subscription plans]()
- [Redis Cloud pricing](https://redis.io/pricing/#monthly)

Region ops/sec = Local read ops/sec +
                    Sum of write ops/sec from all regions

Region 1 ops/sec = 2000 (local read) +
                   1000 (local write) +
                   1000 (write from Region 2) = 4000 ops/sec

Region 2 ops/sec = 2000 (local read) +
                   1000 (local write) +
                   1000 (write from Region 1) = 4000 ops/sec

Total ops/sec = 4000 (Region 1) + 4000 (Region 2)
              = 8000 ops/sec

Region 1 ops/sec = 2000 (local read) +
                   1000 (local write) +
                   2000 (write from Region 2) = 5000 ops/sec

Region 2 ops/sec = 4000 (local read) +
                   2000 (local write) +
                   1000 (write from Region 1) = 7000 ops/sec

Total ops/sec = 5000 (Region 1) + 7000 (Region 2)
              = 12000 ops/sec

Region 1 ops/sec = 2000 (local read) +
                   1000 (local write) +
                   1000 (write from Region 2) +
                   1000 (write from Region 3) = 5000 ops/sec

Region 2 ops/sec = 2000 (local read) +
                   1000 (local write) +
                   1000 (write from Region 1) +
                   1000 (write from Region 3) = 5000 ops/sec

Region 3 ops/sec = 2000 (local read) +
                   1000 (local write) +
                   1000 (write from Region 1) +
                   1000 (write from Region 2) = 5000 ops/sec

Total ops/sec = 5000 (Region 1) + 5000 (Region 2) + 5000 (Region 3)
              = 15000 ops/sec

Region 1 ops/sec = 3000 (local read) +
                   1000 (local write) +
                   3000 (write from Region 2) +
                   2000 (write from Region 3) = 9000 ops/sec

Region 2 ops/sec = 4000 (local read) +
                   3000 (local write) +
                   1000 (write from Region 1) +
                   2000 (write from Region 3) = 10000 ops/sec

Region 3 ops/sec = 1000 (local read) +
                   2000 (local write) +
                   1000 (write from Region 1) +
                   3000 (write from Region 2) = 7000 ops/sec

Total ops/sec = 9000 (Region 1) + 10000 (Region 2) + 7000 (Region 3)
              = 26000 ops/sec


Application failover with Active-Active databases

Summary: How to failover your application to connect to a remote replica.

Overview

Active-Active Redis deployments don't have a built-in failover or failback mechanism for application connections.
An application deployed with an Active-Active database connects to a replica of the database that is geographically nearby.
If that replica is not available, the application can failover to a remote replica, and failback again if necessary.
In this article we explain how this process works.

For other disaster recovery strategies including network-based, proxy-based, and client library approaches, see [Active-Active disaster recovery strategies]().

Active-Active connection failover can improve data availability, but can negatively impact data consistency.
Active-Active replication, like Redis replication, is asynchronous.
An application that fails over to another replica can miss write operations.
If the failed replica saved the write operations in persistent storage,
then the write operations are processed when the failed replica recovers.

Detecting Failure

Your application can detect two types of failure:

1. **Local failures** - The local replica is down or otherwise unavailable
1. **Replication failures** - The local replica is available but fails to replicate to or from remote replicas

You can also use [database availability API requests]() to determine if a database replica is available to handle read and write operations. The lag-aware database availability requests considers CRDT replication lag as a health check criterion to prevent reading stale data during failback scenarios.

Local Failures

Local failure is detected when the application is unable to connect to the database endpoint for any reason. Reasons for a local failure can include: multiple node failures, configuration errors, connection refused, connection timed out, unexpected protocol level errors.

Replication Failures

Replication failures are more difficult to detect reliably without causing false positives. Replication failures can include: network split, replication configuration issues, remote replica failures.

The most reliable method for health-checking replication is by using the Redis publish/subscribe (pub/sub) mechanism.

Note that this document does not suggest that Redis pub/sub is reliable in the common sense. Messages can get lost in certain conditions, but that is acceptable in this case because typically the application determines that replication is down only after not being able to deliver a number of messages over a period of time.

When you use the pub/sub data type to detect failures, the application:

1. Connects to all replicas and subscribes to a dedicated channel for each replica.
1. Connects to all replicas and periodically publishes a uniquely identifiable message.
1. Monitors received messages and ensures that it is able to receive its own messages within a predetermined window of time.

You can also use known dataset changes to monitor the reliability of the replication stream,
but pub/sub is preferred method because:

1. It does not involve dataset changes.
1. It does not make any assumptions about the dataset.
1. Pub/sub messages are delivered as replicated effects and are a more reliable indicator of a live replication link. In certain cases, dataset keys may appear to be modified even if the replication link fails. This happens because keys may receive updates through full-state replication (re-sync) or through online replication of effects.

Impact of sharding on failure detection

If your sharding configuration is symmetric, make sure to use at least one key (PUB/SUB channels or real dataset key) per shard. Shards are replicated individually and are vulnerable to failure. Symmetric sharding configurations have the same number of shards and hash slots for all replicas.
We do not recommend an asymmetric sharding configuration, which requires at least one key per hash slot that intersects with a pair of shards.

To make sure that there is at least one key per shard, the application should:

1. Use the Cluster API to retrieve the database sharding configuration.
1. Compute a number of key names, such that there is one key per shard.
1. Use those key names as channel names for the pub/sub mechanism.

Failing over

When the application needs to failover to another replica, it should simply re-establish its connections with the endpoint on the remote replica. Because Active/Active and Redis replication are asynchronous, the remote endpoint may not have all of the locally performed and acknowledged writes.

It's best if your application doesn't read its own recent writes. Those writes can be either:

1. Lost forever, if the local replica has an event such as a double failure or loss of persistent files.
1. Temporarily unavailable, but will be available at a later time if the local replica's failure is temporary.

<!---
Sample code that maps a hash slot to a key name can be found in this Python script.
 --->

Failback decision

Your application can use the same checks described above to continue monitoring the state of the failed replica after failover.

To monitor the state of a replica during the failback process, you must make sure the replica is available, re-synced with the remote replicas, and not in stale mode. The PUB/SUB mechanism is an effective way to monitor this.

Dataset-based mechanisms are potentially less reliable for several reasons:
1. In order to determine that a local replica is not stale, it is not enough to simply read keys from it. You must also attempt to write to it.
1. As stated above, remote writes for some keys appear in the local replica before the replication link is back up and while the replica is still in stale mode.
1. A replica that was never written to never becomes stale, so on startup it is immediately ready but serves stale data for a longer period of time.

Replica Configuration Changes

All failover and failback operations should be done strictly on the application side, and should not involve changes to the Active-Active configuration.
The only valid case for re-configuring the Active-Active deployment and removing a replica is when memory consumption becomes too high because garbage collection cannot be performed.
Once a replica is removed, it can only be re-joined as a new replica and it loses any writes that were not converged.


Hashes in an Active-Active databases

Summary: Information about using hashes with an Active-Active database.

Content

Hashes are great for structured data that contain a map of fields and
values. They are used for managing distributed user or app session
state, user preferences, form data and so on. Hash fields contain string
type and string types operate just like the standard Redis string types
when it comes to CRDTs. Fields in hashes can be initialized as a string
using HSET or HMSET or can be used to initialize counter types that are
numeric integers using HINCRBY or floats using HINCRBYFLOAT.

Hashes in Active-Active databases behave the same and maintain additional metadata to
achieve an "OR-Set" behavior to handle concurrent conflicting writes.
With the OR-Set behavior, writes to add new fields across multiple Active-Active database
instances are typically unioned except in cases of conflicts.
Conflicting instance writes can happen when an Active-Active database instance deletes a
field while the other adds the same field. In this case and observed
remove rule is followed. That is, remove can only remove fields it has
already seen and in all other cases element add/update wins.

Field values behave just like CRDT strings. String values can be types
string, counter integer based on the command used for initialization of
the field value. See "String Data Type in Active-Active databases" and "String Data Type
with Counter Value in Active-Active databases" for more details.

Here is an example of an "add wins" case:

|  **Time** | **CRDB Instance1** | **CRDB Instance2** |
|  ------: | :------: | :------: |
|  t1 | HSET key1 field1 "a" |  |
|  t2 |  | HSET key1 field2 "b" |
|  t4 | - Sync - | - Sync - |
|  t5 | HGETALL key1
1) "field2"
2) "b"
3) "field1"
4) "a" | HGETALL key1
1) "field2"
2) "b"
3) "field1"
4) "a" |


HyperLogLog in Active-Active databases

Summary: Information about using hyperloglog with an Active-Active database.

Overview

**HyperLogLog** is an algorithm that addresses the [count-distinct problem](https://en.wikipedia.org/wiki/Count-distinct_problem).
To do this it approximates the numbers of items in a [set](https://en.wikipedia.org/wiki/Multiset).
Determining the _exact_ cardinality of a set requires memory according to the cardinality of the set.
Because it estimates the cardinality by probability, the HyperLogLog algorithm can run with more reasonable memory requirements.

HyperLogLog in Redis

Redis Open source implements [HyperLogLog](https://redislabs.com/redis-best-practices/counting/hyperloglog/) (HLL) as a native data structure.
It supports adding elements ([PFADD]() to an HLL, counting elements ([PFCOUNT]() of HLLs, and merging of ([PFMERGE]() HLLs.

Here is an example of a simple write case:

| Time | Replica 1         | Replica 2         |
| ---- | ----------------- | ----------------- |
| t1   | PFADD hll x       |                   |
| t2   | --- sync ---      |                   |
| t3   |                   | PFADD hll y       |
| t4   | --- sync ---      |                   |
| t5   | PFCOUNT hll --> 2 | PFCOUNT hll --> 2 |

Here is an example of a concurrent add case:

| Time | Replica 1         | Replica 2         |
| ---- | ----------------- | ----------------- |
| t1   | PFADD hll x       | PFADD hll y       |
| t2   | PFCOUNT hll --> 1 | PFCOUNT hll --> 1 |
| t3   | --- sync ---      |                   |
| t4   | PFCOUNT hll --> 2 | PFCOUNT hll --> 2 |

The DEL-wins approach

Other collections in the Redis-CRDT implementation use the observed remove method to resolve conflicts.
The CRDT-HLL uses the DEL-wins method.
If a DEL request is received at the same time as any other request (ADD/MERGE/EXPIRE) on the HLL-key
the replicas consistently converge to delete key.
In the observed remove method used by other collections (sets, lists, sorted-sets and hashes),
only the replica that received the DEL request removes the elements, but elements added concurrently in other replicas exist in the consistently converged collection.
We chose to use the DEL-wins method for the CRDT-HLL to maintain the original time and space complexity of the HLL in Redis Open source.

Here is an example of a DEL-wins case:

| HLL  |                 |                 | \|  | Set  |                     |                     |
| ---- | --------------- | --------------- | --- | ---- | ------------------- | ------------------- |
|      |                 |                 | \|  |      |                     |                     |
| Time | Replica 1       | Replica 2       | \|  | Time | Replica 1           | Replica 2           |
|      |                 |                 | \|  |      |                     |                     |
| t1   | PFADD h e1      |                 | \|  | t1   | SADD s e1           |                     |
| t2   | --- sync ---    |                 | \|  | t2   | --- sync ---        |                     |
| t3   | PFCOUNT h --> 1 | PFCOUNT h --> 1 | \|  | t3   | SCARD s --> 1       | SCARD s --> 1       |
| t4   | PFADD h e2      | Del h           | \|  | t4   | SADD s e2           | Del S               |
| t5   | PFCOUNT h --> 2 | PFCOUNT h --> 0 | \|  | t5   | SCARD s --> 2       | SCARD s --> 0       |
| t6   | --- sync ---    |                 | \|  | t6   | --- sync ---        |                     |
| t7   | PFCOUNT h --> 0 | PFCOUNT h --> 0 | \|  | t7   | SCARD s --> 1       | SCARD s --> 1       |
| t8   | Exists h --> 0  | Exists h --> 0  | \|  | t8   | Exists s --> 1      | Exists s --> 1      |
|      |                 |                 | \|  | t9   | SMEMBERS s --> {e2} | SMEMBERS s --> {e2} |

HLL in Active-Active databases versus HLL in Redis Open source

In Active-Active databases, we implemented HLL within the CRDT on the basis of the Redis implementation with a few exceptions:

- Redis keeps the HLL data structure as an encoded string object
    such that you can potentially run any string request can on a key that contains an HLL. In CRDT, only get and set are supported for HLL.
- In CRDT, if you do SET on a key that contains a value encoded as an HLL, then the value will remain an HLL. If the value is not encoded as HLL, then it will be a register.


Data types for Active-Active databases

Summary: Introduction to differences in data types between standalone and Active-Active Redis databases.

Hashes in an Active-Active databases

HyperLogLog in Active-Active databases

Summary: Information about using JSON with an Active-Active database.

JSON in Active-Active databases

Summary: Information about using list with an Active-Active database.

Lists in Active-Active databases

Summary: Information about using sets with an Active-Active database.

Sets in Active-Active databases

Summary: Information about using sorted sets with an Active-Active database.

Sorted sets in Active-Active databases

Summary: Information about using streams with an Active-Active database.

Streams in Active-Active databases

Summary: Information about using strings and bitfields with an Active-Active database.

Strings and bitfields in Active-Active databases

Content

Active-Active databases use conflict-free replicated data types (CRDTs). From a developer perspective, most supported data types work the same for Active-Active and standard Redis databases. However, a few methods also come with specific requirements in Active-Active databases.

Even though they look identical to standard Redis data types, there are specific rules that govern the handling of
conflicting concurrent writes for each data type.

As conflict handling rules differ between data types, some commands have slightly different requirements in Active-Active databases versus standard Redis databases.

See the following articles for more information.


JSON in Active-Active databases

Overview

Active-Active databases support JSON data structures.

The design is based on [A Conflict-Free Replicated JSON Datatype](https://arxiv.org/abs/1608.03960) by Kleppmann and Beresford, but the implementation includes some changes. Several [conflict resolution rule](#conflict-resolution-rules) examples were adapted from this paper as well.

Prerequisites

To use JSON in an Active-Active database, you must enable JSON during database creation.

Active-Active Redis Cloud databases add JSON by default. See [Create an Active-Active subscription]() in the Redis Cloud documentation for details.

In Redis Software, Active-Active databases created with or upgraded to Redis version 8 or later automatically enable JSON. For earlier Redis versions, see [Create an Active-Active JSON database]() in the Redis Stack and Redis Software documentation for instructions.


Lists in Active-Active databases

Content

Redis lists are simply lists of strings, sorted by insertion order. It
is possible to add elements to a Redis List that push new elements to
the head (on the left) or to the tail (on the right) of the list. Redis
lists can be used to easily implement queues (using LPUSH and RPOP, for
example) and stacks (using LPUSH and LPOP, for
example).

Lists in Active-Active databases are just the same as regular Redis Lists. See the
following examples to get familiar with Lists' behavior in an
Active-Active database.

Simple Lists
example:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | LPUSH mylist "hello" |  |
|  t2 | — Sync — | — Sync — |
|  t3 |  | LPUSH mylist "world" |
|  t4 | — Sync — | — Sync — |
|  t5 | LRANGE mylist 0 -1 =>"world" "hello" | LRANGE mylist 0 -1 => "world" "hello" |

**Explanation**:
The final list contains both the "world" and "hello" elements, in that
order (Instance 2 observed "hello" when it added
"world").

Example of Lists with Concurrent
Insertions:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | LPUSH L x |  |
|  t2 | — Sync — | — Sync — |
|  t3 | LINSERT L AFTER x y1 |  |
|  t4 |  | LINSERT L AFTER x y2 |
|  t5 | LRANGE L 0 -1 => x y1 | LRANGE L 0 -1 => x y2 |
|  t6 | — Sync — | — Sync — |
|  t7 | LRANGE L 0 -1 => x y1 y2 | LRANGE L 0 -1 => x y1 y2 |

**Explanation**:
Instance 1 added an element y1 after x, and then Instance 2 added element y2 after x.
The final List contains all three elements: x is the first element, after it y1 and then y2.
The Active-Active database resolves the conflict arbitrarily but applies the resolution consistently across all Active-Active database instances.

Example of Deleting a List while Pushing a New
Element:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | LPUSH L x |  |
|  t2 | — Sync — | — Sync — |
|  t3 | LRANGE L 0 -1 => x | LRANGE L 0 -1 => x |
|  t4 | LPUSH L y | DEL L |
|  t5 | — Sync — | — Sync — |
|  t6 | LRANGE L 0 -1 => y | LRANGE L 0 -1 => y |

**Explanation**
At t4 - t6, DEL deletes only observed elements. This is why L still
contains y.

Example of Popping Elements from a
List:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | LPUSH L x y z |  |
|  t2 | — Sync — | — Sync — |
|  t3 |  | RPOP L => x |
|  t4 | — Sync — | — Sync — |
|  t5 | RPOP L => y |  |
|  t6 | — Sync — | — Sync — |
|  t7 | RPOP L => z | RPOP L => z |

**Explanation**:
At t1, the operation pushes elements x, y, z to List L. At t3, the
sequential pops behave as expected from a queue. At t7, the concurrent
pop in both instances might show the same result. The instance was not
able to sync regarding the z removal so, from the point of view of each
instance, z is located in the List and can be popped. After syncing,
both lists are empty.

Be aware of the behavior of Lists in Active-Active databases when using List as a stack
or queue. As seen in the above example, two parallel RPOP operations
performed by two different Active-Active database instances can get the same element in
the case of a concurrent operation. Lists in Active-Active databases guarantee that each
element is POP-ed at least once, but cannot guarantee that each
element is POP-ed only once. Such behavior should be taken into
account when, for example, using Lists in Active-Active databases as building blocks for
inter-process communication systems.

In that case, if the same element cannot be handled twice by the
applications, it's recommended that the POP operations be performed by
one Active-Active database instance, whereas the PUSH operations can be performed by
multiple instances.


Sets in Active-Active databases

Content

A Redis set is an unordered collection of strings. It is possible to
add, remove, and test for the existence of members with Redis commands.
A Redis set maintains a unique collection of elements. Sets can be great
for maintaining a list of events (click streams), users (in a group
conversation), products (in recommendation lists), engagements (likes,
shares) and so on.

Sets in Active-Active databases behave the same and maintain additional metadata to
achieve an "OR-Set" behavior to handle concurrent conflicting
writes. With the OR-Set behavior, writes across multiple Active-Active database instances
are typically unioned except in cases of conflicts. Conflicting instance
writes can happen when a Active-Active database instance deletes an element while the
other adds the same element. In this case and observed remove rule is
followed. That is, remove can only remove instances it has already seen
and in all other cases element add wins.

Here is an example of an "add wins" case:

|  **Time** | **CRDB Instance1** | **CRDB Instance2** |
|  ------: | :------: | :------: |
|  t1 | SADD key1 "a" |  |
|  t2 |  | SADD key1 "b" |
|  t3 | SMEMBERS key1 "a" | SMEMBERS key1 "b" |
|  t4 | — Sync — | — Sync — |
|  t3 | SMEMBERS key1 "a" "b" | SMEMBERS key1 "a" "b" |

Here is an example of an "observed remove" case.

|  **Time** | **CRDB Instance1** | **CRDB Instance2** |
|  ------: | :------: | :------: |
|  t1 | SMEMBERS key1 "a" "b" | SMEMBERS key1 "a" "b" |
|  t2 | SREM key1 "a" | SADD key1 "c" |
|  t3 | SREM key1 "c" |  |
|  t4 | — Sync — | — Sync — |
|  t3 | SMEMBERS key1 "c" "b" | SMEMBERS key1 "c" "b" |


Sorted sets in Active-Active databases

Content

[Redis Geospatial (Geo)]() is based on Sorted Sets, so the same Active-Active database development instructions apply to Geo.

Similar to Redis Sets, Redis Sorted Sets are non-repeating collections
of Strings. The difference between the two is that every member of a
Sorted Set is associated with a score used to order the Sorted Set from
lowest to highest. While members are unique, they may have the same
score.

With Sorted Sets, you can quickly add, remove or update elements as
well as get ranges by score or by rank (position). Sorted Sets in Active-Active databases
behave the same and maintain additional metadata to handle concurrent
conflicting writes. Conflict resolution is done in two
phases:

1. First, the database resolves conflict at the set level using "OR
    Set" (Observed-Remove Set). With OR-Set behavior, writes across
    multiple Active-Active database instances are typically unioned except in cases of
    conflicts. Conflicting writes can happen when an Active-Active database instance
    deletes an element while the other adds or updates the same element.
    In this case, an observed Remove rule is followed, and only
    instances it has already seen are removed. In all other cases, the
    Add / Update element wins.
1. Second, the database resolves conflict at the score level. In this
    case, the score is treated as a counter and applies the same
    conflict resolution as regular counters.

See the following examples to get familiar with Sorted Sets'
behavior in Active-Active database:

Example of Simple Sorted Set with No
Conflict:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | ZADD Z 1.1 x |  |
|  t2 | — Sync — | — Sync — |
|  t3 |  | ZADD Z 1.2 y |
|  t4 | — Sync — | — Sync — |
|  t5 | ZRANGE Z 0 -1 => x y | ZRANGE Z 0 -1 => x y |

**Explanation**:
When adding two different elements to a Sorted Set from different
replicas (in this example, x with score 1.1 was added by Instance 1 to
Sorted Set Z, and y with score 1.2 was added by Instance 2 to Sorted Set
Z) in a non-concurrent manner (i.e. each operation happened separately
and after both instances were in sync), the end result is a Sorted
Set including both elements in each Active-Active database instance.
Example of Sorted Set and Concurrent
Add:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | ZADD Z 1.1 x |  |
|  t2 |  | ZADD Z 2.1 x |
|  t3 | ZSCORE Z x => 1.1 | ZSCORE Z x => 2.1 |
|  t4 | — Sync — | — Sync — |
|  t5 | ZSCORE Z x => 2.1 | ZSCORE Z x => 2.1 |

**Explanation**:
When concurrently adding an element x to a Sorted Set Z by two different
Active-Active database instances (Instance 1 added score 1.1 and Instance 2 added score
2.1), the Active-Active database implements Last Write Win (LWW) to determine the score of
x. In this scenario, Instance 2 performed the ZADD operation at time
t2\>t1 and therefore the Active-Active database sets the score 2.1 to
x.

Example of Sorted Set with Concurrent Add Happening at the Exact Same
Time:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | ZADD Z 1.1 x | ZADD Z 2.1 x |
|  t2 | ZSCORE Z x => 1.1 | ZSCORE Z x => 2.1 |
|  t3 | — Sync — | — Sync — |
|  t4 | ZSCORE Z x => 1.1 | ZSCORE Z x => 1.1 |

**Explanation**:
The example above shows a relatively rare situation, in which two Active-Active database
instances concurrently added the same element x to a Sorted Set at the
same exact time but with a different score, i.e. Instance 1 added x with
a 1.1 score and Instance 2 added x with a 2.1 score. After syncing, the
Active-Active database realized that both operations happened at the same time and
resolved the conflict by arbitrarily (but consistently across all Active-Active database
instances) giving precedence to Instance 1.
Example of Sorted Set with Concurrent Counter
Increment:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | ZADD Z 1.1 x |  |
|  t2 | — Sync — | — Sync — |
|  t3 | ZINCRBY Z 1.0 x | ZINCRBY Z 1.0 x |
|  t4 | — Sync — | — Sync — |
|  t5 | ZSCORE Z x => 3.1 | ZSCORE Z x => 3.1 |

**Explanation**:
The result is the sum of all
ZINCRBY
operations performed by all Active-Active database instances.

Example of Removing an Element from a Sorted
Set:

|  **Time** | **CRDB Instance 1** | **CRDB Instance 2** |
|  ------: | :------: | :------: |
|  t1 | ZADD Z 4.1 x |  |
|  t2 | — Sync — | — Sync — |
|  t3 | ZSCORE Z x => 4.1 | ZSCORE Z x => 4.1 |
|  t4 | ZREM Z x | ZINCRBY Z 2.0 x |
|  t5 | ZSCORE Z x => nill | ZSCORE Z x => 6.1 |
|  t6 | — Sync — | — Sync — |
|  t7 | ZSCORE Z x => 2.0 | ZSCORE Z x => 2.0 |

**Explanation**:
At t4 - t5, concurrent ZREM and ZINCRBY operations ran on Instance 1
and Instance 2 respectively. Before the instances were in sync, the ZREM
operation could only delete what had been seen by Instance 1, so
Instance 2 was not affected. Therefore, the ZSCORE operation shows the
local effect on x. At t7, after both instances were in-sync, the Active-Active database
resolved the conflict by subtracting 4.1 (the value of element x in
Instance 1) from 6.1 (the value of element x in Instance 2).


Streams in Active-Active databases

Overview

A [Redis Stream]() is a data structure that acts like an append-only log.
Each stream entry consists of:

- A unique, monotonically increasing ID
- A payload consisting of a series key-value pairs

You add entries to a stream with the XADD command. You access stream entries using the XRANGE, XREADGROUP, and XREAD commands (however, see the caveat about XREAD below).

Streams and Active-Active

Active-Active databases allow you to write to the same logical stream from more than one region.
Streams are synchronized across the regions of an Active-Active database.

In the example below, we write to a stream concurrently from two regions. Notice that after syncing, both regions have identical streams:

Time
Region 1
Region 2

t1
XADD messages * text hello
XADD messages * text goodbye

t2
XRANGE messages - +
→ [1589929244828-1]
XRANGE messages - +
→ [1589929246795-2]

t3
— Sync —
— Sync —

t4
XRANGE messages - +
→ [1589929244828-1, 1589929246795-2]
XRANGE messages - +
→ [1589929244828-1, 1589929246795-2]

Notice also that the synchronized streams contain no duplicate IDs. As long as you allow the database to generate your stream IDs, you'll never have more than one stream entry with the same ID.

Redis Open Source uses one radix tree (referred to as `rax` in the code base) to implement each stream. However, Active-Active databases implement a single logical stream using one `rax` per region.
Each region adds entries only to its associated `rax` (but can remove entries from all `rax` trees).
This means that XREAD and XREADGROUP iterate simultaneously over all `rax` trees and return the appropriate entry by comparing the entry IDs from each `rax`.

Conflict resolution

Active-Active databases use an "observed-remove" approach to automatically resolve potential conflicts.

With this approach, a delete only affects the locally observable data.

In the example below, a stream, `x`, is created at _t1_. At _t3_, the stream exists in two regions.

Time
Region 1
Region 2

t1
XADD messages * text hello

t2
— Sync —
— Sync —

t3
XRANGE messages - +
→ [1589929244828-1]
XRANGE messages - +
→ [1589929244828-1]

t4
DEL messages
XADD messages * text goodbye

t5
— Sync —
— Sync —

t6
XRANGE messages - +
→ [1589929246795-2]
XRANGE messages - +
→ [1589929246795-2]

At _t4_, the stream is deleted from Region 1. At the same time, an entry with ID ending in `3700` is added to the same stream at Region 2. After the sync, at _t6_, the entry with ID ending in `3700` exists in both regions. This is because that entry was not visible when the local stream was deleted at _t4_.

ID generation modes

Usually, you should allow Redis streams generate its own stream entry IDs. You do this by specifying `*` as the ID in calls to XADD. However, you _can_ provide your own custom ID when adding entries to a stream.

Because Active-Active databases replicate asynchronously, providing your own IDs can create streams with duplicate IDs. This can occur when you write to the same stream from multiple regions.

| Time | Region 1                      | Region 2                      |
| ---- | ------------------------------- | ------------------------------- |
| _t1_   | `XADD x 100-1 f1 v1`              | `XADD x 100-1 f1 v1`              |
| _t2_   | _— Sync —_                    | _— Sync —_                    |
| _t3_   | `XRANGE x - +`
 **→ [100-1, 100-1]** | `XRANGE x - +`
 **→ [100-1, 100-1]** |

In this scenario, two entries with the ID `100-1` are added at _t1_. After syncing, the stream `x` contains two entries with the same ID.

Stream IDs in Redis Open Source consist of two integers separated by a dash ('-'). When the server generates the ID, the first integer is the current time in milliseconds, and the second integer is a sequence number. So, the format for stream IDs is MS-SEQ.

To prevent duplicate IDs and to comply with the original Redis streams design, Active-Active databases provide three ID modes for XADD:

1. **Strict**: In _strict_ mode, XADD allows server-generated IDs (using the '`*`' ID specifier) or IDs consisting only of the millisecond (MS) portion. When the millisecond portion of the ID is provided, the ID's sequence number is calculated using the database's region ID. This prevents duplicate IDs in the stream. Strict mode rejects full IDs (that is, IDs containing both milliseconds and a sequence number).
1. **Semi-strict**: _Semi-strict_ mode is just like _strict_ mode except that it allows full IDs (MS-SEQ). Because it allows full IDs, duplicate IDs are possible in this mode.
1. **Liberal**: XADD allows any monotonically ascending ID. When given the millisecond portion of the ID, the sequence number will be set to `0`. This mode may also lead to duplicate IDs.

The default and recommended mode is _strict_, which prevents duplicate IDs.

Why do you want to prevent duplicate IDs? First, XDEL, XCLAIM, and other commands can affect more than one entry when duplicate IDs are present in a stream. Second, duplicate entries may be removed if a database is exported or renamed.

To change XADD's ID generation mode, use the `rladmin` command-line utility:

Set _strict_ mode:
[code example]

Set _semi-strict_ mode:
[code example]

Set _liberal_ mode:
[code example]

Iterating a stream with XREAD

In Redis Open Source and in non-Active-Active databases, you can use XREAD to iterate over the entries in a Redis Stream. However, with an Active-Active database, XREAD may skip entries. This can happen when multiple regions write to the same stream.

In the example below, XREAD skips entry `115-2`.

| Time | Region 1                                         | Region 2                                         |
| ---- | -------------------------------------------------- | -------------------------------------------------- |
| _t1_   | `XADD x 110 f1 v1`                                   | `XADD x 115 f1 v1`                                   |
| _t2_   | `XADD x 120 f1 v1`                                   |                                                    |
| _t3_   | `XADD x 130 f1 v1`                                   |                                                    |
| _t4_   | `XREAD COUNT 2 STREAMS x 0`
**→ [110-1, 120-1]**       |                                                    |
| _t5_   | _— Sync —_                                       | _— Sync —_                                       |
| _t6_   | `XREAD COUNT 2 STREAMS x 120-1`
**→ [130-1]**            |                                                    |
| _t7_   | `XREAD STREAMS x 0`
**→[110-1, 115-2, 120-1, 130-1]** | `XREAD STREAMS x 0`
**→[110-1, 115-2, 120-1, 130-1]** |

You can use XREAD to reliably consume a stream only if all writes to the stream originate from a single region. Otherwise, you should use XREADGROUP, which always guarantees reliable stream consumption.

Consumer groups

Active-Active databases fully support consumer groups with Redis Streams. Here is an example of creating two consumer groups concurrently:

| Time | Region 1                  | Region 2                  |
| ---- | --------------------------- | --------------------------- |
| _t1_   | `XGROUP CREATE x group1 0`        | `XGROUP CREATE x group2 0`        |
| _t2_   | `XINFO GROUPS x`
**→ [group1]**     | `XINFO GROUPS x`
**→ [group2]**     |
| _t3_   | _— Sync —_                | — Sync —                |
| _t4_   | `XINFO GROUPS x`
**→ [group1, group2]** | `XINFO GROUPS x`
**→ [group1, group2]** |

Redis Open Source uses one radix tree (`rax`) to hold the global pending entries list and another `rax` for each consumer's PEL.
The global PEL is a unification of all consumer PELs, which are disjoint.

An Active-Active database stream maintains a global PEL and a per-consumer PEL for each region.

When given an ID different from the special ">" ID, XREADGROUP iterates simultaneously over all of the PELs for all consumers.
It returns the next entry by comparing entry IDs from the different PELs.

Conflict resolution

The "delete wins" approach is a way to automatically resolve conflicts with consumer groups.
In case of concurrent consumer group operations, a delete will "win" over other concurrent operations on the same group.

In this example, the DEL at _t4_ deletes both the observed `group1` and the non-observed `group2`:

| Time | Region 1              | Region 2              |
| ---- | ----------------------- | ----------------------- |
| _t1_   | `XGROUP CREATE x group1 0`    |                         |
| _t2_   | _— Sync —_            | _— Sync —_            |
| _t3_   | `XINFO GROUPS x`
**→ [group1]** | `XINFO GROUPS x`
**→ [group1]** |
| _t4_   | `DEL x`                   | `XGROUP CREATE x group2 0`    |
| _t5_   | _— Sync —_            | _— Sync —_            |
| _t6_   | `EXISTS x`
**→ 0** | `EXISTS x`
**→  0**          |

In this example, the XGROUP DESTROY at _t4_ affects both the observed `group1` created in Region 1 and the non-observed `group1` created in Region 3:

| time | Region 1              | Region 2              | Region 3            |
| ---- | ----------------------- | ----------------------- | --------------------- |
| _t1_   | `XGROUP CREATE x group1 0`    |                         |                       |
| _t2_   | _— Sync —_            | _— Sync —_            |                       |
| _t3_   | `XINFO GROUPS x`
**→ [group1]** | `XINFO GROUPS x`
**→  [group1]** | `XINFO GROUPS x`
**→  []** |
| _t4_   |                         | `XGROUP DESTROY x group1`     | `XGROUP CREATE x group1 0` |
| _t5_   | _— Sync —_            | _— Sync —            | — Sync —          |
| _t6_   | `EXISTS x`
**→  0**          | `EXISTS x`
**→ 0**          | `EXISTS x`
**→  0**    |

Group replication

Calls to XREADGROUP and XACK change the state of a consumer group or consumer. However, it's not efficient to replicate every change to a consumer or consumer group.

To maintain consumer groups in Active-Active databases with optimal performance:

1. Group existence (CREATE/DESTROY) is replicated.
1. Most XACK operations are replicated.
1. Other operations, such as XGROUP, SETID, DELCONSUMER, are not replicated.

For example:

| Time | Region 1                                        | Region 2               |
| ---- | ------------------------------------------------- | ------------------------ |
| _t1_   | `XADD messages 110 text hello`                                |                          |
| _t2_   | `XGROUP CREATE messages group1 0`                              |                          |
| _t3_   | `XREADGROUP GROUP group1 Alice STREAMS messages >`
**→ [110-1]** |                          |
| _t4_   | _— Sync —_                                      | _— Sync —_             |
| _t5_   | `XRANGE messages - +`
**→ [110-1]**                          | XRANGE messages - +
**→ [110-1]** |
| _t6_   | `XINFO GROUPS messages`
**→ [group1]**                            | XINFO GROUPS messages
**→ [group1]**   |
| _t7_   | `XINFO CONSUMERS messages group1`
**→ [Alice]**                      | XINFO CONSUMERS messages group1
**→ []**  |
| _t8_   | `XPENDING messages group1 - + 1`
**→ [110-1]**                     | XPENDING messages group1 - + 1
**→ []** |

Using XREADGROUP across regions can result in regions reading the same entries.
This is due to the fact that Active-Active Streams is designed for at-least-once reads or a single consumer.
As shown in the previous example, Region 2 is not aware of any consumer group activity, so redirecting the XREADGROUP traffic from Region 1 to Region 2 results in reading entries that have already been read.

Replication performance optimizations

Consumers acknowledge messages using the XACK command. Each ack effectively records the last consumed message. This can result in a lot of cross-region traffic. To reduce this traffic, we replicate XACK messages only when all of the read entries are acknowledged.

| Time | Region 1                                                      | Region 2   | Explanation                                                                                |
| ---- | --------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------- |
| _t1_   | `XADD x 110-0 f1 v1`                                              |              |                                                                                |
| _t2_   | `XADD x 120-0 f1 v1`                                              |              |                                                                                |
| _t3_   | `XADD x 130-0 f1 v1`                                              |              |                                                                                |
| _t4_   | `XGROUP CREATE x group1 0`                                            |              |                                                                                |
| _t5_   | `XREADGROUP GROUP group1 Alice STREAMS x >` <br/>**→ [110-0, 120-0, 130-0]** |              |                                                                                |
| _t6_   | `XACK x group1 110-0`                                                   |              |                                                                                |
| _t7_   | _— Sync —_                                                    | _— Sync —_ | 110-0 and its preceding entries (none) were acknowledged. We replicate an XACK effect for 110-0.                |
| _t8_   | `XACK x group1 130-0`                                                   |              |                                                                                |
| _t9_   | _— Sync —_                                                    | _— Sync —_ | 130-0 was acknowledged, but not its preceding entries (120-0). We DO NOT replicate an XACK effect for 130-0     |
| _t10_  | `XACK x group1 120-0`                                                   |              |                                                                                |
| _t11_  | _— Sync —_                                                    | _— Sync —_ | 120-0 and its preceding entries (110-0 through 130-0) were acknowledged. We replicate an XACK effect for 130-0. |

In this scenario, if we redirect the XREADGROUP traffic from Region 1 to Region 2 we do not re-read entries 110-0, 120-0 and 130-0.
This means that the XREADGROUP does not return already-acknowledged entries.

Guarantees

Unlike XREAD, XREADGOUP will never skip stream entries.

In traffic redirection, XREADGROUP may return entries that have been read but not acknowledged. It may also even return entries that have already been acknowledged.

When entries are added from multiple regions, Redis guarantees ordered entries in the reply of a single read command (`XREAD`, `XREADGROUP`, or `XRANGE`). However, ordered IDs are not guaranteed for a sequence of read commands.
For example, two subsequent `XREADGROUP GROUP group consumer COUNT 1 STREAMS key >` commands may reply with decreasing IDs.

Summary

With Active-Active streams, you can write to the same logical stream from multiple regions. As a result, the behavior of Active-Active streams differs somewhat from the behavior you get with Redis Open Source. This is summarized below:

Stream commands

1. When using the _strict_ ID generation mode, XADD does not permit full stream entry IDs (that is, an ID containing both MS and SEQ).
1. XREAD may skip entries when iterating a stream that is concurrently written to from more than one region. For reliable stream iteration, use XREADGROUP instead.
1. XSETID fails when the new ID is less than current ID.

Consumer group notes

The following consumer group operations are replicated:

1. Consecutive XACK operations
1. Consumer group creation and deletion (that is, XGROUP CREATE and XGROUP DESTROY)

All other consumer group metadata is not replicated.

A few other notes:

1. XGROUP SETID and DELCONSUMER are not replicated.
1. Consumers exist locally (XREADGROUP creates a consumer implicitly).
1. Renaming a stream (using RENAME) deletes all consumer group information.

rladmin tune db crdb crdt_xadd_id_uniqueness_mode strict

rladmin tune db crdb crdt_xadd_id_uniqueness_mode semi-strict

rladmin tune db crdb crdt_xadd_id_uniqueness_mode liberal


Overview

Active-Active databases support both strings and bitfields.

Active-Active **bitfield** support was added in RS version 6.0.20.

Changes to both of these data structures will be replicated across Active-Active member databases.

Replication semantics

Except in the case of [string counters]() (see below), both strings and bitfields are replicated using a "last write wins" approach. The reason for this is that strings and bitfields are effectively binary objects. So, unlike with lists, sets, and hashes, the conflict resolution semantics of a given operation on a string or bitfield are undefined.

How "last write wins" works

A wall-clock timestamp (OS time) is stored in the metadata of every string
and bitfield operation. If the replication syncer cannot determine the order of operations,
the value with the latest timestamp wins. This is the only case with Active-Active databases where OS time is used to resolve a conflict.

Here's an example where an update happening to the same key at a later
time (t2) wins over the update at t1.

|  **Time** | **Region 1** | **Region 2** |
|  :------: | :------: | :------: |
|  t1 | SET text "a" |  |
|  t2 |  | SET text "b" |
|  t3 | — Sync — | — Sync — |
|  t4 | SET text "c" |  |
|  t5 | — Sync — | — Sync — |
|  t6 |  | SET text "d" |

String counter support

When you're using a string as counter (for instance, with the [INCR]() or [INCRBY]() commands),
then conflicts will be resolved semantically.

On conflicting writes, counters accumulate the total counter operations
across all member Active-Active databases in each sync.

Here's an example of how counter
values works when synced between two member Active-Active databases. With
each sync, the counter value accumulates the private increment and
decrements of each site and maintain an accurate counter across
concurrent writes.

|  **Time** | **Region 1** | **Region 2** |
|  :------: | :------: | :------: |
|  t1 | INCRBY counter 7 |  |
|  t2 |  | INCRBY counter 3 |
|  t3 | GET counter
7 | GET counter
3 |
|  t4 | — Sync — | — Sync — |
|  t5 | GET counter
10 | GET counter
10 |
|  t6 | DECRBY counter 3 |  |
|  t7 |  | INCRBY counter 6 |
|  t8 | — Sync — | — Sync — |
|  t9 | GET counter
13 | GET counter
13 |

Active-Active databases support 59-bit counters.
This limitation is to protect from overflowing a counter in a concurrent operation.


Develop applications with Active-Active databases

Summary: Overview of how developing applications differs for Active-Active databases from standalone Redis databases.

Overview

Developing geo-distributed, multi-master applications can be difficult.
Application developers may have to understand a large number of race
conditions between updates to various sites, network, and cluster
failures that could reorder the events and change the outcome of the
updates performed across geo-distributed writes.

Active-Active databases (formerly known as CRDB) are geo-distributed databases that span multiple Redis Software clusters.
Active-Active databases depend on [multi-master replication](https://en.wikipedia.org/wiki/Multi-master_replication) and [conflict-free
replicated data types (CRDTs)](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) to power a simple development experience
for geo-distributed applications. Active-Active databases allow developers to use existing
Redis data types and commands, but automatically handle conflicting concurrent writes to the same key
across multiple geographies. For example, developers can simply use the
`INCR` or `INCRBY` method in Redis in all instances of the geo-distributed
application, and Active-Active databases handle the additive nature of `INCR` to reflect the
correct final value.

The following example displays a sequence of events
over time: t1 to t9. This Active-Active database has two member Active-Active databases: member CRDB1 and
member CRDB2. The local operations running in each member Active-Active database are
listed under the member Active-Active database name. The sync events represent the moment
when synchronization catches up to distribute all local member Active-Active database
updates to other participating clusters and other member Active-Active databases.

|  **Time** | **Member CRDB1** | **Member CRDB2** |
|  :------: | :------: | :------: |
|  t1 | INCRBY key1 7 |  |
|  t2 |  | INCRBY key1 3 |
|  t3 | GET key1
7 | GET key1
3 |
|  t4 | — Sync — | — Sync — |
|  t5 | GET key1
10 | GET key1
10 |
|  t6 | DECRBY key1 3 |  |
|  t7 |  | INCRBY key1 6 |
|  t8 | — Sync — | — Sync — |
|  t9 | GET key1
13 | GET key1
13 |

Databases provide various approaches to address some of these concerns:

- **Active-Passive geo-distributed deployments**: With active-passive
    distributions, all writes go to an active cluster. Redis Sofware
    provides a [Replica Of]() capability that provides a similar approach.
    This can be employed when the workload is heavily balanced toward
    reads and few writes. However, WAN performance and availability
    can be unreliable, and traveling large distances for writes takes away
    from application performance and availability.
- **Two-phase commit (2PC)**: This approach is designed around a protocol
    that commits a transaction across multiple transaction managers.
    Two-phase commit provides a consistent transactional write across
    regions but fails transactions unless all participating transaction
    managers are available at the time of the transaction. The number
    of messages exchanged and its cross-regional availability
    requirement make two-phase commit unsuitable for even moderate
    throughputs and cross-geo writes that go over WANs.
- **Sync update with quorum-based writes**: This approach synchronously
    coordinates a write across the majority of replicas across
    clusters spanning multiple regions. However, just like two-phase
    commit, the number of messages exchanged and its cross-regional
    availability requirement make geo-distributed quorum writes
    unsuitable for moderate throughputs and cross-geo writes that go
    over WANs.
- **Last-Writer-Wins (LWW) conflict resolution**: Some systems provide
    simplistic conflict resolution for all types of writes where
    system clocks are used to determine the winner across conflicting
    writes. LWW is lightweight and can be suitable for simpler data.
    However, LWW can be destructive to updates that are not necessarily
    conflicting. For example, adding a new element to a set across two
    geographies concurrently would result in only one of these new
    elements appearing in the final result with LWW.
- **MVCC (multi-version concurrency control)**: MVCC systems maintain
    multiple versions of data and may expose ways for applications to
    resolve conflicts. Even though an MVCC system can provide a flexible
    way to resolve conflicting writes, it comes at the cost of great
    complexity in the development of a solution.

Even though types and commands in Active-Active databases look identical to standard Redis
types and commands, the underlying types in Redis Software are enhanced to maintain
more metadata to create the conflict-free data type experience. This
section explains what you need to know about developing with Active-Active databases on
Redis Software.

Lua scripts

Active-Active databases support Lua scripts, but unlike standard Redis, Lua scripts always
execute in effects replication mode. There is currently no way to
execute them in script-replication mode.

Eviction

The default policy for Active-Active databases is _noeviction_ mode. Redis Software version 6.0.20 and later support all eviction policies for Active-Active databases, unless [Redis Flex or Auto Tiering]() (previously known as Redis on Flash) is enabled.

For details, see [eviction for Active-Active databases (Redis Software)]() or [eviction for Active-Active databases (Redis Cloud)]().

Expiration

Expiration is supported with special multi-master semantics.

If a key's expiration time is changed at the same time on different
members of the Active-Active database, the longer extended time set via TTL on a key is
preserved.

If this command was performed on key1 on cluster #1:

[code example]

If this command was performed on key1 on cluster #2:

[code example]

The `EXPIRE` command setting the key to 50 would win.

And if this command was performed on key1 on cluster #3:

[code example]

It would win out of the three clusters hosting the Active-Active database as it sets the
TTL on key1 to an infinite time.

The replica responsible for the winning expire value is also
responsible for expiring the key and propagating a DEL effect when this
happens. From this point on, a losing replica is not responsible
for expiring the key, unless another `EXPIRE` command resets the TTL.
Furthermore, a replica that is not the owner of the expired value:

- Silently ignores the key if a user attempts to access it in READ
    mode, for example, treating it as if it was expired but not propagating a
    DEL.
- Expires it (sending a DEL) before making any modifications if a user
    attempts to access it in WRITE mode.

Expiration values are in the range of [0, 2^49] for Active-Active databases and [0, 2^64] for regular databases.

Tombstones

For conflict resolution purposes, Active-Active databases cannot immediately release a deleted key. Instead, the key is logically deleted but remains in memory as a tombstone until the garbage collector can safely remove it.

When a deleted key becomes a tombstone, it frees some memory previously consumed by the key. The size of each tombstone varies depending on the data type and the key's history.

The garbage collector automatically removes a tombstone when all instances in the Active-Active database have observed the deletion operation.

To monitor tombstones, you can use shard-level metrics exposed by [`INFO crdt`](#info) and Grafana.

Out-of-Memory (OOM) {#outofmemory-oom}

If a member Active-Active database is out of memory, that member is marked as
"inconsistent", the member stops responding to user traffic, and
the syncer initiates full reconciliation with other peers in the Active-Active database.

Active-Active database key counts

Keys are counted differently for Active-Active databases:

- DBSIZE (in `shard-cli dbsize`) reports key header instances
    that represent multiple potential values of a key before a replication conflict is resolved.
- expired_keys (in `bdb-cli info`) can be more than the keys count in DBSIZE (in `shard-cli dbsize`)
    because expires are not always removed when a key becomes a tombstone.
- The Expires average TTL (in `bdb-cli info`) is computed for local expires only.

INFO

The `INFO` command has an additional CRDT section that provides advanced troubleshooting information:

|  **Section** | **Field** | **Description** |
|  ------ | ------ | ------ |
|  **CRDT Context** | crdt_config_version | Current Active-Active database configuration version. |
|   | crdt_slots | Hash slots assigned and reported by this shard. |
|   | crdt_replid | Unique replica/shard IDs. |
|   | crdt_clock | Clock value of local vector clock. |
|   | crdt_ovc | Locally observed Active-Active database vector clock. |
|  **Peers** | | A list of currently connected peer replication peers. This is similar to the replicas list reported by Redis. |
|  **Backlogs** | | A list of peer replication backlogs currently maintained. Typically in a full mesh topology, only a single backlog is used for all peers, as the requested IDs are identical. |
|  **CRDT Stats** | crdt_sync_full | Number of inbound full synchronization processes performed. |
|   | crdt_sync_partial_ok | Number of partial (backlog based) re-synchronization processes performed. |
|   | crdt_sync_partial-err | Number of partial re-synchronization processes failed due to exhausted backlog. |
|   | crdt_merge_reqs | Number of inbound merge requests processed. |
|   | crdt_effect_reqs | Number of inbound effect requests processed. |
|   | crdt_ovc_filtered_effect_reqs | Number of inbound effect requests filtered due to old vector clock. |
|   | crdt_gc_pending | Number of elements pending garbage collection. |
|   | crdt_gc_attempted | Number of attempts to garbage collect tombstones. |
|   | crdt_gc_collected | Number of tombstones garbage collected successfully. |
|   | crdt_gc_gvc_min | The minimal globally observed vector clock, as computed locally from all received observed clocks. |
|   | crdt_stale_released_with_merge | Indicates the last stale flag transition was a result of a complete full sync. |
|  **CRDT Replicas** | | A list of crdt_replica \<uid> entries, each describes the known state of a remote instance with the following fields: |
|   | config_version | Last configuration version reported. |
|   | shards | Number of shards. |
|   | slots | Total number of hash slots. |
|   | slot_coverage | A flag indicating remote shards provide full coverage (all shards are alive). |
|   | max_ops_lag | Number of local operations not yet observed by the least updated remote shard. |
|   | min_ops_lag | Number of local operations not yet observed by the most updated remote shard. |


Active-Active Redis applications

Summary: General information to keep in mind while developing applications for an Active-Active database.

Data types for Active-Active databases

Overview

Developing globally distributed applications can be challenging, as
developers have to think about race conditions and complex combinations
of events under geo-failovers and cross-region write conflicts. In Redis Cloud, Active-Active databases
simplify developing such applications by directly using built-in smarts
for handling conflicting writes based on the data type in use. Instead
of depending on just simplistic "last-writer-wins" type conflict
resolution, geo-distributed Active-Active databases combine techniques defined in CRDT
(conflict-free replicated data types) research with Redis types to
provide smart and automatic conflict resolution based on the data type's
intent.

An Active-Active database is a globally distributed database that spans multiple cloud provider regions. Each Active-Active database can have many Active-Active database instances
that come with added smarts for handling globally distributed writes
using the proven
[CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
approach.
[CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
research describes a set of techniques for creating systems that can
handle conflicting writes. CRDBs powered by Multi-Master Replication
(MMR) provide a straightforward and effective way to replicate your
data between regions and simplify development of complex applications
that can maintain correctness under geo-failovers and concurrent
cross-region writes to the same data.

Active-Active databases replicate data between multiple Redis Cloud provider regions. Common uses for Active-Active databases include disaster recovery,
geographically redundant applications, and keeping data closer to your
users' locations. MMR is always multi-directional amongst the regions
configured in the Active-Active database. For unidirectional replication, see [Active-Passive replication]().

Example of synchronization

[Learn more about
synchronization for
each supported data type]() and [how to develop applications]() with them on Redis Cloud.


Active-Active Redis

Summary: Overview of the Active-Active feature for Redis Cloud.

Create an Active-Active database

Summary: Learn how to add and edit regions for an Active-Active deployment.

Manage regions in Active-Active databases

Active-Active Redis applications

Overview

Active-Active databases store data across multiple regions and availability zones.  This improves scalability, performance, and availability, especially when compared to standalone databases.

To create Active-Active databases, you need a Redis Cloud Pro subscription that enables Active-Active Redis and defines the regions for each copy of your databases. See [Create an Active-Active database]() for instructions.

Active-Active databases are distributed across multiple regions (geo-distribution).  This improves performance by reducing latency for nearby users and improves availability by protecting against data loss in case of network or resource failure.

Active-Active databases allow read and write operations in each copy.  Each copy eventually reflects changes made in other copies ([eventual consistency]()).  Conflict-free replicated data types (CRDTs) synchronize read and write operations between copies.  CRDTs ensure consistency and resolve conflicts.

Active-Active databases use TLS to synchronize data between regions.  You can also use TLS to encrypt client connections.  See [Transport Layer Security (TLS)]() for more information.

When developing for Active-Active databases, you need to consider some important differences. See [Develop applications with Active-Active databases]() for related information.

Active-Active subscriptions on Redis Cloud are limited to a maximum of 10 regions and 10 databases.

Active-Active geo-distributed replication highlights

Multi-zone

Geo-distributed replication maintains copies of both primary and replica shards in multiple clusters. These clusters can be spread across multiple availability zones. Active-Active Redis uses zone awareness to spread your primary and replica shards across zones, which helps protect against data loss from regional outages.

Local latency with unique endpoints

Applications can connect to a specific copy of an Active-Active database using its unique endpoint. For local latency, configure your application to use a database endpoint in the closest region.

Conflict resolution

Active-Active databases use special data types called conflict-free replicated data types (CRDT). These automatically resolve conflicts that occur when writes are made to different clusters at the same time.

Failover handling

After a failure at the process, node, or zone level, Active-Active databases automatically promote replica shards to replace failed primaries, copy data to new replica shards, and migrate shards to new nodes as needed. This reduces downtime and makes the most of your computing resources, even in the event of a failure.

However, Active-Active databases do not have a built-in [failover](https://en.wikipedia.org/wiki/Failover) or failback mechanism for application connections. To handle cluster-level failures, you should implement one of the following disaster recovery strategies to redirect traffic between regions:

- [Network-based](): Global traffic managers and load balancers for routing.

- [Proxy-based](): Software proxies handle detection and routing logic.

- [Client library-based](): Database client libraries with built-in failover logic.

- [Application-based](): Custom application-level monitoring and connectivity management.

For more information and guidance on which disaster recovery strategy to implement, see [Disaster recovery strategies for Active-Active databases]().

Data automatically syncs to a recovered cluster when it returns to a healthy state.


Overview

You can add and edit regions for an Active-Active deployment after it has been created by going to the **Regions** tab of the [subscription page]().

Add a new region

To add a new region to an Active-Active deployment:

1. In the **Regions** tab of the subscription page, select **Add region**.

1. In the **Region setup** step:

    1. Select the desired region from the **Region** list.

    1. If you chose to deploy your Active-Active database to an existing [Bring your own Cloud]() account, you can define the VPC ID for the new region. Select **In existing VPC** and the set the VPC ID for the region.

    1. Enter a unique CIDR address for the region.

    Select **Continue**.

1. In the **Throughput** step, enter the desired read and write throughput for the new region.

    You can also select **Set throughput as existing region** to duplicate the throughput settings from an existing region.

1. Review the required resources and updated price for the database in the **Required resources** step.

1. Select **Continue** to add the region to your Active-Active deployment.

Redis Cloud will provision the new region in the background and add it to all databases in the subscription. You aren't allowed to make changes to the database settings while this process is running.

Your database will still be available, but you may notice some increased latency. This process will take some time depending on the size of your database.

Edit regions

To edit the local throughput settings for a database instance or remove a region from the deployment, select **Edit regions** in the **Regions** tab of the subscription page.

From here, you can:

- [Edit local throughput](#edit-local-throughput) for a database instance
- [Remove a region](#remove-region) from the subscription

After making the desired changes, [save and confirm the changes](#save-and-confirm-changes).

Edit local throughput

To edit the local throughput settings for a database instance:

1. Select the region you want to edit.

1. Add or reduce the local read and write throughput for each database in that region in the **Local reads ops/sec** and **Local writes ops/sec** fields.

Remove region

To remove a region from an Active-Active deployment, select the **Delete** button for the region you want to remove.

Save and confirm changes

After making your changes, select **Save changes** to apply them. You'll need to review and confirm the changes and any updated costs before they are applied. Select **Confirm** to apply the changes.

Redis Cloud will make the desired changes in the background. You aren't allowed to make changes to the database settings while this process is running.

Your databases will still be available, but you may notice some increased latency. This process will take some time depending on the size of your database.