

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用只读副本的最佳实践
<a name="ReadReplicas"></a>

许多应用程序（例如会话存储、排行榜和推荐引擎）都需要高可用性，且处理的读取操作要远多于写入操作。这类应用程序通常可以容忍稍微陈旧的数据（最终一致性），意味着如果不同用户在短时间内看到相同数据的不同版本，这是可以接受的。例如：
+ 缓存的查询结果通常可以容忍稍微陈旧的数据，特别是对于可信来源位于外部的旁路缓存模式。
+ 在游戏排行榜中，分数更新延迟几秒钟通常不会对用户体验产生重大影响。
+ 对于会话存储，跨副本传播会话数据时出现一些轻微延迟通常不会影响应用程序的功能。
+ 推荐引擎通常使用历史数据分析，因此对实时一致性要求较低。

最终一致性意味着在复制过程完成后，所有副本节点最终都将返回相同的数据，且通常在毫秒内完成。对于此类用例，实现只读副本是减少从 ElastiCache实例读取时延迟的有效策略。

在 Amazon 中使用只读副本 ElastiCache 可通过以下方式显著提高性能：

**增强的读取可扩展性**
+ 将读取操作分配到多个副本节点
+ 从主节点卸载读取流量
+ 通过处理来自地理位置较近的副本的请求来降低读取延迟

**优化的主节点性能**
+ 将主节点资源专门用于写入操作
+ 减少主节点连接开销
+ 提高写入性能，并在流量高峰期保持较短的响应时间

## 在 ElastiCache 无服务器中使用从副本读取
<a name="ReadReplicas.serverless"></a>

ElastiCache serverless 为不同的一致性要求提供了两个不同的端点。这两个端点使用相同的 DNS 名称，但采用不同的端口。要使用该 read-from-replica端口，您必须通过[配置您的 VPC 的安全组和网络访问控制列表来授权从您的客户端应用程序访问](set-up.md#elasticache-install-grant-access-VPN)这两个端口。

**主端点（端口 6379）**
+ 用于需要即时一致性的操作
+ 保证读取最多的 up-to-date数据
+ 最适合关键事务和写入操作
+ 对于写入操作是必需的
+ 示例：`test-12345.serverless.use1.cache.amazonaws.com:6379`

**针对延迟进行了优化的端点（端口 6380）**
+ 针对可容忍最终一致性的读取操作进行了优化
+ 如果可能， ElastiCache Serverless 会自动将读取请求路由到客户端本地可用区中的副本节点。这种优化避免了从不同可用区的节点检索数据时产生的额外网络延迟，从而降低了整体延迟。
+ ElastiCache 如果本地节点不可用，serverless 会自动选择其他区域中的可用节点
+ 示例：`test-12345.serverless.use1.cache.amazonaws.com:6380`
+ 如果您提供“从副本读取”配置，Glide 和 Lettuce 等客户端将自动检测读取操作，并将其路由至针对延迟进行了优化的端点。如果您的客户端不支持路由配置（例如 valkey-java 和旧版 jedis），则必须定义正确的端口和客户端配置才能从副本读取。

## 在 ElastiCache Serverless 中连接到只读副本-Valkey 和 Glide
<a name="ReadReplicas.connecting-primary"></a>

以下代码片段显示了如何在 Valkey glide 库中为 ElastiCache Serverless 配置从副本读取。您无需为“从副本读取”指定端口，但需要配置路由配置 `ReadFrom.PREFER_REPLICA`。

```
package glide.examples;

import glide.api.GlideClusterClient;
import glide.api.logging.Logger;
import glide.api.models.configuration.GlideClusterClientConfiguration;
import glide.api.models.configuration.NodeAddress;
import glide.api.models.exceptions.ClosingException;
import glide.api.models.exceptions.ConnectionException;
import glide.api.models.exceptions.TimeoutException;
import glide.api.models.configuration.ReadFrom;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class ClusterExample {

    public static void main(String[] args) {
        // Set logger configuration
        Logger.setLoggerConfig(Logger.Level.INFO);

        GlideClusterClient client = null;

        try {
            System.out.println("Connecting to Valkey Glide...");

            // Configure the Glide Client
            GlideClusterClientConfiguration config = GlideClusterClientConfiguration.builder()
                .address(NodeAddress.builder()
                    .host("your-endpoint")
                    .port(6379)
                    .build())
                .useTLS(true)
                .readFrom(ReadFrom.PREFER_REPLICA)
                .build();

            // Create the GlideClusterClient
            client = GlideClusterClient.createClient(config).get();
            System.out.println("Connected successfully.");

            // Perform SET operation
            CompletableFuture<String> setResponse = client.set("key", "value");
            System.out.println("Set key 'key' to 'value': " + setResponse.get());

            // Perform GET operation
            CompletableFuture<String> getResponse = client.get("key");
            System.out.println("Get response for 'key': " + getResponse.get());

            // Perform PING operation
            CompletableFuture<String> pingResponse = client.ping();
            System.out.println("PING response: " + pingResponse.get());

        } catch (ClosingException | ConnectionException | TimeoutException | ExecutionException e) {
            System.err.println("An exception occurred: ");
            e.printStackTrace();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // Close the client connection
            if (client != null) {
                try {
                    client.close();
                    System.out.println("Client connection closed.");
                } catch (ClosingException | ExecutionException e) {
                    System.err.println("Error closing client: " + e.getMessage());
                }
            }
        }
    }
}
```