Databases 17 min read

Why Lettuce Beats Jedis: Async Redis Client Deep Dive for High‑Performance Caching

This article explains why the Lettuce asynchronous Redis client, built on Netty, outperforms the traditional Jedis client for high‑concurrency caching, covering Redis client differences, Netty NIO fundamentals, Redis Cluster architecture, smart client redirection handling, and practical Java code examples.

JD Cloud Developers
JD Cloud Developers
JD Cloud Developers
Why Lettuce Beats Jedis: Async Redis Client Deep Dive for High‑Performance Caching

1. Redis Clients

To support broader business scenarios, a visual orchestration system needs asynchronous cache operations; therefore an async Redis client is considered.

Jedis/Lettuce

Redis officially recommends clients such as Jedis and Lettuce. Jedis is the classic Java implementation, providing comprehensive command support and is the default in Spring Boot 1.x. However, Jedis uses blocking I/O, synchronous calls, and its instances are not thread‑safe, requiring a connection pool that can become a performance bottleneck under high concurrency.

In Spring Boot 2.x the default client switched to Lettuce because it offers non‑blocking, asynchronous operations.

Jedis vs Lettuce comparison
Jedis vs Lettuce comparison

Asynchronous Client Lettuce

Since Spring Boot 2.0, Lettuce is the default Redis client. It is built on Netty’s NIO framework, allowing a single connection to efficiently handle many concurrent requests, unlike Jedis’s connection‑pool model. Lettuce also supports a richer feature set and often matches or exceeds Jedis performance.

Netty, an open‑source Java framework, provides an asynchronous, event‑driven network programming model. Its core concepts include Channel (connection), EventLoop (single‑threaded event processor), and non‑blocking I/O, which together give NIO its performance advantage over traditional blocking I/O.

Netty NIO core logic
Netty NIO core logic

Lettuce leverages a single EventLoop thread, a FIFO command queue, and Redis’s own NIO server model, ensuring ordered processing. Combined with TCP’s guaranteed order, Lettuce naturally uses pipelining , allowing multiple commands to be sent without waiting for each response, which greatly improves throughput compared to Jedis’s sequential request handling.

Lettuce pipelining
Lettuce pipelining

2. Redis Cluster Mode

Before Redis 3.0, building a cluster was complex. Redis Cluster introduces sharding, high availability, read/write separation, and true distributed storage.

Cluster nodes communicate via a gossip protocol, exchanging metadata. Unlike centralized coordination services (e.g., Zookeeper), Redis Cluster’s metadata is distributed, enhancing fault tolerance.

Each node typically opens two ports: one for client API (e.g., 6379) and another (port+10000) for gossip communication.

The gossip protocol includes messages such as meet , ping , pong , and fail , which manage node discovery, health checks, and failure detection.

Data is addressed using 16,384 hash slots. When a new node joins, slots are rebalanced without blocking the master process, minimizing performance impact.

Redis Cluster hash slots
Redis Cluster hash slots

High availability is achieved through subjective and objective fail detection, followed by master‑slave election. The election selects a slave with the highest replication offset to become the new master.

3. Using Lettuce with Redis Cluster

Establishing a Connection

Lettuce usage follows three steps:

Create a RedisClient (or RedisClusterClient) from connection information.

Obtain a StatefulRedisConnection (or StatefulRedisClusterConnection).

Retrieve a command interface from the connection and execute Redis commands.

Lettuce supports reactive, synchronous, and asynchronous command APIs; the async API is used in the example below.

List<RedisURI> servers = new ArrayList<>();
servers.add(RedisURI.create("127.0.0.1", 7000));
servers.add(RedisURI.create("127.0.0.1", 7001));
servers.add(RedisURI.create("127.0.0.1", 7002));
servers.add(RedisURI.create("127.0.0.1", 7003));
servers.add(RedisURI.create("127.0.0.1", 7004));
servers.add(RedisURI.create("127.0.0.1", 7005));

RedisClusterClient client = RedisClusterClient.create(servers);
StatefulRedisClusterConnection<String, String> connection = client.connect();
RedisAdvancedClusterAsyncCommands<String, String> commands = connection.async();
RedisFuture<String> future = commands.get("test-lettuce-key");
try {
    String result = future.get();
    log.info("Get command returned: {}", result);
} catch (Exception e) {
    log.error("Get command execution failed", e);
}

The log shows the request was routed to node 7004 and the value was retrieved successfully.

Lettuce GET result
Lettuce GET result

Smart Client Features

During cluster topology changes (expansion, node failure, slot migration), a smart client maintains a local hash‑slot‑to‑node map. Both Jedis and Lettuce are smart clients. When a MOVED error is received, the client updates its map and retries the command on the new node.

When an ASK error occurs during online slot migration, the client sends an ASKING command to the target node without updating the map, then executes the original command.

Node failures trigger master‑slave election; after a failover, the client must refresh its topology. Jedis automatically pulls the new topology, while Lettuce requires explicit configuration.

Enabling adaptive topology refresh in Lettuce:

ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
    .enableAllAdaptiveRefreshTriggers()
    .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30))
    .build();

redisClusterClient.setOptions(ClusterClientOptions.builder()
    .topologyRefreshOptions(topologyRefreshOptions)
    .timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(30)))
    .build());

With this setting, Lettuce recovers connections shortly after a failover, allowing normal data access.

4. Summary

For cache operations, stable client‑cluster connections are essential to prevent data loss. Lettuce, as a popular asynchronous client, can handle many cluster‑related incidents, but proper configuration—especially topology refresh—is required to fully leverage its capabilities.

The article summarizes common issues encountered when developing cache‑related features and provides underlying knowledge to help developers use Lettuce effectively.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavarediscachingJedisClusterLettuce
JD Cloud Developers
Written by

JD Cloud Developers

JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.