Lettuce 指南

将您的 Lettuce 应用程序连接到 Redis 数据库

Lettuce 是 Redis 的异步 Java 客户端。如果您需要同步 Java 客户端,请使用 Jedis。以下部分解释了如何安装 Lettuce 并将您的应用程序连接到 Redis 数据库。

Lettuce 需要一个正在运行的 Redis 或 Redis Stack 服务器。有关 Redis 安装说明,请参见 入门

安装

要将 Lettuce 作为依赖项包含在您的应用程序中,请按如下所示编辑相应的依赖项文件。

如果您使用 Maven,请将以下依赖项添加到您的 pom.xml

<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.3.2.RELEASE</version> <!-- Check for the latest version on Maven Central -->
</dependency>

如果您使用 Gradle,请将此行包含在您的 build.gradle 文件中

dependencies {
    compileOnly 'io.lettuce:lettuce-core:6.3.2.RELEASE'
}

如果您希望直接使用 JAR 文件,请从 Maven Central 或任何其他 Maven 存储库下载最新的 Lettuce 和(可选)Apache Commons Pool2 JAR 文件。

要从源代码构建,请参见 Lettuce 源代码 GitHub 存储库 上的说明。

连接

首先创建到您的 Redis 服务器的连接。使用 Lettuce 可以通过多种方式实现这一点。以下是一些方法。

异步连接

package org.example;
import java.util.*;
import java.util.concurrent.ExecutionException;

import io.lettuce.core.*;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.StatefulRedisConnection;

public class Async {
  public static void main(String[] args) {
    RedisClient redisClient = RedisClient.create("redis://localhost:6379");

    try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
      RedisAsyncCommands<String, String> asyncCommands = connection.async();

      // Asynchronously store & retrieve a simple string
      asyncCommands.set("foo", "bar").get();
      System.out.println(asyncCommands.get("foo").get()); // prints bar

      // Asynchronously store key-value pairs in a hash directly
      Map<String, String> hash = new HashMap<>();
      hash.put("name", "John");
      hash.put("surname", "Smith");
      hash.put("company", "Redis");
      hash.put("age", "29");
      asyncCommands.hset("user-session:123", hash).get();

      System.out.println(asyncCommands.hgetall("user-session:123").get());
      // Prints: {name=John, surname=Smith, company=Redis, age=29}
    } catch (ExecutionException | InterruptedException e) {
      throw new RuntimeException(e);
    } finally {
      redisClient.shutdown();
    }
  }
}

参考指南 中了解有关异步 Lettuce API 的更多信息。

响应式连接

package org.example;
import java.util.*;
import io.lettuce.core.*;
import io.lettuce.core.api.reactive.RedisReactiveCommands;
import io.lettuce.core.api.StatefulRedisConnection;

public class Main {
  public static void main(String[] args) {
    RedisClient redisClient = RedisClient.create("redis://localhost:6379");

    try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
      RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();

      // Reactively store & retrieve a simple string
      reactiveCommands.set("foo", "bar").block();
      reactiveCommands.get("foo").doOnNext(System.out::println).block(); // prints bar

      // Reactively store key-value pairs in a hash directly
      Map<String, String> hash = new HashMap<>();
      hash.put("name", "John");
      hash.put("surname", "Smith");
      hash.put("company", "Redis");
      hash.put("age", "29");

      reactiveCommands.hset("user-session:124", hash).then(
              reactiveCommands.hgetall("user-session:124")
                  .collectMap(KeyValue::getKey, KeyValue::getValue).doOnNext(System.out::println))
          .block();
      // Prints: {surname=Smith, name=John, company=Redis, age=29}

    } finally {
      redisClient.shutdown();
    }
  }
}

参考指南 中了解有关响应式 Lettuce API 的更多信息。

Redis 集群连接

import io.lettuce.core.RedisURI;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands;

// ...

RedisURI redisUri = RedisURI.Builder.redis("localhost").withPassword("authentication").build();

RedisClusterClient clusterClient = RedisClusterClient.create(redisUri);
StatefulRedisClusterConnection<String, String> connection = clusterClient.connect();
RedisAdvancedClusterAsyncCommands<String, String> commands = connection.async();

// ...

connection.close();
clusterClient.shutdown();

TLS 连接

部署应用程序时,请使用 TLS 并遵循Redis 安全指南

RedisURI redisUri = RedisURI.Builder.redis("localhost")
                                 .withSsl(true)
                                 .withPassword("secret!") // use your Redis password
                                 .build();

RedisClient client = RedisClient.create(redisUri);

Lettuce 中的连接管理

Lettuce 使用ClientResources 来有效地管理共享资源,例如事件循环组和线程池。对于连接池,Lettuce 利用RedisClientRedisClusterClient,可以有效地处理多个并发连接。

超时

Lettuce 为许多操作提供超时,例如命令执行、SSL 握手和哨兵发现。默认情况下,Lettuce 对这些操作使用 60 秒的全局超时值,但您可以使用每个操作的单独超时值来覆盖全局超时值。

提示
选择合适的超时值对于应用程序的性能和稳定性至关重要,并且针对每个环境。仅当您遇到默认值的有关问题时,才需要配置超时。在某些情况下,默认值基于特定于环境的设置(例如,操作系统设置),而在其他情况下,它们内置于 Lettuce 驱动程序中。有关设置特定超时的更多详细信息,请参阅Lettuce 参考指南

以下是设置套接字级超时的示例。TCP_USER_TIMEOUT 设置适用于服务器停止响应而不确认最后一个请求的情况,而KEEPALIVE 设置适用于检测客户端和服务器之间没有流量的死连接。

RedisURI redisURI = RedisURI.Builder
        .redis("localhost")
        // set the global default from the default 60 seconds to 30 seconds
        .withTimeout(Duration.ofSeconds(30)) 
        .build();

try (RedisClient client = RedisClient.create(redisURI)) {
    // or set specific timeouts for things such as the TCP_USER_TIMEOUT and TCP_KEEPALIVE

    // A good general rule of thumb is to follow the rule
    // TCP_USER_TIMEOUT = TCP_KEEP_IDLE+TCP_KEEPINTVL * TCP_KEEPCNT
    // in this case, 20 = 5 + 5 * 3

    SocketOptions.TcpUserTimeoutOptions tcpUserTimeout = SocketOptions.TcpUserTimeoutOptions.builder()
            .tcpUserTimeout(Duration.ofSeconds(20))
            .enable().build();

    SocketOptions.KeepAliveOptions keepAliveOptions = SocketOptions.KeepAliveOptions.builder()
            .interval(Duration.ofSeconds(5))
            .idle(Duration.ofSeconds(5))
            .count(3).enable().build();

    SocketOptions socketOptions = SocketOptions.builder()
            .tcpUserTimeout(tcpUserTimeout)
            .keepAlive(keepAliveOptions)
            .build();

    client.setOptions(ClientOptions.builder()
            .socketOptions(socketOptions)
            .build());

    StatefulRedisConnection<String, String> connection = client.connect();
    System.out.println(connection.sync().ping());
}

连接池

使用 Lettuce 的典型方法是创建一个RedisClient 实例并重用它来建立与 Redis 服务器的连接。这些连接是多路复用的;也就是说,可以同时在单个或一组小连接上运行多个命令,这使得显式池不太实用。

Lettuce 提供了要与 Lettuce 异步连接方法一起使用的池配置。

package org.example;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.TransactionResult;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.codec.StringCodec;
import io.lettuce.core.support.*;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

public class Pool {
  public static void main(String[] args) {
    RedisClient client = RedisClient.create();

    String host = "localhost";
    int port = 6379;

    CompletionStage<BoundedAsyncPool<StatefulRedisConnection<String, String>>> poolFuture
        = AsyncConnectionPoolSupport.createBoundedObjectPoolAsync(
            () -> client.connectAsync(StringCodec.UTF8, RedisURI.create(host, port)),
            BoundedPoolConfig.create());

    // await poolFuture initialization to avoid NoSuchElementException: Pool exhausted when starting your application
    AsyncPool<StatefulRedisConnection<String, String>> pool = poolFuture.toCompletableFuture()
        .join();

    // execute work
    CompletableFuture<TransactionResult> transactionResult = pool.acquire()
        .thenCompose(connection -> {

          RedisAsyncCommands<String, String> async = connection.async();

          async.multi();
          async.set("key", "value");
          async.set("key2", "value2");
          System.out.println("Executed commands in pipeline");
          return async.exec().whenComplete((s, throwable) -> pool.release(connection));
        });
    transactionResult.join();

    // terminating
    pool.closeAsync();

    // after pool completion
    client.shutdownAsync();
  }
}

在此设置中,LettuceConnectionFactory 是您需要实现的自定义类,它遵循 Apache Commons Pool 的PooledObjectFactory 接口,以管理池化StatefulRedisConnection 对象的生命周期事件。

DNS 缓存和 Redis

当您连接到具有多个端点(例如 Redis Enterprise Active-Active)的 Redis 数据库时,建议禁用 JVM 的 DNS 缓存以在多个端点之间负载均衡请求。

您可以在应用程序的代码中使用以下代码段来实现这一点

java.security.Security.setProperty("networkaddress.cache.ttl","0");
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "0");

了解更多

RATE THIS PAGE
Back to top ↑